Anton Krouglov
Anton Krouglov

Reputation: 3399

How to force implied PowerShell Format-Table to repeat headers for repeated output?

I am trying to repeat *nix watch functionality as provided by johnrizzo1 here.

function Watch {
    [CmdletBinding(SupportsShouldProcess=$True,ConfirmImpact='High')]
    param (
        [Parameter(Mandatory=$False,
                   ValueFromPipeline=$True,
                   ValueFromPipelineByPropertyName=$True)]
        [int]$n = 10,

        [Parameter(Mandatory=$True,
                   ValueFromPipeline=$True,
                   ValueFromPipelineByPropertyName=$True)]
        [string]$command
    )
    process {
        $cmd = [scriptblock]::Create($command);
        While($True) {
            Clear-Host;
            Write-Host "Command: " $command;
            $cmd.Invoke();
            sleep $n;
        }
    }
}

Export-ModuleMember -function Watch

watch -n 1 '$PSVersionTable.PSVersion'

The problem is that only 1st run displays headers. After that is looks ugly as headers are being stripped from output:

Command:  $PSVersionTable.PSVersion                                     
5      0      10586  117

By the way all other PS solutions to watch in the link above suffer from the same problem.

Upvotes: 0

Views: 817

Answers (3)

Scy Watcher
Scy Watcher

Reputation: 35

Try this - Pipe the command via the Format-Table -RepeatHeader parameter.

$cmd.Invoke() | Format-Table -RepeatHeader:$true

For my issue, I was clearing the screen between each PS command, Powershell would only present the table headers on the first run. The Format-Table -RepeatHeader Parameter is designed for when output fills an entire page and to re-present the table headers on each page. For my purposes, it worked when re-running same command in same script block after a Clear-Host command

function Watch {
[CmdletBinding(SupportsShouldProcess=$True,ConfirmImpact='High')]
param (
    [Parameter(Mandatory=$False,
               ValueFromPipeline=$True,
               ValueFromPipelineByPropertyName=$True)]
    [int]$n = 10,

    [Parameter(Mandatory=$True,
               ValueFromPipeline=$True,
               ValueFromPipelineByPropertyName=$True)]
    [string]$command
)
process {
    $cmd = [scriptblock]::Create($command)
    While($True) {
        Clear-Host
        Write-Host "Command: " $command
        $cmd.Invoke() | Format-Table -RepeatHeader:$true
        sleep $n
    }
}

}

watch -n 1 '$PSVersionTable.PSVersion'

Upvotes: 1

Shawn Esterman
Shawn Esterman

Reputation: 2342

This will work now, but your output is forced to be piped to Format-Table so it will always be in Table format.

function Watch {
    [CmdletBinding(SupportsShouldProcess=$True,ConfirmImpact='High')]
    param (
        [Parameter(Mandatory=$False,
                   ValueFromPipeline=$True,
                   ValueFromPipelineByPropertyName=$True)]
        [int]$n = 10,

        [Parameter(Mandatory=$True,
                   ValueFromPipeline=$True,
                   ValueFromPipelineByPropertyName=$True)]
        [string]$command
    )
    process {
        $cmd = [scriptblock]::Create($command)
        While($True) {
            Clear-Host
            Write-Host "Command: " $command
            $cmd.Invoke() | Format-Table -HideTableHeaders:$false
            sleep $n
        }
    }
}

watch -n 1 '$PSVersionTable.PSVersion'

Upvotes: 1

Lieven Keersmaekers
Lieven Keersmaekers

Reputation: 58441

Most likely this has other issues but simply changing

$cmd.invoke();

to

$cmd.invoke() | ft;

works for me

Upvotes: 1

Related Questions