stash/Get-Privileges.ps1

using namespace System.Text
# Easiest way: whoami /priv /fo csv | ConvertFrom-Csv
function Get-Privileges {
  [CmdletBinding()]param()

  begin {
    New-Delegate advapi32 {
      bool GetTokenInformation([ptr, uint, buf, uint, uint_])
      bool LookupPrivilegeDisplayNameW([string, buf, buf, uint_, uint_])
      bool LookupPrivilegeNameW([string, buf, buf, uint_])
      bool OpenProcessToken([ptr, uint, ptr_])
    }

    New-Delegate kernel32 {
      bool CloseHandle([ptr])
    }

    $token, $sz = [IntPtr]::Zero, 0
  }
  process {}
  end {
    try {
      if (!$advapi32.OpenProcessToken.Invoke([IntPtr]-1, 0x08, [ref]$token)) {
        throw [InvalidOperationException]::new('Cannot access token.')
      }

      # TokenPrivileges = 0x03
      if (!$advapi32.GetTokenInformation.Invoke($token, 0x03, $null, 0, [ref]$sz) -and $sz -ne 0) {
        $buf = [Byte[]]::new($sz)
        if (!$advapi32.GetTokenInformation.Invoke($token, 0x03, $buf, $buf.Length, [ref]$sz)) {
          throw [InvalidOperationException]::new('Cannot get token information.')
        }
      }
      # getting PrivilegeCount (first field of TOKEN_PRIVILEGES)
      $PrivilegeCount = [BitConverter]::ToUInt32($buf[0..3], 0)
      # other bytes of $buf are Privileges (LUID_AND_ATTRIBUTES[$PrivilegeCount])
      $Privileges = $buf[4..$buf.Length] # sizeof(LUID_AND_ATTRIBUTES) = 0x0C
      [Array]::Resize([ref]$buf, 255)
      for ($i = 0; $i -lt $Privileges.Length; $i++) {
        # sizeof(LUID) = 0x08, Attributes takes 4 bytes
        $LUID, $Attributes = $Privileges[0..7], [BitConverter]::ToUInt32($Privileges[8..11], 0)
        $buf.Clear()
        $sz = $buf.Length
        if ($advapi32.LookupPrivilegeNameW.Invoke($null, $LUID, $buf, [ref]$sz)) {
          $name = $buf[0..($sz * 2 - 1)] # keep in mind that is Unicode data
          $buf.Clear()
          $sz = $buf.Length
          if ($advapi32.LookupPrivilegeDisplayNameW.Invoke($null, $name, $buf, [ref]$sz, [ref]$null)) {
            [PSCustomObject]@{
              Privilege = [Encoding]::Unicode.GetString($name)
              Description = [Encoding]::Unicode.GetString($buf[0..($sz * 2 - 1)])
              Attributes = (
                ('Disabled','Default Enabled')[$Attributes -band 1], 'Enabled'
              )[($Attributes -band 2) -eq 2]
            }
          }
        }
        $Privileges = $Privileges[12..$Privileges.Length]
      }
    }
    catch { Write-Verbose $_ }
    finally {
      if ($token -ne [IntPtr]::Zero) {
        if (!$kernel32.CloseHandle.Invoke($token)) {
          Write-Verbose 'Cannot release token.'
        }
      }
    }
  }
}