I am new to powershell and just learning it. I have some experience in C#. I am trying to use the foreach-object -Parallel option but cant get all the Write-* functions to work.
function writeTest {
1..1 | ForEach-Object -Parallel {
Write-Host "host"
Write-Output "Output"
Write-Information "information" -InformationAction Continue
Write-Verbose "verbose"
Write-Warning "Warning"
Write-Error "error"
}
}
Function called like: writeTest -verbose
Outputs:
host
Output
WARNING: Warning
Write-Error: error
My question is why doesn't write-verbose and write-information display anything?
Please forgive any ignorance.
You're seeing a bug in
ForEach-Object -Parallel/Start-ThreadJob, present up to at least PowerShell Core 7.0:Your
Write-Informationoutput should show, because you've used-InformationAction Continueto turn it on; while yourWrite-Verboseoutput not showing is expected, because you didn't turn it on with-Verbose, it also wouldn't show if you did use-Verbose, due to the bug.See GitHub issue #13816.
The workaround is to also set the preference variable
$InformationPreferencein order to turn on the information stream, before callingForEach-Object -Parallel(see below).Separately, there's a conceptual problem with your code:
You're passing the
-Verbosecommon parameter to yourwrite-Testfunction, yet this function isn't declared as an advanced function (which requires a[CmdletBinding()]attribute above aparam(...)block and/or at least one parameter with an[Parameter(...)]attribute - see about_Functions_Advanced), so the parameter will have no effect.Even if it did take effect, which means that PowerShell translates it into a function-local
$VerbosePreferencevariable with value'Continue', theForEach-Object -Parallelblock would not see that variable, because the$using:scope is needed to reference variable values from the caller's scope; see this answer.To put it all together.
Note the expression passed to the
-Verboseswitch, of necessity separated from the switch name with:--Verbose:($using:VerbosePreference -eq 'Continue')- which in effect only turns on verbose output if the$VerbosePreferencevalue in the function's main thread ($using:) is set to'Continue', which in turn happens when-Verboseis passed to the advanced function from the outside (it would also happen if$VerbosePreferencewere set to'Continue'in the caller's scope, due to PowerShell's dynamic scoping; see this answer).General information about PowerShell output streams:
Both
Write-VerboseandWrite-Informationare silent by default, as isWrite-Debug.You can make their output show in one of two ways:
Per-command, via a common parameter: Add
-Verboseto aWrite-Verbosecall andInformationAction Continueto aWrite-Informationcall (as you've done).Scope-wide, via preference variables: set
$VerbosePreference = 'Continue'and$InformationPreference = 'Continue'- but the caveat is that neither functions that live in (other) modules nor code that runs in a different thread or process sees these variables by default:$using:scope is required, as shown above.See about_Redirection, about_CommonParameters, and about_Preference_Variables