Phenomenal number of ACLs, itty-bitty living space

I recently had a need to backup file and folder ACLs for a client that would then need to restore them to their original objects following a hardware upgrade that would wipe them out. Easy enough, but the catch was that there was 1.5 million of them. Fortunately, getting ACLs in PowerShell is easy.

See?

Now, if you needed multiple ACLs, say, all 1.5 million of them on a file share, you could use Get-ChildItem to feed files and folders to Get-Acl. But then what? Export-Clixml is a generally great way to convert a PowerShell object to XML and save it to file.

You then get an ugly monstrosity that looks like this.

In my case, there’s a serious problem with this approach. Ballpark 100 lines per ACL x 1.5 million filesystem objects = 150 million lines of backup data, and my small test on several thousand files and folders was already about 32MB on disk. In production, it would balloon to a hefty size and this needed to run on a server with 3.5GB of RAM and space constraints. Yeah… I’m not offering that as a solution to anybody.

Luckily, we can do a little dotnet black magic to trim this down to something much more manageable. Thanks to sk82jack and Chris Dent in the PowerShell Discord, I learned that the SDDL is the only component that’s really necessary for recreating the ACL object. They look like this:

File ACLs are [System.Security.AccessControl.FileSecurity] type objects and folder ACLs are [System.Security.AccessControl.DirectorySecurity] type objects.

Instantiating one of these just gives us a blank object, but we can feed the SDDL as a string to the SetSecurityDescriptorSddlForm() method in order to populate it.

I haven’t seen a way to fill in the path but that’s easily worked around. Armed with this information, I would only need to backup the full path of each object, whether it is a file or a folder, and the SDDL.

Now we’re getting somewhere. Flat objects like this will export nicely to CSV, which would be significantly smaller on disk than the ps1xml we started with. When I run the code above against a directory tree with about 56k objects and pipe it to Export-Csv, I end up with a 16MB CSV. Some PowerShell napkin math to double-check this…

… So around 430MB. That sounds like a much more reasonable backup size to me and it won’t chew through what little RAM I have to work with. If we went with Export-Clixml, it would have ended up around 8GB, taken significantly longer to run, and probably would have crashed.

So how would we restore these?

And simple as that the ACLs right back where they came from.

About Mark Roloff

Mark Roloff is a delivery engineer at Corus360 in Denver, CO, working with Azure, PowerShell, and whatever else falls in his lap. He enjoys a good craft brew, sci-fi, and solving interesting problems.