Passing through -Verbose status to module cmdlets Passing through -Verbose status to module cmdlets powershell powershell

Passing through -Verbose status to module cmdlets


It is possible to pass-through most of the common parameters using the matching preference variables and a syntax like this, -Parameter:$ParameterPreference. So, for the specific case of verbose, the syntax is -Verbose:$VerbosePreference.

There are a couple of exceptions:

  • Debug : the value of $DebugPreference is automatically passed-through, but specifying the -Debug switch forces $DebugPreference to Inquire.
  • WhatIf : automatically passed-through.

I have modified the OP code sample as follows:

[CmdletBinding(SupportsShouldProcess=$true)]param(    [Switch]$FullPassThru)New-Module -Name TempModule -ScriptBlock {        function Test-ModuleVerbose        {            [CmdletBinding(SupportsShouldProcess=$true)]            param ()            Write-Host "1: Module: verbose parameter is bound : $($PSCmdlet.MyInvocation.BoundParameters['Verbose'])"            Write-Host "2: Module: verbose preference         : $VerbosePreference"            # Write-Verbose will just work without any change            Write-Verbose "Verbose"            # Other commands need the $VerbosePreference passed in            Set-Item -Path Env:\DEMONSTRATE_PASS_THRU `                     -Value 'You can safely delete this variable' `                     -Verbose:$VerbosePreference        }        function Test-ModulePreferencePassThru        {            [CmdletBinding(SupportsShouldProcess=$true)]            param()            Write-Debug   "DebugPreference: $DebugPreference"            Write-Warning "WarningPreference: $WarningPreference"            Write-Error   "ErrorActionPreference: $ErrorActionPreference"            Set-Item -Path Env:\DEMONSTRATE_PASS_THRU `                     -Value 'You can safely delete this variable' `                     -Verbose:$VerbosePreference `                     -WarningAction:$WarningPreference `                     -ErrorAction:$ErrorActionPreference        }    } | Out-Nullfunction Test-Verbose{    [CmdletBinding(SupportsShouldProcess=$true)]    param()    Write-Host ("Verbose preference: $VerbosePreference")    Test-ModuleVerbose -Verbose:$VerbosePreference}function Test-PreferencePassThru{    [CmdletBinding(SupportsShouldProcess=$true)]    param()    Test-ModulePreferencePassThru -Verbose:$VerbosePreference}try{    if ($FullPassThru -eq $false)    {        # just demonstrate -verbose pass-through        Test-Verbose    }    else    {        # most of the preferences can be explicitly passed-through, however:        #        #  -Debug  : $DebugPreference is automatically passed-through        #            and -Debug forces $DebugPreference to 'Inquire'        #  -WhatIf : automatically passed-through        Test-ModulePreferencePassThru -Verbose:$VerbosePreference `                                        -WarningAction:$WarningPreference `                                        -ErrorAction:$ErrorActionPreference | Out-Null    }}finally{    # cleanup    Remove-Item -Path Env:\DEMONSTRATE_PASS_THRU -Force | Out-Null}

Save the above as test.ps1. When invoked from the console:

PS C:\temp> .\test.ps1Verbose preference: SilentlyContinue1: Module: verbose parameter is bound : False2: Module: verbose preference         : SilentlyContinuePS C:\temp> .\test.ps1 -VerboseVERBOSE: Exporting function 'Test-ModuleVerbose'.VERBOSE: Exporting function 'Test-ModulePreferencePassThru'.VERBOSE: Importing function 'Test-ModulePreferencePassThru'.VERBOSE: Importing function 'Test-ModuleVerbose'.Verbose preference: Continue1: Module: verbose parameter is bound : True2: Module: verbose preference         : ContinueVERBOSE: VerboseVERBOSE: Performing the operation "Set Item" on target "Item: DEMONSTRATE_PASS_THRU Value: You can safely delete this variable".

Furthermore, pass-through for $DebugPreference, $WarningPreference and $ErrorActionPreference also works:

PS C:\temp> $VerbosePreference  = 'Continue'PS C:\temp> $DebugPreference = 'Continue'PS C:\temp> $WarningPreference = 'Continue'PS C:\temp> $ErrorActionPreference = 'Continue'PS C:\temp> .\test.ps1 -FullPassThruVERBOSE: Exporting function 'Test-ModuleVerbose'.VERBOSE: Exporting function 'Test-ModulePreferencePassThru'.VERBOSE: Importing function 'Test-ModulePreferencePassThru'.VERBOSE: Importing function 'Test-ModuleVerbose'.DEBUG: DebugPreference: ContinueWARNING: WarningPreference: ContinueTest-ModulePreferencePassThru : ErrorActionPreference: ContinueAt C:\OAASMain\Online\ContainerService\Tools\docker\test.ps1:72 char:9+         Test-ModulePreferencePassThru -Verbose:$VerbosePreference `+         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~    + CategoryInfo          : NotSpecified: (:) [Write-Error], WriteErrorException    + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Test-ModulePreferencePassThruVERBOSE: Performing the operation "Set Item" on target "Item: DEMONSTRATE_PASS_THRU Value: You can safely delete this variable".

-WhatIf is automatically passed-through:

PS C:\temp> .\test.ps1 -FullPassThru -WhatIfWhat if: Performing the operation "Remove Item" on target "Item: DEMONSTRATE_PASS_THRU".

This also handles -WarningAction and -ErrorAction:

PS C:\temp> .\test.ps1 -FullPassThru -WarningAction Ignore -ErrorAction StopTest-ModulePreferencePassThru : ErrorActionPreference : StopAt C:\OAASMain\Online\ContainerService\Tools\docker\test.ps1:72 char:9+         Test-ModulePreferencePassThru -Verbose:$VerbosePreference `+         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~    + CategoryInfo          : NotSpecified: (:) [Write-Error], WriteErrorException    + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Test-ModulePreferencePassThru


There is a variable named $VerbosePreference you can check to see how Verbose output should be handled. However, scripts loaded into a separate scope is giving you the issues. If you read the Get-Help about_scopes, you'll see:

Script:
The scope that is created while a script file runs. Only the commands in the script run in the script scope. To the commands in a script, the script scope is the local scope.

You can add the script to the current scope instead using dot source notation. From the same help file, below the heading Using Dot Source Notation with Scope it is stated that:

Scripts and functions follow all the rules of scope. You create them in a particular scope, and they affect only that scope unless you use a cmdlet parameter or a scope modifier to change that scope.

But, you can add a script or function to the current scope by using dot source notation. Then, when a script runs in the current scope, any functions, aliases, and variables that the script creates are available in the current scope.

I suggest reading up more about scopes in the Get-Help about_scopes help chapter.

For a quick test of whether this works or not:

[CmdletBinding()]PARAM()New-Module -Name TempModule -ScriptBlock {    function Show-ModuleVerbosePreference    {        [CmdletBinding()]        PARAM()        Write-Host "Verbose preference in module function: $VerbosePreference"    }} | Out-Nullfunction Show-ScriptVerbosePreference{    [CmdletBinding()]    PARAM()    Write-Host "Verbose preference in script function: $VerbosePreference"}Show-ScriptVerbosePreferenceShow-ModuleVerbosePreference</pre>

And if we try to call this script file using different methods we get the following output:

PS C:\> .\verbosity.ps1Verbose preference in script function: SilentlyContinueVerbose preference in module function: SilentlyContinuePS C:\> .\verbosity.ps1 -VerboseVERBOSE: Exporting function 'Show-ModuleVerbosePreference'.VERBOSE: Importing function 'Show-ModuleVerbosePreference'.Verbose preference in script function: ContinueVerbose preference in module function: SilentlyContinuePS C:\> . .\verbosity.ps1Verbose preference in script function: SilentlyContinueVerbose preference in module function: SilentlyContinuePS C:\> . .\verbosity.ps1 -VerboseVERBOSE: Exporting function 'Show-ModuleVerbosePreference'.VERBOSE: Importing function 'Show-ModuleVerbosePreference'.Verbose preference in script function: ContinueVerbose preference in module function: Continue

So by using dot source notation we have added the script scope into the current scope which seems to make the VerbosePreference setting visible in the module method as well.


In my .psm1, I place a command similar to this:

If ((Get-PSCallStack)[1].Arguments -like '\*Verbose=True\*') {    Write-Host 'The .ps1 script importing this module is Verbose'};

You may use the script block to set a variable, such as $VerbosePreference in your module scope, or your own unique variable for your own logic.