get NTFS permissions and group Identities with same Permissions


So i am auditing ntfs permissions, and I would like to group all the identities that have the same permissions and create a ps object out of it . so for example if “Domain Admins” “Office managers” “JSmith” All have Read/write id like to have them all in the read/write property, read only … etc

The properties would be

Path , Read/write , Read
\server\folder1 , “Domain Admins” “Office managers” “JSmith” ; “jdoe”
heres i swhat I have so far

$targetServer    = '\\Server01'    #Enter hostname
$targetDirectory = 'Departments' #Enter directory name
$target          = Join-Path -ChildPath $targetDirectory -Path $targetServer
$arrResults      = @() #Initialize array used to store custom object output
$exportPath      = 'C:\temp\ntfsCheck.csv' #Enter name of the CSV output file
#Query target directory for all 'folders' (excludes files via Where statement)
Get-ChildItem -Recurse -Path $target | Where { $_.PSIsContainer } |
forEach {
    $objPath = $_.FullName
    $coLACL  = Get-Acl -Path $objPath
    forEach ( $objACL in $colACL ) {
        forEach ( $accessRight in $objACL.Access ) {
            $objResults = New-Object –TypeName PSObject
            $objResults | Add-Member –MemberType NoteProperty –Name DirectoryPath      –Value $objPath
            $objResults | Add-Member –MemberType NoteProperty –Name Identity           –Value $accessRight.IdentityReference
            $objResults | Add-Member –MemberType NoteProperty –Name SystemRights       –Value $accessRight.FileSystemRights
            $objResults | Add-Member –MemberType NoteProperty –Name SystemRightsType   –Value $accessRight.AccessControlType
            $objResults | Add-Member -MemberType NoteProperty -Name IsInherited        -Value $accessRight.IsInherited
            $objResults | Add-Member -MemberType NoteProperty -Name InheritanceFlags   -Value $accessRight.InheritanceFlags
            $objResults | Add-Member –MemberType NoteProperty –Name RulesProtected     –Value $objACL.AreAccessRulesProtected
            $arrResults += $objResults


What version of PowerShell are you running?

Hello Bob

I am running version 4.0

Please take another look at what you want for output.

\\server\folder1 , "Domain Admins" "Office managers" "JSmith" ; "jdoe"

This is a little confusing.

  • You have two different delimiters comma and semi-colon. Is that for a reason?
  • Are we to assume that if you have multiple identities (for instance in your Read/Write column) that you want them altogether in the field, separated by spaces?

In the meantime, here is a rework of your code above. It is more efficient to create an object and add all the data at once via a hash. And concatenating to an array is the least efficient thing you can do in PowerShell.

#requires -version 3

$targetServer    = '\\myserver'    #Enter hostname
$targetDirectory = 'myshare'       #Enter share name
$target          = Join-Path -ChildPath $targetDirectory -Path $targetServer
$exportPath      = 'C:\ephemeral\ntfsCheck.csv' #Enter name of the CSV output file
#Query target directory for all 'folders' (excludes files via Where statement)
$results = Get-ChildItem -Recurse -Path $target -Directory | forEach {
    $objPath = $_.FullName
    $coLACL  = Get-Acl -Path $objPath
    forEach ( $objACL in $colACL ) {
        forEach ( $accessRight in $objACL.Access ) {
                DirectoryPath = $objPath
                Identity = $accessRight.IdentityReference
                SystemRights = $accessRight.FileSystemRights
                SystemRightsType = $accessRight.AccessControlType
                IsInherited = $accessRight.IsInherited
                InheritanceFlags = $accessRight.InheritanceFlags
                RulesProtected = $objACL.AreAccessRulesProtected

Hello Bob

Thank you for getting back , the ; delimiter is an error it should be a comma.

Yes i want all the identities altogether in the field, separated by spaces

Here is an example of the final output

Path Read Write Deny
DNS01\ Everyone “Administrators, Users”
DNS02\Backup “Administrators, Contoso\sales, Users” “Administrators, Users”

I’m sorry, but this example makes even less sense. You seem to be missing the path. And SystemRights returns a much different list of rights.

ok no problem lets disregard the example can we just group them and delimit with a comma?

No. Not until you’re very clear on what you want them grouped by. In your latest example you’re looking at read and write. However, that’s not what is returned from SystemRights. For instance, how do you want to handle Modify, Full Control, Synchronize, ReadAndExecute, etc.?

Ok i want them grouped by if they have the same permissions they are all part of that group They just have to all Have the identical perms for the folder they are on

If I understand you correctly (and let me know if I’m not), you’re looking for something like this:

$targetServer    = '\\Server01'    #Enter hostname
$targetDirectory = 'Departments' #Enter directory name
$target          = Join-Path -ChildPath $targetDirectory -Path $targetServer
$exportPath      = 'D:\temp\ntfsCheck.csv' #Enter name of the CSV output file

# Need to keep track of all unique Type/Rights combinations so we can
# build CSV headers later
$AllPropertyNames = New-Object System.Collections.Generic.List[string]
$AllPropertyNames += 'Path' # We know we'll want this in our header

$CollectedData = dir -Path $target -Recurse -Directory | ForEach-Object {

    $DACL = $_ | Get-Acl | select -ExpandProperty Access

    $ObjectProperties = @{
        Path = $_.FullName
    $DACL | Group AccessControlType, FileSystemRights | ForEach-Object {
        $PropertyName = $_.Name -replace ',\s'  # Get rid of commas and spaces

        # Remember to keep track of all property names we've seen
        if (-not $AllPropertyNames.Contains($PropertyName)) {
            $AllPropertyNames += $PropertyName

        $ObjectProperties[$PropertyName] = ($_.Group | ForEach-Object {
            $Suffix = if ($_.InheritanceFlags -ne 3 -or $_.PropagationFlags -ne 0) {
                " (Special)"
            else { "" }

            '{0}{1}' -f $_.IdentityReference, $Suffix
         }) -join "`n"
    [PSCustomObject] $ObjectProperties


$CollectedData | select $AllPropertyNames | Export-Csv $exportPath -NoTypeInformation

The most imporant part is collecting all of the different headers you need while you’re collecting info from each folder, then using that list when exporting your CSV. This causes all of your results to be stored in memory, though, which means it’s possible to exhaust all of your memory. If you have enough folders to cause that to happen, then there are some things you might try so that you aren’t storing everything in memory (temporarily writing the data to XML might help).

One thing you didn’t mention, but I figured you might find important, is checking the inheritance and propagation flags (the part of the ACE that specifies if it applies to the Folder, Subfolders, and Files). I set this up to add ‘(Special)’ after any principal that has an ACE that doesn’t apply to all three of those.

You can also tweak this to exclude inherited rights (or to even include that info in the CSV header).

Give it a shot and let me know if you have any questions about it…

Great! I am going to try it now

Exactly!! I am going to show my team your code and will let you know but it looks great! Thank you

How would tweak it to Include inherited rights in the csv header ?

I can think of at least three ways to handle inherited rights:

  1. Just get rid of any rights that are inherited. That would give you a CSV that just contains explicit rights.

  2. Add another suffix to the principal, like the ‘(Special)’ one when an ACE is inherited.

  3. Include inheritance status in the headers like you asked. To do that, you could just change the ‘group-object’ call from

Group AccessControlType, FileSystemRights

to this

Group { "{0}{1}{2}" -f $_.AccessControlType, $_.FileSystemRights, "$(if (-not $_.IsInherited) { 'Not'})Inherited" }

You can change the format up if you don’t like the order I’ve put it in…

awesome thx I learned alot off of this thread

One other ? We have decided we want to export in tab delimmited and with

Multiple groups we want to enclose in parenthesis and separated by a comma+space

e.g. “SomeGroup, Contonso\domain admins” what do you think?

Both of those should be simple tweaks.

To change the principal separator, change where it says -join “`n” to -join ', '

To change the delimiter in the CSV, add -Delimiter “`t” to Export-CSV.

cool thx sooo much

You’re welcome