Watch-Command.psm1
function WriteHost { param( [parameter( position = 0, ValueFromPipeline )] [string] $Message, [ValidateSet('Default','Changed','Hilight')] $State = 'Default' ) begin { $drawWidth = $Host.UI.rawui.WindowSize.Width $backgroundColor = @{} switch($State) { 'Changed' { $backgroundColor['BackgroundColor'] = 'DarkGreen' } 'Hilight' { $backgroundColor['BackgroundColor'] = 'DarkCyan' } } } process { $foregroundColor = @{} Switch -regex ($Message) { '^ERROR:' { $foregroundColor['ForegroundColor'] = 'Red' $backgroundColor['BackgroundColor'] = 'Black' } } if($Message.Length -ge $drawWidth) { $Message = $Message.Substring(0,$drawWidth) } # Fill line with space so whole line gets color $formatted = "{0,-$drawWidth}" -f $Message Write-Host $formatted @foregroundColor @backgroundColor } } function Watch-Command { <# .Description Executes a command multiple times for monitoring results .Notes The output will be trimmed to to fit your console window, Supports resizing you have to force quit the function or it will keep running #> [Alias('Watch')] [cmdletbinding()] param ( # The command to execute each loop [Alias('Replay','Watch','Replay-Command')] [Parameter( Mandatory, Position = 0 )] [scriptblock] $ScriptBlock, # how long to delay between executions [Alias('Delay')] $Seconds = 5, [switch] $ShowChanges ) begin { Clear-Host } process { $previous = @() $ghost = @() while($true) { $output = @() $esc = [char]27 $setCursorTop = "$esc[0;0H" $hideCursor = "$esc[?25l" $showCursor = "$esc[?25h" $message = "{0:HH:mm:ss} Refresh {1}: {2,-60}" -f (Get-Date),$Seconds, $ScriptBlock.ToString() try { $errorOffset = $error.Count $output = [string[]]@(& $ScriptBlock *>&1 | Out-String -Stream) # First line is often blank so drop it if so if([string]::IsNullOrWhiteSpace($output[0])) { $output = [string[]]@($output | Select-Object -Skip 1) } } catch { $output = [string[]]@( # Skipping error[0] because it is our scriptblock.invoke() $error.RemoveAt(0) $startAt = ($error.count - $errorOffset) - 1 $error[$startAt..0] | Out-String -Stream | ForEach-Object{"ERROR:$_"} ) } Write-Host "$hideCursor${setCursorTop}" -NoNewline WriteHost "$message" -State Default # Need to leave room at the end so that we don't scroll console $drawArea = $Host.UI.rawui.WindowSize.Height - 2 for($index = 0; $index -lt $drawArea; $index++ ) { if($ShowChanges) { if($output[$index] -ne $previous[$index]) { WriteHost $output[$index] -State Changed } elseif($output[$index] -ne $ghost[$index]) { WriteHost $output[$index] -State Hilight } else { WriteHost $output[$index] } } else { WriteHost $output[$index] } } Write-Host $showCursor -NoNewline Start-Sleep -Seconds $Seconds $ghost = $previous $previous = $output } } } |