Reputation: 964
Maybe there's no way to do this in PowerShell.
If I have the file verboseTest.ps1
[CmdletBinding()] # CmdletBinding attribute enables -verbose flag
Param()
Write-Verbose 'verbose test'
If I call .\verboseTest.ps1
, I see nothing as expected.
If I call .\verboseTest.ps1 -Verbose
I see the output.
VERBOSE: verbose test outer
as expected.
But if I call .\verboseTest.ps1 4>&1
I don't. The verbose stream is lost.
Now, Info behaves completely differently.
I have the file infoTest.ps1
and it behaves sanely.
[CmdletBinding()] # Add CmdletBinding attribute
Param()
Write-Information 'info test outer'
If I call .\infoTest.ps1
, I see nothing as expected.
If I call .\infoTest.ps1 -InformationAction 'Continue'
, which is analogous to the -Verbose
flag, it succeeds and outputs info test outer
to the console.
And if I call .\infoTest.ps1 6>&1
it also outputs info test outer
to the console! So somehow the "information" stream behaves completely differently from the "verbose" stream.
The behavior of the info stream makes sense. The write-information commands write to the stream, and I can redirect it or view it or not as I see fit. The "verbose" does not! I have to enable showing it in the output in order to redirect it? Am I doing something wrong? How does this make sense?
Do I have to enable verbose preference in order to redirect the output? And if so, can I do that inside the method or does it change it globally session-wide?
Upvotes: 2
Views: 595
Reputation: 437383
Unfortunately, the verbose stream (stream number 4
) isn't just silent when not explicitly turned on, but no data is written to it.
That is, Write-Verbose
statements are effective no-ops[1], unless -Verbose
is passed or preference variable $VerbosePreference
is set to Continue
.
Among PowerShell's silent-by-default output streams - verbose (4
), debug (5
) and information (6
) - the information stream is the lone exception: Write-Information
statements always write to it, whether it happens to be silenced or not.
Setting preference variable $VerbosePreference
to Continue
turns on verbose output for all commands in the current scope and any child scopes - but there's an important exception:
Advanced functions implemented in modules see only a global instance of $VerbosePreference
when called from a script; by contrast, binary cmdlets are not affected.
This highly problematic behavior is discussed in this GitHub issue.
You can work around that problem as follows:
# Create a script-local copy of the global parameter-defaults
# hashtable.
# Note: If you want to clear the global presets, call .Clear()
# after cloning.
$PSDefaultParameterValues = $PSDefaultParameterValues.Clone()
# Preset the -Verbose switch for all commands that support it.
$PSDefaultParameterValues['*:Verbose'] = $true
# ... call commands, which will behave as if -Verbose had been passed.
[1] However, the cmdlet is still called, which means that arguments you pass to it are evaluated, so it is hypothetically still possible for a silent Write-Verbose
call to have side effects, such as when passing an expandable string as the message that contains a subexpression ($(...)
) with side effects.
Upvotes: 4