Search code examples
powershell

How can I capture the value of an untranslated SID in a Try/Catch code block?


I'm relatively new to PowerShell, so this may be something simple. I am attempting to display the translated name and original SIDs for the Groups associated with the current login. The Translated names are easy enough:

[System.Security.Principal.WindowsIdentity]::GetCurrent().Groups.Translate([System.Security.Principal.NTAccount]).Value

This display as such and includes an orphaned SID that could not be translated:

Everyone 
BUILTIN\Administrators 
BUILTIN\Users
NT AUTHORITY\INTERACTIVE
CONSOLE LOGON
NT AUTHORITY\Authenticated Users
NT AUTHORITY\This Organization
LOCAL
S-1-12-X-XXXXXXXX-XXXXXXXX-XXXXXXXX-XXXXXXX
NT AUTHORITY\Cloud Account Authentication

The orphaned SID has been redacted with Xs. This is part of a larger script and I am attempting to capture this section as HTML like the following:

$currentUser = [System.Security.Principal.WindowsIdentity]::GetCurrent() | Select-Object Name, @{n='Groups';e={$_.Groups | Foreach-Object {
    try
    {
    $_.Translate([System.Security.Principal.NTAccount]).Value + ' (' + $_.Value +')'
    }
    catch [Exception]
    {
     Out-Null
     }
    }}} | ConvertTo-Html -As List -Fragment

In this example, I am suppressing the Exception, but I have not found a way to display the object that is causing the exception ("Translate" with "1" argument(s): "Some or all identity references could not be translated.").

Is there a way to list the object that caused the exception? I tried with the following:

$_.Exception.TargetObject

The TargetObject was empty. Is there perhaps an if/else construct that could be used if an exception is encountered?


Solution

  • The problem in this question is that the Foreach-Object cmdlet uses the current item ($PSItem or $_) and the Catch block also uses (overrules) the current item to reference the exception information.

    A minimal reproducible example to show this, would be:

    1..5 | Foreach-Object { try { 1 / ( 3 - $_ ) } catch { "Error processing: $_" } }
    0.5
    1
    Error processing: Attempted to divide by zero.
    -1
    -0.5
    

    Note that the same issue exists in an embedded Foreach-Object loop.

    Probably the easiest (and cleanest) way around this is to assign the current item to another variable which might be done further into the pipeline than the solution you present in your self-answer:

    1..5 | Foreach-Object { $n = $_; try { 1 / ( 3 - $_ ) } catch { "Error processing: $n" } }
    0.5
    1
    Error processing: 3
    -1
    -0.5
    

    For your specific case, the Foreach-Object loop might probably be something similar to this:

    ... | Foreach-Object {
        $Sid = $_
        try { "$($_.Translate([System.Security.Principal.NTAccount]).Value) ($($_.Value))" }
        catch { $Sid.Value } # or better: catch [<Specific Exception>] { $Sid.Value }
    }