8

I've been trying write safe code that supports -whatif with the ShouldProcess method so my users have an idea of what a cmdlet is supposed to do before they run it for real.

However I’ve run into a bit of a snag. If I call a script with -whatif as an argument, $pscmdlet.ShouldProcess will return false. All well and good. If I call a cmdlet defined in the same file (that has SupportsShouldProcess=$true) it will return false as well.

However, if I am calling a cmdlet defined in another module I have loaded using Import-Module, it will return true. The -whatif context does not seem to get passed through to calls in the other module.

I don't want to have to manually pass in a flag to every cmdlet. Does anyone have a better solution?

This issue seems related to this question. However, they are not talking about the cross-module problem.

Example Script:

#whatiftest.ps1
[CmdletBinding(SupportsShouldProcess=$true)]
param()

Import-Module  -name .\whatiftest_module  -Force

function Outer
{
    [CmdletBinding(SupportsShouldProcess=$true)]
    param()
    if( $pscmdlet.ShouldProcess("Outer"))
    {
        Write-Host "Outer ShouldProcess"
    }
    else
    {
        Write-Host "Outer Should not Process"
    }

    Write-Host "Calling Inner"
    Inner
    Write-Host "Calling InnerModule"
    InnerModule
}

function Inner
{
    [CmdletBinding(SupportsShouldProcess=$true)]
    param()

    if( $pscmdlet.ShouldProcess("Inner"))
    {
        Write-Host "Inner ShouldProcess"
    }
    else
    {
        Write-Host "Inner Should not Process"
    }
}

    Write-Host "--Normal--"
    Outer

    Write-Host "--WhatIf--"
    Outer -WhatIf

The Module:

#whatiftest_module.psm1
 function InnerModule
 {
    [CmdletBinding(SupportsShouldProcess=$true)]
    param()    

    if( $pscmdlet.ShouldProcess("InnerModule"))
    {
        Write-Host "InnerModule ShouldProcess"
    }
    else
    {
        Write-Host "InnerModule Should not Process"
    }
 }

Output:

F:\temp> .\whatiftest.ps1
--Normal--
Outer ShouldProcess
Calling Inner
Inner ShouldProcess
Calling InnerModule
InnerModule ShouldProcess
--WhatIf--
What if: Performing operation "Outer" on Target "Outer".
Outer Should not Process
Calling Inner
What if: Performing operation "Inner" on Target "Inner".
Inner Should not Process
Calling InnerModule
InnerModule ShouldProcess
Community
  • 1
  • 1
shopsinc
  • 183
  • 1
  • 4
  • In my experience, even when passing thru the common parameters `-WhatIf:$WhatIf -Confirm:$Confirm -Debug:$Debug -Verbose:$Verbose`, they will be ignored on cross-module boundaries... – oɔɯǝɹ Feb 10 '18 at 16:09

1 Answers1

6

To do this, you can use a technique I call "CallStack peeking". Use Get-PSCallStack to look up at whatever called the function. Each item will have an InvocationInfo, and a inside of that will be a property called "BoundParameters". This has the parameters @ each level. If -WhatIf was passed to any of them, you can act like -WhatIf was passed to your function.

Hope this helps

Start-Automating
  • 8,067
  • 2
  • 28
  • 47
  • 3
    This approach will soon lead to subtle defects. What happens when `-WhatIf` or `-Confirm` is specified, but a function in the middle of the call stack has logic that requires to not use `-WhatIf`? And do you look up for all other common parameters, like `-Verbose`, `-Debug` ? What happens when a new common parameter is introduced? Do you take into account the global $ConfirmPreference value? – oɔɯǝɹ Feb 14 '18 at 15:54