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-Information
output should show, because you've used-InformationAction Continue
to turn it on; while yourWrite-Verbose
output 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
$InformationPreference
in 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
-Verbose
common parameter to yourwrite-Test
function, 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
$VerbosePreference
variable with value'Continue'
, theForEach-Object -Parallel
block 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
-Verbose
switch, of necessity separated from the switch name with:
--Verbose:($using:VerbosePreference -eq 'Continue')
- which in effect only turns on verbose output if the$VerbosePreference
value in the function's main thread ($using:
) is set to'Continue'
, which in turn happens when-Verbose
is passed to the advanced function from the outside (it would also happen if$VerbosePreference
were 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-Verbose
andWrite-Information
are silent by default, as isWrite-Debug
.You can make their output show in one of two ways:
Per-command, via a common parameter: Add
-Verbose
to aWrite-Verbose
call andInformationAction Continue
to aWrite-Information
call (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