How to Query Active Directory Users by SID in PowerShell and C# for Change Detection


3 views

When monitoring Active Directory changes through security logs, we often encounter scenarios where we only have the Security Identifier (SID) but need to retrieve full user details. This becomes critical when implementing change notification systems or auditing solutions.

Here's a robust PowerShell solution to find users by SID:


# Convert the SID string to .NET SecurityIdentifier object
$sidString = "S-1-5-21-3968247570-3627839482-368725868-1110"
$sid = New-Object System.Security.Principal.SecurityIdentifier($sidString)

# Search Active Directory
$searcher = [ADSISearcher]"(objectSid=$($sid.Value))"
$user = $searcher.FindOne()

if ($user) {
    $properties = $user.Properties
    Write-Output "Found user: $($properties['name'])"
    Write-Output "Email: $($properties['mail'])"
    Write-Output "SAM Account: $($properties['samaccountname'])"
} else {
    Write-Output "User not found"
}

For application integration, here's how to implement this in C#:


using System.DirectoryServices;

public ADUser GetUserBySid(string sidString)
{
    var sid = new System.Security.Principal.SecurityIdentifier(sidString);
    
    using (DirectorySearcher searcher = new DirectorySearcher())
    {
        searcher.Filter = $"(objectSid={sid.Value})";
        searcher.PropertiesToLoad.AddRange(new[] {
            "name", "mail", "samaccountname", "userPrincipalName"
        });

        SearchResult result = searcher.FindOne();
        
        if (result != null)
        {
            return new ADUser {
                Name = result.Properties["name"][0].ToString(),
                Email = result.Properties["mail"][0].ToString(),
                SamAccountName = result.Properties["samaccountname"][0].ToString()
            };
        }
    }
    return null;
}

For environments with multiple domains, you'll need to:

  1. Parse the SID to extract domain identifier
  2. Connect to the appropriate domain controller
  3. Handle referral chasing if needed

When processing large volumes of change notifications:

  • Cache frequently accessed SID-to-user mappings
  • Implement proper connection pooling
  • Consider using System.DirectoryServices.AccountManagement for simpler code

Always include proper exception handling:


try {
    // AD query code
} 
catch (DirectoryServicesCOMException ex) {
    // Handle specific AD errors
}
catch (System.Runtime.InteropServices.COMException ex) {
    // Handle general COM errors
}

When monitoring Active Directory changes through security logs, we often encounter situations where we need to identify users solely by their Security Identifier (SID). Traditional lookup methods relying on attributes like sAMAccountName or userPrincipalName may not work when those same attributes are being modified.

Here's how to retrieve full user details using just the SID in PowerShell:


# Example SID from security logs
$userSID = 'S-1-5-21-3968247570-3627839482-368725868-1110'

# Basic lookup
$user = Get-ADUser -Filter {SID -eq $userSID} -Properties *

# Alternative more reliable method using .NET
$sid = New-Object System.Security.Principal.SecurityIdentifier($userSID)
$user = [ADSI]"LDAP://"
$user.GetType().GetProperties() | Select Name, Value

# To get specific properties
$samAccount = $user.sAMAccountName
$email = $user.mail
$displayName = $user.displayName

For developers working with C# applications:


using System.DirectoryServices;

public ADUser GetUserBySid(string sidString)
{
    var sid = new SecurityIdentifier(sidString);
    string path = $"LDAP://";
    
    using (DirectoryEntry userEntry = new DirectoryEntry(path))
    {
        return new ADUser {
            SamAccountName = userEntry.Properties["sAMAccountName"].Value?.ToString(),
            Email = userEntry.Properties["mail"].Value?.ToString(),
            DisplayName = userEntry.Properties["displayName"].Value?.ToString()
        };
    }
}

When working with SID-based lookups, consider these edge cases:


# Check if SID exists before querying
try {
    $user = Get-ADUser -Identity $userSID -ErrorAction Stop
} catch [Microsoft.ActiveDirectory.Management.ADIdentityNotFoundException] {
    Write-Warning "User with SID $userSID not found"
}

# Handle well-known SIDs
if ($userSID -like 'S-1-5-21-*') {
    # Regular user SID
} elseif ($userSID -like 'S-1-5-32-*') {
    # Built-in group SID
}

When processing multiple SIDs in bulk:


# Efficient batch processing
$sidList = @('SID1','SID2','SID3')
$users = $sidList | ForEach-Object {
    try {
        Get-ADUser -Identity $_ -Properties mail,displayName -ErrorAction Stop
    } catch {
        [PSCustomObject]@{SID=$_; Found=$false}
    }
}