Workaround For AD PSDrive Bug In Server 2019
PSPath to the rescue
TL;DR
Until Microsoft fixes the bug with the AD PSDrive provider, use the fully qualified PSPath to the object instead of the “AD:
$DN = (Get-ADUser jdoe).distinguishedName
$objectPath = "Microsoft.ActiveDirectory.Management.dll\ActiveDirectory:://RootDSE/$DN"
Get-Acl -Path $objectPath
The Story
I was browsing r/PowerShell recently and came across a thread from someone who had run into a PowerShell bug after upgrading to Windows Server 2019 (1809). The user was attempting to run Get-Acl
against an AD object using the object’s distinguished name like this:
$DN = (Get-ADUser jdoe).distinguishedName
$ACL = Get-Acl -Path "AD:\$DN"
The code works just fine in Server 2016 and earlier. But the same code throws an error in Server 2019 and reportedly Windows 10 (1903) as well.
Get-Acl : The object name has bad syntax
At line:1 char:8
+ $ACL = Get-Acl -Path "AD:\$DN"
+ ~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (\\RootDSE\CN=Do...C=example,DC=com:String) [Get-Acl], ADException
+ FullyQualifiedErrorId : ADProvider:ItemExists::ADError,Microsoft.PowerShell.Commands.GetAclCommand
The problem is this particular user’s DN had an escaped comma in it because the CN value was set to “Doe, Jane”. Commas are allowed in object names in AD, but they tend to cause all sorts of problems with LDAP path parsing code due to the escaping. The resulting DN of the object looks something like this:
CN=Doe\, Jane,CN=Users,DC=example,DC=com
Historically, the Windows native Active Directory PowerShell cmdlets and PSDrive provider have no issues dealing with this. But apparently a bug crept into the latest releases. It should be noted that the bug exists with any cmdlet that depends on the Active Directory PSDrive provider. Get-Acl
just happens to be the one this user was using. But it also affects something as simple as Get-Item
.
The Workaround
One of the things I tried while poking around this bug looking for a workaround was running Get-ChildItem
against the parent container and then running Get-Acl
against the PSPath
parameter of the results like this.
Get-ChildItem "CN=Users,DC=example,DC=com" | ForEach-Object { Get-Acl -Path $_.PSPath }
To my pleasant surprise, it worked without issue. So I took a look at the format of the PSPath for these objects and found this for my problematic test user.
Microsoft.ActiveDirectory.Management.dll\ActiveDirectory:://RootDSE/CN=Doe\, Jane,CN=Users,DC=example,DC=com
We can generalize this out to a somewhat ugly (but at least usable) path prefix for any DN and work it into the original code like this.
$DN = (Get-ADUser jdoe).distinguishedName
$objectPath = "Microsoft.ActiveDirectory.Management.dll\ActiveDirectory:://RootDSE/$DN"
$ACL = Get-Acl -Path $objectPath