Search code examples
powershelltry-catch

Catch block does not print out Warning message into console after


I am writing a simple script that checks for a local user account. I would like to use the try_catch error to handle errors but I am not able to figure out why the catch block in my script won't print out the warning message in the script. Any guidance is appreciated.

function checkAccount($user)
{
    try {
       Get-CimInstance Win32_UserAccount| Where-Object -Property Name -Contains $user |Select-Object -ExpandProperty Name -ErrorAction Stop
    }
    catch {
        Write-Warning -Message "Oops, ran into an issue"
    }
}

Solution

    • There are two commands that could report non-terminating errors in your pipeline - Get-CimInstance and Select-Object[1] - so you should use -ErrorAction Stop with both.

    • A simpler alternative is to set the $ErrorActionPreference preference variable to 'Stop' for your entire function:

    function checkAccount($user)
    {
        # Make all errors in this scope (and descendant scopes) (script)-terminating, 
        # which enables them to be caught with try / catch.
        $ErrorActionPreference = 'Stop'
        try {
           Get-CimInstance Win32_UserAccount | 
             Where-Object -Property Name -eq $user | 
             Select-Object -ExpandProperty Name
        }
        catch {
            Write-Warning -Message "Oops, ran into an issue"
        }
    }
    

    Also note that I've replaced -Contains with -eq, given that the -contains operator is for testing if a collection contains a given value, whereas you're processing the user accounts one by one.
    If, by contrast, your intent is to perform substring matching, use something -like *$user* instead.

    Caveat:

    • Advanced (cmdlet-like) functions imported from script modules do not see preference variables, unless they happen to be defined in the global scope - see GitHub issue #4568 for a discussion of this problematic behavior.

    If, by contrast, your intent was simply to test if a given user account exists, you could define your function as follows, using the approved verb Test and - accordingly - making the function return a [bool] value ($true or $false):

    function Test-Account($user)
    {
        [bool] (
          Get-CimInstance Win32_UserAccount | 
             Where-Object -Property Name -eq $user
        )
    }
    
    • The commands involved will not report errors under normal conditions, so there's no need for explicit error handling.

    • The [bool] cast takes advantage of PowerShell's to-Boolean conversion rules and the fact that a (non-primitive) object converts to $true, whereas lack of output or $null convert to $false - see the bottom section of this answer for a summary of the conversion rules.


    [1] Get-CimInstance should normally only report an error for an invalid class name, and Select-Object -ExpandProperty only for a non-existent property name (unlike with -Property). The Where-Object call should never report an error, given that it doesn't enforce the existence of the specified property (however, with invalid syntax any cmdlet call would report a statement-terminating error).