I needed a (nice) way to document all non-inherited ACLs (access control lists) on a folder. I wanted this to be exported as a CSV file with a delimiter of my choice. I also wanted to add a log file, in case of any error or strange behavior I could find out what, or where it went wrong.
The command icacls saves this info pretty cryptic, thus I decided to create my own script for this purpose. Next to this script, it is recommended to export the rights as well, for which the icacls command is very useful. This can be done by running this command (as posted here):icacls (folder)\* /save aclfile.txt /t
This can restore the ACLs (in case of emergency):icacls (folder)\ /restore aclfile.txt
Once I was working on this, I thought of creating a nice script, with help text information and some parameters so the script can be used in many ways from the command line (and any of my colleagues who don’t use Powershell that much, would be able to understand it and maybe learn something from it as well)
I need to get the list of folders, so I used$Dirs = Get-ChildItem "$Path" -directory -recurse -ErrorAction SilentlyContinue
Once I had the list of folders, I can loop through them and get the ACL information:$aclCheck = Get-Acl -Path $dir.FullName | where {$_.Access.IsInherited -eq $false} -ErrorAction SilentlyContinue
In some cases I want to log all the information found, thus I wanted to use Write-Verbose
, so this only gets added to the log, when the -Verbose switch is used. But sinds the Get-Acl
command gives me an object, I needed to convert the object to a string, otherwise Write-Verbose
wouldn’t work. This is what I used for that (thank you Powershell-Everyday-FAQ):Write-Verbose ($aclCheck.Access | Select-Object IdentityReference,AccessControlType,FileSystemRights | ft -AutoSize | Out-String)
Now I want to add the information to my own created object, so I can export this to CSV later$DirectoryList = New-Object psobject
Add-Member -InputObject $DirectoryList -MemberType NoteProperty -Name "FolderWithChangedACL" -Value $dir.FullName
Add-Member -InputObject $DirectoryList -MemberType NoteProperty -Name "Identity" -Value $user.IdentityReference
Add-Member -InputObject $DirectoryList -MemberType NoteProperty -Name "AccessControlType" -Value $user.AccessControlType
Add-Member -InputObject $DirectoryList -MemberType NoteProperty -Name "FileSystemRights" -Value $user.FileSystemRights
$DirectoryListWithChangedACL += $DirectoryList
And in the end I want to export the information and set my own delimiter (as we have several servers with US and several with EU notation, but I want Excel to treat them all the same and be able to open all the files without the need to use the text to columns feature). Otherwise the -UseCulture switch could have been used, so the OS determines which delimiter should be used.$DirectoryListWithChangedACL | Export-Csv $ExportFile -Delimiter $CSVDelimiter -NoTypeInformation
I ran into several issues though, as described above, but also this issue: As part of the parameters, I used $PSScriptRoot
to save the files in the same folder as the script is running from. But once I ran the script with Powershell ISE, it would omit the $PSScriptRoot
(as it is $null
at the time of calling the parameters). According to Powershell github issues 4688, it could be solved by adding [CmdletBinding()]
above the param section, or by making the parameter mandatory. I didn’t want this parameter to become mandatory, so I tried [CmdletBinding()]
, but this didn’t work. Of course I could use .\
before the file name, but in that case Start-Transcript
command wouldn’t show me the complete path of the file (even though Stop-Transcript
did). Because of this I didn’t think this was a satisfactory solution, thus I built in an extra check after the parameters are declared:If($LogFile.StartsWith("\")) { $LogFile = "$PSScriptRoot$LogFile" }
Then I added the help text and examples, thus if you runget-help .\GetChangedACLs.ps1
or: get-help .\GetChangedACLs.ps1 -Detailed
you’ll get all the information you need to run the script.
In the most minimal way, you’d run this:.\GetChangedACLs.ps1 -Path "path to check for ACL changes"
or if you want detailed information, you can run.\GetChangedACLs.ps1 -Path "path to check for ACL changes" -FullDetails
In that case it’ll show a summary of the folders it has encountered, where ACL inheritance is disabled and it’ll log this in a log file and export the information to a CSV. If you add -Verbose
, it’ll add more information to the log file and the -FullDetails
switch will export all access rights for each folder and each user as well.
You can download the complete script here.

