Windows Server TechCenter > Windows Server Forums > Windows PowerShell > PowerShell v2 CTP3 advanced function parameter '-WarningAction' not working
Ask a questionAsk a question
 

AnswerPowerShell v2 CTP3 advanced function parameter '-WarningAction' not working

  • Tuesday, November 03, 2009 1:42 AMMichael Ward27 Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Has Code

    I'm currently in the process of writing some PowerShell scripts for managing our environment, and want to make use of the 'WarningAction' common parameter. However it doesn't seem to work :-(.

    I'm using the [CmdletBinding()] attribute in my script to enable common parameters (http://msdn.microsoft.com/en-us/library/dd901844(VS.85).aspx).

    Consider the following PowerShell v2 CTP3 script test.ps1:

    ==============

    [CmdletBinding()]
    param()

    Write-Host "warning: $WarningPreference"
    Write-Host "error: $ErrorActionPreference"

    Write-Warning "b"
    Write-Error "c"
    ==============

    If I execute the script as follows:

    ==============
    PS > .\test.ps1 -ErrorAction SilentlyContinue
    warning: Continue
    error: SilentlyContinue
    WARNING: b
    ==============

    As expected, the $ErrorActionPreference is set to 'SilentlyContinue', and the output from the Write-Error cmd is suppressed.

    However, if I execute:

    ==============
    PS > .\test.ps1 -WarningAction SilentlyContinue
    warning: Continue
    error: Continue
    WARNING: b
    D:\Misc\scripts\PowerShell\test.ps1 : c
    At line:1 char:11
    + .\test.ps1 <<<<  -WarningAction SilentlyContinue
        + CategoryInfo          : NotSpecified: (:) [Write-Error], WriteErrorException
        + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,test.ps1
    ==============

    The $WarningPreference isn't set, and the output from the Write-Warning cmd is not suppressed as would be expected.

    Does this happen for anyone else? Or is there something obvious I'm missing?

    Running Get-Help indicates that -WarningAction is supported:

    ==============
    PS D:\> Get-Help .\test.ps1
    test.ps1 [-Verbose] [-Debug] [-ErrorAction <ActionPreference>] [-WarningAction <ActionPreference>] [-ErrorVariable <String>] [-WarningVariable <String>] [-OutVariable <String>] [-OutBuffer <Int32>]
    ==============

    Thanks
    Michael

    Note: I have already posted another version of this question in the Scripting Guys forum (see link below). It was suggested I post this here as well.
    http://social.technet.microsoft.com/Forums/en/ITCG/thread/1e7ea871-432f-4650-ac1e-5a5a5e663f40

Answers

  • Tuesday, November 03, 2009 6:24 AMJoel -Jaykul- BennettMVPUsers MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     AnswerHas Code
    Believe it or not, for that parameters to take effect you need to use the special methods documented in about_Functions_Advanced_Methods which are all methods of the special magic variable $PSCmdlet ...

    [CmdletBinding()]
    param()
    
    Write-Host "warning: $WarningPreference"
    Write-Host "error: $ErrorActionPreference"
    
    $PSCmdlet.WriteWarning( "b" )
    $PSCmdlet.WriteError( "c" )


    The documentation actually says that you "can also use the various Write cmdlets," but at least in this case, it's wrong. :-(
  • Thursday, November 05, 2009 6:31 AMJoel -Jaykul- BennettMVPUsers MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Answer
    Ok, now, this is mostly a joke, but .. if you REALLY need those warnings to behave, it has to look something like this:



    function TestWarningA {[CmdletBinding()]param()
       # This has no effect on the WarningVariable, but without it the warnings are displayed in the host
       if($PSBoundParameters.ContainsKey("WarningAction")){ $local:WarningPreference = $PSBoundParameters['WarningAction'] }

       Write-Host "Script A: $WarningPreference"

       $PSCmdlet.WriteWarning("WA1")  # this is the only thing affected by -WarningAction
       if($PSBoundParameters.ContainsKey("WarningVariable")){
          Write-Warning "WA2" -WarningVariable $("+$($PSBoundParameters['WarningVariable'].TrimStart('+'))")
       } else {
          Write-Warning "WA2"
       }
      
       $PSCmdlet.WriteError((new-object System.Management.Automation.ErrorRecord( (new-object System.Exception "EA1"), "TestError", "NotSpecified", $null)))
       Write-Error "EA2"
      
       if($PSBoundParameters.ContainsKey("WarningVariable")){
          TestWarningB -WarningVariable $("+$($PSBoundParameters['WarningVariable'].TrimStart('+'))")
       } else {
          TestWarningB
       }
      
    }

    function TestWarningB {[CmdletBinding()]param()

       Write-Host "Script B: $WarningPreference $($PSBoundParameters['WarningVariable'])"
      
       $PSCmdlet.WriteWarning("WB1")
       if($PSBoundParameters.ContainsKey("WarningVariable")){
          Write-Warning "WB2" -WarningVariable $("+$($PSBoundParameters['WarningVariable'].TrimStart('+'))")
       } else {
          Write-Warning "WB2"
       }
      
       $PSCmdlet.WriteError( (new-object System.Management.Automation.ErrorRecord( (new-object System.Exception "EB1"), "TestError", "NotSpecified", $null)) )
       Write-Error "EB2"
    }

    TestWarningA -WarningAction:SilentlyContinue -WarningVariable wv -ErrorAction:SilentlyContinue -ErrorVariable ev



All Replies

  • Tuesday, November 03, 2009 2:15 AMMarco ShawMVP, ModeratorUsers MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    At this point, v2 has been offiicially released for all platforms.  That being said, I did try this on PowerShell v2 on Server 2008 R2 and got the same error.  I'll ask around and make sure to test on a RTM release...
  • Tuesday, November 03, 2009 6:24 AMJoel -Jaykul- BennettMVPUsers MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     AnswerHas Code
    Believe it or not, for that parameters to take effect you need to use the special methods documented in about_Functions_Advanced_Methods which are all methods of the special magic variable $PSCmdlet ...

    [CmdletBinding()]
    param()
    
    Write-Host "warning: $WarningPreference"
    Write-Host "error: $ErrorActionPreference"
    
    $PSCmdlet.WriteWarning( "b" )
    $PSCmdlet.WriteError( "c" )


    The documentation actually says that you "can also use the various Write cmdlets," but at least in this case, it's wrong. :-(
  • Wednesday, November 04, 2009 1:43 AMMichael Ward27 Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Ahhh... thanks Joel, that does work! So is that a bug or what? Write-Error and the others like Write-Verbose and Write-Debug seem to work fine, it's just Write-Warning that isn't.

    So using the $PSCmdlet.WriteWarning() format I was able suppress the error and capture it using -WarningVariable. Mission accomplished!

    Michael

    Oh btw I also tried this in Windows 7, same problem. So looks like this is a problem in RTM.
  • Wednesday, November 04, 2009 11:45 PMMichael Ward27 Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    Ok... after playing around a bit more with this, I've stumbled across my next problem. Using $PSCmdlet.WriteWarning(), how can I pass the warnings back through multiple levels of calling scripts?

    For example, consider the following two scripts:

    ====
    # TestWarningA.ps1
    [CmdletBinding()]
    param()

    Write-Host "Script A"
    $PSCmdlet.WriteWarning("A")

    .\TestWarningB.ps1
    ====

    and

    ====
    # TestWarningB.ps1
    [CmdletBinding()]
    param()

    Write-Host "Script B"
    $PSCmdlet.WriteWarning("B")
    ====

    Executing TestWarningA.ps1 with -WarningAction SilentlyContinue returns:

    ====
    PS D:\> .\TestWarningA.ps1 -WarningAction SilentlyContinue
    Script A
    Script B
    WARNING: B
    ====

    The warning in TestWarningB.ps1 is not suppressed as I had intended and only the first warning is returned to the -WarningVariable. The same scenario but using Write-Error does work as expected. Is there a way to work around this using $PSCmdlet.WriteWarning()?

    I need to be able to capture all the warnings from the sub scripts to action appropriately in the master script (e.g. log to event log).

    Let me know if I should log this as a new forum entry - will do so if I get no response due to this thread already being marked 'answered'.

    Thanks
    Michael

  • Thursday, November 05, 2009 1:56 AMMarco ShawMVP, ModeratorUsers MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    I've unmarked Jaykul's response as the answer, but may go back on that later.
  • Thursday, November 05, 2009 6:05 AMJoel -Jaykul- BennettMVPUsers MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Ugh.  Yeah, it was definitely a bug already, in my opinion, this makes it doubly so.

    Marco: aww, you could at least vote me helpful :-P

    The problem is that the WarningAction common parameter doesn't actually set/override the value of the $WarningPreference variable the way it's supposed to (try printing it out, you'll see), and therefore the setting isn't propagated to nested commands.

    If you put a line: { Get-Variable -Scope Local } in your TestWarningA, you'll see that passing -ErrorAction:SilentlyContinue actually results in the variable being defined for that local scope, but the same is NOT true for the -WarningAction:SilentlyContinue parameter (which it seems should behave the same way).

    You could make it work for any given function by adding this at the top:

       if($PSBoundParameters.ContainsKey("WarningAction")){
          $local:WarningPreference = $PSBoundParameters['WarningAction']
       }

    I'll send a note to the MVP mailing list, but I filed a bug too: https://connect.microsoft.com/PowerShell/feedback/ViewFeedback.aspx?FeedbackID=508387
  • Thursday, November 05, 2009 6:31 AMJoel -Jaykul- BennettMVPUsers MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Answer
    Ok, now, this is mostly a joke, but .. if you REALLY need those warnings to behave, it has to look something like this:



    function TestWarningA {[CmdletBinding()]param()
       # This has no effect on the WarningVariable, but without it the warnings are displayed in the host
       if($PSBoundParameters.ContainsKey("WarningAction")){ $local:WarningPreference = $PSBoundParameters['WarningAction'] }

       Write-Host "Script A: $WarningPreference"

       $PSCmdlet.WriteWarning("WA1")  # this is the only thing affected by -WarningAction
       if($PSBoundParameters.ContainsKey("WarningVariable")){
          Write-Warning "WA2" -WarningVariable $("+$($PSBoundParameters['WarningVariable'].TrimStart('+'))")
       } else {
          Write-Warning "WA2"
       }
      
       $PSCmdlet.WriteError((new-object System.Management.Automation.ErrorRecord( (new-object System.Exception "EA1"), "TestError", "NotSpecified", $null)))
       Write-Error "EA2"
      
       if($PSBoundParameters.ContainsKey("WarningVariable")){
          TestWarningB -WarningVariable $("+$($PSBoundParameters['WarningVariable'].TrimStart('+'))")
       } else {
          TestWarningB
       }
      
    }

    function TestWarningB {[CmdletBinding()]param()

       Write-Host "Script B: $WarningPreference $($PSBoundParameters['WarningVariable'])"
      
       $PSCmdlet.WriteWarning("WB1")
       if($PSBoundParameters.ContainsKey("WarningVariable")){
          Write-Warning "WB2" -WarningVariable $("+$($PSBoundParameters['WarningVariable'].TrimStart('+'))")
       } else {
          Write-Warning "WB2"
       }
      
       $PSCmdlet.WriteError( (new-object System.Management.Automation.ErrorRecord( (new-object System.Exception "EB1"), "TestError", "NotSpecified", $null)) )
       Write-Error "EB2"
    }

    TestWarningA -WarningAction:SilentlyContinue -WarningVariable wv -ErrorAction:SilentlyContinue -ErrorVariable ev



  • Thursday, November 05, 2009 7:58 PMMichael Ward27 Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Wow you guys rock!

    Joel - thanks for the code example, no way I could have figured that out myself. Looking at the code I'm not sure I'm that keen on getting it working :-). I didn't mention before, but I actually have three levels of scripts so far calling each other so would have to do this at each level... yikes.

    I'm happy knowing it's a bug that will (hopefully!) be fixed sometime... but I won't hold my breath. In the meantime I'll use Write-Error or Write-Output instead (which won't work exactly as I imagined it happening, but will have to make do!).

    So Joel answered both my questions, does that mean he gets twice the credit?

    Michael