powershell - How can I capture the value of an untranslated SID in a TryCatch code block? - Stack Overflow

admin2025-04-17  3

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?

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?

Share Improve this question asked Jan 30 at 18:17 QwertyQwerty 1938 bronze badges
Add a comment  | 

5 Answers 5

Reset to default 2

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 }
}

Unless there is a way to capture the error caused further up the pipeline, this workaround did the job for my purposes.

$getToken = [System.Security.Principal.WindowsIdentity]::GetCurrent()
$groupSIDs = $getToken.Groups
$getGroups = foreach($sid in $groupSIDs) {
        try {
  (($sid).Translate([System.Security.Principal.NTAccount]).Value) + " ($sid)"
        }
        catch {
              $sid.Value
        }
}
$getToken | Select-Object Name, @{n='Groups';e={$getGroups}} | ConvertTo-Html -As List -Fragment

UPDATE: Since I have already defined [System.Security.Principal.WindowsIdentity]::GetCurrent() in the variable $getToken, I might as well re-use it where appropriate.

Of course, you can. Just replace Out-Null to $_.Value But! if you will maintain this code in future, you won't be pleasure to yourself =))

Maybe something like this is your case:

$CurrentUser = [System.Security.Principal.WindowsIdentity]::GetCurrent()
$User = [PSCustomObject]@{
    Name = $CurrentUser.Name
    Groups = @()
}

foreach ($GroupSID in $CurrentUser.Groups) {
    try {
        $User.Groups += "$($GroupSID.Translate([System.Security.Principal.NTAccount]).Value) ($($GroupSID.Value))" 
    }
    catch {
        Write-Warning "Cannot translate $($GroupSID.Value)"
        $User.Groups += $GroupSID.Value
    }
}


# Join array to string for Html
$User | Select-Object Name, @{n='GroupList'; e={$PSItem.Groups -join ', '}} | ConvertTo-Html -As List -Fragment

You could use Update-TypeData to add a ScriptMethod where you define the try / catch logic:

$updateTypeDataSplat = @{
    TypeName   = 'System.Security.Principal.SecurityIdentifier'
    MemberType = 'ScriptMethod'
    MemberName = 'SafeTranslate'
    Value      = {
        try {
            '{0} ({1})' -f $this.Translate([System.Security.Principal.NTAccount]), $this
        }
        catch {
            # Can use `$_.Exception` here to get more details on why it failed
            'Failed to Translate ({0})' -f $this
        }
    }
}

Update-TypeData @updateTypeDataSplat

Then you could do:

[System.Security.Principal.WindowsIdentity]::GetCurrent() |
    Select-Object Name, @{ N='Groups'; E={ $_.Groups.SafeTranslate() }} |
    ConvertTo-Html -As List -Fragment

As far as I know, you can not iterate further up the pipeline, you will have to split your code a little. Something like this - I think you will have to further work out the html conversion but it could get you started:

$user = [System.Security.Principal.WindowsIdentity]::GetCurrent()
$groups = $user.groups
$result = @()
$result += [pscustomobject]@{
    name = $user.name
    groups = @()
}
foreach ($g in $groups){
    Try{
        $result[0].groups += $g.Translate([System.Security.Principal.NTAccount]).Value + ' (' + $g.Value +')'
    }
    Catch{
        $result[0].groups += $g
    }
}    
$result
转载请注明原文地址:http://anycun.com/QandA/1744898888a89192.html