PSH V1 Get-Tail
In PSH V2, Get-Content –Tail 10 –Wait will display the last 10 lines of a file, then poll it every second and display any additions to it. In PSH V1, Get-Content didn’t have a –Tail flag, so if you wanted to do the equivalent of the Unix tail(1), you’d have to let Get-Content scroll through the entire file. This was my workaround from those days, but it’s still handy to illustrate how to work with FileStreams and StreamReaders.
function Get-Tail {
param (
[string]$path = $null,
[int]$last = 10,
[int]$ms = 250,
[switch]$follow
);
$ErrorActionPreference = $stop;
try {
# validate input
if (!$path) { Write-Warning "-path not specified, required."; return; }
if (!(Test-Path $path)) { Write-Warning "Unable to find -path $path"; return; }
# create file stream
$fileStream = New-Object -ErrorAction SilentlyContinue -TypeName IO.FileStream -ArgumentList ((Get-Item $path).FullName), ([System.IO.FileMode]::Open), ([System.IO.FileAccess]::Read), ([System.IO.FileShare]::ReadWrite);
# create stream reader for file stream
$streamReader = New-Object -ErrorAction SilentlyContinue -TypeName System.IO.StreamReader -ArgumentList ($fileStream, [System.Text.Encoding]::ASCII, $true);
if (!$streamReader) { Write-Warning "Unable to open -path $path"; return; }
}
catch { Write-Warning "Insert error handling here"; }
$baseStream = $streamReader.BaseStream;
[long]$position = $baseStream.Length - 1;
$linesCounted = 0;
# go back -last number of lines;
while ($position -ge 0) {
$baseStream.Position = $position;
if ($baseStream.ReadByte() -eq 10) {
$linesCounted++;
if ($position -eq ($baseStream.Length - 1)) { $last++; }
if ($linesCounted -ge $last) { break; }
}
$position--;
}
# if -last number is greater than length of file, leave at start
if ($position -eq -1) { $null = $baseStream.Seek(0, [System.IO.SeekOrigin]::Begin); }
# read from -last number of lines to end of file
$null0 = [char]0;
while ($line = $streamReader.ReadLine()) {
if ($line -notmatch "^$null0$") { $line -replace $null0; }
}
# if -follow specified, sleep for -ms milliseconds, then attempt to read again.
while ($follow) {
Start-Sleep -Milliseconds $ms;
while ($line = $streamReader.ReadLine()) {
if ($line -and ($line -notmatch "^$null0$")) { $line -replace $null0; }
}
}
}