Skip to content

Instantly share code, notes, and snippets.

@maximd
Forked from rmbolger/Get-UidFromSid.ps1
Created June 30, 2022 20:33
Show Gist options
  • Save maximd/851a400b809fbb5a0562a17fbc970f81 to your computer and use it in GitHub Desktop.
Save maximd/851a400b809fbb5a0562a17fbc970f81 to your computer and use it in GitHub Desktop.
Functions for converting a SID to a UID for use with RFC2307 attributes in Active Directory
function Get-UidFromSid
{
[CmdletBinding()]
param(
[Parameter(Mandatory=$true,Position=0,ValueFromPipeline,ValueFromPipelineByPropertyName)]
[System.Security.Principal.SecurityIdentifier]$sid
)
Process {
# convert sid to byte array
$sidBytes = New-Object byte[] $sid.BinaryLength
$sid.GetBinaryForm($sidBytes, 0)
Write-Verbose ("SID bytes: $([System.BitConverter]::ToString($sidBytes))")
# copy the sections we need
$ridDomainBytes = New-Object byte[] 8
[System.Array]::Copy($sidBytes, 16, $ridDomainBytes, 0, 4)
$ridUserBytes = New-Object byte[] 8
[System.Array]::Copy($sidBytes, 24, $ridUserBytes, 0, 4)
Write-Verbose ("Domain portion: $([System.BitConverter]::ToString($ridDomainBytes))")
Write-Verbose ("User portion: $([System.BitConverter]::ToString($ridUserBytes))")
# fix endian'ness if necessary
if (![System.BitConverter]::IsLittleEndian)
{
[System.Array]::Reverse($ridDomainBytes)
[System.Array]::Reverse($ridUserBytes)
}
# convert the byte arrays to longs
$ridDomain = [System.BitConverter]::ToInt64($ridDomainBytes, 0);
$ridUser = [System.BitConverter]::ToInt64($ridUserBytes, 0);
Write-Verbose "Domain(Int64) = $ridDomain, User(Int64) = $ridUser"
# Now we're going to use the first 9 bits of the domain rid followed by the
# first 22 bits of the user rid to make a single 31 bit integer (32-bit signed)
# that will be the new unique UID value for this SID
$ridDomain = ($ridDomain -band 0x1ff) -shl 22
$ridUser = $ridUser -band 0x3fffff
Write-Verbose "Domain(Int64) = $ridDomain, User(Int64) = $ridUser"
return ($ridDomain + $ridUser)
}
<#
.SYNOPSIS
Calculate the UID value for a Windows SID.
.DESCRIPTION
This function duplicates Centrify's algorithm for generating unique UID
values for Active Directory users and groups. The original algorithm was
provided by Centrify and ported to PowerShell by Ryan Bolger.
.PARAMETER sid
The SecurityIdentifier (SID) object to calculate against.
.OUTPUTS
System.Int32 value of the resulting UID.
.EXAMPLE
Get-UidFromSid ([System.Security.Principal.SecurityIdentifier]'S-1-5-21-3040497277-3966670145-4188292625-1137')
Calculate a UID from a fictional SID.
.EXAMPLE
Get-ADUser myuser | Get-UidFromSid
Calculate a UID from an existing Active Directory user via pipeline input.
#>
}
// using System;
// using System.Security.Principal;
public static long GetUidFromSid(SecurityIdentifier sid)
{
//convert to byte array
byte[] sidBytes = new byte[sid.BinaryLength];
sid.GetBinaryForm(sidBytes, 0);
// copy the sections we need
byte[] ridDomainBytes = new byte[8];
Array.Copy(sidBytes, 16, ridDomainBytes, 0, 4);
byte[] ridUserBytes = new byte[8];
Array.Copy(sidBytes, 24, ridUserBytes, 0, 4);
// fix endian'ness if necessary
if (!BitConverter.IsLittleEndian)
{
Array.Reverse(ridDomainBytes);
Array.Reverse(ridUserBytes);
}
// convert the byte arrays to longs
long ridDomain = BitConverter.ToInt64(ridDomainBytes, 0);
long ridUser = BitConverter.ToInt64(ridUserBytes, 0);
// Now we're going to use the first 9 bits of the domain rid followed by the
// first 22 bits of the user rid to make a single 31 bit integer (32-bit signed)
// that will be the new unique UID value for this SID
ridDomain = (ridDomain & 0x1ff) << 22;
ridUser = ridUser & 0x3fffff;
return (ridDomain + ridUser);
}
from __future__ import print_function
import sys
# This script is designed to accept a SID in SDDL format from stdin and output
# a UID value that can be used in the uidNumber or gidNumber attribute on an
# Active Directory domain object. The algorithm was originally provided by
# Centrify and has been ported to Python by Ryan Bolger.
# The code was originally written for Python 2.6.6 on RHEL 6 and has also been
# tested with Python 2.7.6 on Windows.
# All verbose output should be written to stderr and the only output in stdout
# should be the UID/GID value.
# Usage examples:
#
# echo S-1-5-21-3040497277-3966670145-4188292625-1137 | python SIDtoUID.py
# adquery user da06076 --sid | python SIDtoUID.py
#
# The SID in the example above should convert to UID 1346372721
def SIDtoUID(strSid):
# An Active Directory SID in SDDL form for non-built-in users/groups should
# always be in the following format:
# S-1-5-21-XXXXXXXXXX-XXXXXXXXXXX-XXXXXXXXXX-YYYY
# The X's are three 32-bit integers that comprise the 96-bit randomly
# generated domain identifier
# The Y's are a single 32-bit integer that is the object's relative ID in
# the domain (RID)
# For the purpose of this algorithm, we only care about the second section of
# the domain identifier and the user/group RID. So instead of fully parsing
# the complete SDDL into its binary form, we're going to take a short cut and
# just grab those chunks with only some basic sanity checking.
# make sure the beginning looks right
if not strSid.startswith('S-1-5-21-'):
print("ERROR: SID string was invalid.", file=sys.stderr)
exit(1)
# make sure we have the right number of elements
elements = strSid.upper().split("-")
if len(elements) != 8:
print("ERROR: Not enough sub-authority elements found.", file=sys.stderr)
exit(1)
# grab the elements we care about
ridDomain = int(elements[5])
ridUser = int(elements[7])
# Now we're going to use the first 9 bits of the domain rid followed by the
# first 22 bits of the user rid to make a single 31 bit integer (32-bit signed)
# that will be the new unique UID value for this SID
ridDomain = (ridDomain & 0x1ff) << 22
ridUser = ridUser & 0x3fffff
uid = ridDomain + ridUser
return uid
for line in sys.stdin:
print(SIDtoUID(line))
#!/usr/bin/env bash
# This script is designed to accept a SID in SDDL format from stdin and output
# a UID value that can be used in the uidNumber or gidNumber attribute on an
# Active Directory domain object. The algorithm was originally provided by
# Centrify and has been ported to Bash by Ryan Bolger.
# All verbose output should be written to stderr and the only output in stdout
# should be the UID/GID value.
# Usage examples:
#
# echo S-1-5-21-3040497277-3966670145-4188292625-1137 | ./SIDtoUID.sh
# adquery user da06076 --sid | ./SIDtoUID.sh
#
# The SID in the example above should convert to UID 1346372721
set -o nounset -o pipefail
#set -x
SIDtoUID()
{
# make sure the beginning looks right
if [[ $1 != S-1-5-21-* ]]; then
>&2 echo "ERROR: SID string was invalid."
exit 1
fi
# make sure we have the right number of elements
IFS='-' read -ra elements <<< "$1"
if [[ ${#elements[@]} != 8 ]]; then
>&2 echo "ERROR: Not enough sub-authority elements found."
exit 1
fi
# grab the elements we care about
ridDomain=${elements[5]}
ridUser=${elements[7]}
# Now we're going to use the first 9 bits of the domain rid followed by the
# first 22 bits of the user rid to make a single 31 bit integer (32-bit signed)
# that will be the new unique UID value for this SID
let "ridDomain = ($ridDomain & 0x1ff) << 22"
let "ridUser = ($ridUser & 0x3fffff)"
let "uid = $ridDomain + $ridUser"
echo $uid
}
# grab SIDs from file in first argument or stdin
while read sid; do
SIDtoUID $sid
done < "${1:-/dev/stdin}"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment