HOWTO: Unique NTFS Permissions Reporting Tool

If you found this post via a search engine, you’ve likely received a ticket/request from some manager requesting an audit report of the permissions on an important share within your company. Unfortunately for you, this folder contains literally tens of thousands of folders and hundreds of thousands of files.  Oh and since there has been no proper governance of it over the years, inheritance is broken all over the place and permissions are assigned many levels deep with no rhyme or reason.  You’ve now been tasked with cleaning this up.  You realize that trying to analyze this manually is simply impossible so you’re looking for some kind of tool to assist you.  You’ve found tools like the NTFS Permissions Reporter (http://www.cjwdev.com/Software/NtfsReports/Info.html) but quickly found this costs hundreds of dollars in order to produce any kind of intelligible report.  You’re not allowed to spend any money so you’re stumped.  So now what?

I found myself recently in this exact situation and decided to use this as my first real attempt at building a full-fledged tool with PowerShell.  Wait!  Don’t run away yet.  There is nothing to be afraid of here as I’ve designed this tool to be useful even if you have absolutely no PowerShell experience.  Again, you don’t care how you get the report, you just care that it’s readable.  That’s what I’m here to help you with.  The tool to do that I call the ntfsreporter and it works as follows:

  • Accepts a parent folder (can be a local folder or a UNC path on a remote machine)
  • Builds a list of all files and folders including all subfolders and files along with the permissions assigned to each

Here’s where it gets interesting:

  • Compares the permissions on each item to that of its parent.  If the permissions match, it is ignored.  If the permissions don’t match, this means someone has unexpected rights so include it in the report
  • Has the option to easily specify a list of accounts to automatically ignore in the report.  So if you have Domain Admins or some special account that has access everywhere anyway, you can easily exclude it
  • Has the option to include SIDs if desired for user accounts that no longer exist but still have permissions allocated (disabled by default)
  • Clearly identifies what permissions have been added or removed on a per file and folder basis

Does this sound like it might be helpful for you?  Excellent, let’s get started.

Requirements

  • PowerShell 3.0 or newer (Available here if required)
  • Run as an account with permissions to read the permissions on the destination folder (typically a Domain Admin account)

Installation and Usage

You may receive an alarm about scripts being disabled

image

If so, close your PowerShell session and re-launch PowerShell as an administrator and type Set-ExecutionPolicy RemoteSigned

image

  • Go back into C:\Temp and type Unblock-File .\ntfsreporter.psm1.  If this works, it will not return any output
  • Try to import the module again

image

  • You are now ready to use the NTFS reporting tool.  Type:

Get-UniqueNTFSPermissions [Local or UNC Path]

  • In this case, let’s use c:\accountinghome which is my test folder with a bunch of specific permissions configured
  • The tool will take a while to run depending on the number of files and folders.  A progress bar will be displayed during execution

image

  • Once it’s finished, you’ll have four columns:
    • File/FolderPath / Assigned NTFS Permissions/ Accounts added compared to the parent permission / Accounts removed compared to the parent permission

image

  • As we can see, we have a number of permissions for CREATOR OWNER and BUILTIN\Administrators we don’t care about.  To remove these use the parameter –ExcludedAccounts which accepts a comma delimited list

image

  • It’s still kind of hard to read so let’s export it to the clipboard so we can paste it into Excel being careful to use a different delimiter character than a comma as that is already used to separate permissions

Get-UniqueNTFSPermissions c:\accountinghome –ExcludedAccounts “CREATOR OWNER, BUILTIN\Administrators” | ConvertTo-CSV –Delimiter * –NoTypeInformation | clip

image

  • As you can see, it’s not exactly readable yet.  In order to separate out the columns, highlight all of column A and choose Data from the Ribbon and select Text To Columns
  • Choose Delimited and then select Other and type in an asterisk (aka the “*”) and press Finish

image

  • Congratulations, you now have an intelligible report of only the unique NTFS permissions on the folder you provided and all sub folders!

If the script ran into any “access denied” or other problems accessing any files or folders, they will all be displayed first.  Also as noted, if the file or folders permissions match those of the parent, they are not included in this report.  This makes the resulting report much, much easier to digest and analyze.

image

What can you expect in terms of performance?  On my machine using a local SSD, this script was capable of scanning roughly 120 folders/files per second.  That works out to be roughly 430,000 files/folders per hour, give or take.  Put another way, if you were to leave this script running say over night for a 10 hour period, it would be capable of scanning roughly 4.3 million files/folders.  Note however that I have tested it at this scale and so it may not function as expected.  I have scanned 120,000 items without issue however so I’m optimistic it will scale.  It’s also worth noting that I have also included a full help system that can be accessible by typing Get-Help Get-UniqueNTFSPermissions –showwindow along with full comments within the code itself if you want to dig in and make changes to suit you needs.  Be sure to check out the examples (Get-UniqueNTFSPermissions –examples) for additional tricks on how to use this cmdlet!

This represents many hours of frustration, trial and error but the end result is something I hope many people will find useful.  If you find any bugs or make any improvements, feel free to leave a comment!

23 comments

Skip to comment form

    • Kevin K on August 3, 2015 at 7:17 pm
    • Reply

    Thanks, worked like a charm!

  1. Glad to hear it worked for you!

    • Ricky on August 7, 2015 at 6:55 am
    • Reply

    Hi, thanks for sharing your work!

    Just one question, does it address the 256 character limit in the NTFS system? I have a script that does only a fraction of what yours does and it works well most of the time. It’s only when it scans for folders/files that have exceeded the 256 character limit that it breaks.

    I’ve done a lot of research on this and there doesn’t seem to be an easy way to solve it. Tried mapping a temporary drive in powershell, but still fails. Just wondering if your script covers this issue? I guess I’ll run it and find out…

      • Ricky on August 7, 2015 at 7:35 am
      • Reply

      Hmm so I’ve given it a test and it works great. But I need to be able to know what permissions the users have against the folders. Would you be able to update the script to include that?

      Also, it looks like the script/module has no problem scanning for folders past the 256 character limit. I’m not sure how you did it and typing Get-Help Get-UniqueNTFSPermissions –showwindow doesn’t show me the source code (it does show a window with some examples though).

      1. Hi Ricky,

        You can view the source code by opening the file ntfsreporter.psm1 in notepad or better still in the PowerShell ISE which is built into Windows. As for getting around the NTFS character length limit, I can’t quite remember what I did now as I wrote this script a while ago. I wrote another PowerShell script on this site to delete files with paths longer than 256 characters so I know I was aware of the issue.

    • Ricky on August 7, 2015 at 7:44 am
    • Reply

    Running into an issue “The specified wildcard character pattern is not valid:” and then the name of the file (I won’t list it here for security reasons).

    1. Can you post the full command you are trying to run? Are you saying this error only occurs for a single file in your file system? It’s possible that file contains a character that my script or PowerShell is not sanitizing. Can you try simplifying the filename and seeing if the error still occurs?

        • Adam Plocher on April 9, 2016 at 2:24 pm
        • Reply

        I’m also getting this error:

        C:\temp> Get-UniqueNTFSPermissions C:\Temp
        The specified wildcard character pattern is not valid: [.exe
        C:\temp>

        I have several folders in C:\TEMP so Step 1 ran for a couple mins – not sure if it was starting Step 2 or if it was still in the middle of Step 1.

        • Adam Plocher on April 9, 2016 at 2:27 pm
        • Reply

        Oh wow, apparently [.exe actually is on my filesystem (in multiple locations). It’s included with “Git for Windows”

        C:\temp>where /R \ “[.exe”

        C:\Program Files\Git\usr\bin\[.exe
        C:\Temp\cmder\vendor\git-for-windows\usr\bin\[.exe
        C:\Temp\cmder\vendor.old\git-for-windows\usr\bin\[.exe
        C:\Temp\cmder\vendor.old\git-for-windows – Copy\usr\bin\[.exe
        C:\Temp\cmder – Copy\vendor\git-for-windows\usr\bin\[.exe
        C:\Temp\cmder – Copy\vendor\git-for-windows – Copy\usr\bin\[.exe

        • Adam Plocher on April 9, 2016 at 2:41 pm
        • Reply

        To fix this problem, simply change “-Path” to “-LiteralPath” in your Get-Acl calls:

        $true {$FullPerms = ((Get-Acl -LiteralPath $Path | select -expandproperty access | select identityreference -unique).identityreference) }
        $false {$FullPerms = ((Get-Acl -LiteralPath $Path | select -expandproperty access | select identityreference -unique).identityreference) | Where-Object { $_ -notmatch ‘S-1-5’ } }

        Works great for me now. Thanks!

    • joe on January 6, 2016 at 4:35 pm
    • Reply

    I was using this to go through a large file structure an in the end I got the following error:
    “The specified wildcard pattern is not valid: name of a file”

  2. Hi Joe,

    I’m afraid I don’t know what the issue would be off hand. Can you post the exact command you are running as well as the full details of the output error including the line number? What version of PowerShell are you running this on? (You can check that by typing $PSVersionTable).

    • chris borg on January 29, 2016 at 12:29 pm
    • Reply

    for some reason I cant get this to run on the file share \\servername\shared folder but will work if I use \\servername\d$ but this does every folder on this drive. I can run this locally as I would need to reboot the server to update .net and install powershell 3.0 I also noticed it doesn’t like scanning folders with [ in the name

    • Daniel on February 17, 2016 at 5:58 am
    • Reply

    Hi,

    I have done a slight alteration to only bring back only folders and not files which is working well.
    Get-ChildItem $Path -Recurse -ErrorVariable Err -ErrorAction SilentlyContinue -Attributes Directory | ForEach-Object {

    However, it still brings back too many differences and that’s because of the owner on the folder has a special permission. Just wondering if it would be possible to grab the owner field and if that is the only difference, exclude it from returned results.

    Also as others, I am getting an error with [ bracket for some folders I try the script against.

    Otherwise, great script. Well done.

    • Steve on September 12, 2016 at 4:22 pm
    • Reply

    Hi Robbie,

    “The specified wildcard character pattern is not valid”

    This script does look promising (thanks), but my folder tree is full of files and folders with “[” and “]” all over the place, and changing Get-Acl to use ‘LiteralPath’ does not fix the problem for me.

    This is the command and output (sorry, masked most of the characters, but you get the idea I hope):

    Get-UniqueNTFSPermissions \\servername\x$\shared\sharename -ExcludedAccounts “NT AUTHORITY\SYSTEM,XXXXXXXXX\Domain Admins,CREATOR OWNER” |ConvertTo-csv -Delimiter * >xxxx.csv
    The specified wildcard character pattern is not valid: Xxxxxxxxx Xx. [xxxx Xxxxxxx Xx. xxx Xxxxxxxx

    That is all, there is no script line number mentioned in the error.

    Also this output provides no clue as to where the script has got to in the folder tree, so we have to do a dir /s to list the folders to text file and search that for the text.
    This reveals the following path:

    \\servername\x$\shared\sharename\XXX Xxxxxx XX – XX\X XXXXX (XX XXX XXXXX)\Xxxxxx Xxxxxxxx\XXXX-XX\Xxxxxx Xxxxxxxx XXXX-XX\Xxxxxxxxx Xx. [xxxx Xxxxxxx Xx. xxx Xxxxxxxx

    Any idea how I can make this script work with these characters ?

    Also Powershell version is:

    Name Value
    —- —–
    PSVersion 4.0
    WSManStackVersion 3.0
    SerializationVersion 1.1.0.1
    CLRVersion 4.0.30319.18444
    BuildVersion 6.3.9600.18144
    PSCompatibleVersions {1.0, 2.0, 3.0, 4.0}
    PSRemotingProtocolVersion 2.2

    Can you help 🙂

    thanks

    • Steve on September 12, 2016 at 4:33 pm
    • Reply

    OK, I’ll answer my own question:

    After editing the module with Get-Acl corrections -> Import-Module .\ntfsreporter.psm1 -force

    1. Hi Steve.

      Ahh, yes. That makes sense. I just tried it myself and sure enough it was ignoring any paths with square brackets for me. As a guy named Adam earlier calls out, you need to change the Get-ACL call from -Path to -LiteralPath.
      I have updated the original post with this change.

      Of course once it’s changed, you have to reload the module in your PowerShell session. You can do that by either using a Remove-Module / Import-Module, the -Force you found or by simply closing and relaunching PowerShell. I’m glad you got it working and I’m glad this script is providing some value.

  3. Thanks a lot for this script, it was easy to use and very valuable.

    • Peter on June 26, 2017 at 9:09 am
    • Reply

    Hi Robbie,

    thank you very much for the script.

    The good thing is that it worked for me in that it ran on large folders without crashing or producing any errors. Nevertheless, it didn’t do exactly what I expected. For example, if there is a folder

    c:\folder1
    where
    user1 has special permissions
    Traverse folder / execute file, List folder / read data, Read attributes, Read extended attributes, Create files / write data, Create folders / append data, Write attributes, Write extended attributes, Read permissions, Change permissions,

    and if there is a folder
    c:\folder1\folder2
    where
    user1 has full control (i.e. user1 has additional permissions Delete subfolders and files, Delete, and Take ownership),

    your script does NOT report any difference between c:\folder1 and c:\folder1\folder2.

    Since I am working a lot with such special permissions and structure like that one shown above, I currently can’t use your script. Would you eventually be willing to change it accordingly? We eventually could consider this behavior a bug 🙂

    Thank you very much,

    Peter

  4. I just want to mention I’m beginner to weblog and certainly loved this web page. More than likely I’m planning to bookmark your blog post . You amazingly come with good posts. Thanks for sharing with us your web-site.
    repliques bijoux cartier http://www.bijouxpopulaire.com/category

  5. Yoս mᴡde a few nice points there. I did a search on the issue and found a good numbeг of folks wіll cknsent wіth ʏour blog.

    • Klavs on January 23, 2018 at 11:05 am
    • Reply

    I can recommend a free NTFS reporting tool which allows to export results to a CSV file so you can filter, analyze and format data as you need – AD FastReporter Free.

    • Wendy on September 18, 2019 at 6:49 pm
    • Reply

    I just discovered this tool and it’s great – but I’m getting errors on folder paths longer than 256 characters. Is there any way around this with the get-acl command? thanks.

    Get-Acl : Cannot find path
    because it
    does not exist.
    At C:\Windows\system32\WindowsPowerShell\v1.0\Modules\ntfsreporter\ntfsreporter.psm1:159 char:36
    + $false {$FullPerms = ((Get-Acl -LiteralPath $Path | selec …
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : ObjectNotFound: (:) [Get-Acl], ItemNotFoundException
    + FullyQualifiedErrorId : GetAcl_PathNotFound,Microsoft.PowerShell.Commands.GetAclCommand

Leave a Reply to Robbie Cancel reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.