Search code examples
powershellwrite-hostswitch-parameter

PowerShell switch parameter doesn't work as expected


I have the following PowerShell function to help me do benchmarks. The idea is that you provide the command and a number and the function will run the code that number of times. After that the function will report the testing result, such as Min, Max and Average time taken.

function Measure-MyCommand()
{
    [CmdletBinding()]
    Param (
        [Parameter(Mandatory = $True)] [scriptblock] $ScriptBlock,
        [Parameter()] [int] $Count = 1,
        [Parameter()] [switch] $ShowOutput
    )

    $time_elapsed = @();
    while($Count -ge 1) {
        $timer = New-Object 'Diagnostics.Stopwatch';
        $timer.Start();
        $temp = & $ScriptBlock;
        if($ShowOutput) {
            Write-Output $temp;
        }
        $timer.Stop();
        $time_elapsed += $timer.Elapsed;
        $Count--;
    }

    $stats = $time_elapsed | Measure-Object -Average -Minimum -Maximum -Property Ticks;

    Write-Host "Min: $((New-Object 'System.TimeSpan' $stats.Minimum).TotalMilliseconds) ms";
    Write-Host "Max: $((New-Object 'System.TimeSpan' $stats.Maximum).TotalMilliseconds) ms";
    Write-Host "Avg: $((New-Object 'System.TimeSpan' $stats.Average).TotalMilliseconds) ms";
}

The problem is with the switch parameter $ShowOutput. As I understand, when you provide a switch parameter, its value is true. Otherwise it's false. However it doesn't seem to work. See my testing.

PS C:\> Measure-MyCommand -ScriptBlock {Write-Host "f"} -Count 3 -ShowOutput
f
f
f
Min: 0.4935 ms
Max: 0.8392 ms
Avg: 0.6115 ms
PS C:\> Measure-MyCommand -ScriptBlock {Write-Host "f"} -Count 3
f
f
f
Min: 0.4955 ms
Max: 0.8296 ms
Avg: 0.6251 ms
PS C:\>

Can anyone help to explain it please?


Solution

  • This is because Write-Host doesn't return the object and is not a part of pipeline stream, instead it sends text directly to console. You can't simply hide Write-Host output by writing it to variable, because Write-Host writes to console stream which isn't exposed in PowerShell before version 5. What you need is to replace Write-Host with Write-Output cmdlet call. Then you get what you expect. This solution is valid for PowerShell 2.0+.

    Update:

    Starting with PowerShell 5, Write-Host writes to its dedicated stream and you can handle and redirect this stream somewhere else. See this response for more details: https://stackoverflow.com/a/60353648/3997611.