Created
October 30, 2025 16:13
-
-
Save steve-ross/310a0f7e9b6ea7efdc5b4b3ec9d9c814 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # Active Directory Account Investigation Script | |
| # Purpose: Investigate gb12359 and hj03694 for identity contamination causes | |
| # Run this on a Windows server with Active Directory PowerShell module | |
| Write-Host "=============================================================================" -ForegroundColor Cyan | |
| Write-Host "ACTIVE DIRECTORY IDENTITY CONTAMINATION INVESTIGATION" -ForegroundColor Cyan | |
| Write-Host "=============================================================================" -ForegroundColor Cyan | |
| Write-Host "" | |
| $user1 = "gb12359" | |
| $user2 = "hj03694" | |
| # Function to display section headers | |
| function Write-Section { | |
| param([string]$Title) | |
| Write-Host "`n" -NoNewline | |
| Write-Host "=" * 80 -ForegroundColor Yellow | |
| Write-Host $Title -ForegroundColor Yellow | |
| Write-Host "=" * 80 -ForegroundColor Yellow | |
| } | |
| # Function to compare two values and highlight differences | |
| function Compare-Values { | |
| param( | |
| [string]$Property, | |
| $Value1, | |
| $Value2 | |
| ) | |
| if ($Value1 -ne $Value2) { | |
| Write-Host " *** MISMATCH DETECTED ***" -ForegroundColor Red | |
| Write-Host " $user1 ${Property}: $Value1" -ForegroundColor Red | |
| Write-Host " $user2 ${Property}: $Value2" -ForegroundColor Red | |
| } | |
| } | |
| #------------------------------------------------------------------------------ | |
| # 1. BASIC ACCOUNT INFORMATION | |
| #------------------------------------------------------------------------------ | |
| Write-Section "1. BASIC ACCOUNT INFORMATION" | |
| try { | |
| $account1 = Get-ADUser $user1 -Properties * | |
| $account2 = Get-ADUser $user2 -Properties * | |
| Write-Host "`n$user1 Account:" -ForegroundColor Green | |
| Write-Host " SamAccountName: $($account1.SamAccountName)" | |
| Write-Host " UserPrincipalName: $($account1.UserPrincipalName)" | |
| Write-Host " DistinguishedName: $($account1.DistinguishedName)" | |
| Write-Host " Enabled: $($account1.Enabled)" | |
| Write-Host " WhenCreated: $($account1.WhenCreated)" | |
| Write-Host " WhenChanged: $($account1.WhenChanged)" | |
| Write-Host "`n$user2 Account:" -ForegroundColor Green | |
| Write-Host " SamAccountName: $($account2.SamAccountName)" | |
| Write-Host " UserPrincipalName: $($account2.UserPrincipalName)" | |
| Write-Host " DistinguishedName: $($account2.DistinguishedName)" | |
| Write-Host " Enabled: $($account2.Enabled)" | |
| Write-Host " WhenCreated: $($account2.WhenCreated)" | |
| Write-Host " WhenChanged: $($account2.WhenChanged)" | |
| # Check if WhenChanged is recent (around Sept 26 or Oct 27) | |
| Write-Host "`n*** CRITICAL: Check if WhenChanged matches contamination dates ***" -ForegroundColor Magenta | |
| Write-Host "Contamination occurred on: 2025-09-26 and 2025-10-27" -ForegroundColor Magenta | |
| } catch { | |
| Write-Host "ERROR: Failed to retrieve basic account info: $_" -ForegroundColor Red | |
| exit 1 | |
| } | |
| #------------------------------------------------------------------------------ | |
| # 2. ACCOUNT RELATIONSHIPS & REFERENCES | |
| #------------------------------------------------------------------------------ | |
| Write-Section "2. ACCOUNT RELATIONSHIPS (CRITICAL CHECK)" | |
| Write-Host "`nChecking if $user1 has ANY references to $user2..." -ForegroundColor Yellow | |
| # Check all proxy addresses | |
| Write-Host "`nProxy Addresses ($user1):" | |
| if ($account1.proxyAddresses) { | |
| foreach ($proxy in $account1.proxyAddresses) { | |
| Write-Host " $proxy" | |
| if ($proxy -match $user2) { | |
| Write-Host " *** FOUND REFERENCE TO $user2 IN PROXY ADDRESS ***" -ForegroundColor Red | |
| } | |
| } | |
| } else { | |
| Write-Host " (none)" | |
| } | |
| # Check alternate security identities | |
| Write-Host "`nAlternate Security Identities ($user1):" | |
| if ($account1.altSecurityIdentities) { | |
| foreach ($altId in $account1.altSecurityIdentities) { | |
| Write-Host " $altId" | |
| if ($altId -match $user2) { | |
| Write-Host " *** FOUND REFERENCE TO $user2 IN ALT SECURITY ID ***" -ForegroundColor Red | |
| } | |
| } | |
| } else { | |
| Write-Host " (none)" | |
| } | |
| # Check manager relationship | |
| Write-Host "`nManager/Assistant Relationships:" | |
| Write-Host " $user1 Manager: $($account1.Manager)" | |
| Write-Host " $user2 Manager: $($account2.Manager)" | |
| if ($account1.Manager -match $user2) { | |
| Write-Host " *** $user1 HAS $user2 AS MANAGER ***" -ForegroundColor Red | |
| } | |
| # Check if accounts share the same objectGUID or objectSID | |
| Write-Host "`nUnique Identifiers (should be different):" | |
| Write-Host " $user1 ObjectGUID: $($account1.ObjectGUID)" | |
| Write-Host " $user2 ObjectGUID: $($account2.ObjectGUID)" | |
| Compare-Values "ObjectGUID" $account1.ObjectGUID $account2.ObjectGUID | |
| Write-Host " $user1 SID: $($account1.SID)" | |
| Write-Host " $user2 SID: $($account2.SID)" | |
| Compare-Values "SID" $account1.SID $account2.SID | |
| #------------------------------------------------------------------------------ | |
| # 3. CRITICAL ATTRIBUTES COMPARISON | |
| #------------------------------------------------------------------------------ | |
| Write-Section "3. CRITICAL ATTRIBUTES COMPARISON" | |
| $criticalAttrs = @( | |
| 'sAMAccountName', | |
| 'mail', | |
| 'givenName', | |
| 'sn', | |
| 'cn', | |
| 'displayName', | |
| 'employeeID', | |
| 'employeeNumber' | |
| ) | |
| Write-Host "`nComparing attributes that appear in CAS logs:" | |
| foreach ($attr in $criticalAttrs) { | |
| $val1 = $account1.$attr | |
| $val2 = $account2.$attr | |
| Write-Host "`n $attr" | |
| Write-Host " $user1: $val1" | |
| Write-Host " $user2: $val2" | |
| } | |
| # Check for custom attributes that might contain cross-references | |
| Write-Host "`nCustom Attributes:" | |
| $customAttrs = @('extensionAttribute1', 'extensionAttribute2', 'extensionAttribute3', | |
| 'extensionAttribute4', 'extensionAttribute5') | |
| foreach ($attr in $customAttrs) { | |
| if ($account1.$attr) { | |
| Write-Host " $user1 $attr = $($account1.$attr)" | |
| if ($account1.$attr -match $user2) { | |
| Write-Host " *** FOUND REFERENCE TO $user2 ***" -ForegroundColor Red | |
| } | |
| } | |
| } | |
| #------------------------------------------------------------------------------ | |
| # 4. LDAP QUERY TEST | |
| #------------------------------------------------------------------------------ | |
| Write-Section "4. LDAP DIRECT QUERY TEST" | |
| Write-Host "`nTesting LDAP queries for $user1..." | |
| # Test if sAMAccountName query returns exactly one result | |
| $ldapFilter = "(sAMAccountName=$user1)" | |
| Write-Host "Filter: $ldapFilter" | |
| $results = Get-ADUser -LDAPFilter $ldapFilter | |
| $count = ($results | Measure-Object).Count | |
| Write-Host "Results returned: $count" | |
| if ($count -eq 1) { | |
| Write-Host " ✓ Correct - exactly one account returned" -ForegroundColor Green | |
| } else { | |
| Write-Host " *** PROBLEM: Multiple accounts returned! ***" -ForegroundColor Red | |
| foreach ($result in $results) { | |
| Write-Host " - $($result.SamAccountName) : $($result.DistinguishedName)" -ForegroundColor Red | |
| } | |
| } | |
| #------------------------------------------------------------------------------ | |
| # 5. SEARCH FOR DUPLICATE OR ORPHANED ACCOUNTS | |
| #------------------------------------------------------------------------------ | |
| Write-Section "5. DUPLICATE/ORPHANED ACCOUNT CHECK" | |
| Write-Host "`nSearching for any accounts with similar names or IDs..." | |
| # Search by email domain | |
| if ($account2.mail) { | |
| $email = $account2.mail | |
| Write-Host "`nAccounts with email $email or similar:" | |
| Get-ADUser -Filter "mail -eq '$email'" -Properties SamAccountName, mail, Enabled | | |
| Format-Table SamAccountName, mail, Enabled -AutoSize | |
| } | |
| # Search by givenName + surname combination | |
| Write-Host "`nAccounts with similar name to $user2:" | |
| $givenName = $account2.GivenName | |
| $surname = $account2.Surname | |
| if ($givenName -and $surname) { | |
| Get-ADUser -Filter "GivenName -eq '$givenName' -and Surname -eq '$surname'" -Properties SamAccountName, mail, Enabled | | |
| Format-Table SamAccountName, mail, Enabled -AutoSize | |
| } | |
| #------------------------------------------------------------------------------ | |
| # 6. ACCOUNT HISTORY & MODIFICATIONS | |
| #------------------------------------------------------------------------------ | |
| Write-Section "6. RECENT ACCOUNT MODIFICATIONS" | |
| Write-Host "`nChecking recent modifications around contamination dates..." | |
| Write-Host "Contamination dates: 2025-09-26, 2025-10-27" | |
| Write-Host "`n$user1 modification history:" | |
| Write-Host " Created: $($account1.WhenCreated)" | |
| Write-Host " Last Modified: $($account1.WhenChanged)" | |
| Write-Host " Password Last Set: $($account1.PasswordLastSet)" | |
| Write-Host "`n$user2 modification history:" | |
| Write-Host " Created: $($account2.WhenCreated)" | |
| Write-Host " Last Modified: $($account2.WhenChanged)" | |
| Write-Host " Password Last Set: $($account2.PasswordLastSet)" | |
| # Check for account renames | |
| if ($account1.msDS-PrincipalName) { | |
| Write-Host "`n$user1 previous principal names: $($account1.'msDS-PrincipalName')" | |
| } | |
| #------------------------------------------------------------------------------ | |
| # 7. GROUP MEMBERSHIPS | |
| #------------------------------------------------------------------------------ | |
| Write-Section "7. GROUP MEMBERSHIP COMPARISON" | |
| Write-Host "`nGroup memberships ($user1):" | |
| $groups1 = $account1.MemberOf | |
| Write-Host " Total groups: $($groups1.Count)" | |
| Write-Host "`nGroup memberships ($user2):" | |
| $groups2 = $account2.MemberOf | |
| Write-Host " Total groups: $($groups2.Count)" | |
| # Find common groups | |
| $commonGroups = $groups1 | Where-Object { $groups2 -contains $_ } | |
| Write-Host "`nCommon groups: $($commonGroups.Count)" | |
| if ($commonGroups.Count -gt 0) { | |
| foreach ($group in $commonGroups | Select-Object -First 10) { | |
| Write-Host " - $group" | |
| } | |
| } | |
| #------------------------------------------------------------------------------ | |
| # 8. EXPORT FULL ATTRIBUTES TO FILES | |
| #------------------------------------------------------------------------------ | |
| Write-Section "8. EXPORTING DETAILED ACCOUNT DATA" | |
| $outputPath = "C:\Temp\AD_Investigation" | |
| New-Item -ItemType Directory -Force -Path $outputPath | Out-Null | |
| $account1 | Format-List * | Out-File "$outputPath\${user1}_full_attributes.txt" | |
| $account2 | Format-List * | Out-File "$outputPath\${user2}_full_attributes.txt" | |
| Write-Host "`nFull account details exported to:" | |
| Write-Host " $outputPath\${user1}_full_attributes.txt" | |
| Write-Host " $outputPath\${user2}_full_attributes.txt" | |
| # Create a comparison report | |
| $comparison = @" | |
| ACCOUNT COMPARISON REPORT | |
| Generated: $(Get-Date) | |
| Account 1: $user1 | |
| Account 2: $user2 | |
| CRITICAL CHECKS: | |
| - Do accounts share any identifiers? $(if ($account1.ObjectGUID -eq $account2.ObjectGUID) { 'YES - PROBLEM!' } else { 'No' }) | |
| - Does $user1 reference $user2 in proxy addresses? $(if ($account1.proxyAddresses -match $user2) { 'YES - PROBLEM!' } else { 'No' }) | |
| - Modified near contamination dates? | |
| $user1 last modified: $($account1.WhenChanged) | |
| $user2 last modified: $($account2.WhenChanged) | |
| Contamination dates: 2025-09-26, 2025-10-27 | |
| RECOMMENDATIONS: | |
| 1. Review the full attribute files for any cross-references | |
| 2. Check if $user1 was renamed or migrated around Sept 26, 2025 | |
| 3. Verify LDAP query returns exactly one result | |
| 4. Look for stale referrals or orphaned objects | |
| 5. Check AD replication health for the dates in question | |
| "@ | |
| $comparison | Out-File "$outputPath\comparison_report.txt" | |
| Write-Host "`nComparison report: $outputPath\comparison_report.txt" | |
| #------------------------------------------------------------------------------ | |
| # SUMMARY | |
| #------------------------------------------------------------------------------ | |
| Write-Section "INVESTIGATION SUMMARY" | |
| Write-Host "`n1. Check the exported files in: $outputPath" -ForegroundColor Cyan | |
| Write-Host "2. Look for ANY cross-references between accounts" -ForegroundColor Cyan | |
| Write-Host "3. Verify account modification dates match contamination timeline" -ForegroundColor Cyan | |
| Write-Host "4. If no obvious issues found, check AD replication and LDAP server logs" -ForegroundColor Cyan | |
| Write-Host "`nNext: Review exported files and search for '$user2' in $user1 attributes`n" -ForegroundColor Yellow |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment