When dealing with multiple Windows machines in an enterprise environment or during software deployment, verifying consistent directory structures and permissions becomes crucial. A common pain point emerges when:
- Driver updates modify ACLs unexpectedly
- File deployments miss critical permission settings
- Security policies create inconsistent access controls
For quick comparisons without third-party tools, PowerShell provides powerful capabilities:
# Basic directory comparison with hashes
$sourceFiles = Get-ChildItem -Recurse C:\source\path
$destFiles = Get-ChildItem -Recurse \\remote\path
Compare-Object $sourceFiles $destFiles -Property Name, Length, LastWriteTime
# NTFS permission comparison
Function Compare-FolderPermissions {
param(
[string]$Path1,
[string]$Path2
)
$acl1 = Get-Acl $Path1
$acl2 = Get-Acl $Path2
return Compare-Object $acl1.Access $acl2.Access -Property IdentityReference, FileSystemRights
}
# Example usage:
Compare-FolderPermissions -Path1 "C:\Program Files\App" -Path2 "\\server\C$\Program Files\App"
Microsoft's built-in Robocopy offers verbose comparison capabilities:
robocopy C:\source \\remote\destination /L /X /E /ZB /COPY:DATSOU /LOG:comparison.log /TEE /NP /R:0 /W:0
Key switches:
- /L - List-only mode (no actual copying)
- /COPY:DATSOU - Compare Data, Attributes, Timestamps, Security, Owner, Auditing info
- /X - Report all extra files (not just differing ones)
For integration into deployment tools or custom solutions:
using System.IO;
using System.Security.AccessControl;
public class PermissionComparer
{
public void CompareDirectories(string dir1, string dir2)
{
var dir1ACL = Directory.GetAccessControl(dir1);
var dir2ACL = Directory.GetAccessControl(dir2);
// Compare access rules
var rules1 = dir1ACL.GetAccessRules(true, true, typeof(System.Security.Principal.NTAccount));
var rules2 = dir2ACL.GetAccessRules(true, true, typeof(System.Security.Principal.NTAccount));
// Implementation for detailed comparison would go here
}
}
For GUI-based solutions consider:
- AccessEnum (Sysinternals) - Lightweight permission snapshot tool
- Beyond Compare - Commercial tool with permission comparison
- TreeComp - Specialized in folder structure analysis
Sample script for build pipelines:
# PowerShell script for Azure DevOps
$expectedAcl = Get-Acl "C:\reference\permissions"
$targetAcl = Get-Acl $(Build.ArtifactStagingDirectory)
$diff = Compare-Object $expectedAcl.Access $targetAcl.Access -Property IdentityReference, FileSystemRights
if ($diff) {
Write-Error "Permission mismatch detected!"
$diff | Format-Table -AutoSize
exit 1
}
When troubleshooting:
- Always check inherited vs explicit permissions separately
- Compare effective permissions (use
whoami /priv
) - Remember that SYSTEM and admin permissions may differ
- Account for UAC virtualization in Program Files
When troubleshooting Windows system issues, comparing directory structures and NTFS permissions between machines is a common but surprisingly complex task. Standard file comparison tools like WinMerge focus primarily on file contents rather than metadata, leaving administrators without a clear way to audit permission differences programmatically.
Windows PowerShell provides native capabilities for comparing both directory structures and permissions. Here's a comprehensive script that outputs differences in a machine-readable format:
# Compare directories and permissions between two paths
$sourcePath = "\\Machine1\C$\Program Files\App"
$targetPath = "\\Machine2\C$\Program Files\App"
$outputFile = "C:\Temp\PermissionDiff.txt"
function Get-PermissionHash {
param ($path)
Get-ChildItem $path -Recurse | ForEach-Object {
$acl = Get-Acl $_.FullName
[PSCustomObject]@{
Path = $_.FullName
Permissions = $acl.Access |
Select-Object IdentityReference, FileSystemRights, AccessControlType
LastWriteTime = $_.LastWriteTime
Attributes = $_.Attributes
}
}
}
$sourceData = Get-PermissionHash $sourcePath
$targetData = Get-PermissionHash $targetPath
Compare-Object $sourceData $targetData -Property Path,Permissions,LastWriteTime,Attributes |
Where-Object { $_.SideIndicator -eq "<=" } |
Export-Csv $outputFile -NoTypeInformation
For quick structural comparisons, Robocopy's logging feature can identify missing files:
robocopy "\\Machine1\C$\Program Files\App" "\\Machine2\C$\Program Files\App" /L /X /XD /E /NP /LOG:C:\Temp\DirDiff.txt
For enterprise environments, these tools provide advanced comparison capabilities:
- Beyond Compare (with Pro version's ACL comparison)
- SetACL Studio - Specialized for permission auditing
- TreeSize Professional - Includes permission reporting
Once differences are identified, you can use icacls to synchronize permissions:
# Export permissions from reference machine
icacls "C:\Program Files\App\*" /save permExport.txt /t /c
# Apply to target machine
icacls "C:\Program Files\App" /restore permExport.txt
Remember to account for:
- Inherited vs explicit permissions
- Local vs domain accounts (SID resolution)
- System-reserved directories requiring TrustedInstaller access