PowerShell can show you the NTFS permissions on any folder without opening a single Properties dialog. The cmdlet that does the work is Get-Acl, which reads a folder's security descriptor and exposes its owner and access control list (ACL) as objects you can filter, sort, and export.

This cheat sheet collects the commands administrators reach for most often: viewing a single folder's permissions, walking a whole directory tree, isolating a specific user or group, spotting explicit and inherited entries, and saving the results to CSV. Every snippet works in Windows PowerShell 5.1 and PowerShell 7, and none of them change anything on disk.

The One-Line Answer

To view the permissions on a folder, call Get-Acl and expand the Access property:

(Get-Acl -Path "C:\Data").Access |
    Format-Table IdentityReference, FileSystemRights, AccessControlType, IsInherited -AutoSize

The output lists one row per access control entry (ACE):

IdentityReference            FileSystemRights AccessControlType IsInherited
-----------------            ---------------- ----------------- -----------
BUILTIN\Administrators            FullControl             Allow        True
NT AUTHORITY\SYSTEM               FullControl             Allow        True
CORP\Finance-RW                        Modify             Allow       False
CORP\Domain Users              ReadAndExecute             Allow        True

That is usually enough to answer "who has access to this folder?" for a single path. The rest of this page covers the variations you need once the question becomes "which folders?", "which users?", or "show me everything in a spreadsheet".

Understanding Get-Acl Output

Get-Acl returns a System.Security.AccessControl.DirectorySecurity object. Pipe it to Format-List to see every property:

Get-Acl -Path "C:\Data" | Format-List
PropertyWhat it tells you
PathThe folder the descriptor belongs to, prefixed with the provider name
OwnerThe account that owns the folder (owners can always change its permissions)
GroupThe primary group, rarely meaningful on Windows
AccessThe list of access control entries, one FileSystemAccessRule per entry
AreAccessRulesProtectedTrue when inheritance from the parent is disabled
SddlThe whole descriptor in Security Descriptor Definition Language, useful for comparisons

Each entry in Access has its own set of properties:

PropertyMeaningTypical values
IdentityReferenceThe user or group the entry applies toCORP\jsmith, BUILTIN\Users, or a raw SID if the account no longer exists
FileSystemRightsThe rights granted or deniedFullControl, Modify, ReadAndExecute, Write, or a number for generic masks
AccessControlTypeWhether the entry allows or deniesAllow, Deny
IsInheritedWhether the entry came from a parent folderTrue, False
InheritanceFlagsWhat the entry passes down to childrenContainerInherit (subfolders), ObjectInherit (files), None
PropagationFlagsHow far inheritance propagatesNone, InheritOnly, NoPropagateInherit

Tip: Get-Acl needs Read Permissions on the folder, but not read access to its contents. Running an elevated session avoids most "access denied" errors on system folders.

View Permissions for One Folder

For a quick look, expand Access and pick the columns you care about:

Get-Acl -Path "C:\Data" |
    Select-Object -ExpandProperty Access |
    Format-Table IdentityReference, FileSystemRights, AccessControlType, IsInherited, InheritanceFlags -AutoSize

To include the folder path in each row (useful once you start combining multiple folders), add a calculated property:

$path = "C:\Data"
(Get-Acl -Path $path).Access |
    Select-Object @{Name = "Path"; Expression = { $path }},
                  IdentityReference, FileSystemRights, AccessControlType, IsInherited

Paths containing square brackets or other wildcard characters need -LiteralPath instead of -Path:

Get-Acl -LiteralPath "C:\Data\Reports [2025]"

View Permissions for Every Subfolder

Pipe a recursive directory listing into Get-Acl. The -Directory switch skips files, which is what you want for a folder permissions report:

Get-ChildItem -Path "C:\Data" -Directory -Recurse -ErrorAction SilentlyContinue |
    Get-Acl |
    Select-Object Path, Owner, AreAccessRulesProtected

To list every access control entry for every subfolder, flatten the results so each entry becomes its own row:

