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 your Write-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 calling ForEach-Object -Parallel
(see below).
Separately, there's a conceptual problem with your code:
You're passing the -Verbose
common parameter to your write-Test
function, yet this function isn't declared as an advanced function (which requires a [CmdletBinding()]
attribute above a param(...)
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'
, the ForEach-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.
function Write-Test {
# Mark the function as an advanced one, so that it accepts
# common parameters such as -Verbose
[CmdletBinding()]
param()
# WORKAROUND: Turn the information stream on
# via its *preference variable* AS WELL:
$InformationPreference = 'Continue'
1..1 | ForEach-Object -Parallel {
Write-Host "host"
Write-Output "Output"
Write-Information "information" -InformationAction Continue
Write-Verbose "verbose" -Verbose:($using:VerbosePreference -eq 'Continue')
Write-Warning "Warning"
Write-Error "error"
}
}
Write-Test -Verbose
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
and Write-Information
are silent by default, as is Write-Debug
.
You can make their output show in one of two ways:
Per-command, via a common parameter: Add -Verbose
to a Write-Verbose
call and InformationAction Continue
to a Write-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:
- In the module case, you must either use common parameters explicitly or set the preference variable in the global scope, which is not advisable; the problem is discussed in GitHub issue #4568.
- In the other thread/process case, the
$using:
scope is required, as shown above.
See about_Redirection, about_CommonParameters, and about_Preference_Variables
Get-Variable -Name *prefer*
... [grin] – Eastern