Checking for an elevated PowerShell prompt

I just built a tool for a team of consultants to use, and some of the commands require elevation.  Rather than relying on telling them it needs to be elevated, I wanted to be able to exit immediately if the session wasn't so precious time wasn't wasted.

First, we need to figure out who the user is. To do that, you can use the [System.Security.Principal.WindowsIdentity]::GetCurrent() method and save it to a variable.

 $WindowsIdentity = [System.Security.Principal.Windowsidentity]::GetCurrent()

If you're curious about what's inside, check it out:

 PS C:\> $WindowsIdentity
AuthenticationType : Kerberos
ImpersonationLevel : None
IsAuthenticated    : True
IsGuest            : False
IsSystem           : False
IsAnonymous        : False
Name               : NORTHAMERICA\aaguilme
Owner              : S-1-5-21-124525095-708259637-1543119021-1436192
User               : S-1-5-21-124525095-708259637-1543119021-1436192
Groups             : {S-1-5-21-124525095-708259637-1543119021-513, S-1-1-0, S-1-5-32-559, S-1-5-32-545...}
Token              : 2564
AccessToken        : Microsoft.Win32.SafeHandles.SafeAccessTokenHandle
UserClaims         : {https://schemas.xmlsoap.org/ws/2005/05/identity/claims/name: NORTHAMERICA\aaguilme,
                     https://schemas.microsoft.com/ws/2008/06/identity/claims/primarysid:
                     S-1-5-21-124525095-708259637-1543119021-1436192,
                     https://schemas.microsoft.com/ws/2008/06/identity/claims/primarygroupsid:
                     S-1-5-21-124525095-708259637-1543119021-513,
                     https://schemas.microsoft.com/ws/2008/06/identity/claims/groupsid:
                     S-1-5-21-124525095-708259637-1543119021-513...}
DeviceClaims       : {}
Claims             : {https://schemas.xmlsoap.org/ws/2005/05/identity/claims/name: NORTHAMERICA\aaguilme,
                     https://schemas.microsoft.com/ws/2008/06/identity/claims/primarysid:
                     S-1-5-21-124525095-708259637-1543119021-1436192,
                     https://schemas.microsoft.com/ws/2008/06/identity/claims/primarygroupsid:
                     S-1-5-21-124525095-708259637-1543119021-513,
                     https://schemas.microsoft.com/ws/2008/06/identity/claims/groupsid:
                     S-1-5-21-124525095-708259637-1543119021-513...}
Actor              :
BootstrapContext   :
Label              :
NameClaimType      : https://schemas.xmlsoap.org/ws/2005/05/identity/claims/name
RoleClaimType      : https://schemas.microsoft.com/ws/2008/06/identity/claims/groupsid

PS C:\> $WindowsIdentity | gm
   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;}

Now, we need to instantiate a new Windows Security Principal object using the identity we just created as its argument. This object is necessary because it exposes the IsInRole method.

$Principal = New-Object System.Security.Principal.WindowsPrincipal($WindowsIdentity)

Again, we can explore what's inside:

 PS C:\> $Principal
Identity     : System.Security.Principal.WindowsIdentity
UserClaims   : {https://schemas.xmlsoap.org/ws/2005/05/identity/claims/name: NORTHAMERICA\aaguilme,
               https://schemas.microsoft.com/ws/2008/06/identity/claims/primarysid:
               S-1-5-21-124525095-708259637-1543119021-1436192,
               https://schemas.microsoft.com/ws/2008/06/identity/claims/primarygroupsid:
               S-1-5-21-124525095-708259637-1543119021-513,
               https://schemas.microsoft.com/ws/2008/06/identity/claims/groupsid:
               S-1-5-21-124525095-708259637-1543119021-513...}