Get-ChildItem -Path "C:\Data" -Directory -Recurse -ErrorAction SilentlyContinue |
    ForEach-Object {
        $folder = $_.FullName
        (Get-Acl -LiteralPath $folder).Access | ForEach-Object {
            [PSCustomObject]@{
                Path        = $folder
                Identity    = $_.IdentityReference.Value
                Rights      = $_.FileSystemRights
                Type        = $_.AccessControlType
                IsInherited = $_.IsInherited
            }
        }
    } | Format-Table -AutoSize

Folders you cannot read are skipped silently. To capture them for follow-up, collect the errors instead of discarding them:

Get-ChildItem -Path "C:\Data" -Directory -Recurse -ErrorAction SilentlyContinue -ErrorVariable scanErrors |
    Get-Acl -ErrorAction SilentlyContinue -ErrorVariable +scanErrors
$scanErrors | Select-Object -ExpandProperty TargetObject

Performance note: Get-Acl queries each folder individually, so a tree with 100,000 folders means 100,000 security descriptor reads plus a name lookup for every SID. Expect minutes to hours on large file servers. Limit the scan with -Depth on Get-ChildItem, or see the alternatives below for large environments.

Filter by User or Group

Once entries are flattened, Where-Object narrows them to a specific account or group. Match on IdentityReference, which is a DOMAIN\Name string:

# every folder under C:\Data where CORP\jsmith is named directly in the ACL
Get-ChildItem -Path "C:\Data" -Directory -Recurse -ErrorAction SilentlyContinue |
    ForEach-Object {
        $folder = $_.FullName
        (Get-Acl -LiteralPath $folder).Access |
            Where-Object { $_.IdentityReference.Value -eq "CORP\jsmith" } |
            Select-Object @{Name = "Path"; Expression = { $folder }}, FileSystemRights, AccessControlType, IsInherited
    }

Use -like with wildcards for partial matches, such as every group with "Finance" in its name:

(Get-Acl -Path "C:\Data").Access |
    Where-Object { $_.IdentityReference.Value -like "*Finance*" }

Important: this only finds accounts that are named directly in the ACL. A user who has access because they belong to CORP\Finance-RW will not appear when you search for their username. Resolving that requires expanding group membership, which Get-Acl does not do (see limitations).

Find Explicit Permissions and Broken Inheritance

Explicit entries (those added directly to a folder rather than inherited) are where most permission sprawl lives. Filter on IsInherited:

# folders that have at least one explicit (non-inherited) entry
Get-ChildItem -Path "C:\Data" -Directory -Recurse -ErrorAction SilentlyContinue |
    Get-Acl |
    Where-Object { $_.Access | Where-Object { -not $_.IsInherited } } |
    Select-Object Path

Folders where inheritance has been disabled entirely report AreAccessRulesProtected as True:

# folders that no longer inherit permissions from their parent
Get-ChildItem -Path "C:\Data" -Directory -Recurse -ErrorAction SilentlyContinue |
    Get-Acl |
    Where-Object { $_.AreAccessRulesProtected } |
    Select-Object Path, Owner

Our guide to broken inheritance explains why these folders deserve attention and how to decide which breaks are legitimate.

Find Everyone, Deny, and Orphaned SID Entries

A few identity patterns are worth searching for on their own. Grants to Everyone or Authenticated Users expose data to the whole organization:

Get-ChildItem -Path "C:\Data" -Directory -Recurse -ErrorAction SilentlyContinue |
    ForEach-Object {
        $folder = $_.FullName
        (Get-Acl -LiteralPath $folder).Access |
            Where-Object {
                $_.IdentityReference.Value -in @("Everyone", "NT AUTHORITY\Authenticated Users", "BUILTIN\Users") -and
                $_.AccessControlType -eq "Allow"
            } |
            Select-Object @{Name = "Path"; Expression = { $folder }}, IdentityReference, FileSystemRights, IsInherited
    }

