Goatee PFE

Blog of Microsoft Premier Field Engineer Ashley McGlone featuring PowerShell scripts for Active Directory.

How To Remove SID History With PowerShell

How To Remove SID History With PowerShell

  • Comments 18
  • Likes

Update:  To see all articles in this series click here.


In the United States we celebrate Thanksgiving tomorrow.  No matter where you are in the world let us all give thanks for PowerShell.  If Windows were the pumpkin pie, then PowerShell would be the whipped cream on top.  If Active Directory were the turkey, then PowerShell would be the stuffing.  If Exchange were the mashed potatoes, then PowerShell would be the gravy.  Eating and scripting are complementary passions, so we give thanks for both.

This post is part four in the "PowerShell: SID Walker, Texas Ranger" series on documenting and remediating SID history in your AD forest. Go back and read over the previous articles in the series if you haven't had a chance yet. In today's post we will look at the final step of remediating SID history:  removing the SID history data from our migrated AD objects.  Cleaning up this stale data will greatly reduce the chance of token size issues for your users.


In an earlier post I explained the process for cleaning up SID history, and the last step is actually removing the data from your environment.  This is the last step.  It is crucial that you have already remediated your ACLs, swapping old SIDs for new SIDs.  The preferred method is the ADMT, and then for NAS file shares you can use the function I provided in part 2Please note that removing SID history may cause significant impact to your users if you have not taken the time to migrate resource ACLs.  I highly recommend reviewing the ADMT Guide to make sure you have completed all migration steps up to this point.  You have been warned.  Proceed carefully.  As a backout plan make sure you have a good system state backup from two DCs per domain.  Using VBScript to clear SID history was painful. PowerShell achieves the same end with far fewer lines of code.

Get-SIDHistory | Remove-SIDHistory

I decided to divide this function into two parts.  I wanted a dynamic AD query to retrieve users and groups by specific criteria as a way to surgically target the SID history removal.  Then I wanted to pipe the entries returned into a dedicated function for doing the actual removal.  This allows us to craft the right AD query in a safe environment before pulling the trigger on SID history.


When removing SID history it is best to proceed in phases by department or business unit.  You know the drill.  Start with a few users in IT, then all of IT, then company departments beginning with the least critical business impact (ie. Grounds Keeping before Purchasing).  You must send notification to your users asking them to verify that all of their resource access and drive letters are still good after the change.

Using Get-ADObject to query by name or OU is pretty straightforward, so I won't go into much detail there.  The magic of this function, though, is the -DomainName parameter.  You can specify the FQDN of the former domain for which you wish to remove SID history.  Now that is cool!  We can easily target the SID history by domain, because the SID object has a property called AccountDomainSid. We don't even have to parse it out. When we get back the SID history entries, we can filter on this attribute to target a specific domain in the SID history.

In order for this to work you have to first use Export-DomainSIDs to create the DomainSIDs.CSV file that maps the domain names to the domain SIDs.  If you don't know the old domain name, then you can use the -DomainSID switch to remove SID history for any unnamed domain.  You can copy the old domain SID from the SIDHistoryReport.CSV file produced by the function Export-SIDMapping (included in the attached code).  You could also modify the DomainSIDs.CSV file by manually adding any other domain names and SIDs from your own documentation.

Another feature of the Get-SIDHistory query is that it handles the multi-value nature of the sIDHistory attribute.  We do this using the ExpandProperty parameter of Select-Object which I demonstrated here.  This allows us to identify and target specific SID history entries when a user has been migrated more than once.  The ExpandProperty parameter ensures that we get a result row for every SID history entry regardless of the count.

Here is an example without ExpandProperty:

Get-ADUser user1 -Property sIDHistory | Select-Object name, sIDHistory | Format-Table name, sIDHistory –AutoSize

