Search code examples
powershellnull-conditional-operator

How to Skip Null Objects returned from CimInstance


Get-CimInstance -ComputerName $pc -Class Win32_UserProfile | Where-Object { $_.LocalPath.split('\')[-1] -eq $compare } | Remove-CimInstance

Because some system profiles have empty values for LocalPath, I get the following:

You cannot call a method on a null-valued expression. At line:52 char:88

Where-Object { $_.LocalPath.split('')[-1] -eq $compare })

Any way either first check for empty value and skip to next?

ty


Solution

  • In PowerShell (Core) 7.1 and above, you can use the null-conditional operator, ?.:

    Get-CimInstance -ComputerName $pc -Class Win32_UserProfile | 
      Where-Object { $_.LocalPath?.split('\')[-1] -eq $compare } | 
      Remove-CimInstance
    

    As a general caveat:

    • While ?. works as expected with properties, with variables it unfortunately and unexpectedly requires the variable name to be enclosed in {...}, because - surprisingly - ? is a legal character in a variable name.
    • For instance, Set-StrictMode -Version 2; $foo = $null; ${foo}?.ToUpper() works, but using $foo?.ToUpper() instead does not, because PowerShell looks for a variable named $foo? (sic), which doesn't exist. Requesting that this counterintuitive behavior be changed - even though it is technically a breaking change - is the subject of GitHub issue #14025.

    In Windows PowerShell you can use PowerShell's implicit to-Boolean conversion rules:

    Get-CimInstance -ComputerName $pc -Class Win32_UserProfile | 
      Where-Object { $_.LocalPath -and $_.LocalPath.split('\')[-1] -eq $compare } | 
      Remove-CimInstance
    
    • Due to use of $_.LocalPath as an operand with the -and operator, it is implicitly coerced to a Boolean, and $null is coerced to $false; similarly, an empty string would yield $false - see the bottom section of this answer for a summary of PowerShell's to-Boolean conversion rules.

    • Since -and short-circuits (as does -or), the RHS expression is never evaluated if $_.LocalPath yields $false, thereby avoiding the error.

    • Note that -eq has higher precedence than -and (and -or), so no parentheses are needed around the RHS expression - see the conceptual about_Operator_Precedence help topic