Deny entries override allows and are a frequent cause of confusing "access denied" errors:

(Get-Acl -Path "C:\Data").Access | Where-Object { $_.AccessControlType -eq "Deny" }

Orphaned SIDs belong to deleted accounts. Windows cannot translate them to a name, so IdentityReference contains the raw SID string:

(Get-Acl -Path "C:\Data").Access |
    Where-Object { $_.IdentityReference.Value -match "^S-1-5-21-" }

See the dedicated guides on Everyone Full Control and orphaned SIDs for remediation steps.

View and Search by Folder Owner

The owner is a property of the security descriptor rather than an access entry:

(Get-Acl -Path "C:\Data").Owner
# every subfolder owned by a specific account
Get-ChildItem -Path "C:\Data" -Directory -Recurse -ErrorAction SilentlyContinue |
    Get-Acl |
    Where-Object { $_.Owner -eq "CORP\jsmith" } |
    Select-Object Path, Owner

Folders owned by individual users (rather than Administrators or a service group) are worth reviewing, because an owner can always regain Full Control regardless of the ACL.

Network Shares and Remote Servers

Get-Acl accepts UNC paths, so you can read the NTFS permissions on a share from any machine that can reach it:

(Get-Acl -Path "\\FileServer01\Finance").Access | Format-Table -AutoSize

Note that this returns the NTFS permissions of the folder behind the share, not the share permissions themselves. Share-level permissions are a separate layer; read them on the file server with Get-SmbShareAccess:

Invoke-Command -ComputerName FileServer01 -ScriptBlock {
    Get-SmbShareAccess -Name "Finance"
}

For large remote trees, run the whole scan on the file server with Invoke-Command so the security descriptor reads happen locally instead of across the network:

Invoke-Command -ComputerName FileServer01 -ScriptBlock {
    Get-ChildItem -Path "D:\Shares\Finance" -Directory -Recurse -ErrorAction SilentlyContinue |
        Get-Acl |
        Select-Object Path, Owner, AreAccessRulesProtected
}

Effective access over the network is the more restrictive of the share and NTFS layers. Our share permissions FAQ walks through how the two combine.

Export Folder Permissions to CSV

The flattened-entry pattern from earlier is exactly what you want in a spreadsheet. This script records every access entry for every folder in a tree and writes it to CSV:

$root   = "C:\Data"
$output = "C:\Reports\folder-permissions.csv"

$folders = @(Get-Item -LiteralPath $root) +
           (Get-ChildItem -Path $root -Directory -Recurse -ErrorAction SilentlyContinue)

$folders | ForEach-Object {
    $folder = $_.FullName
    $acl = Get-Acl -LiteralPath $folder -ErrorAction SilentlyContinue
    if ($null -eq $acl) { return }

    foreach ($ace in $acl.Access) {
        [PSCustomObject]@{
            Path             = $folder
            Owner            = $acl.Owner
            InheritanceOff   = $acl.AreAccessRulesProtected
            Identity         = $ace.IdentityReference.Value
            Rights           = $ace.FileSystemRights.ToString()
            Type             = $ace.AccessControlType.ToString()
            IsInherited      = $ace.IsInherited
            InheritanceFlags = $ace.InheritanceFlags.ToString()
            PropagationFlags = $ace.PropagationFlags.ToString()
        }
    }
} | Export-Csv -Path $output -NoTypeInformation -Encoding UTF8

Open the result in Excel, filter the IsInherited column to FALSE, and you have a list of every explicit permission in the tree. Keep a dated copy each time you run it and you can diff two exports to see what changed.

Keep the root folder: Get-ChildItem returns only descendants, so the script above adds the root with Get-Item first. Without it, the top-level folder's own permissions are missing from the report.

FileSystemRights Reference

FileSystemRights is a flags enumeration. The named values you will see most often, and what they correspond to in the Windows Security tab:

