Watch-Command.ps1 – watch commands output repeatedly


Synopsis

The script executes a command repeatedly, collects the output and displays exactly one screen portion of it; out-of-screen lines and line ends are truncated. The script avoids screen blinking effect because normally it does not use Clear-Host, instead it refills the entire screen with fresh output. This is the good. The bad is that this approach may not work if a command itself operates on console output directly (e.g. uses *-Host).


Examples

# PowerShell commands:
Watch-Command {Get-Process}
Watch-Command {Get-Process | Format-Table Name, Id, WS, CPU, Description, Path -Auto}

# Native executable commands:
Watch-Command {netstat -e -s}
Watch-Command {cmd /c dir /a-d /o-d %temp%}

Watch-Command.ps1

##
## Author   : Roman Kuzmin
## Synopsis : Watch one screen of commands output repeatedly
## Modified : 2006.11.06
##
## -Command: script block which output is being watched
## -Seconds: refresh rate in seconds
##
## *) Commands should not operate on console.
## *) Tabs are simply replaced with spaces.
## *) * indicates truncated lines.
## *) Empty lines are removed.
## *) Ctrl-C to stop.
##

param([scriptblock]$Command_ = {Get-Process}, [int]$Seconds_ = 3)

$private:sb = New-Object System.Text.StringBuilder
$private:w0 = $private:h0 = 0
for(;;) {

    # invoke command, format output data
    $private:n = $sb.Length = 0
    $private:w = $Host.UI.RawUI.BufferSize.Width
    $private:h = $Host.UI.RawUI.WindowSize.Height-1
    [void]$sb.EnsureCapacity($w*$h)
    .{
        & $Command_ | Out-String -Stream | .{process{
            if ($_ -and ++$n -le $h) {
                $_ = $_.Replace("`t", ' ')
                if ($_.Length -gt $w) {
                    [void]$sb.Append($_.Substring(0, $w-1) + '*')
                }
                else {
                    [void]$sb.Append($_.PadRight($w))
                }
            }
        }}
    }>$null

    # fill screen
    if ($w0 -ne $w -or $h0 -ne $h) {
        $w0 = $w; $h0 = $h
        Clear-Host; $private:origin = $Host.UI.RawUI.CursorPosition
    }
    else {
        $Host.UI.RawUI.CursorPosition = $origin
    }
    Write-Host $sb -NoNewLine
    $private:cursor = $Host.UI.RawUI.CursorPosition
    if ($n -lt $h) {
        Write-Host (' '*($w*($h-$n)+1)) -NoNewLine
    }
    elseif($n -gt $h) {
        Write-Host '*' -NoNewLine
    }
    $Host.UI.RawUI.CursorPosition = $cursor
    Start-Sleep $Seconds_
}

Advertisements
  1. #1 by Lee on September 26, 2006 - 5:27 pm

    That is excellent.  I like how it uses the power of the script block.  You might also find this related post interesting: http://www.leeholmes.com/blog/AccessingPerformanceCountersInPowerShell.aspx

  2. #2 by Thomas G Mayfield on November 15, 2012 - 4:19 pm

    A newbie question: How do I include this in my PowerShell profile? If I just:
    . “Watch-Command.ps1”
    then it executes as it’s not in a function block.

  3. #3 by Roman Kuzmin on November 17, 2012 - 6:53 am

    I would include this script in my profile simply as an alias, e.g. “Set-Alias wcm [Path\]Watch-Command.ps1”. Then call it as “wcm”. The Path can be omitted if the script is in the system path. Still, if you want to have it included as a function then wrap the whole script text as “function wcm { the original text }”. Then you can dot-source the script in your profile and this function “wcm” will be available for use.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: