Yesterday I posted a function to create a summary report of ACL information using Windows PowerShell. I posted this in response to a question in the Ask Don and Jeff forum at PowerShell.com. I received an appreciative followup. The next step for this IT Pro it seems is to get a detailed list of the user based access control entries. Here is some of my response.
ManageEngine ADManager Plus - Download Free Trial
Exclusive offer on ADManager Plus for US and UK regions. Claim now!
What you are experiencing is both the pleasure and pain of PowerShell. You can get to some amazing information, but sometimes it is buried deeply and takes a little work to unwind. Assuming you have my function loaded in your shell, try this on a small test folder.
dir c:\work -recurse | Where {$_.PSIsContainer} |
get-aclinfo | Where {$_.UserAcl -gt 0} |
ForEach {
$path=$_.Path
$_ | select -expand accessrules |
where {$_.identityreference -notmatch "BUILTIN|NT AUTHORITY|EVERYONE|CREATOR OWNER"} |
Select @{Name="Path";Expression={$Path}},IdentityReference,FileSystemRights
}
The first part command, DIR, gets goes through C:\Work recursively. These objects are piped to Where-Object which only keeps containers, i.e. folders. These folder objects are then piped to my Get-ACLInfo function. Its results are then piped to another Where-Object to filter out anything that doesn't have a UserACL value greater than 0.
Now it gets a little trickier. I want to display both the file path and get at the underlying, nested access rules. So I'll pipe each of my aclinfo objects to ForEach-Object. The first thing I do is save the path property from the incoming object. Then I pipe the object to Select-Object, expanding the Accessrules property. Remember, this is a collection of accessrule objects.
These in turn are filtered again to weed out the system accounts. You could also modify the filter to match say on a domain name or specific username. Finally, the filtered results are piped to Select-Object which shows the username, their rights, and a custom property that uses the saved Path variable.
Here's what the end result looks like:
Path IdentityReference FileSystemRights
---- ----------------- ----------------
C:\work\foo SERENITY\fooby FullControl
C:\work\foo\test SERENITY\fooby FullControl
C:\work\foo\test1 SERENITY\fooby FullControl
C:\work\foo\test2 SERENITY\fooby FullControl
C:\work\foo\test1\foo SERENITY\fooby FullControl
C:\work\foo\test1\foo2 SERENITY\fooby FullControl
C:\work\foo\test1\foo3 SERENITY\fooby FullControl
C:\work\foo\test2\bar SERENITY\fooby FullControl
C:\work\foo\test2\bar2 SERENITY\fooby FullControl
In reality though, you could probably skip my function altogether since all you want are the underlying access rules. Here's a variation that uses Get-ACL.
dir c:\work -recurse | Where {$_.PSIsContainer} | get-acl |
ForEach {
[regex]$regex="\w:\\\S+"
$path=$regex.match($_.Path).Value
$_ | select -expand access |
where {$_.identityreference -notmatch "BUILTIN|NT AUTHORITY|EVERYONE|CREATOR OWNER"} |
Select @{Name="Path";Expression={$Path}},IdentityReference,FileSystemRights
}
The logic is essentially the same except I threw in my regex code to make the folder path easier to read. Otherwise you get a path value like Microsoft.PowerShell.Core\FileSystem::C:\scripts\. I'll admit this is a bit much to get your head around, especially for people still starting out in PowerShell. But I hope my logical explanation helps.
Hi Jeff,
Nice post, thanks, also thanks for all wisdom you spread over the last years.
On the subject of getting info from ACLs, I think it is worth while taking a look at the NTFSSecurity module written by Raimund Andree.
The module gives us cmdlets for Owner(Get,Set), Inheritance(Get,Enable,Disable) and Ace(Add,Get,Remove) and so effectively removes the complexity of having to go through Get-Acl.