name   sidhistory
----   ----------
user1  {S-1-5-21-3013500491-1380372588-2491230877-1122, S-1-5-21-179552...

Here is an example with ExpandProperty:

Get-ADUser user1 -Property sIDHistory | Select-Object name, sIDHistory -ExpandProperty sidHistory | Format-Table name, sIDHistory –AutoSize

name   Value
----   -----
user1  S-1-5-21-3013500491-1380372588-2491230877-1122
user1  S-1-5-21-1795525639-2355993942-847153066-1695

Notice that ExpandProperty modifies the property name to "value".  We can rename that at the end of the pipe using Select-Object:

Select-Object DistinguishedName, @{name="SID";expression={$_.Value}}

Get-SIDHistory takes the parameters you specify, shapes them into an AD query, and then uses Invoke-Expression to run it.  In other words, this is code that writes code.  I love that feature of PowerShell.  The query parameters are cumulative.  Therefore you can pile on two or three criteria for laser accuracy.

Here are a few examples of how you can use Get-SIDHistory:

  • Get-SIDHistory –SamAccountName ashleym
  • Get-SIDHistory –DomainName wingtiptoys.com
  • Get-SIDHistory –DomainName wingtiptoys.com –SamAccountName ashleym
  • Get-SIDHistory –DomainSID S-1-5-21-2371126157-4032412735-3953120161
  • Get-SIDHistory –ObjectClass group
  • Get-SIDHistory –SearchBase "OU=Sales,DC=contoso,DC=com"
  • Get-SIDHistory –MemberOf MigratedUsers
  • Get-SIDHistory | Measure-Object

Experiment with different combinations of parameters until you isolate exactly the targets you need.  Then you can script out multiple statements for each phase of the remediation.


This short TechNet article provides syntax for removing SID history:

Get-ADUser –filter 'sidhistory –like "*"' –searchbase "dc=name,dc=name" –searchscope subtree –properties sidhistory | foreach {Set-ADUser $_ -remove @{sidhistory=$_.sidhistory.value}}

That single line of PowerShell is a "resumé-generating-event".  DO NOT RUN THIS LINE IN YOUR ENVIRONMENT IF YOU WANT TO KEEP YOUR JOB.  Wiping SID history for every user all at once is not a best practice (in case you were wondering).

You can call Remove-SIDHistory by specifying the distinguishedName of the object and the SID entry to remove.  However, that is a lot of complicated typing.  The intention is to use Get-SIDHistory to tailor your query to exactly the results you want, and then simply pipe it to Remove-SIDHistory.  This works through a feature of PowerShell advanced functions called cmdlet binding.  The ValueFromPipelineByPropertyName argument allows us to pipe the output from one function into the next as long as the first output properties match the second input parameters. Features like this make PowerShell truly remarkable.

Get-SIDHistory –SamAccountName ashleym | Remove-SIDHistory

I recommend piping the output of the Remove-SIDHistory to a CSV file for change documentation.  Like this:

Get-SIDHistory –SamAccountName ashleym | Remove-SIDHistory | Export-CSV removed.csv

Your CSV will include a date/time stamp for each entry's removal:


This documentation will come in handy if users start to call and report issues after the removal.  But that shouldn't happen if you are thorough in scrubbing all SID history dependencies prior to removing the data.


If you've been putting off SID history remediation due to the mystery of how to remove it, then your puzzle is solved.  Using the functions in today's post will make the removal process swift and painless.  Let me reiterate that this is the LAST step in the migration process.  Do not proceed until all of your resource translation is complete and verified.  Phase the remediation by user groups to limit any unforeseen impact.  Following these recommendations will make the transition as smooth as possible.

So if you are celebrating Thanksgiving with family tomorrow and everyone around the table shares something they are thankful for, you can be the geek that is thankful for PowerShell.  Most likely no one else at the table will know what you're talking about.  Just smile and nod.

Coming Up Next…

In the next installment of our SID history series we'll provide a handy summary of each post in the series.  We will also take the function library we've been using and upgrade it to a PowerShell module.  Then we'll walk through the entire SID history remediation process using the provided cmdlets in this module.

Attachment: SIDHistoryV1.2.zip

Can you help me?  Yes!

If you would like to have me or another Microsoft PFE visit your company and assist with the ideas presented in this blog post, then contact your Microsoft Premier Technical Account Manager (TAM) for booking information.

For more information about becoming a Microsoft Premier customer email PremSale@microsoft.com.  Tell them GoateePFE sent you.

Sharing Links
  • This is great PoSh code.  Thank you so very much for putting all this together.  I work on several AD migration projects a year and always find it useful to add to my "toolbox".  This is going on the top of my list! :)

    I would like to recomend an update though.  Often times I am in the Source domain/forest running operations against the Target domain/forest.  It would be very useful to have some way to specify the preferred DC that you want to run the cmdlets against.  I hope this feedback helps you as much as your code has helped me.

  • Hi Richard,

    Thanks for the great feedback.  That is good to hear.

    You're not the first to ask for domain/DC targeting with the functions in the module.  It is on my list of future updates.  Thanks for reinforcing this need.


  • "DO NOT RUN THIS LINE IN YOUR ENVIRONMENT IF YOU WANT TO KEEP YOUR JOB" Maybe next time put that before the line :( Just kidding, I'm currently perusing this series in the hope of finding the solution to all my troubles but I'm in fairly uncharted waters for me so I'm treading very carefully... Thanks heaps.

  • Hey ! At first, thanks for the great work, i really appreciate this ! but i have also a little problem. i tested it out in our environment and it seemed as if it works fine so far. i made an output file and removed the sid-history of a test-user account. "status removed" with the actual date and the old sid was listed there. but if i do another get-sidhistory for that user account, that old sid still appears. i even did a 1on1 copy of each method and line here how to remove the sid. im a domain admin and can change everything and every other object / attribute, permissions cant be the problem here. any ideas? :)

  • Hi worksfine,
    Sorry to hear you've run into a snag. Please use the Email Blog Author link at the top right of this page to send me a transcript of your PowerShell session reproducing the problem. (Start-Transcript / Stop-Transcript). Also, what operating system versions and PowerShell versions are involved in your tests?

  • Hello Ashley,

    I was wondering if there is way to delete Sid history for selected users after the migration in batches.
    I have recently completed a migration of about 2500 users and now client wants to proceed to Sid history cleanup, but wants to get it done in smaller user batches.
    Please advise on how to proceed for this one.


  • Hello Mohit,
    Yes, you can remove them in batches. Notice the Get-SIDHistory commands in the middle of the article. You can combine multiple criteria to get the right target audience, and then you can pipe it to Remove-SIDHistory. I also recommend piping the output again to Export-CSV so that you have a record of what changed.
    Hope this helps,

  • Thank you so much Ashley :-) It helped me to remove the SIDHistory from one of the problematic users.


  • Thanks a lot Ashley ;-) this module is very helpful. It helped me to remove SIDHistory from one user in exchange migration and mailbox delegation issue. You save me a lot of time!

  • You could also do this in one line :)

    Set-ADObject -Identity -Remove @{sidhistory=""}

  • Hi Ashley
    Is it possible to remove one single SID from the SIDHistory property.
    Simple example : Use A has 2 SIDs in SIDHistory property. Can i remove one SID and leave the other SID.

  • Hello Sugit,
    Yes. Please read again the paragraphs above explaining the function Get-SidHistory. You can use it to specifically target only the SidHistory entries desired. Then pipe the result to Remove-SidHistory to remove just those, leaving the others. Like this:
    Get-SIDHistory -DomainSID S-1-5-21-2371126157-4032412735-3953120161 -SamAccountName ashleym | Remove-SidHistory
    Hope this helps,

  • Hello Ashley,

    I have been following your articles and they are great help. We are working on creating a migration tool which allows cross forest migration we are stuck at a point where we need to migrate the SIDHistory from one forest to another with the help of Shell script without using ADMT. Do you think this is something you can guide us with?

  • Hi,

    I try to remove the history of one specific group with this line:

    Get-SIDHistory –ObjectClass groupname | Remove-SIDHistory | Export-CSV removed.csv

    When I do this powershell gives the error that the command is incorrect. Any suggestions on which command to use to remove the Sid history are greatly appreciated

Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment