Creating a SID Mapping File with Windows PowerShell

Before I became a “Deployment Guy”, I used to be an “Active Directory Guy” and worked on quite a few Active Directory deployments and migrations.  When users, groups, and computers are migrated to a new domain, the resources (files, shares, user profiles, etc.) need to have the permissions on them changed so that the migrated accounts can access them as before.  If users/groups are migrated before the resources, they can be migrated with SID History (the SID of the old accounts are placed in the sIDHistory attribute of the new account) to allow access to resources before the “security translation” of permissions is completed.

Many domain migration tools like Microsoft’s Active Directory Migration Tool (ADMT) can perform both the object migration and the security translation.  They use their database of migrated objects to do the security translation.  I was brought in on one engagement where a customer had contracted with a vendor to perform their account domain migration with SID History.  However, the resource domains were not migrated at the same time.  They then wanted to collapse their resource domains after the vendor was finished.  Unfortunately, the customer did not own the migration tool that the vendor used and did not have access to the migration database either.

ADMT has the ability to do the security translation using what is called a SID Mapping File.  This is a text file that contain entries that maps the source account to the destination account in either Windows NT account name (domain\name) format or SID format.  The entries look like this:


However, this functionality would be of no use without a way of generating the mapping file.  This could be done manually but would be a tremendous task if the account names were changed.  The MCS lead consultant on the project, Alan von Weltin, hit upon the idea of using the SID History information already present in Active Directory to generate the mapping file.  The accounts in AD had the the SIDs of the source accounts in the sIDHistory attribute.  I was asked to write the script that would query for all security principals that had SID History and for each object write a line to the file that mapped each source SID to the Windows NT account name of the new account.

When I first did this, I used VBScript as the scripting language.  Because SIDs in AD are stored as octet strings, converting them to a readable string is not easy in VBScript.  So I used a DLL available in the old ADSI Resource Kit (ADsSecurity.dll) that provided a COM object (ADsSID) for this conversion.  This ADSI Resource Kit has since been discontinued.  Because of this I wanted to create a new version that did not depend on this DLL.

So in my spare time I worked on a version written in Windows PowerShell.  This allows access to the .NET Framework which has classes in the System.DirectoryServices and System.Security namespaces that make searching AD and translating the SIDs to strings relatively easy.  A customer case recently arose where the SID Mapping was needed again.  This inspired me to finally finish this script and publish it here.

Get-SidMappingAD.ps1 will dump a SID mapping from Active Directory.  You must be logged on with an account that has read access to AD.  Use the -help switch for usage.  Note that the mapping from Get-SidMappingAD.ps1 can be generated from objectSid (not useful for  ADMT security translation but useful for documenting source domain SIDs) or sIDHistory.  You have to use the -sidhistory switch to generate the mapping file from sIDHistory.  (You can also dump the “name” field as the object DN.  Not useable by ADMT but useful for documentation.)

I also created a script (Get-SidMappingSAM.ps1) to dump an objectSid,comutername\name mapping file for a local computer SAM database or a Windows NT domain.


Disclaimer: The information on this site is provided "AS IS" with no warranties, confers no rights, and is not supported by the authors or Microsoft Corporation. Use of included script samples are subject to the terms specified in the Terms of Use.

This post was contributed by Michael Murgolo a Senior Consultant with Microsoft Services, U.S. East Region.

