How to Backup AD forest with Powershell

This is the new release of my powershell script used on our DRM procedure. The old-one is here: https://241931348f64b1d1.wordpress.com/2015/02/16/how-to-backup-ad-forest-with-powershell/

This script use powershell Jobs to remotely run “Windows Backup” on every servers inside a TXT file, in parallel and write a logs that can used for report. The backup is saved on the same machine you are backupping (not on the machine where you are lunching the script).

This script have 2 parmeters:
-ServerList [Suffix of group of servers]

Example: “-ServerList EMEA” means that the script load a precompiled file named D:\Scripts\AD_Backup\DCs_EMEA.txt where you wrote all the servers to backup, and save the log on D:\Scripts\AD_Backup\WorkingFolder\BackupTranscriptEMEA.txt

-BackupPath [Drive\Path on remote server where save the backup]

Example: “-BackupPath D:\” means the backup is saved on drive D: of machine under backup. The volume should be different from the system drive (the disk where the OS is installed) and, in case of DCs, also from the disk where SYSVOL and ADDB is located.

 

First reate a TXT file named DCs_EMEA.txt with a servers list:

Server1
Server2

Then copy the script and name it AD_Backup.ps1:

Param(
  [string]$ServerList,
  [String]$BackupPath = "D:\"
      )

Function Adbackup($BackupPath){
      
    Import-Module servermanager
    #Check if Windows feature is installed- if not attempts to install Windows backup and tools features
    $OSVer = ($PSVersionTable.PSVersion).Major
    Write-host $OSVer
    If ($OSVer -eq 4){
        $FeatureStatus=(Get-WindowsFeature Windows-Server-Backup).Installed
        If($FeatureStatus -eq $False){
            Add-windowsfeature Windows-Server-Backup -OutVariable results
            #Confirm sucessful feature installation
            foreach($result in $results){
                If($result.success){Write-Host "Windows Backup and tools installed successfully on $env:Computername" -ForegroundColor "Green" }
                Else{ Write-Host "Windows Backup and tools installation failed on $env:Computername" -ForegroundColor "Red"}
            }
        }
    }Else{
        $FeatureStatus=(Get-WindowsFeature backup).Installed
        If($FeatureStatus -eq $False){
            Add-windowsfeature backup -OutVariable results
            Add-WindowsFeature backup-tools
            #Confirm sucessful feature installation
            foreach($result in $results){
                If($result.success){Write-Host "Windows Backup and tools installed successfully on $env:Computername" -ForegroundColor "Green" }
                Else{ Write-Host "Windows Backup and tools installation failed on $env:Computername" -ForegroundColor "Red"}
            }
        }
    }
    #Add powershell Windows Backup snap in into PowerShell environment 
    add-pssnapin windows.serverbackup -ea silentlycontinue
    
    #Create a new policy backup 
    $policy = New-WBPolicy 
    #Add system state into the policy 
    #Add-WBSystemState -Policy $policy 
    Add-WBBareMetalRecovery -Policy $policy
    #Declare backup location based on folder name 
    #$backupLocation = New-WBBackupTarget -network $BackupPath -credential $cred  
    $backupLocation = New-WBBackupTarget -VolumePath $BackupPath
    #Add backup location into the policy 
    Add-WBBackupTarget -Policy $policy -Target $backupLocation -force
    
    #Start the Backup
    Start-WBBackup -Policy $policy
}

Start-Transcript -path "D:\Scripts\AD_Backup\WorkingFolder\BackupTranscript$ServerList.txt"

#Check ServerList Path
If (!(Test-Path D:\Scripts\AD_Backup\DCs_$ServerList.txt)){
        Write-Error "$ServerList do not exist"
        Exit
}

Write-Host "Creating Backup Jobs..."
$jobs = invoke-command -ComputerName (Get-Content D:\Scripts\AD_Backup\DCs_$ServerList.txt) -ScriptBlock ${Function:Adbackup} -ArgumentList $BackupPath -AsJob -JobName AD_Backup


#Check Running Jobs
Write-Host "Waiting Jobs..."
$done = Wait-Job -Name AD_Backup -Timeout 10800
Get-Job -Name AD_Backup -IncludeChildJob
if ($done -ne $null){
    
} Else {
    Write-Host "Stopping running Jobs..."
    Stop-Job -Name AD_Backup
}

Write-Host
Write-Host "Jobs Logs:"
Get-Content D:\Scripts\AD_Backup\DCs_$ServerList.txt | Foreach-Object {
    Write-Host "--- Log for $_"
    Get-Job -Name AD_Backup | Receive-Job -Keep -ComputerName $_
    Write-Host
}

