1

I am hoping for a bit of help on an issue I'm having where once I add -ErrorAction SilentlyContinue to my command, no errors are written to the $Error variable. When I remove the ErrorAction, the command works perfectly fine and I can see the errors in the $Error variable but the errors are also printed to the console, which I don't want. Once I add the ErrorAction, the command still works but does not write any errors to the $Error variable.

Below is the function that contains the command.

function removebutton{
    Try{
        Write-Host "Please Wait..."
        Import-CSV $WPFfile_path.Text | foreach{Remove-DistributionGroupMember -Identity $WPFlist_email.Text -Member $_.email -Confirm:$false -ErrorAction SilentlyContinue}
        Write-Host("Completed Processing List")
        [System.Windows.MessageBox]::Show("Completed Processing List")       
            If ($error -ne $null) 
            {
            Write-Host -ForegroundColor Red ($Error | Select-Object Exception -ExpandProperty Exception | Out-String)
            [System.Windows.MessageBox]::Show(($Error | Select-Object Exception -ExpandProperty Exception | Out-String))
            }
            Else 
            {
            }
        Get-DistributiongroupMember $WPFlist_email.Text | Select-Object DisplayName, PrimarySMTPAddress | Out-GridView
        }
    Catch{
        [System.Windows.MessageBox]::Show(($Error[0]))
        }
        }

Any help will be greatly appreciated!

Kind regards, Dust

When I remove the ErrorAction, the command works perfectly fine and I can see the errors in the $Error variable but the errors are also printed to the console, which I don't want. Once I add the ErrorAction, the command still works but does not write any errors to the $Error variable.

Dust Ellse
  • 71
  • 7
  • 1
    Essentially, this command just doesn't add any errors to the $Error variable: Import-CSV $WPFfile_path.Text | foreach{Remove-DistributionGroupMember -Identity $WPFlist_email.Text -Member $_.email -Confirm:$false -ErrorAction SilentlyContinue} – Dust Ellse Jan 08 '23 at 01:41

2 Answers2

2

Note:

  • The following describes PowerShell's normal behavior.
  • As it turns out, an apparent bug in Remove-DistributionGroupMember prevents non-terminating errors from being recorded in $Error with -ErrorAction SilentlyContinue present, which - for reasons unknown - can be bypassed by using 2>$null to silence error output instead.

  • -ErrorAction SilentlyContinue continue does record non-terminating errors in the automatic $Error variable (it is only -ErrorAction Ignore that doesn't).

    • Do not use If ($Error -ne $null) to test if an error occurred in the most recent statement, given that $Error contains all errors that have occurred in the session so far.

      • As an aside: To test a value for $null, place it on the LHS of -eq / -ne, given that these operators act as filters with collections (arrays) as the LHS - see the docs.
    • Instead, use the automatic $? variable: if (-not $?)

      • Alternatively, you could run $Error.Clear() before the statement of interest, which would then allow you to use if ($Error.Count -gt 0), but that comes at the expense of wiping out the session-level history of errors.

      • The best option may be to use the common -ErrorVariable parameter, which allows you to collect a given call's non-terminating errors in a self-chosen variable (which must be specified without $; e.g., -ErrorVariable errs in order to collect errors in $errs); note that -ErrorAction SilentlyContinue (or redirection 2>$null) is still also needed to prevent error output.

  • However, non-terminating errors - which is what the common -ErrorAction parameter exclusively acts on - do not trigger the catch block of try ... catch ... finally statements - only terminating errors do.

    • You can promote non-terminating errors to terminating errors by using -ErrorAction Stop, causing them to trigger the catch block too.
  • Note that, in a catch script block, you can more simply refer to the triggering error via the automatic $_ variable; that is, instead of $Error[0], you can use $_.


For a comprehensive overview of PowerShell's bewilderingly complex error handling, see GitHub docs issue #1583.

mklement0
  • 382,024
  • 64
  • 607
  • 775
  • Thank you for your answer! The issue that I have is that this specific command is not writing to the $Error variable: Import-CSV $WPFfile_path.Text | foreach{Remove-DistributionGroupMember -Identity $WPFlist_email.Text -Member $_.email -Confirm:$false -ErrorAction SilentlyContinue} So when I try to "Write-Host" the $Error variable, nothing shows up. – Dust Ellse Jan 08 '23 at 03:28
  • @DustinEllse, assuming that the `foreach` (`ForEach-Object`) call receives _at least one input object_ and `Remove-DistributionGroupMember` reports any _non-terminating_ errors, they _should_ be recorded in `$Error`. Therefore: (a) does the `foreach` call receive input and (b) _where_ are you trying to use `Write-Host`? – mklement0 Jan 08 '23 at 03:35
  • Yes, foreach receives input. The command works fine and users are removed from the distribution list but if the user was not already part of the DL, the error should be written to the $Error variable, but it stays empty. The Write-Host is in an If statement that tells it to print the $Error variable if there's anything in it: `If ($error -ne $null) {Write-Host -ForegroundColor Red ($Error | Select-Object Exception -ExpandProperty Exception | Out-String)`. I have also checked the $Error variable in the console and it's empty. – Dust Ellse Jan 08 '23 at 03:39
  • @DustinEllse, a simplified example: `$Error.Clear(); try { Get-Item NoSuchFile -ErrorAction SilentlyContinue; Write-Verbose -Verbose $error[0] } catch { 'uh-oh' }`. I'm only aware of two types of errors, non-terminating and terminating, the latter coming in the forms of _statement_-terminating and _script_-terminating (fatal) errors. In the example above, you should see _either_ the `Write-Verbose` output (non-terminating error) _or_ `uh-oh` (terminating error). Are you saying that with `Remove-DistributionGroupMember` you're seeing _neither_? – mklement0 Jan 08 '23 at 03:49
  • @DustinEllse, another thing you could try - though it should normally not make a difference - is to replace `-ErrorAction SilentlyContinue` with `2>$null` and add `-ErrorVariable errs`, which should collect any non-terminating errors in variable `$errs`. – mklement0 Jan 08 '23 at 17:07
  • I've replaced my command with `$Error.Clear(); try { Get-Item NoSuchFile -ErrorAction SilentlyContinue; Write-Verbose -Verbose $error[0] } catch { 'uh-oh' }` and this returns the $Error variable perfectly. Looking more like it's a bug with the Remove-DistributionGroupMember cmdlet. – Dust Ellse Jan 08 '23 at 19:58
  • 1
    For further context, my initial command runs in a function that is called when clicking a button in a GUI that I've written. The command receives variables from text boxes for the location of a CSV file and the address of the DL. Without SilentlyContinue, the GUI works perfectly apart from the fact that it writes errors related to existing members to the console. It also writes to the $Errror variable with no issues. Once I've set it to SilentlyContinue, the $Error variable stays empty and I'm unable to set the -ErrorVariable too (also remains empty). – Dust Ellse Jan 08 '23 at 20:02
0

Amazingly, replacing -ErrorAction SilentlyContinue with 2>$null resolved my issue. The errors are no longer written to console and only written to the $Error variable.

Thank you @mklement0 for your help! Much appreciated! I have bought you a coffee to say thanks!

Dust Ellse
  • 71
  • 7
  • First things first: thank you for the coffee, much appreciated. Very curious that `2>$null` made a difference and it would be good to know why, but I'm glad that it solved your problem. I've also updated my answer with a brief summary. – mklement0 Jan 08 '23 at 20:50