Comments (10)
  1. bjtukker,

    I cannot reproduce your problem.  I just tried Get-SidMappingSAM.ps1 on Windows 7 and Windows Server 2008 R2 and it works fine for me for all the local security principals.

    Also, I'm not sure what you mean by "if the user of the SID I use, doesn't exist anymore".  My script does not query for anything that does not exist.  Are you asking for help with some script you wrote?

    If you are trying to trap and handle errors in a PowerShell script, look at using Try, Catch, and Finally blocks (…/dd315350.aspx).

    Michael Murgolo

  2. Chris,

    I just retested this against an account with multiple SIDs in sIDHistory.  The script retrieved them just fine.  Were you using the -sidhistory switch?

    Yes, AMDT can use multiple Source SIDs.  The syntax is no different.  There will just be multiple lines mapping a SID to the same domainname entry.

    Michael Murgolo

  3. Chris Leturno says:

    So if you are building a SID mapping file using this script. I have noticed that it only pulls the most recent SID out of the SIDHistory attribute. I am in the middle f a migration where SIDHistory was never cleaned up so I have users with up to 5 SIDs in SIDHistory. We are still looking for a resource that utilizes anything past the first SID, but we don’t want to take a risk. Can ADMT use a SID mapping file with more then one SID from the Source domain and if so what is the syntax for multiple SIDS?

  4. Chris says:

    Thanks for you help, I never got back to responding until just now, 30,000 users, 60,000 workstations and 1200 servers later.

    Your response was greatly appreciated and assisted your script helped save me a lot of time.

  5. bjtukker says:

    Hi Chris,

    When running the Get-SidMappingSAM.ps1 against a Windows 2008 machine I receive some errors on local users and groups:

    Name: Cryptographic Operators

    Exception calling "Translate" with "1" argument(s): "Some or all identity references could not be translated."

    At G:ScriptsPowerShellADGet-SidMappingSAM.ps1:111 char:34

    +     $securityidentifier.Translate( <<<< [System.Security.Principal.NTAccount])


    I guess these troubled groups are not "BUILTIN", but of the local system (e.g. SERVER1). This also happens with the SID-500 and SID-501 accounts. Any idea if this is a Windows 2008 (not R2) related issue? And how can I solve this issue?

    Thanks in advance,


  6. bjtukker says:

    It's not a W2K8 issue; I also received the errors on W2K3. With a slight addition to the script after line 140, it's fixed:

           $NtNameString = $NtAccount.Value    

    # If $NtNameString is empty, replace by $computername$

           if ($NtNameString -eq $null) {$NtNameString = '$computername$'}

    # end of edit

    Kind regards,


  7. bjtukker says:

    Hi Michael,

    6 month (+) ago I created the two posts above, but I now see that I addressed the wrong person; instead of Chris, I should have addressed Michael.

    $SID = New-Object System.Security.Principal.SecurityIdentifier($SIDstring[$i])

    $User = $SID.Translate([System.Security.Principal.NTAccount])

    $LocalArray += $User.Value

    How can I prevent that the script fails, if the user of the SID I use, doesn't exist anymore?

      Exception calling "Translate" with "1" argument(s): "Some or all identity references could not be translated."

      At :line:52 char:26

      +$User = $SID.Translate <<<< ([System.Security.Principal.NTAccount])

    Aka, how do I filter out those wrong SID's? Any ideas?



  8. Josef says:

    Why does $User = $SID.Translate([System.Security.Principal.NTAccount]) show the owners domain/user of a given sIDhistrory and not the domain/user this sIDhistory is from?

  9. Michael Bedinghaus says:

    I would like to know if I can use these when I already have the SID and want the identity or alias that is associated with that SID? I do not know what domain the object would be in and our environment has many domains.

  10. Peter Nield says:

    Windows 2008 R2 and later have the "ActiveDirectory" module which makes this a bit simpler:

    import-module ActiveDirectory

    #Export all obejcts with SIDHistory
    $migratedObjects = get-adobject -Filter "SIDHistory -like '*'" -Properties ObjectSID,SIDHistory

    #build table of OldSID,NewSID
    [tag:just] in case SIDHistory is mulitvalued, iterate through SIDHistory
    $xlate=$migratedObjects | foreach {$SID=$_.ObjectSID;$_.SIDHistory | Foreach {"$_,$SID"}}

    $xlate |set-content SIDMapping.csv

    I'd also adde mappings for "DomainDomain Users" and "DomainDomain Administrators" to BUILTINUsers and BUILTINAdminstrators respectively to patch up ACE's to slight more portable ones.

Comments are closed.

Skip to main content