#Remove Jobs
Get-Job –Name AD_Backup | Remove-Job

Stop-Transcript

Now you can run/schedule the script:

./AD_Backup.ps1 -ServerList EMEA -BackupPath D:\

The script will connect to Server1 and Server2 running windows backup with BareMetalRecovery option and saving the backup file respectively on Server1 and Server2 on drive D:\

Remember to adjust the path you find on lines 52,55,76 of script according of your preference.


I also changed a bit the script that collect every backup logs stored on “D:\scripts\AD_Backup\WorkingFolder\” publishing it on sharepoint:

#mail settings
$from = "backup@myad.test"
$to = "me@myad.test"
$emailsubject = "Backup Status - myad.test"
$mailbody = ""

function Publish-File {
	param (
		[parameter( Mandatory = $true, HelpMessage="URL pointing to a SharePoint document library (omit the '/forms/default.aspx' portion)." )]
		[System.Uri]$Url,
		[parameter( Mandatory = $true, ValueFromPipeline = $true, HelpMessage="One or more files to publish. Use 'dir' to produce correct object type." )]
		[System.IO.FileInfo[]]$FileName,
		[system.Management.Automation.PSCredential]$Credential
	)
	$wc = new-object System.Net.WebClient
	if ( $Credential ) { $wc.Credentials = $Credential }
	else { $wc.UseDefaultCredentials = $true }
	$FileName | ForEach-Object {
		$DestUrl = "{0}{1}{2}" -f $Url.ToString().TrimEnd("/"), "/", $_.Name
		Write-Verbose "$( get-date -f s ): Uploading file: $_"
		$wc.UploadFile( $DestUrl , "PUT", $_.FullName )
		Write-Verbose "$( get-date -f s ): Upload completed"
	}
	
}
$Header = @"
<style>
BODY {background-color:white;}
TABLE {border-width: 1px;border-style: solid;border-color: black;border-collapse: collapse;}
TH {border-width: 1px;padding: 3px;border-style: solid;border-color: black;background-color: #6495ED;}
TD {border-width: 1px;padding: 3px;border-style: solid;border-color: black;}
TR:Nth-Child(Even) {Background-Color: #dddddd;}
TR:Hover TD {Background-Color: #C1D5F8;}
</style>
"@

$dateRun = get-date
$dateRunShort = get-date -uformat "%Y%m%d"

#Check ServerList Path
If (!(Test-Path D:\Scripts\AD_Backup\DCs_*)){
        Write-Error "No Servers List found"
        Exit
}

#list of servers to query
$servers = (Get-Content D:\Scripts\AD_Backup\DCs_*)
 
$report = @()

#query the servers in the list
foreach ($server in $servers){
    #$mailbody += $server + ":"
    #$mailbody += invoke-command -computername $server -scriptblock {add-pssnapin windows.serverbackup; get-wbsummary | out-string}
    
    $props=@{
        ComputerName=$server
        LastBackupTime=$null
        LastBackupResultDetailedHR=$null
        IsAlive=$false
    }

    if($result=Invoke-Command -computername $server -ScriptBlock {add-pssnapin windows.serverbackup; get-wbsummary} -Ea 0){
        $props.LastBackupTime=$result.LastBackupTime
        $props.LastBackupResultDetailedHR=$result.LastBackupResultDetailedHR
        $props.IsAlive=$true
    }
    $report += New-Object PsObject -Property $props
}

#send the email
#Send-MailMessage -From $from -To $to -Subject $emailsubject -SmtpServer "smtp.myad.test" -Body $report

#History
$report | Out-File "D:\scripts\AD_Backup\WorkingFolder\AD_Backup-$dateRunShort.txt"

#Sharepoint publication
$b = $report | Sort-Object ComputerName
$outfileData = $b | ConvertTo-HTML -fragment

$FileLog = Get-Content D:\scripts\AD_Backup\WorkingFolder\BackupTranscript*.txt
$outfileLog = $FileLog | out-string 

$outfile = ConvertTo-HTML -head $Header -body "<H2>$emailsubject</H2><P>This page was generated by a Script at $dateRun</P><P>$outfileData</P><H2>Backup Log</H2><PRE><CODE>$outfileLog</CODE></PRE>" -PreContent " " -PostContent " "
$outfile | Out-File D:\scripts\AD_Backup\WorkingFolder\Prod_Environment_Backup.html
Dir D:\scripts\AD_Backup\WorkingFolder\Prod_Environment_Backup.html | Publish-File -Url "https://teams01.myad.test/test/000001/AD Wiki/Pages/"

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s