Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I exclude a block from -WhatIf processing?

Tags:

powershell

I'm writing a Powershell cmdlet that needs to execute a command and store its stderr output to a temporary file for later processing. This output lists COM ports that the cmdlet may use later.

# mostly side-effect-free information gathering
$info = [IO.Path]::GetTempFileName()
info-gather.exe 2>$info
Get-Content $info | ForEach-Object {
    # processing
}
Remove-Item $info

# serious things with serious side effects start here

I would like this cmdlet to implement -WhatIf since it will have non-trivial side effects. However, the -WhatIf behavior takes over the info-gather.exe command and it is simply never executed. Instead, it prints:

What if: Performing the operation "Output to File" on target "temp\path\to\tmp78A4.tmp"

Because this command is never executed, the inner processing doesn't happen either, and the rest of my cmdlet that has actual side effects isn't executed because it doesn't know which ports to use, making -WhatIf largely useless.

How can I bypass -WhatIf for this block without overriding it in the rest of the cmdlet?

like image 483
zneak Avatar asked Mar 29 '16 17:03

zneak


2 Answers

You could use try...finally to set and then reset the $WhatIfPreference variable.

$script:oldWhatIfPrefernence = $WhatIfPreference
try {
    $WhatIfPreference = $false

    $info = [IO.Path]::GetTempFileName()
    info-gather.exe 2>$info
    Get-Content $info | ForEach-Object {
        # processing
    }
    Remove-Item $info
} finally {
    $WhatIfPreference = $script:oldWhatIfPreference
}

If you weren't using the 2> redirection, there is another way. You can pass the -WhatIf switch explicitly to many cmdlets and override -WhatIf for just that part.

Remove-Item $info -WhatIf:$false

Though, zneak's answer that doesn't involve a temporary file is pretty elegant too.

like image 121
chwarr Avatar answered Oct 02 '22 21:10

chwarr


One solution is to "redirect" stderr to stdout. Doing this, Powershell appends error records to the standard output, which can be converted to regular strings using Out-String. In my case (YMMV depending on the program), the first error record says "there was an error with this program" and the second error record is the actual, full stderr output. This is also simplified by the fact that the command doesn't write anything to the standard output, so there's no filtering to do there.

I was able to change the foreach loop to use this:

((info-gather.exe 2>&1)[1] | Out-String) -split "[`r`n]" | foreach-object

Since this does not write to a file, -WhatIf no longer overrides it.

There is probably a simpler and cleaner way to do this (for instance, if there was a way to pipe stderr to Out-String directly).

like image 35
zneak Avatar answered Oct 02 '22 22:10

zneak