Last active
April 7, 2025 12:32
-
-
Save Rapidhands/58fe8bfe6acdafefe8664719f3ecfdf9 to your computer and use it in GitHub Desktop.
How to chek NTFS permissions on subfolders. Example with large comments for explanation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<# | |
.SYNOPSIS | |
Analyzes NTFS permissions on folders and exports results to CSV or XLSX format. | |
.DESCRIPTION | |
This script recursively analyzes NTFS permissions on all subfolders of a specified path | |
and exports the results to either CSV or Excel format. It uses the NTFSSecurity module | |
for accurate permission analysis and ImportExcel for Excel export capabilities. | |
The name of the export file is NTFS_Permissions followed by the current date and time. | |
The script also provides progress updates during the analysis process. | |
The script is amply (and perhaps too much and unnecessarily) commented, | |
but it is intended to be a script providing explanations of the why and how to beginners. | |
The script was also run through the PSScriptAnalyzer module (using its Invoke-ScriptAnalyzer cmdlet) to verify that it complies with best practices. | |
.PARAMETER RootPath | |
The root folder path to analyze. Must be a valid directory path. | |
.PARAMETER ExportPath | |
The directory where the export file will be created. Must be a valid directory path. | |
.PARAMETER ExportFormat | |
The export format, either 'CSV', 'XLSX', or 'Both' | |
Default is XLSX. | |
Valid values are 'CSV', 'XLSX', 'Both'. | |
.EXAMPLE | |
.\Check-NTFS.ps1 -RootPath "C:\Data" -ExportPath "C:\Reports" | |
Analyzes all folders under C:\Data and exports results to a CSV file (default) in C:\Reports | |
.EXAMPLE | |
.\Check-NTFS.ps1 -RootPath "C:\Data" -ExportPath "C:\Reports" -ExportFormat XLSX | |
Analyzes all folders under C:\Data and exports results to an Excel file in C:\Reports | |
.EXAMPLE | |
.\Check-NTFS.ps1 -RootPath "D:\Shared" -ExportPath "D:\Audit" -ExportFormat CSV -Verbose | |
Analyzes permissions with verbose output and exports to CSV format | |
.EXAMPLE | |
.\Check-NTFS.ps1 -RootPath "D:\Shared" -ExportPath "D:\Audit" -ExportFormat Both -Verbose | |
Analyzes permissions with verbose output and exports to both CSV and XLSX formats | |
.EXAMPLE | |
Get-Help .\Check-NTFS.ps1 -showWindow | |
Displays the help information for the script in a window | |
.NOTES | |
Requires modules: NTFSSecurity, ImportExcel | |
Author: O. FERRIERE | |
Version: 1.0 | |
Last Modified: 2024/04/07 | |
#> | |
[CmdletBinding()] | |
[OutputType([System.Void])] | |
param( | |
[Parameter(Mandatory = $true, | |
Position = 0, | |
ValueFromPipeline = $true, | |
ValueFromPipelineByPropertyName = $true, | |
HelpMessage = 'Path of the folder to be analyzed')] | |
[ValidateScript({ | |
if (-Not (Test-Path $_) ) | |
{ | |
throw 'Folder does not exist' | |
} | |
if (-Not (Test-Path $_ -PathType Container) ) | |
{ | |
throw 'The Path argument must be a Directory. Files are not allowed.' | |
} | |
return $true | |
})] | |
[System.IO.DirectoryInfo]$RootPath, | |
[Parameter(Mandatory = $true, | |
Position = 1, | |
HelpMessage = 'Results export path')] | |
[ValidateScript({ | |
if (-Not (Test-Path $_) ) | |
{ | |
throw 'Export path does not exist' | |
} | |
if (-Not (Test-Path $_ -PathType Container) ) | |
{ | |
throw 'The ExportPath argument must be a Directory.' | |
} | |
return $true | |
})] | |
[System.IO.DirectoryInfo]$ExportPath, | |
[Parameter(Position = 2, | |
HelpMessage = 'Results export format')] | |
[ValidateSet('CSV', 'XLSX', 'Both')] | |
[string]$ExportFormat = 'XLSX' | |
) | |
BEGIN | |
{ | |
Write-Verbose "Script started at $(Get-Date)" | |
#region Parameters | |
<# | |
using region to group parameters and their description | |
This is a common practice in PowerShell scripts to improve readability and organization. | |
#> | |
# Initialization of time counter | |
$StopWatch = [System.Diagnostics.Stopwatch]::StartNew() | |
$StartTime = Get-Date | |
$ExportFiles = @() | |
# Initialize result collection | |
<# | |
The use of a generic list allows for efficient dynamic resizing and avoids the overhead of using an array. | |
The final export will be done in a single operation, which is more efficient than exporting each item individually. | |
The final result will be a collection of PSCustomObject, which is suitable for export to CSV or Excel. | |
This approach is more efficient than using an array, as it avoids the need to resize the array dynamically. | |
ref. : https://learn.microsoft.com/en-us/powershell/scripting/developer/cmdlet/using-collections-in-powershell?view=powershell-7.3#using-generic-collections | |
#> | |
$Result = [System.Collections.Generic.List[PSCustomObject]]::new() | |
#endregion Parameters | |
#region Checking and installing required modules if necessary | |
$RequiredModules = @('NTFSSecurity', 'ImportExcel') | |
foreach ($Module in $RequiredModules) | |
{ | |
try | |
{ | |
if (-not (Get-Module -ListAvailable -Name $Module)) | |
{ | |
Write-Verbose "Module $Module not found. Attempting to install..." | |
Install-Module -Name $Module -Scope CurrentUser -Force -AllowClobber | |
Write-Verbose "Module $Module installed successfully" | |
} | |
Import-Module $Module -ErrorAction Stop | |
Write-Verbose "Module $Module loaded successfully" | |
} | |
catch | |
{ | |
throw "Failed to install or load module $Module : $_" | |
} | |
} | |
#endregion Checking and installing required modules if necessary | |
} | |
PROCESS | |
{ | |
try | |
{ | |
Write-Verbose "Starting permissions analysis on $RootPath" | |
# Gathering folders list in recursive way | |
$AllFolders = Get-ChildItem -Path $RootPath.FullName -Directory -Recurse -ErrorAction Stop | |
$TotalFolders = $AllFolders.Count | |
$Current = 0 | |
foreach ($Folder in $AllFolders) | |
{ | |
$Current++ | |
Write-Progress -Activity 'Permissions Analysis' -Status "$Current / $TotalFolders folders" -PercentComplete (($Current / $TotalFolders) * 100) | |
Write-Verbose "Directory Analysis : $($Folder.FullName)" | |
# Gathering ACLs with NTFSSecurity | |
$AllAcls = Get-NTFSAccess -Path $Folder.FullName | |
foreach ($Acl in $AllAcls) | |
{ | |
$Result.Add([PSCustomObject]@{ | |
Path = $Folder.FullName | |
Account = $Acl.Account | |
AccessType = $Acl.AccessRights | |
TypePermission = $Acl.AccessControlType | |
Herite = $Acl.IsInherited | |
Source = if ($Acl.IsInherited) | |
{ | |
'Inherited' | |
} | |
else | |
{ | |
'Direct' | |
} | |
AnalysisDate = Get-Date | |
}) | |
} | |
} | |
} | |
catch | |
{ | |
Write-Error "Error during processing : $_" | |
throw | |
} | |
} | |
END | |
{ | |
try | |
{ | |
Write-Verbose "Exporting results to $ExportPath" | |
$exportFiles = @() | |
# Export results according to the chosen format | |
$ExcelParams = @{ | |
Path = Join-Path -Path $ExportPath.FullName -ChildPath $('NTFS_Permissions_At_' + $(Get-Date -Format yyyy-MM-dd) + '.xlsx') | |
AutoSize = $true | |
TableName = 'NTFS_Permissions' | |
Worksheet = 'Permissions' | |
FreezeTopRow = $true | |
AutoFilter = $true | |
} | |
$CsvParams = @{ | |
Path = Join-Path -Path $ExportPath.FullName -ChildPath $('NTFS_Permissions_At_' + $(Get-Date -Format yyyy-MM-dd) + '.csv') | |
NoTypeInformation = $true | |
Encoding = 'UTF8' | |
} | |
switch ($ExportFormat) | |
{ | |
'XLSX' | |
{ | |
$Result | Export-Excel @ExcelParams | |
$exportFiles += $ExcelParams.Path | |
} | |
'CSV' | |
{ | |
$Result | Export-Csv @CsvParams | |
$exportFiles += $CsvParams.Path | |
} | |
'Both' | |
{ | |
$Result | Export-Excel @ExcelParams | |
$Result | Export-Csv @CsvParams | |
$exportFiles += $ExcelParams.Path, $CsvParams.Path | |
Write-Verbose 'Exported in both formats successfully' | |
} | |
} | |
} | |
catch | |
{ | |
Write-Error "Error during export : $_" | |
throw | |
} | |
finally | |
{ | |
# Stopping the stopwatch and displaying the execution summary | |
$stopWatch.Stop() | |
<# | |
There are different ways to calculate the exectution time in PowerShell. | |
The method used here is the most efficient and accurate. | |
The use of the StopWatch class allows for precise measurement of elapsed time. | |
The StopWatch class is part of the System.Diagnostics namespace and provides a high-resolution timer. | |
It is more efficient than using the Get-Date cmdlet for measuring elapsed time. | |
#> | |
<# | |
there are different ways to display the execution summary in PowerShell. | |
The method used here is the most efficient and user-friendly. | |
The use of Write-Host allows for colored output, which is more readable and visually appealing. | |
The use of Write-Progress allows for a progress bar to be displayed, which is more informative and user-friendly. | |
The use of Write-Verbose allows for detailed output, which is more informative and useful for debugging. | |
The Best Practices recommendation are to avoid using Write-Host for outputting information. | |
"Avoid using Write-Host because it might not work in all hosts, | |
does not work when there is no host, and (prior to PS 5.0) cannot be suppressed, captured, or redirected. | |
Instead, use Write-Output, Write-Verbose, or Write-Information." | |
However, in this case, the use of Write-Host is justified because the script is intended to be run interactively and the output is meant to be displayed on the console. | |
The use of Write-Host allows for colored output, which is more readable and visually appealing. | |
#> | |
Write-Host "`n=== Execution Summary ===" -ForegroundColor Cyan | |
Write-Host "Start of analysis : $StartTime" | |
Write-Host "End of analysis : $(Get-Date)" | |
Write-Host "Elapsed time : $($StopWatch.Elapsed.Hours)h $($StopWatch.Elapsed.Minutes)m $($StopWatch.Elapsed.Seconds)s" | |
Write-Host "Total folders analyzed : $($Result.Count)" | |
Write-Host "`n Export Files created :" -ForegroundColor Cyan | |
foreach ($file in $exportFiles) | |
{ | |
Write-Host "- $file" | |
} | |
Write-Host "========================`n" | |
Write-Progress -Activity 'Permissions Analysis' -Completed | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment