????
Current Path : C:/Windows/System32/WindowsPowerShell/v1.0/Modules/WindowsServerBackup/ |
Current File : C:/Windows/System32/WindowsPowerShell/v1.0/Modules/WindowsServerBackup/WindowsServerBackupAcl.psm1 |
######################################################################################### # Copyright (c) Microsoft Corporation # # Windows Server Backup ACL PowerShell Module # # ######################################################################################### $DATETIME_FORMAT = "yyyy-MM-dd-HH-mm-ss" ######################################################################################### # Function: Backup-ACL # # Outputs an XML file which contains the ACL details of the folder for # which backup of ACL was requested. # # Ex: Backup-ACL -Path <path/to/folder> -DestinationPath <path/to/xml/or/path/to/create/xml> -LogPath <path/for/logs> # # Input: # Path: String - Path for which the ACL should be backed up. # DestinationPath: String - Destination folder for the XML Generated. # LogPath: String - Destination folder for the logs. # ScheduleTrigger: System.Object - Trigger object to trigger this as a scheduled task. # # Return: None. ######################################################################################### Function Backup-ACL { [CmdletBinding(SupportsShouldProcess = $True)] Param( [parameter(Mandatory = $true, ValueFromPipeline = $true, HelpMessage = "Path for which permission needs to be backed up")] [ValidateNotNullOrEmpty()] [ValidateScript({ Test-Path $_ -PathType Any })] [String]$Path, [parameter(Mandatory = $true, ValueFromPipeline = $true, HelpMessage = "Path where permission backup needs to be stored")] [ValidateNotNullOrEmpty()] [string]$DestinationPath, [parameter(Mandatory = $true, ValueFromPipeline = $true, HelpMessage = "Path where logs need to be stored")] [ValidateNotNullOrEmpty()] [ValidateScript({ Test-Path $_ -PathType Container })] [string]$LogPath, [parameter(Mandatory = $false, ValueFromPipeline = $true, HelpMessage = "Specifies trigger to create a scheduled task to backup permissions of the said folder")] [System.Object]$ScheduleTrigger ) $isAdmin = IsAdmin if(-not $isAdmin) { Write-Error "This command requires to be run on an elevated powershell session." return; } $PathInfo=[System.Uri]$Path; if($PathInfo.IsUnc) { Write-Error "UNC path is not supported for Backing up permissions (ACL) " $Path return } $datetime = Get-Date -DisplayHint DateTime -Format $DATETIME_FORMAT #Converting it to a Path Object $Path = Convert-Path $Path if($Path[$Path.Length - 1] -eq '\') { $Path = $Path.Substring(0,$Path.Length-1) } $bkpName = "Backup-" + $Path.ToString().Replace("\", "-") $bkpName = $bkpName.ToString().Replace(":", "") $bkpName = $bkpName.ToString().Replace("?", "") $bkpName = $bkpName.ToString().Replace(" ", "") $errlogs = $LogPath + "\" + $bkpName + "-" + $datetime + ".err" $logs = $LogPath + "\" + $bkpName + "-" + $datetime + ".log" if($ScheduleTrigger -like $null) { Start-Transcript -Path $errlogs -Append if (Test-Path $DestinationPath -PathType Leaf) { $extn = [IO.Path]::GetExtension($DestinationPath) if ($extn -ne ".xml") { Write-Error "The backup need to be stored in XML file. Please verify the DestinationPath"; Stop-Transcript return } $DestinationPath = Resolve-Path $DestinationPath $aclXmlFilePath = $DestinationPath } elseif(Test-Path $DestinationPath -PathType Container) { $DestinationPath = Resolve-Path $DestinationPath $aclXmlFilePath = $DestinationPath + "\" + $bkpName + "-" + $datetime + ".xml" } else { $extn = [IO.Path]::GetExtension($DestinationPath) if ($extn -ne ".xml") { Write-Error "The backup need to be stored in XML file. Please verify the DestinationPath"; Stop-Transcript return } if(!(New-Item $DestinationPath -Type File)) { Write-Error "Invalid Destination path." Stop-Transcript return } $DestinationPath = Resolve-Path $DestinationPath $aclXmlFilePath = $DestinationPath } $xmlsettings = [System.Xml.XmlWriterSettings]::new() $xmlsettings.Indent = $true $xmlsettings.IndentChars = " " $xmlWriter = [System.XML.XmlWriter]::Create($aclXmlFilePath, $xmlsettings) $xmlWriter.WriteStartDocument() $xmlWriter.WriteComment('System Information') $xmlWriter.WriteStartElement("Objects") Write-Host "Backing up permissions (ACL) for Path $Path ..." try { # Get the actual root folders path seperately. $rootAcl = $null; $rootAcl = Get-Item -Path $Path -force | Get-Acl | Select-Object -Property 'PSPath', 'Sddl' if($null -eq $rootAcl) { Write-Errror "Access denied for the root folder." Stop-Transcript return } $xmlWriter.WriteStartElement("Object") $xmlWriter.WriteElementString("Root",$rootAcl.PSpath) $xmlWriter.WriteElementString("Sddl",$rootAcl.Sddl) $xmlWriter.WriteEndElement() $currentDirPath = "" Get-ChildItem -Path $Path -Recurse -force | Get-Acl | Select-Object -Property 'PSPath', 'Sddl', 'PSParentPath' | ForEach-Object { if ($currentDirPath -ne $_.PSParentPath) { if ($currentDirPath -ne "") { Write-Log -Message "Done backing up permissions for dir $currentDirPath" -FilePath $logs } $currentDirPath = $_.PSParentPath } $xmlWriter.WriteStartElement("Object") $xmlWriter.WriteElementString("PSPath",$_.PSpath) $xmlWriter.WriteElementString("Sddl",$_.Sddl) $xmlWriter.WriteEndElement() } if ($currentDirPath -ne "") { Write-Log -Message "Done backing up permissions for dir $currentDirPath" -FilePath $logs } } catch [System.Exception] { $err = "Error $_.Exception.Message Occured At $_.InvocationInfo.Line" Write-Error $err } finally { $xmlWriter.WriteEndElement() $xmlWriter.WriteEndDocument() $xmlWriter.Flush() $xmlWriter.Close() } Write-Host "Backup permissions for $Path complete! Refer $logs for summary and $errlogs for error." Stop-Transcript } else { #This has to be a seperate command. Write-Host "Creating a backup task... " $taskname = "Backup Permission " + $bkpName Get-ScheduledTask -TaskName $taskname -ErrorAction SilentlyContinue -OutVariable task if(!$task) { $location = Get-Location $cmd = "Backup-ACL -Path '$Path' -DestinationPath $DestinationPath -LogPath $LogPath" $description = "Backup Ntfs Permission (ACL) for Path $Path" $action = New-ScheduledTaskAction -Execute 'Powershell.exe' -Argument $cmd -WorkingDirectory $location Register-ScheduledTask -Action $action -Trigger $ScheduleTrigger -TaskName $taskname -ErrorAction Stop -Description $description -RunLevel Highest Write-Host "Backup Permission Task is scheduled successfully for Path $Path" } else { Write-Host "Not able to schedule new backup task as task is already scheduled!" } } } ######################################################################################### # Function: Restore-ACL # # Takes an XML file, generated by Backup-ACL which contains the ACL details of the folder # for which backup of ACL was requested and applies it to the Path given. # # Ex: Restore-ACL -Path <path> -XmlPath <path/to/xml> -LogPath <path> # # Input: # Path: String - Path for which the ACL should be backed up. # XmlPath: String - The XML file that contains ACL information. # LogPath: string - Path to store the logs. # # Return: None. ######################################################################################### Function Restore-ACL { [CmdletBinding(SupportsShouldProcess = $True)] Param( [parameter(Mandatory = $true, ValueFromPipeline = $true, Position = 0, HelpMessage = "Path for which permission needs to be restored")] [ValidateNotNullOrEmpty()] [ValidateScript( { Test-Path $_ -PathType Any })] [String]$Path, [parameter(Mandatory = $true, ValueFromPipeline = $true, HelpMessage = "The XML file that contains ACL information. ")] [ValidateNotNullOrEmpty()] [ValidateScript( { Test-Path $_ -PathType Leaf })] [String]$XmlPath, [parameter(Mandatory = $true, ValueFromPipeline = $true, HelpMessage = "Path where logs need to be stored")] [ValidateNotNullOrEmpty()] [ValidateScript( { Test-Path $_ -PathType Container })] [String]$LogPath ) $isAdmin = IsAdmin if(-not $isAdmin) { Write-Error "This command requires to be run on an elevated powershell session." return; } $PathInfo=[System.Uri]$Path; if($PathInfo.IsUnc) { Write-Error "UNC path is not supported for Restoring up permissions (ACL) " $Path return } $datetime = Get-Date -DisplayHint DateTime -Format $DATETIME_FORMAT $Path = Convert-Path $Path # Remove last '\' if($Path[$Path.Length - 1] -eq '\') { $Path = $Path.Substring(0,$Path.Length-1) } $restoreName = "restore-" + $Path.ToString().Replace("\", "-") $restoreName = $restoreName.ToString().Replace(":", "") $restoreName = $restoreName.ToString().Replace("?", "") $restoreName = $restoreName.ToString().Replace(" ", "") $errlogs = $LogPath + "\" + $restoreName + "-" + $datetime + ".err" $logs = $LogPath + "\" + $restoreName + "-" + $datetime + ".log" Start-Transcript $errlogs Write-Host "Restoring permissions (ACL) started for Path $Path ..." $recStr = "Microsoft.PowerShell.Core\FileSystem::" + $Path + "*" $xmlPath = Resolve-Path $XmlPath $xmlReader = [System.Xml.xmlReader]::Create($XmlPath); $currentDirPath = "" while ($xmlReader.Read()) { if($xmlReader.NodeType -eq [System.Xml.XmlNodeType]::Element -and $xmlReader.Name -eq "Root") { $xmlReader.ReadStartElement("Root") $PSPath = $xmlReader.ReadString() $xmlReader.ReadEndElement() $xmlReader.ReadStartElement("Sddl") $Sddl = $xmlReader.ReadString() $xmlReader.ReadEndElement() if($PSPath -like $recStr) { Apply-ACL -PSPath $PSPath -Sddl $Sddl } } elseif($xmlReader.NodeType -eq [System.Xml.XmlNodeType]::Element -and $xmlReader.Name -eq "PSPath") { $xmlReader.ReadStartElement("PSPath") $PSPath = $xmlReader.ReadString() $xmlReader.ReadEndElement() $xmlReader.ReadStartElement("Sddl") $Sddl = $xmlReader.ReadString() $xmlReader.ReadEndElement() if($PSPath -like $recStr) { if ($currentDirPath -ne $parentPath) { if ($currentDirPath -ne "") { Write-Log -Message "Done restoring permissions for dir $currentDirPath" -FilePath $logs } $currentDirPath = $parentPath } Apply-ACL -PSPath $PSPath -Sddl $Sddl $parentPath = [IO.Path]::GetDirectoryName($PSPath) } } } if ($currentDirPath -ne "") { Write-Log -Message "Done restoring permissions for dir $currentDirPath" -FilePath $logs } $xmlReader.Close() Write-Host "Restore permissions for $Path complete! Refer $logs for summary and $errlogs for error." Stop-Transcript } ######################################################################################### # Internal Function: Apply-ACL # # Apply ACL on specified Paths ######################################################################################### function Apply-ACL { [CmdletBinding()] param([Parameter(Mandatory=$true)] [System.String]$PSPath, [Parameter(Mandatory=$true)] [System.String]$Sddl ) try { $acl = Get-Acl -LiteralPath $PSPath #Remove inheritance $acl.SetAccessRuleProtection($true, $true) #Restore persmissions from the backup $acl.SetSecurityDescriptorSddlForm($Sddl) Set-Acl -LiteralPath $PSPath -AclObject $acl } catch { $err = "Error " + $_.Exception.Message + " Occured At Path " + $errPath + " At " + $_.InvocationInfo.Line Write-Error $err } } ######################################################################################### # Internal Function: IsAdmin # # Checks if the user running the current session of PS is an admin. ######################################################################################### function IsAdmin { [CmdletBinding()] param() return ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator") } ######################################################################################### # Internal Function: Write-Log # # Writes the log to the specific file. ######################################################################################### function Write-Log { [CmdletBinding()] param([Parameter(Mandatory=$true)] [System.String]$Message, [Parameter(Mandatory=$true)] [System.String]$FilePath ) Add-Content -Path $FilePath -Value $Message } ######################################################################################### Export-ModuleMember Backup-ACL Export-ModuleMember Restore-ACL #########################################################################################