PowerShell and Law 4
On the front page of this site you will find my laws of computing. Law 4 states “Computers don’t do what you tell them to do.  They do what a programmer told them to do.” This is demonstrated quite clearly by some of my recent experiences with PowerShell.
I had need at work to script the creation of some directories with a rather complex permissions scheme. This is something that when I did it manually would require about three hours to complete, as setting a bunch of complex NTFS permissions will make you go cross-eyed and brainless (with apologies to the Talking Heads). PowerShell has Get-Acl and Set-Acl, but no Cmdlets for manipulating DACLs or creating new ACEs. No problem thought I, because PowerShell allows you to call into .NET classes, and I could use that to manipulate the DACLs returned by Get-Acl.
I started building a module to work with NTFS Permissions and ran into some odd problems. Every time I manipulated the DACLs and attempted to pass them on through the pipeline by emitting them, the Path property became blank. Yet the original DACL would retain the Path and all of my manipulations. So I sent the original and my copy through Get-Member. Hmm… The path on the original is a PSProvider path, and it also contains a number of PowerShell NoteProperties. The copy was missing the NoteProperties and the path was blank. Yet, the .NET type listed by Get-Member for both the original and the copy were identical – curiouser and curiouser said Alice.
So, apparently the object returned by Get-Acl is not a pure .NET type, but has been modified with some additional properties so that it works better with PowerShell. This makes sense when you think about it, as PowerShell was built on .NET 2.0 after .NET has shipped; so the native .NET classes have no way of knowing what is occurring within PowerShell. It makes sense, but it isn’t documented (at least that I could find) that Get-Acl adds these NoteProperties to the returned .NET object. So PowerShell was doing exactly what it had been programmed to do, and .NET was doing exactly what is was programmed to do. And my script was lost in the middle.
Perhaps there is a way to get a copy of the original object intact with the NoteProperties and my changes. I haven’t found it. But for now I am happy that Set-Acl accepts a -Path parameter if the passed in DACL is missing one, which of course mine were. So now my three hours of coma-inducing work occurs nearly instantly once I press enter. Now the longest part of the operation is verifying that I haven’t mistyped the user IDs that need access to the special directories.