????

Your IP : 3.148.113.158


Current Path : C:/Windows/System32/WindowsPowerShell/v1.0/Modules/WindowsServerBackup/
Upload File :
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

#########################################################################################