Bulk updating Group Policy Drive Maps

Using PowerShell to update the Drives.xml file with replacement groups.

2 min read
Bulk updating Group Policy Drive Maps
Photo by Christopher Gower / Unsplash

Since part of my current job is consolidating multiple Active Directory domains into one, I have to ensure that users do not notice a difference when they are migrated.

One client site that I need to migrate has a weird setup, where every single root folder is in Group Policy Drive maps. While in and of itself this may not sound weird, they are a large organisation, and they have approximately 350 drives listed. These are then set to mapping to a single drive letter, and moving on to the next if that one is not available.

As we are migrating them from one domain to another, the group that they use to map the file is obviously changing to the new domain, so we need to replace them all with the new equivalent groups.

Now this may or may not be over-engineered, but I couldn't think of an easy way to do a simple replace as strings could be partial stings of other mapping groups.

The full and most up to date code is in my GitHub repo, if I ever make changes to the code but don't update this post.

How it works

Skipping the initial section including loading files.

We load just the part of the XML that we want to play around with.

$m = $mappings | Select-XML -XPath "//Drive" | ForEach-Object {$_.node.InnerXML}

We start a loop for each item in the 'm' variable.

This part was borrowed from this site. Not sure right now if it is actually needed, but I also have no empty filters to test against. We have two tags, we will separate them for further processing. Then if there are any empty filters, we put in a non-shortened structure that can be navigated against. This doesn't get applied back to the XML file, it is just for processing.

$tags = $map -split "<Filters>"
if ($tags[1])
{
    if ($tags.Length -gt 1)
    {
        $tags[1] = "<Filters>" + $tags[1]
        $Filters = [xml]$tags[1]
    }
}
else
{
    $tags[0] = $tags[0] -split "<Filters />"
    $FilStr = "<Filters></Filters>"
    $Filters = [xml]$FilStr
}

We then loop through the filter groups and try and find the matching group in the matching file and return the index within the matching file. As the GPO XML has the group as DOMAIN\GroupName, we split the string and get just what is after the backslash.

$GrpNum = [System.Array]::FindIndex($GrpList.srcgroupname,[Predicate[string]]{$args[0] -eq $($Group.name -split '\\')[1]})

If we have found a match, we will update the variable where we pulled the XML contents to. As per the above, we are needing only the group not the domain, and since replace uses regex you need to use the backslash before the other backslash. (Yes, I probably could have and should have put it in a separate variable rather than do what I did, but I like to show off with inefficient code sometimes... 🤣)

if($GrpNum -and ($GrpNum -ne -1)){
    $NewSid = (Get-ADGroup -identity $($GrpList.GGroupName[$GrpNum])).sid.value
    $mappings.Drives.Drive.Filters.FilterGroup[$i].Name = [string]$($FilterGroups.name -replace "$($group.name -replace '\\','\\')","$TargetDomain\$($GrpList.GGroupName[$GrpNum])")
    $mappings.Drives.Drive.Filters.FilterGroup[$i].sid = $NewSid
}

Then we finish up saving the XML to a new file.

Since I have verified that you can just drop in the modified file into the GPO, move this into the appropriate folder and it should just work on next refresh.

Me on Mastodon - This link is here for verification purposes.