On first execution, the script back up folders Access Control List and on the second execution it generates report which shows the folder Access Control List modifications, if any. The report is in human readable format. Please note that script DOES NOT show who have made the modification.
<#
.Synopsis
.Description
Back up the folder called "Access Control List" to an XML file. Upon the next execution, compare the folders back up and the current ACL
and show ACL discrepancy report. If ACL discrepancy exists, recover folders ACL from back.
.Example
.\Track-NTFSChanges.ps1 -Path E:\ -BackupACL
<Back up all folders and subfolders ACL under E: drive into XML>
.Example
.\Track-NTFSChanges.ps1 -Path E:\ -DiscrepancyReport
<Compare folder current and back up ACL permissions and generate folder ACL discrepancy report>
.Example
.\Track-NTFSChanges.ps1 E:\ -FixACL
<Recoveer folder ACL from back up if it was modified since last back up.>
.Notes
Author: Artak Gabrielyan
Date: January 29, 2016
Version: 1
.Link
https://www.linkedin.com/in/artakgabrielyan
https://www.upwork.com/freelancers/~010927360345e1d2a2
#>
Param(
[parameter(Mandatory=$True,
helpmessage='Recursive folder path to backup Access Control List')]
[String]$Path,
[parameter(Mandatory=$False,
helpmessage='Switch to compare folder current access control list with old ACL.')]
[Switch]$DiscrepancyReport,
[parameter(Mandatory=$False,
helpmessage='switch to compare folder current access control list with old ACL and recover old ACL')]
[Switch]$FixACL,
[parameter(Mandatory=$False,
helpmessage='switch to perform folder Access Control List backup.')]
[Switch]$BackupACL
)
Begin{
$BackupDirectory = "$((Get-Location).Path)\"
# Does log folder exist
$logDirectory = $LogFile -replace (($logfile -split "\\")[-1]) , ""
If (!(Test-Path $logDirectory))
{
Write-Host "`n$(get-date -f 'yyyy-MM-dd HH:mm:ss') Error: '$($logfile)' log directory doesn't exist.`n" -ForegroundColor Red
Break
}
$LogMsg = "`n$(Get-Date -f 'yyyy-MM-dd HH:mm:ss') ### Script is started. ###`n"
Write-Host $LogMsg -foregroundcolor cyan
If (!($DiscrepancyReport) -and !($FixACL) -and !($BackupACL))
{
$LogMsg = "$(Get-Date -f 'yyyy-MM-dd HH:mm:ss') At least one inpute parameter should be submitted!"
Write-Host $LogMsg -foregroundcolor Red
Return
}
If (!(Test-Path $Path -PathType 'Container'))
{
Throw "$(Get-Date -f 'yyyy-MM-dd HH:mm:ss') '$($Path)' folder doesn't exist or it is not a folder!"
Return
}
[Array]$Global:Folders = (Get-Item $Path).FullName
$Folders += (Get-ChildItem $Path -Directory).FullName
}
Process{
## Check file paths existance ##################
If (!(Test-Path $BackupDirectory ))
{
$LogMsg = "$(Get-Date -f 'yyyy-MM-dd HH:mm:ss') error '$($BackupDirectory )' folder does not exist!"
Write-Host $LogMsg -foregroundcolor red
Break
}
# Compare ACL of each folder, subfolder and if there is necessity recover accessed from last ACL back
Function Compare-ACL{
Param(
[Parameter(Mandatory=$false)]
[Switch]$FixACL
)
# Take acl from xml file, the last screenshoted acl
$XMLpath = Get-ChildItem $BackupDirectory -filter Track-NTFSChanges*.xml | sort creationtime -descending | select -first 1
# Snapshot file doesn't exist
If (!($xmlpath))
{
$LogMsg = "$(Get-Date -f 'yyyy-MM-dd HH:mm:ss') The ACL permission back up file is found in current directory"
Write-Host $LogMsg -ForegroundColor Red
Return
}
$Xml = Import-Clixml $xmlpath.fullname
$LogMsg = "$(Get-Date -f 'yyyy-MM-dd HH:mm:ss') The latest ACL permission backup\snapshot file is $($BackupDirectory )$($xmlpath)."
Write-Host $LogMsg -foregroundcolor cyan
$historyACL= @()
# Take actual ACL and compare with historical, old acl ###############
$Folders| foreach-object{
$FolderPath = $_
Write-Host "`n*** $FolderPath" -f Cyan
$CurrentACL = @()
$HistoryACL = @()
If (!(Test-Path $FolderPath))
{
$LogMsg = "$(get-date -f 'yyyy-MM-dd HH:mm:ss') error: '$($FolderPath)' folder doesn't exist."
Write-Host $LogMsg -foregroundcolor red
Break
}
# Get folder current ACL
$OriginalACL = (Get-Acl -path $FolderPath).Access
# Replace ACL showed as number with named ACL
$OriginalACL | Foreach {
Switch($_.filesystemrights)
{
'268435456' {$Rights = 'FullControl'}
'-536805376' {$Rights = 'Modify'}
'-1610612736' {$Rights = 'ReadAndExecute'}
Default {$Rights = $_}
}
$Permission = $_.identityreference.value, $Rights, $_.inheritanceflags, "none", $_.accesscontroltype
$Accessrule = new-object system.security.accesscontrol.filesystemaccessrule($Permission)
$CurrentACL += $accessrule
}
# Get ACL from XML file, historical
$Xml | ? {$_.direction -eq $FolderPath } | foreach-object{
$Permission = $_.identityreference.value, $_.filesystemrights, $_.inheritanceflags.value, "none", $_.accesscontroltype.value
$AccessRule = new-object system.security.accesscontrol.filesystemaccessrule $Permission
$HistoryACL += $AccessRule
}
# Compare old and current ACLs and show difference
$DiffACL = Compare-Object $historyACL $currentACL -property identityreference, accesscontroltype,filesystemrights
If (!($DiffACL))
{
$LogMsg = "$(get-date -f 'yyyy-MM-dd HH:mm:ss') The '$($FolderPath)' folder ACL is not modified!"
write-host $LogMsg -foregroundcolor cyan
Return
}
#### Show in table ACL discrepancies
$DiscrepACL = @()
# Select unique users and for each user show old and current ACL permissions
$DiffACL | Select -ExpandProperty IdentityReference -Unique | ForEach-Object {
$ResultACL = @()
$UserName = $_
Write-Host $UserName -ForegroundColor Cyan
# Filter each user historical and current access
$HistACL = $HistoryACL | Where {$_.IdentityReference.value -eq $UserName } | sort FileSystemRights, AccessControlType, IsInherited, InheritanceFlags
$CurrentACL = $CurrentACL | Where {$_.IdentityReference.value -eq $UserName } | sort FileSystemRights, AccessControlType, IsInherited, InheritanceFlags
# If same user has multiple layer (inherited) and different ACL permissions for same folder
If ($HistACL.count -ge $CurrentACL.count)
{
# drow ACL discrepancies table
For($i =0; $i -le $HistACL.count-1; $i++)
{
'FileSystemRights','AccessControlType', 'IdentityReference', 'IsInherited','InheritanceFlags','PropagationFlags' | ForEach{
If ($HistACL)
{
$oValue = ($HistACL[$i] | select -ExpandProperty $_ )
}
Else {$oValue = ''}
if ($CurrentACL)
{
$cValue = ($CurrentACL[$i] | select -ExpandProperty $_)
}
Else {$cValue =''}
$ACLitem = New-Object PSObject
$ACLitem | Add-Member -type NoteProperty -Name "NAME" -Value "$_"
$ACLitem | Add-Member -type NoteProperty -Name "Old" -Value $oValue
$ACLitem | Add-Member -type NoteProperty -Name "Current" -Value $cValue
$ResultACL += $ACLitem
}
$ACLitem = New-Object PSObject
$ACLitem | Add-Member -type NoteProperty -Name "NAME" -Value $null
$ACLitem | Add-Member -type NoteProperty -Name "Old" -Value $null
$ACLitem | Add-Member -type NoteProperty -Name "Current" -Value $null
$ResultACL += $ACLitem
}
# display ACL discrepancies table
$ResultACL
}
# If same user has one layer (not inherited) ACL permissions for same folder
Else
{
# Drow ACL discrepancies table
For($i =0; $i -le $CurrentACL.count-1; $i++)
{
'FileSystemRights','AccessControlType', 'IdentityReference', 'IsInherited','InheritanceFlags','PropagationFlags' | ForEach{
if ($HistACL)
{
$oValue = ($HistACL[$i] | select -ExpandProperty $_ )
}
Else {$oValue = ''}
if ($CurrentACL)
{
$cValue = ($CurrentACL[$i] | select -ExpandProperty $_)
}
Else {$cValue =''}
$ACLitem = New-Object PSObject
$ACLitem | Add-Member -type NoteProperty -Name "NAME" -Value "$_"
$ACLitem | Add-Member -type NoteProperty -Name "Old" -Value $oValue
$ACLitem | Add-Member -type NoteProperty -Name "Current" -Value $cValue
$ResultACL += $ACLitem
}
$ACLitem = New-Object PSObject
$ACLitem | Add-Member -type NoteProperty -Name "NAME" -Value $null
$ACLitem | Add-Member -type NoteProperty -Name "Old" -Value $null
$ACLitem | Add-Member -type NoteProperty -Name "Current" -Value $null
$ResultACL += $ACLitem
}
# display ACL discrepancies table
$ResultACL
}
If (($CurrentACL -ne $null) -and ($FixACL -eq $true))
{
Fix-ACL $FolderPath $CurrentACL 'remove'
}
If (($HistACL -ne $null) -and ($FixACL -eq $true))
{
Fix-ACL $FolderPath $HistACL 'recover'
}
}
}
}
# Remove unnecessary ACL or add missing ACL to folder
Function Fix-ACL
{
Param(
[parameter(Mandatory=$True)]
[Array]$FolderPath,
[parameter(Mandatory=$True)]
[Array]$ACL,
[parameter(Mandatory=$True) ]
[String]$Action)
Write-Host "Remove ACL" -f Cyan
$ACL
# Remove Permission ####
If ($Action -eq 'remove')
{
$ACL| Foreach{
$Permission = $_.identityreference.value, $_.filesystemrights, $_.inheritanceflags, `
"none", $_.accesscontroltype
$AccessRule = New-Object system.security.accesscontrol.filesystemaccessrule $Permission
$itemACL = Get-Acl -path $FolderPath
$itemACL.removeaccessruleall($AccessRule)
Set-Acl $FolderPath $itemACL
}
$LogMsg ="$(get-date -f 'yyyy-MM-dd HH:mm:ss') FixACL: The modified ACL is removed!"
Write-Host $LogMsg -foregroundcolor cyan
}
# recover\set permission #####
Elseif ($Action -eq 'recover')
{
$ACL | Foreach{
$Permission = $_.identityreference.value, $_.filesystemrights, $_.inheritanceflags, "none", $_.accesscontroltype
$accessrule = new-object system.security.accesscontrol.filesystemaccessrule $Permission
$itemACL = Get-Acl -path $FolderPath
$itemACL.AddAccessRule($accessrule)
set-acl $FolderPath $itemacl
}
$LogMsg = "$(get-date -f 'yyyy-MM-dd HH:mm:ss') fixacl: acl recovered, from backup!"
Write-Host $LogMsg -foregroundcolor cyan
}
}
# Snapshot ACL for folders and keep them in xml file as back up
Function Backup-ACL{
$fullACL = @()
## Back up ACL and export to xml ###############
$Folders | sort -unique | foreach-object{
$FolderPath = $_
$FoldersACL = @()
$ACL = @()
If (!(Test-Path $FolderPath))
{
$LogMsg = "$(Get-Date -f 'yyyy-MM-dd HH:mm:ss') Error: '$($FolderPath)' folder doesn't exist."
Write-Host $LogMsg -ForegroundColor red
Return
}
$currentACL = (Get-Acl -Path $FolderPath).access
$currentACL | ForEach-Object{
# Replace permission showed as number with name, string
Switch($_.filesystemrights)
{
'268435456' {$Rights = 'FullControl'}
'-536805376' {$Rights = 'Modify'}
'-1610612736' {$Rights= 'ReadAndExecute'}
Default {$Rights = $_}
}
$ACL = New-Object psobject -property @{
direction = $FolderPath
filesystemrights = $Rights
accesscontroltype = $_.accesscontroltype
identityreference = $_.identityreference
isinherited = $_.isinherited
inheritanceflags = $_.inheritanceflags
propagationflags = $_.propagationflags
}
$FoldersACL += $acl
}
$fullACL += $FoldersACL
}
if ($fullACL)
{
# Back up ACL into xml and keep as back up
$clixmlpath = "$($BackupDirectory )Track-NTFSChanges-$(get-date -f 'yyyymmddhhmmss').xml"
$fullACL | export-clixml $clixmlpath
$LogMsg = "$(get-date -f 'yyyy-MM-dd HH:mm:ss') The folders ACLs back up is successfully permformed to '$($clixmlpath)'. "
write-host $LogMsg -foregroundcolor cyan
}
else
{
$LogMsg = "$(get-date -f 'yyyy-MM-dd HH:mm:ss') error: the ACL back up is not permformed, please check files path. "
write-host $LogMsg -foregroundcolor red
}
}
# Retrive users if
Function Retrive-User{
Param(
[parameter(Mandatory=$false)]
[string]$Users
)
If ($Users -like "*\*")
{
$Arr = $Users -split "\\", ""
$Domain = $Arr[0]
$Account = $Arr[1]
# Does USER exist
if (Get-WmiObject win32_useraccount -Filter "name = '$($Account)' AND domain = '$($Domain)'")
{
Return 1
}
# Does GROUP exist
ElseIf (Get-WmiObject win32_group -Filter "name = '$($Account)' AND domain = '$($Domain)'")
{
Return 1
}
Else
{
# User is not found
$LogMsg = "$(get-date -f 'yyyy-MM-dd HH:mm:ss') '$($Users)' is not found and"
Write-Host $LogMsg -foregroundcolor Red
Return 0
}
}
ElseIf ($Users -eq 'Everyone')
{
Return 1
}
ElseIf ($Users -eq 'Authenticated Users')
{
Return 1
}
Else
{
$LogMsg = "$(get-date -f 'yyyy-MM-dd HH:mm:ss') $($Users) is not found."
Write-Host $LogMsg -foregroundcolor Red
Return 0
}
}
}
End{
# Create folder structure based from csv file
if ($CreateFolders)
{
Backup-ACL
}
# compare csv folders acl with old, back up acl and recovery acl.
if ($FixACL)
{
Compare-ACL -FixACL
}
elseif ($DiscrepancyReport) # compare csv folders acl with old, back up acl and just report
{
Compare-ACL
}
# Backup folder ACL
if ($BackupACL -and !($CreateFolders))
{
Backup-ACL
}
$LogMsg = "`n$(get-date -f 'yyyy-MM-dd HH:mm:ss') ### Script is finished. ###"
Write-Host $LogMsg -foregroundcolor cyan
}
<# .Synopsis .Description Back up the folder called "Access Control List" to an XML file. Upon the next execution, compare the folders back up and the current ACL and show ACL discrepancy report. If ACL discrepancy exists, recover folders ACL from back. .Example .\Track-NTFSChanges.ps1 -Path E:\ -BackupACL <Back up all folders and subfolders ACL under E: drive into XML> .Example .\Track-NTFSChanges.ps1 -Path E:\ -DiscrepancyReport <Compare folder current and back up ACL permissions and generate folder ACL discrepancy report> .Example .\Track-NTFSChanges.ps1 E:\ -FixACL <Recoveer folder ACL from back up if it was modified since last back up.> .Notes Author: Artak Gabrielyan Date: January 29, 2016 Version: 1 .Link https://www.linkedin.com/in/artakgabrielyan https://www.upwork.com/freelancers/~010927360345e1d2a2 #> Param( [parameter(Mandatory=$True, helpmessage='Recursive folder path to backup Access Control List')] [String]$Path, [parameter(Mandatory=$False, helpmessage='Switch to compare folder current access control list with old ACL.')] [Switch]$DiscrepancyReport, [parameter(Mandatory=$False, helpmessage='switch to compare folder current access control list with old ACL and recover old ACL')] [Switch]$FixACL, [parameter(Mandatory=$False, helpmessage='switch to perform folder Access Control List backup.')] [Switch]$BackupACL ) Begin{ $BackupDirectory = "$((Get-Location).Path)\" # Does log folder exist $logDirectory = $LogFile -replace (($logfile -split "\\")[-1]) , "" If (!(Test-Path $logDirectory)) { Write-Host "`n$(get-date -f 'yyyy-MM-dd HH:mm:ss') Error: '$($logfile)' log directory doesn't exist.`n" -ForegroundColor Red Break } $LogMsg = "`n$(Get-Date -f 'yyyy-MM-dd HH:mm:ss') ### Script is started. ###`n" Write-Host $LogMsg -foregroundcolor cyan If (!($DiscrepancyReport) -and !($FixACL) -and !($BackupACL)) { $LogMsg = "$(Get-Date -f 'yyyy-MM-dd HH:mm:ss') At least one inpute parameter should be submitted!" Write-Host $LogMsg -foregroundcolor Red Return } If (!(Test-Path $Path -PathType 'Container')) { Throw "$(Get-Date -f 'yyyy-MM-dd HH:mm:ss') '$($Path)' folder doesn't exist or it is not a folder!" Return } [Array]$Global:Folders = (Get-Item $Path).FullName $Folders += (Get-ChildItem $Path -Directory).FullName } Process{ ## Check file paths existance ################## If (!(Test-Path $BackupDirectory )) { $LogMsg = "$(Get-Date -f 'yyyy-MM-dd HH:mm:ss') error '$($BackupDirectory )' folder does not exist!" Write-Host $LogMsg -foregroundcolor red Break } # Compare ACL of each folder, subfolder and if there is necessity recover accessed from last ACL back Function Compare-ACL{ Param( [Parameter(Mandatory=$false)] [Switch]$FixACL ) # Take acl from xml file, the last screenshoted acl $XMLpath = Get-ChildItem $BackupDirectory -filter Track-NTFSChanges*.xml | sort creationtime -descending | select -first 1 # Snapshot file doesn't exist If (!($xmlpath)) { $LogMsg = "$(Get-Date -f 'yyyy-MM-dd HH:mm:ss') The ACL permission back up file is found in current directory" Write-Host $LogMsg -ForegroundColor Red Return } $Xml = Import-Clixml $xmlpath.fullname $LogMsg = "$(Get-Date -f 'yyyy-MM-dd HH:mm:ss') The latest ACL permission backup\snapshot file is $($BackupDirectory )$($xmlpath)." Write-Host $LogMsg -foregroundcolor cyan $historyACL= @() # Take actual ACL and compare with historical, old acl ############### $Folders| foreach-object{ $FolderPath = $_ Write-Host "`n*** $FolderPath" -f Cyan $CurrentACL = @() $HistoryACL = @() If (!(Test-Path $FolderPath)) { $LogMsg = "$(get-date -f 'yyyy-MM-dd HH:mm:ss') error: '$($FolderPath)' folder doesn't exist." Write-Host $LogMsg -foregroundcolor red Break } # Get folder current ACL $OriginalACL = (Get-Acl -path $FolderPath).Access # Replace ACL showed as number with named ACL $OriginalACL | Foreach { Switch($_.filesystemrights) { '268435456' {$Rights = 'FullControl'} '-536805376' {$Rights = 'Modify'} '-1610612736' {$Rights = 'ReadAndExecute'} Default {$Rights = $_} } $Permission = $_.identityreference.value, $Rights, $_.inheritanceflags, "none", $_.accesscontroltype $Accessrule = new-object system.security.accesscontrol.filesystemaccessrule($Permission) $CurrentACL += $accessrule } # Get ACL from XML file, historical $Xml | ? {$_.direction -eq $FolderPath } | foreach-object{ $Permission = $_.identityreference.value, $_.filesystemrights, $_.inheritanceflags.value, "none", $_.accesscontroltype.value $AccessRule = new-object system.security.accesscontrol.filesystemaccessrule $Permission $HistoryACL += $AccessRule } # Compare old and current ACLs and show difference $DiffACL = Compare-Object $historyACL $currentACL -property identityreference, accesscontroltype,filesystemrights If (!($DiffACL)) { $LogMsg = "$(get-date -f 'yyyy-MM-dd HH:mm:ss') The '$($FolderPath)' folder ACL is not modified!" write-host $LogMsg -foregroundcolor cyan Return } #### Show in table ACL discrepancies $DiscrepACL = @() # Select unique users and for each user show old and current ACL permissions $DiffACL | Select -ExpandProperty IdentityReference -Unique | ForEach-Object { $ResultACL = @() $UserName = $_ Write-Host $UserName -ForegroundColor Cyan # Filter each user historical and current access $HistACL = $HistoryACL | Where {$_.IdentityReference.value -eq $UserName } | sort FileSystemRights, AccessControlType, IsInherited, InheritanceFlags $CurrentACL = $CurrentACL | Where {$_.IdentityReference.value -eq $UserName } | sort FileSystemRights, AccessControlType, IsInherited, InheritanceFlags # If same user has multiple layer (inherited) and different ACL permissions for same folder If ($HistACL.count -ge $CurrentACL.count) { # drow ACL discrepancies table For($i =0; $i -le $HistACL.count-1; $i++) { 'FileSystemRights','AccessControlType', 'IdentityReference', 'IsInherited','InheritanceFlags','PropagationFlags' | ForEach{ If ($HistACL) { $oValue = ($HistACL[$i] | select -ExpandProperty $_ ) } Else {$oValue = ''} if ($CurrentACL) { $cValue = ($CurrentACL[$i] | select -ExpandProperty $_) } Else {$cValue =''} $ACLitem = New-Object PSObject $ACLitem | Add-Member -type NoteProperty -Name "NAME" -Value "$_" $ACLitem | Add-Member -type NoteProperty -Name "Old" -Value $oValue $ACLitem | Add-Member -type NoteProperty -Name "Current" -Value $cValue $ResultACL += $ACLitem } $ACLitem = New-Object PSObject $ACLitem | Add-Member -type NoteProperty -Name "NAME" -Value $null $ACLitem | Add-Member -type NoteProperty -Name "Old" -Value $null $ACLitem | Add-Member -type NoteProperty -Name "Current" -Value $null $ResultACL += $ACLitem } # display ACL discrepancies table $ResultACL } # If same user has one layer (not inherited) ACL permissions for same folder Else { # Drow ACL discrepancies table For($i =0; $i -le $CurrentACL.count-1; $i++) { 'FileSystemRights','AccessControlType', 'IdentityReference', 'IsInherited','InheritanceFlags','PropagationFlags' | ForEach{ if ($HistACL) { $oValue = ($HistACL[$i] | select -ExpandProperty $_ ) } Else {$oValue = ''} if ($CurrentACL) { $cValue = ($CurrentACL[$i] | select -ExpandProperty $_) } Else {$cValue =''} $ACLitem = New-Object PSObject $ACLitem | Add-Member -type NoteProperty -Name "NAME" -Value "$_" $ACLitem | Add-Member -type NoteProperty -Name "Old" -Value $oValue $ACLitem | Add-Member -type NoteProperty -Name "Current" -Value $cValue $ResultACL += $ACLitem } $ACLitem = New-Object PSObject $ACLitem | Add-Member -type NoteProperty -Name "NAME" -Value $null $ACLitem | Add-Member -type NoteProperty -Name "Old" -Value $null $ACLitem | Add-Member -type NoteProperty -Name "Current" -Value $null $ResultACL += $ACLitem } # display ACL discrepancies table $ResultACL } If (($CurrentACL -ne $null) -and ($FixACL -eq $true)) { Fix-ACL $FolderPath $CurrentACL 'remove' } If (($HistACL -ne $null) -and ($FixACL -eq $true)) { Fix-ACL $FolderPath $HistACL 'recover' } } } } # Remove unnecessary ACL or add missing ACL to folder Function Fix-ACL { Param( [parameter(Mandatory=$True)] [Array]$FolderPath, [parameter(Mandatory=$True)] [Array]$ACL, [parameter(Mandatory=$True) ] [String]$Action) Write-Host "Remove ACL" -f Cyan $ACL # Remove Permission #### If ($Action -eq 'remove') { $ACL| Foreach{ $Permission = $_.identityreference.value, $_.filesystemrights, $_.inheritanceflags, ` "none", $_.accesscontroltype $AccessRule = New-Object system.security.accesscontrol.filesystemaccessrule $Permission $itemACL = Get-Acl -path $FolderPath $itemACL.removeaccessruleall($AccessRule) Set-Acl $FolderPath $itemACL } $LogMsg ="$(get-date -f 'yyyy-MM-dd HH:mm:ss') FixACL: The modified ACL is removed!" Write-Host $LogMsg -foregroundcolor cyan } # recover\set permission ##### Elseif ($Action -eq 'recover') { $ACL | Foreach{ $Permission = $_.identityreference.value, $_.filesystemrights, $_.inheritanceflags, "none", $_.accesscontroltype $accessrule = new-object system.security.accesscontrol.filesystemaccessrule $Permission $itemACL = Get-Acl -path $FolderPath $itemACL.AddAccessRule($accessrule) set-acl $FolderPath $itemacl } $LogMsg = "$(get-date -f 'yyyy-MM-dd HH:mm:ss') fixacl: acl recovered, from backup!" Write-Host $LogMsg -foregroundcolor cyan } } # Snapshot ACL for folders and keep them in xml file as back up Function Backup-ACL{ $fullACL = @() ## Back up ACL and export to xml ############### $Folders | sort -unique | foreach-object{ $FolderPath = $_ $FoldersACL = @() $ACL = @() If (!(Test-Path $FolderPath)) { $LogMsg = "$(Get-Date -f 'yyyy-MM-dd HH:mm:ss') Error: '$($FolderPath)' folder doesn't exist." Write-Host $LogMsg -ForegroundColor red Return } $currentACL = (Get-Acl -Path $FolderPath).access $currentACL | ForEach-Object{ # Replace permission showed as number with name, string Switch($_.filesystemrights) { '268435456' {$Rights = 'FullControl'} '-536805376' {$Rights = 'Modify'} '-1610612736' {$Rights= 'ReadAndExecute'} Default {$Rights = $_} } $ACL = New-Object psobject -property @{ direction = $FolderPath filesystemrights = $Rights accesscontroltype = $_.accesscontroltype identityreference = $_.identityreference isinherited = $_.isinherited inheritanceflags = $_.inheritanceflags propagationflags = $_.propagationflags } $FoldersACL += $acl } $fullACL += $FoldersACL } if ($fullACL) { # Back up ACL into xml and keep as back up $clixmlpath = "$($BackupDirectory )Track-NTFSChanges-$(get-date -f 'yyyymmddhhmmss').xml" $fullACL | export-clixml $clixmlpath $LogMsg = "$(get-date -f 'yyyy-MM-dd HH:mm:ss') The folders ACLs back up is successfully permformed to '$($clixmlpath)'. " write-host $LogMsg -foregroundcolor cyan } else { $LogMsg = "$(get-date -f 'yyyy-MM-dd HH:mm:ss') error: the ACL back up is not permformed, please check files path. " write-host $LogMsg -foregroundcolor red } } # Retrive users if Function Retrive-User{ Param( [parameter(Mandatory=$false)] [string]$Users ) If ($Users -like "*\*") { $Arr = $Users -split "\\", "" $Domain = $Arr[0] $Account = $Arr[1] # Does USER exist if (Get-WmiObject win32_useraccount -Filter "name = '$($Account)' AND domain = '$($Domain)'") { Return 1 } # Does GROUP exist ElseIf (Get-WmiObject win32_group -Filter "name = '$($Account)' AND domain = '$($Domain)'") { Return 1 } Else { # User is not found $LogMsg = "$(get-date -f 'yyyy-MM-dd HH:mm:ss') '$($Users)' is not found and" Write-Host $LogMsg -foregroundcolor Red Return 0 } } ElseIf ($Users -eq 'Everyone') { Return 1 } ElseIf ($Users -eq 'Authenticated Users') { Return 1 } Else { $LogMsg = "$(get-date -f 'yyyy-MM-dd HH:mm:ss') $($Users) is not found." Write-Host $LogMsg -foregroundcolor Red Return 0 } } } End{ # Create folder structure based from csv file if ($CreateFolders) { Backup-ACL } # compare csv folders acl with old, back up acl and recovery acl. if ($FixACL) { Compare-ACL -FixACL } elseif ($DiscrepancyReport) # compare csv folders acl with old, back up acl and just report { Compare-ACL } # Backup folder ACL if ($BackupACL -and !($CreateFolders)) { Backup-ACL } $LogMsg = "`n$(get-date -f 'yyyy-MM-dd HH:mm:ss') ### Script is finished. ###" Write-Host $LogMsg -foregroundcolor cyan }
If there is necessity it could recover old permissions.
.\Track-NTFSChanges.ps1 -Path E:\ -BackupACL
.\Track-NTFSChanges.ps1 -Path E:\ -DiscrepancyReport
.\Track-NTFSChanges.ps1 -path E:\ -FixACL