ValueSecurity tab equivalentNotes
FullControlFull controlIncludes changing permissions and taking ownership
Modify, SynchronizeModifyRead, write, execute, and delete
ReadAndExecute, SynchronizeRead & executeThe usual "read-only" grant for folders
Read, SynchronizeReadRead without traverse/execute
Write, SynchronizeWriteCreate and modify, but not read
DeleteSubdirectoriesAndFilesDelete subfolders and filesAppears in advanced (special) permissions
268435456Full control (generic)GENERIC_ALL on an inherit-only entry
-1610612736Read & execute (generic)GENERIC_READ plus GENERIC_EXECUTE on an inherit-only entry
-536805376Modify (generic)GENERIC_WRITE plus GENERIC_READ plus GENERIC_EXECUTE

Synchronize is added automatically to most named rights and can be ignored. The numeric values are generic access masks that Windows uses on inherit-only entries; they are normal and not a sign of a damaged ACL. To test for a specific right regardless of how it is expressed, use a bitwise comparison:

# entries that include write access, however it is expressed
(Get-Acl -Path "C:\Data").Access |
    Where-Object { ($_.FileSystemRights -band [System.Security.AccessControl.FileSystemRights]::Write) -ne 0 }

icacls Equivalents

If you prefer the classic command line, icacls covers the same ground with terser output. It is also handy inside batch files and scheduled tasks where PowerShell is unavailable.

TaskPowerShellicacls
View one folder(Get-Acl "C:\Data").Accessicacls "C:\Data"
View a whole treeGet-ChildItem -Recurse -Directory | Get-Aclicacls "C:\Data" /t
Find one accountWhere-Object IdentityReference -eq ...icacls "C:\Data" /t /findsid CORP\jsmith
Save ACLs to a fileExport-Csv (see above)icacls "C:\Data" /save acls.txt /t
Check for damaged ACLsn/aicacls "C:\Data" /verify /t

icacls prints rights as letter codes: (F) full control, (M) modify, (RX) read and execute, (R) read, (W) write, with (I) marking inherited entries and (OI), (CI) marking object and container inheritance.

Where Get-Acl Runs Out of Road

Get-Acl is the right tool for checking a folder or scripting a one-off export. It becomes awkward as soon as the question shifts from "what is on this ACL?" to "who can actually get in?" across a file server:

  • No group expansion. Entries name groups, not the users inside them. Answering "does jsmith have access?" means resolving nested Active Directory membership yourself.
  • No effective access. Combining allow and deny entries, nested groups, and share permissions into a single answer is left to you.
  • Slow on large trees. One descriptor read and one SID lookup per folder adds up to hours on servers with hundreds of thousands of folders.
  • Long paths. Paths beyond 260 characters need the \\?\ prefix or PowerShell 7, and deeply nested trees still trip up Get-ChildItem.
  • No shares. Share permissions require a separate cmdlet and a separate join in your script.
  • Raw output. Turning a CSV into something a manager or auditor can read is another project.

Permissions Reporter was built for exactly that point. It scans local and network folders in parallel, expands direct and nested group membership, reports share permissions alongside NTFS permissions, ships with filter presets for explicit entries, Everyone grants, broken inheritance, and orphaned SIDs, and exports to Excel, PDF, HTML, XML, CSV, and JSON. The command-line interface slots into the same scheduled tasks and scripts you already use, so it complements PowerShell rather than replacing it. The Basic edition is free.

Related Resources

PowerShell Folder Permissions FAQ

How do I view folder permissions in PowerShell?

+

What does Get-Acl actually return?

+

How do I see the permissions of every subfolder?

+

Why does FileSystemRights show a number instead of a name?

+

Can Get-Acl tell me which users can access a folder?

+

Does Get-Acl show share permissions?

+

How do I export folder permissions to CSV with PowerShell?

+

See every folder's permissions across your entire file system in minutes!

Download Free

Safe. Trusted. Guaranteed.

  • 100% malware free
  • 100% spyware free
  • 100% adware free
  • 100% quality software