.netpowershellwindows-identity

How do I get the/create a WindowsIdentity for a SID using .Net in PowerShell?


Using this in PowerShell will get the WindowsIdentity of myself in PowerShell.

[System.Security.Principal.WindowsIdentity]::GetCurrent()

This will contain the following members

   TypeName: System.Security.Principal.WindowsIdentity

Name               MemberType Definition
----               ---------- ----------
AddClaim           Method     void AddClaim(System.Security.Claims.Claim claim)
AddClaims          Method     void AddClaims(System.Collections.Generic.IEnumerable[System.Security.Claims.Claim] cl...
Clone              Method     System.Security.Claims.ClaimsIdentity Clone()
Dispose            Method     void Dispose(), void IDisposable.Dispose()
Equals             Method     bool Equals(System.Object obj)
FindAll            Method     System.Collections.Generic.IEnumerable[System.Security.Claims.Claim] FindAll(System.Pr...
FindFirst          Method     System.Security.Claims.Claim FindFirst(System.Predicate[System.Security.Claims.Claim] ...
GetHashCode        Method     int GetHashCode()
GetObjectData      Method     void ISerializable.GetObjectData(System.Runtime.Serialization.SerializationInfo info, ...
GetType            Method     type GetType()
HasClaim           Method     bool HasClaim(System.Predicate[System.Security.Claims.Claim] match), bool HasClaim(str...
Impersonate        Method     System.Security.Principal.WindowsImpersonationContext Impersonate()
OnDeserialization  Method     void IDeserializationCallback.OnDeserialization(System.Object sender)
RemoveClaim        Method     void RemoveClaim(System.Security.Claims.Claim claim)
ToString           Method     string ToString()
TryRemoveClaim     Method     bool TryRemoveClaim(System.Security.Claims.Claim claim)
WriteTo            Method     void WriteTo(System.IO.BinaryWriter writer)
AccessToken        Property   Microsoft.Win32.SafeHandles.SafeAccessTokenHandle AccessToken {get;}
Actor              Property   System.Security.Claims.ClaimsIdentity Actor {get;set;}
AuthenticationType Property   string AuthenticationType {get;}
BootstrapContext   Property   System.Object BootstrapContext {get;set;}
Claims             Property   System.Collections.Generic.IEnumerable[System.Security.Claims.Claim] Claims {get;}
DeviceClaims       Property   System.Collections.Generic.IEnumerable[System.Security.Claims.Claim] DeviceClaims {get;}
Groups             Property   System.Security.Principal.IdentityReferenceCollection Groups {get;}
ImpersonationLevel Property   System.Security.Principal.TokenImpersonationLevel ImpersonationLevel {get;}
IsAnonymous        Property   bool IsAnonymous {get;}
IsAuthenticated    Property   bool IsAuthenticated {get;}
IsGuest            Property   bool IsGuest {get;}
IsSystem           Property   bool IsSystem {get;}
Label              Property   string Label {get;set;}
Name               Property   string Name {get;}
NameClaimType      Property   string NameClaimType {get;}
Owner              Property   System.Security.Principal.SecurityIdentifier Owner {get;}
RoleClaimType      Property   string RoleClaimType {get;}
Token              Property   System.IntPtr Token {get;}
User               Property   System.Security.Principal.SecurityIdentifier User {get;}
UserClaims         Property   System.Collections.Generic.IEnumerable[System.Security.Claims.Claim] UserClaims {get;}

But how do I get the WindowsIdentity for a known user SID?

I've tried creating and using a SecurityIdentifier as below, but that will give me an error.

$Sid = 'ENTER SID HERE'
$SecurityIdentifier = [System.Security.Principal.SecurityIdentifier]$Sid
$WindowsIdentity = New-Object System.Security.Principal.WindowsIdentity $SecurityIdentifier

New-Object : Exception calling ".ctor" with "1" argument(s): "The name provided is not a properly formed account name. "

I tried using type casting, [System.Security.Principal.WindowsIdentity]$SecurityIdentifier, as well but the New-Object cmdlet gave a somewhat better error description.

It was suggested to me elsewhere that How to get NT Account from the SID using PowerShell is a duplicate to this question. But that answer returns an NTAccount object that only contains the following members.

   TypeName: System.Security.Principal.NTAccount

Name              MemberType Definition
----              ---------- ----------
Equals            Method     bool Equals(System.Object o)
GetHashCode       Method     int GetHashCode()
GetType           Method     type GetType()
IsValidTargetType Method     bool IsValidTargetType(type targetType)
ToString          Method     string ToString()
Translate         Method     System.Security.Principal.IdentityReference Translate(type targetType)
Value             Property   string Value {get;}

I need a WindowsIdentity object.


Solution

  • I'm not sure why you're so hung up on that specific object type, but you can do it if you try...

    Convert the SID string to a [System.Security.Principal.SecurityIdentifier] object, and use the Translate(type targetType) method to make it an NTAccount object. This gets you an actual name and context for the user. A little string manipulation converts domain\user to a UserPrincipalName user@domain and that's all you need to generate a WindowsIdentity object.

    Function Convert-SIDtoWindowsID {
    [CmdletBinding()]
    Param(
        [parameter(ValueFromPipeline)]
        [System.Security.Principal.SecurityIdentifier]$SID
    )
        $UPN=$SID.Translate([System.Security.Principal.NTAccount]) -replace '(.+?)\\(.+)','$2@$1'
        [System.Security.Principal.WindowsIdentity]::new($UPN)
    }
    

    Then you can just do:

    Convert-SIDtoWindowsID 'S-1-5-21-1111111111-2222222222-3333333333-44444444'