Forum Discussion

ThomasLehmann's avatar
ThomasLehmann
Copper Contributor
Feb 05, 2024

Import-Module for advanced functions doesn't work as expected

Using [CmdletBinding(SupportShouldProcess)] on functions using them inside the main script does work as expected: When passing -WhatIf or -Confirm:$true to the script then those parameters are passed to the advanced function too.

 

However when moving those function into a module (Example: Tools.psm1) the function is imported and can be called but those parameters are NOT passed to that function.

 

Any ideas are welcome.

 

Kind Regards,

Thomas

  • LainRobertson's avatar
    LainRobertson
    Silver Contributor

    ThomasLehmann 

     

    Hi, Thomas.

     

    WhatIf is a bit of a dog's breakfast and always has been, but it does work across both "live" functions as well as an exported module member - in its own odd fashion.

     

    Given you're already familiar with using WhatIf in a "live" setting, I'll provide an example for the module context.

     

    Example module

    function Invoke-Wazzup
    {
        [cmdletbinding(SupportsShouldProcess=$true)]
        param(
            [parameter(ValueFromPipeline=$true)] $Stuff
        )
    
        begin
        {
            Write-Verbose -Verbose -Message "Prepare yourself... ($WhatIfPreference)";
        }
    
        process
        {
            if ($true -eq $WhatIfPreference)
            {
                Write-Information -InformationAction:Continue -MessageData "We thought about writing something witty, but -WhatIf says ""NO!""";
            }
            else
            {
                Write-Verbose -Verbose -Message "Wazzup?! Oh, the input was:";
                $_;
            }
        }
    
        end
        {
            Write-Verbose -Verbose -Message "Yep, we're done.";
        }
    }
    
    Export-ModuleMember -Function @("Invoke-Wazzup");

     

    Example use and output

     

     

    Under "normal" circumstances, you might expect to see a variable named "$WhatIf" added where you would proceed to use it the same as any other switch via the .IsPresent() method, but WhatIf isn't like that.

     

    Instead, providing the WhatIf parameter for the command changes the value of the $WhatIfPreference variable within the localised scope. So, in my function above, when I provide -WhatIf when calling the function, then $WhatIfPreference = $true only inside the function.

     

    Cheers,

    Lain

    • ThomasLehmann's avatar
      ThomasLehmann
      Copper Contributor

      LainRobertson 

      My Module function (test) looks like following:

      function Test-WriteMessage {
          [CmdletBinding(SupportsShouldProcess=$true)]
          param ([String] $Message)
      
          Write-Message "-WhatIf:$WhatIfPreference -Confirm:$ConfirmPreference"
      
          if ($PSCmdlet.ShouldProcess($Message, 'Writing a message')) {
              Write-Message $Message
          } else {
              Write-Message "$Message (simulated)"
          }
      }

      And my main.ps1 looks like following:

      [CmdletBinding(SupportsShouldProcess)]
      param()
      
      Import-Module $PSScriptRoot\Tools -Force
      
      Write-Debug "is just a test"
      Write-Message "hello world!"
      Test-WriteMessage "hello world!"

      When calling .\Main.ps1 -WhatIf then I get

       

      hello world!
      -WhatIf:False -Confirm:High
      hello world!

       

      However when moving the Test-WriteMessage into "Main.ps1":

       

      hello world!
      -WhatIf:True -Confirm:High
      What if: Performing the operation "Writing a message" on target "hello world!".
      hello world! (simulated)

       

       

      • LainRobertson's avatar
        LainRobertson
        Silver Contributor

        ThomasLehmann 

         

        Hi, Thomas.

         

        I changed your example a little as I have no such commandlet as "Write-Message", but that has no bearing on the test itself, which was successful for me both from the command line and indirectly via a script.

         

        Module (forum.psm1)

         

        function Test-WriteMessage {
            [CmdletBinding(SupportsShouldProcess=$true)]
            param ([String] $Message)
        
            Write-Information -InformationAction:Continue -MessageData "-WhatIf:$WhatIfPreference -Confirm:$ConfirmPreference";
        
            if ($PSCmdlet.ShouldProcess($Message, 'Writing a message')) {
                Write-Information -InformationAction:Continue -MessageData $Message;
            } else {
                Write-Information -InformationAction:Continue -MessageData "$Message (simulated)";
            }
        }
        
        Export-ModuleMember -Function @(
            "Test-WriteMessage"
        );

         

         

        Command line test

         

        PowerShell script test (.\forums.ps1 - not to be confused with the above .psm1)

        Import-Module -Name .\forum.psm1;
        Test-WriteMessage -Message "Foo";
        Test-WriteMessage -Message "Foo" -WhatIf;
        Remove-Module -Name "Forum";

         

         

        So, whether the function is called live or via a script, your example is working for me.

         

        It's worth noting that in your example main.ps1, you're never calling your function with the -WhatIf parameter. I'm assuming while testing you are remembering to do that.

         

        Cheers,

        Lain

Resources