If you are doing a migration from one domain to another, you may need to change groups (old groups for new groups!). We did trying playing around with SID History, but with limited success.
With this script, you need to give it a CSV file containing a list of the groups that you want swapped (two columns, oldgroup & newgroup, in a file called groups.csv), and you will also need to edit the variables for in the script for your domain names.
There is a $removeoldgroup variable. If this is set to true, the old group is replaced. If it set to false, it is left. The script also checks to see if a particaular ACL entry is inherited. This is important because otherwise, you can get duplicate entries on the ACL (although no necessarily visible from the GUI, or having any effect in normal user use, it isn’t very clean).
Finally, as we had several areas where “Administrators” had been removed, the script will also add them back in if they are missing.
There are three files that are created by the script.
“Before Permission Changes.txt” – This will contain a list of folders and ACL’s before any processing is done.
“After Permission Changes.txt” – This will contain a list of folders and ACL’s once the processing is complete.
“folders done.txt” – This will contain a list of all folders that have been modified, as well as the date/time.
A few things to note.
1) It will fail to handle long paths (260 or more characters). You will need to create a share further down the tree in order to successfully process those. I looked at other ways around this, but didn’t find one which appealed.
2) I ran this from my Windows7 workstation against the server using UNC paths. I did test this on the server itself (Windows Server 2008, not R2), and it didn’t work as I expected with the subfolders. I don’t know if this is to do with an older version of Powershell, or an older version of .NET…
2) Test, test, test. I spent the best part of a week testing this in different scenarios, including reversing things to put the old groups back. Still, we have 140,000 folders and and problems would be a potential nightmare to solve. If you have more folders, do more testing 🙂
$destinationpath = "\\server1\share1" $oldDomain = "EMEA" $newDomain = "IPRUK" $removeoldgroup = $false "Job started at " + (Get-Date) ` | Out-File "folders Done.txt" -Append #Build a list of folders $folders = Get-childitem $destinationpath -recurse ` | where {$_.mode -like "d----"} #Get the ACL's and store in a txt file for future review. $folders | Get-Acl ` | Format-List @{l='Directory';e={($_.PSpath).substring(38)}},` accessToString ` | Out-File -FilePath "Before permission changes.txt" #Read the groups from a CSV with two columns, oldgroup & newgroup. $groups = import-csv groups.csv foreach ($folder in $folders){ $aclaccess = Get-Acl $folder.FullName | select Access -ExpandProperty Access Foreach ($group in $groups) { $oldgroup = $olddomain + "\" + $group.oldgroup $newgroup = $newdomain + "\" + $group.newgroup Foreach ($accessright in $aclaccess) { [string]$aclIdentity = $accessright.IdentityReference If ($oldgroup -eq $aclIdentity) { #We don't need to change if it is inherited If (!$accessright.IsInherited) { #We have a match, so grab the full ACL from folder. $acl = Get-Acl $folder.fullname #Build new access rule to add to ACL. $FileSystemRights = $accessright.FileSystemRights $InheritanceFlags = $accessright.InheritanceFlags $PropogationFlags = $accessright.PropagationFlags $ACEtype = $accessright.AccessControlType $permission = ($newgroup, ` $Filesystemrights, ` $InheritanceFlags, ` $PropogationFlags, ` $ACEtype) $Rule = New-Object ` System.Security.AccessControl.FileSystemAccessRule $permission Try { $acl.AddAccessRule($rule) } Catch { $FolderFullName = $folder.FullName $Datenow = (Get-Date) "$Datenow - $folderfullname, $permission : " + ` $_ | Out-File "Group Errors.txt" -Append } #Build rule to remove from ACL. If ($removeoldgroup){ $permission = ($oldgroup, ` $Filesystemrights, ` $InheritanceFlags, ` $PropogationFlags, ` $ACEtype) $Rule = New-Object ` System.Security.AccessControl.FileSystemAccessRule $permission $acl.RemoveAccessRuleAll($Rule) } #Apply new access rule to folder. Set-Acl $folder.FullName $acl #Check for builtin\administrators, add if missing $adminright = $acl.access ` | Where {$_.IdentityReference -eq "BUILTIN\Administrators"} If (!$adminright){ #Build new access rule to add to ACL. $FileSystemRights = "FullControl" $InheritanceFlags = "ContainerInherit,ObjectInherit" $PropogationFlags = "None" $ACEtype = "Allow" $permission = ("BUILTIN\Administrators", ` $Filesystemrights, ` $InheritanceFlags, ` $PropogationFlags, ` $ACEtype) $Rule = New-Object ` System.Security.AccessControl.FileSystemAccessRule $permission $acl.AddAccessRule($rule) #Apply new access rule to folder. Set-Acl $folder.FullName $acl } } } } } $FolderFullName = $folder.FullName "$folderFullName completed at " + (Get-Date) ` | Out-File "folders Done.txt" -Append } #Final report on permissions. $folders | Get-Acl ` | Format-List @{l='Directory';e={($_.PSpath).substring(38)}},` accessToString ` | Out-File -FilePath "After permission changes.txt" "Job completed at " + (Get-Date) ` | Out-File "folders Done.txt" -Append
So, this, combined with Finding Long Paths, and the script for modifying USER permissions, means that I have the scripts I wanted to proceed with our domain migration!