Search code examples
powershellpowershell-cmdlet

How to propagate -Verbose to module functions?


According to answers like this one and my own experience, Powershell can take care of propagating -Verbose (and -Debug) automatically, which is very convenient. However this stops working when the functions which I want to propagate verbosity to are in a module. Code used for testing this:

Create a directory called Mod somewhere, suppose in c:, and add 2 files:

File c:\Mod\Functions.ps1:

function Show-VerbosityB { [cmdletbinding()]Param()
  Write-Output "Show-VerbosityB called"
  Write-Verbose "Show-VerbosityB is Verbose"
}

File c:\Mod\Mod.psd1:

@{
ModuleVersion = '1.0.0.0'
NestedModules = @('Functions.ps1')
FunctionsToExport = @('*-*')
}

Now crate the main script, say c:\Foo.ps1:

Import-Module c:\Mod

function Show-VerbosityA { [cmdletbinding()]Param()
  Write-Output "Show-VerbosityA called"
  Write-Verbose "Show-VerbosityA is Verbose"
}

function Show-Verbosity { [cmdletbinding()]Param()
  Write-Output "Show-Verbosity called"
  Write-Verbose "Show-Verbosity is Verbose"
  Write-Output "Testing propagation"
  Show-VerbosityA
  Show-VerbosityB
}

Show-Verbosity -Verbose

Results in

PS> . C:\Foo.ps1
Show-Verbosity called
VERBOSE: Show-Verbosity is Verbose
Testing propagation
Show-VerbosityA called
VERBOSE: Show-VerbosityA is Verbose
Show-VerbosityB called

Why is the Write-Verbose in the module's function skipped, why does propagation not behave like it does for Show-VerbosityA? (If I just dot-source Functions.ps1 instead of importing the module, the line VERBOSE: Show-VerbosityB is Verbose is printed). I could make propagation manual by e.g. calling Show-VerbosityB -Verbose:$PSBoundParameters['Verbose']. Or are there other, preferrably shorter, ways? It is quite messy if functions behave differently depending on whether they are part of a module or dot-sourced.


Solution

  • The reason this is happening is because the $VerbosePreference is not propagated when the module is called. I modified your script to explicitly print the value at the same points you are outputting via Write-Verbose and Write-Output.

    This powershell.org post proposes adding this to the module, which worked like a charm for me:

    if (-not $PSBoundParameters.ContainsKey('Verbose'))
    {
        $VerbosePreference = $PSCmdlet.GetVariableValue('VerbosePreference')
    }
    

    One of the comments mentions bug report with link (it doesn't exist or I don't have permissions to view)

    The issue is discussed in a TechNet post, with a link to a Get-CallerPreferance function that addresses this issue.


    Module:

    function Show-VerbosityB { [cmdletbinding()]Param()
    
        <# uncomment to get verbose preference from caller, when verbose switch not explicitly used.
        if (-not $PSBoundParameters.ContainsKey('Verbose'))
        {
            $VerbosePreference = $PSCmdlet.GetVariableValue('VerbosePreference')
        }
        #>
    
        Write-Output "`nShow-VerbosityB called"
        Write-output "Global pref: $($global:VerbosePreference)"
        Write-output "Script pref: $($script:VerbosePreference)"
        Write-output "Effect pref: $VerbosePreference"
        Write-Verbose "Show-VerbosityB is Verbose"
    }
    

    Caller:

    Import-Module C:\Mod
    
    Write-output "On startup: $VerbosePreference"
    
    function Show-VerbosityA { [cmdletbinding()]Param()
      Write-Output "`nShow-VerbosityA called"
      Write-output "Global pref: $($global:VerbosePreference)"
      Write-output "Script pref: $($script:VerbosePreference)"
      Write-output "Effect pref: $VerbosePreference"
      Write-Verbose "Show-VerbosityA is Verbose"
    }
    
    function Show-Verbosity { [cmdletbinding()]Param()
      Write-Output "`nShow-Verbosity called"
      Write-output "Global pref: $($global:VerbosePreference)"
      Write-output "Script pref: $($script:VerbosePreference)"
      Write-output "Effect pref: $VerbosePreference"
      Write-Verbose "Show-Verbosity is Verbose"
      Write-Output "`nTesting propagation"
      Show-VerbosityA
      Show-VerbosityB
    }
    
    Show-Verbosity -Verbose