0

I am in a multilanguage client environment. The local administrators are "Administratoren", "Administrators","Administradores","Administrateurs" and so on. This works to get the group members using Invoke-Expression:

PS C:\> Get-LocalGroupMember -SID "S-1-5-32-544"

ObjectClass Name                 PrincipalSource
----------- ----                 ---------------
Benutzer    PC-JOU\Administrator Local          
Benutzer    PC-JOU\Jou           Local

Working example using the normal group name, for example on a German client WITHOUT needing Invoke-*:

PS C:\> $ADSI = [ADSI]"WinNT://IP-of-computer/Administratoren"
PS C:\> $ADSI.Invoke("Members") | foreach {$_.GetType().InvokeMember("ADsPath", 'GetProperty', $null, $_, $null)}
WinNT://PC-JOU/Administrator
WinNT://PC-JOU/Jou

But I cannot get this to work with a SID to have this international:

PS C:\> $ADSI = [ADSI]"WinNT://IP-of-computer/S-1-5-32-544"
PS C:\> $ADSI.Invoke("Members") | foreach {$_.GetType().InvokeMember("ADsPath", 'GetProperty', $null, $_, $null)}
Ausnahme beim Abrufen des Elements "Invoke": "Der Gruppenname konnte nicht gefunden werden."
In Zeile:1 Zeichen:1
+ $ADSI.Invoke("Members") | foreach {$_.GetType().InvokeMember("ADsPath ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], ExtendedTypeSystemException
    + FullyQualifiedErrorId : CatchFromBaseGetMember

I got so far to see the propertyvalue of the sid:

PS C:\> $ADSI.objectSid
1
2
0
0
0
0
0
5
32
0
0
0
32
2
0
0

PS C:\> $ADSI.objectSid.GetType()

IsPublic IsSerial Name                                     BaseType                                                                                                                                          
-------- -------- ----                                     --------                                                                                                                                          
True     False    PropertyValueCollection                  System.Collections.CollectionBase                                                                                                                 

Any idea how I can get this to work, using [ADSI] with the SID value of the local admin? It would save me using Invoke-Expression method.

Joachim Otahal
  • 272
  • 2
  • 9
  • 1
    You can get the Administrators group name through WMI, just need a little google – Santiago Squarzon Feb 20 '22 at 07:16
  • 1
    That was PERFECT !!! It works across all OS-es down to Windows 2000 (required, and there is no ps-remote never ever) and in all languages (required). With the right local administrator group name everything else is already solved. THANK YOU! – Joachim Otahal Feb 20 '22 at 08:02
  • You can get it remotely with my code too, you just have to understand how remote vs local works – Doug Maurer Feb 20 '22 at 15:33
  • No you can use winrm, wmi, psexec, etc to run remotely. I didn’t assume what your remoting capabilities were. If I did I guess I could’ve made you happy, if I was right like Santiago was. But what if wmi wasn’t available? You just assumed how it was supposed to be ran and assumed wrong and have been nothing but rude and unreasonable. Just like you assumed I downvoted. Maybe it was Santiago as it was his answer that you tried to steal credit from. – Doug Maurer Feb 21 '22 at 23:00
  • I appreciate that you tried to help me, but how should I know you expected your code in an invoke-* script-block when you don't write it? Your solution requires Invoke-* to work in multi-language correctly, and there is no invoke-* command anywhere in your solution. If you look at the edit history of my question you can see the screenshot trying your solution, and how it fails. – Joachim Otahal Feb 22 '22 at 05:05

2 Answers2

1

How about just looking up the group name via the SID first.

$AdminGroupSid = 'S-1-5-32-544'
$AdminGroup = New-Object System.Security.Principal.SecurityIdentifier($AdminGroupSid)
$AdminGroupName = $AdminGroup.Translate([System.Security.Principal.NTAccount]).Value -replace '.+\\'

Now just process your normal code

$ADSI = [ADSI]"WinNT://IP-of-computer/$AdminGroupName"
$ADSI.Invoke("Members") | ForEach-Object {
    $_.GetType().InvokeMember("ADsPath", 'GetProperty', $null, $_, $null)
}
Doug Maurer
  • 8,090
  • 3
  • 12
  • 13
  • I'd say: You skipped the "Different locale" part in my question, the very fist line! Doesn't work if one machine is English, and the other is German with pure ADSI. Your version only works if they are the same locale since your first three lines will spit out "Administrators" when executed on an English machine, which will not work if the target machine is, for example, German where that group is named "Administratoren". – Joachim Otahal Feb 20 '22 at 01:28
  • I did try it. The machine I am asking from is an english machine. You first three lines gives me the string "Administrators". Then using `$ADSI = [ADSI]"WinNT://IP-of-computer/$AdminGroupName"`, where IP is the other machine, installed in German does not give me an error. But then `$ADSI.Invoke("Members")` gives me an error. w8. firing it up again... – Joachim Otahal Feb 20 '22 at 06:16
1

SOLVED: As per comment from Santiago Squarzon, I can get the actual local administrator group name with WMI. With the right group name everything else is solved.

Working example: I query from an English domain controller, getting the local "Administratoren" from the German remote machine:

$RemoteAdminGroupName = (Get-WmiObject Win32_Group -Computername 192.168.33.57 -Filter "SID='S-1-5-32-544'").Name
"local admin group on remote machine: $RemoteAdminGroupName"
$ADSI = [ADSI]"WinNT://192.168.33.57/$RemoteAdminGroupName"
$ADSI.Invoke("Members") | foreach {$_.GetType().InvokeMember("ADsPath", 'GetProperty', $null, $_, $null)}

Result:

local admin group on remote machine: Administratoren
WinNT://S2016-DE-TEST/Administrator
WinNT://PKI-TEST/Domain Admins

enter image description here

Joachim Otahal
  • 272
  • 2
  • 9
  • Thanks for updating (+1 from me). I agree that down-voting without comment is counterproductive. – mklement0 Mar 20 '22 at 17:58
  • As an aside: The CIM cmdlets (e.g., `Get-CimInstance`) superseded the WMI cmdlets (e.g., `Get-WmiObject`) in PowerShell v3 (released in September 2012). Therefore, the WMI cmdlets should be avoided, not least because PowerShell (Core) v6+, where all future effort will go, doesn't even _have_ them anymore. Note that WMI still _underlies_ the CIM cmdlets, however. For more information, see [this answer](https://stackoverflow.com/a/54508009/45375). – mklement0 Mar 20 '22 at 17:59
  • 1
    @mklement0 I know the WMI/CIM situation, and as soon as there is a need I will test and update the answer. However not all CIM conversion are without problems, as you can see from this question: https://stackoverflow.com/questions/71538713/powershell-cim-method-delete-is-missing-in-win32-shadowcopy . Other typical differences are different data types for date representations in the "same" output and so on. – Joachim Otahal Mar 21 '22 at 16:54