DeviceClaims : {}
Claims       : {https://schemas.xmlsoap.org/ws/2005/05/identity/claims/name: NORTHAMERICA\aaguilme,
               https://schemas.microsoft.com/ws/2008/06/identity/claims/primarysid:
               S-1-5-21-124525095-708259637-1543119021-1436192,
               https://schemas.microsoft.com/ws/2008/06/identity/claims/primarygroupsid:
               S-1-5-21-124525095-708259637-1543119021-513,
               https://schemas.microsoft.com/ws/2008/06/identity/claims/groupsid:
               S-1-5-21-124525095-708259637-1543119021-513...}
Identities   : {NORTHAMERICA\aaguilme}

PS C:\windows\system32> $Principal | gm
   TypeName: System.Security.Principal.WindowsPrincipal

Name          MemberType Definition
----          ---------- ----------
AddIdentities Method     void AddIdentities(System.Collections.Generic.IEnumerable[System.Security.Claims.ClaimsIden...
AddIdentity   Method     void AddIdentity(System.Security.Claims.ClaimsIdentity identity)
Clone         Method     System.Security.Claims.ClaimsPrincipal Clone()
Equals        Method     bool Equals(System.Object obj)
FindAll       Method     System.Collections.Generic.IEnumerable[System.Security.Claims.Claim] FindAll(System.Predica...
FindFirst     Method     System.Security.Claims.Claim FindFirst(System.Predicate[System.Security.Claims.Claim] match...
GetHashCode   Method     int GetHashCode()
GetType       Method     type GetType()
HasClaim      Method     bool HasClaim(System.Predicate[System.Security.Claims.Claim] match), bool HasClaim(string t...
IsInRole      Method     bool IsInRole(string role), bool IsInRole(System.Security.Principal.WindowsBuiltInRole role...
ToString      Method     string ToString()
WriteTo       Method     void WriteTo(System.IO.BinaryWriter writer)
Claims        Property   System.Collections.Generic.IEnumerable[System.Security.Claims.Claim] Claims {get;}
DeviceClaims  Property   System.Collections.Generic.IEnumerable[System.Security.Claims.Claim] DeviceClaims {get;}
Identities    Property   System.Collections.Generic.IEnumerable[System.Security.Claims.ClaimsIdentity] Identities {g...
Identity      Property   System.Security.Principal.IIdentity Identity {get;}
UserClaims    Property   System.Collections.Generic.IEnumerable[System.Security.Claims.Claim] UserClaims {get;}

Like I previously mentioned, the IsInRole method is the one we're interested in, since we're trying to see if the user is running the PowerShell prompt as the Administrator Role.  You can see the valid roles here (https://msdn.microsoft.com/en-us/library/system.security.principal.windowsbuiltinrole(v=vs.110).aspx).

From here, the final step is to query whether or not the user is executing using the "Administrator" role. To check that, you can either build a variable for the built-in administrator role or just pass the string "Administrator."

 $AdminRole = [System.Security.Principal.WindowsBuiltInRole]::Administrator

$Principal.IsInRole("Administrator")
$Principal.IsInRole($AdminRole)

The result is the same when you query....sometimes. I've found that passing the string "Administrator" when the session is elevated will result in an error, while passing a string when the session is *not* elevated will return a Boolean.  Passing the object created by [System.Security.Principal.WindowsBuiltInRole] always returns the correct value, so that's what I'd recommend using.

 PS C:\> $Principal.IsInRole($AdminRole)
True
 # Check if Elevated
$WindowsIdentity = [system.security.principal.windowsidentity]::GetCurrent()
$Principal = New-Object System.Security.Principal.WindowsPrincipal($WindowsIdentity)
$AdminRole = [System.Security.Principal.WindowsBuiltInRole]::Administrator
if ($Principal.IsInRole($AdminRole))
{
Write-Host -ForegroundColor Green "Elevated PowerShell session detected. Continuing."
}
else
{
Write-Host -ForegroundColor Red "This application/script must be run in an elevated PowerShell window. Please launch an elevated session and try again."
Break
}