I was working on a recent project that required scripting ACLs, and so I had a Windows PowerShell console open in addition to the ISE. This allowed me to quickly check the owner of a directory (or folder). I could press the up arrow to rerun my command, and I could quickly see if the owner had changed according to my script. Let’s say my directory is called ‘TestFolder’ and is located at the root of the C:\ drive.
PS C:\> New-Item -Path TestFolder -ItemType Directory
Directory: C:\
Mode LastWriteTime Length Name
---- ------------- ------ ----
d---- 10/21/2014 9:19 PM TestFolder
To get the ACL information for the folder, you can use the Get-Acl cmdlet, as in the example below.
PS C:\> Get-Acl -Path .\TestFolder
Directory: C:\
Path Owner Access
---- ----- ------
TestFolder BUILTIN\Administrators BUILTIN\Administrators Allow FullCo...
Being the PowerShell enthusiast that I am, I modified my command so that only the information I wanted (the path and the owner) was being returned. This is done using the Select-Object cmdlet. Unfortunately, when the command returned those two properties, the Path property was no longer what I was expecting – take a look below. While the example above only returned the name of the folder (TestFolder), I thought I would change this to show the full path (C:\TestFolder) since I was now dealing with a string that included it.
PS C:\> Get-Acl -Path .\TestFolder | Select-Object -Property Path,Owner
Path Owner
---- -----
Microsoft.PowerShell.Core\FileSystem::C:\TestFolder BUILTIN\Administrators
The first thing I thought to do was to split the path at the two colons (::) and grab the second element, which I thought would end up being C:\TestFolder. The split method didn’t work so well; here’s what I ended up with.
PS C:\> Get-Acl -Path .\TestFolder | Select-Object -Property @{N='Path';E={($PSItem.Path).Split('::')[-1]}},Owner
Path Owner
---- -----
\TestFolder BUILTIN\Administrators
The reason this didn’t work is because the Split() method doesn’t split on each occurrence of two, back-to-back colons like you might expect, it splits on every colon. Since C:\ has a colon, it split there as well. FYI: The use of [-1] returns the last element in an array – good to know, I know. Here’s an example that may help better explain. In this example below, the string is split on every exclamation point (!) and every question mark (?) – not only on the combination of both (!?).
PS C:\> $String = 'Today is the 21st! That is great news, right?'
PS C:\> $String
Today is the 21st! That is great news, right?
PS C:\> $String.Split('!?')
Today is the 21st
That is great news, right
PS C:\>
What I then decided to do to get this the way I wanted it, was to first replace the two, back-to-back colons with a single character (that was not a part of the string), and then split on that single character. It worked, and here’s what that looks like.
PS C:\> Get-Acl -Path .\TestFolder | Select-Object -Property @{N='Path';E={(($PSItem.Path).Replace('::','@')).Split('@')[-1]}},Owner
Path Owner
---- -----
C:\TestFolder BUILTIN\Administrators
PS C:\>
It was about this point, that I wanted to see if the -split operator would have handled this the same way and required the additional work that the Replace()/Split() methods did. Of course, after all I did to get this to work how I wanted, I determined I should have started with the -split operator. The -split operator isn’t looking at the characters individually, but instead of, as a whole – two, back-to-back colons is two back-to-back colons.
PS C:\> Get-Acl -Path .\TestFolder | Select-Object -Property @{N='Path';E={(($PSItem.Path) -split '::')[-1]}},Owner
Path Owner
---- -----
C:\TestFolder BUILTIN\Administrators
A note, if the @{N=…;E={…}} syntax is confusing, or new to you, then spend some time reading this: http://technet.microsoft.com/en-us/library/ff730948.aspx, and then run Get-Help about_Hash_Tables.
This happens just about every time I get to ready to publish a new post. I discovered a better way to handle the problem – much like I did when I considered the -split operator. It turns out that I could have used a built-in cmdlet to convert the path for me. That’s right, there’s a cmdlet that would have handled everything. Using the Convert-Path cmdlet will convert something like this: Microsoft.PowerShell.Core\FileSystem::C:\TestFolder to this: C:\TestFolder. Here’s the example.
PS C:\> Get-Acl -Path .\TestFolder | Select-Object -Property @{N='Path';E={Convert-Path $PSItem.Path}},Owner
Path Owner
---- -----
C:\TestFolder BUILTIN\Administrators
PS C:\>
Well, that’s it for this one. As much as I might seem irritated about how I did this three different ways – from the most work to the least – I understand how important this learning process is, and that one day I will be grateful for having gone down this path… (pun intended).