This script will check for GPO's modified in the last day and then only export the data if changes have been made.  This will keep the number of backups and files down to the minimun needed.
This script will create GPO Reports to track changes and backup the GPO's so you can easily locate changes that have been made and recover.
Below is a list of the files created from this script:
    <Year>-<Month>-<Date>-<Hour>-<Minuite>-<Domain>.zip              - This contains a backup of all your GPO's the folder is create with the name for each GPO for easy Recovery or viewing
    <Year>-<Month>-<Date>-<Hour>-<Minuite>-<Domain>-GPOChanges.csv   - This file contains the Changed GPO Information like Name, ID, Owner, Domain, Creation Time, & Modified Time.
    <Year>-<Month>-<Date>-<Hour>-<Minuite>-<Domain>-GPOList.csv      - This file contains GPO Information like Name, ID, Owner, Domain, Creation Time, & Modified Time.
    <Year>-<Month>-<Date>-<Hour>-<Minuite>-<Domain>-GPOReport.csv    - This file Contains GPO Information like Name, Links, Revision Number, & Security Filtering
    <Year>-<Month>-<Date>-<Hour>-<Minuite>-<Domain>-GPOReport.xml    - This a backup of all the GPO's in a single file incase you need to look for a setting and do not know which GPO it is on.
    <Year>-<Month>-<Date>-<Hour>-<Minuite>-<Domain>-UnlinkedGPOReport.csv    - This file Contains GPO Information like Name, ID, Status, Creation Time, & Modified Time
This script was based off of one from Microsoft to backup GPO's by name, I have added more as the need and to make things simplier when backup up GPO's
Revision History
    2017-08-18 - Initial Release
    2017-08-18 - Added and change/notes for drive mapping incase user was mapping to the full path of the folder
    2017-08-18 - Added Changed GPO Report and eMail Notification for GPO's that changed
    2017-08-25 - Added Unlinked GPO Report

Thanks for others on here that I have pulled parts from to make a more comprehensive script

This script is for backups.  To restore you can do the following steps
  1. Extract the zip file to a location for use
  2. open GPMC
  3. Right Click Group Policy Objects
  4. Select Manage Backups
  5. Change Folder to the extracted zip file location and select the folder for the GPO you wish to restore, with the browse button
  6. Select on the GPO and click restore  
PowerShell
Edit|Remove
<# 
Name: GPOBackup.ps1 
 
This script will check for GPO's modified in the last day and then only export the data if changes have been made.  This will keep the number of backups and files down to the minimun needed. 
 
This script will create GPO Reports to track changes and backup the GPO's so you can easily locate changes that have been made and recover. 
Below is a list of the files created from this script: 
    <Year>-<Month>-<Date>-<Hour>-<Minuite>-<Domain>.zip                      - This contains a backup of all your GPO's the folder is create with the name for each GPO for easy Recovery or viewing 
    <Year>-<Month>-<Date>-<Hour>-<Minuite>-<Domain>-GPOChanges.csv           - This file contains the Changed GPO Information like Name, ID, Owner, Domain, Creation Time, & Modified Time. 
    <Year>-<Month>-<Date>-<Hour>-<Minuite>-<Domain>-GPOList.csv              - This file contains GPO Information like Name, ID, Owner, Domain, Creation Time, & Modified Time. 
    <Year>-<Month>-<Date>-<Hour>-<Minuite>-<Domain>-GPOReport.csv            - This file Contains GPO Information like Name, Links, Revision Number, & Security Filtering 
    <Year>-<Month>-<Date>-<Hour>-<Minuite>-<Domain>-GPOReport.xml            - This a backup of all the GPO's in a single file incase you need to look for a setting and do not know which GPO it is on. 
    <Year>-<Month>-<Date>-<Hour>-<Minuite>-<Domain>-UnlinkedGPOReport.csv    - This file Contains GPO Information like Name, ID, Status, Creation Time, & Modified Time 
 
 
This script was based off of one from Microsoft to backup GPO's by name, I have added more as the need and to make things simplier when backup up GPO's 
 
Michael Patterson 
scripts@mwpatterson.com 
 
Revision History 
    2017-08-18 - Initial Release 
    2017-08-18 - Added and change/notes for drive mapping incase user was mapping to the full path of the folder 
    2017-08-18 - Added Changed GPO Report and eMail Notification for GPO's that changed 
    2017-08-25 - Added Unlinked GPO Report 
    2017-08-31 - Changed Location for Variables to start of Script, Code Cleanup & Formatting 
    2017-12-08 - Added moving to sub folder for yearto keep clutter down, could take it down to mmonth as well by changing $year from "yyyy" to "yyyy-MM" 
    2017-12-27 - Cleanup 
    2018-01-31 - Added check to not send emails 
 
Thanks for others on here that I have pulled parts from to make a more comprehensive script 
 
This script is for backups.  To restore you can do the following steps 
    Extract the zip file to a location for use 
    Open GPMC 
    Right Click Group Policy Objects 
    Select Manage Backups 
    Change Folder to the extracted zip file location and select the folder for the GPO you wish to restore, with the browse button 
    Select on the GPO and click restore   
 
#> 
#Clear Screen 
Clear-Host 
 
#Send Email 
#$sendEmail = "Yes" 
$sendEmail = "No" 
 
 
#Move GPOBackup off of System 
#$moveBackups = "Yes" 
$moveBackups = "No" 
 
#Set Share Location - Used for Direct Share Access 
$useShare = "Yes" 
$year = get-date -Format "yyyy" 
$shareLocation = "\\Server.local\Share\Folder\GPO" 
$shareLocation = $shareLocation + "\" + $year 
 
#Set Network Location - Used when Mapping a Drive 
#$useShare = "No" 
$year = get-date -Format "yyyy" 
#$networkDrive = "\\Server.local\Share\Folder" 
$networkDrive = "\\Server.local\Share\Folder\GPO" 
$networkDrive = $networkDrive + "\" + $year 
 
#Set Drive Letter - Used when Mapping a Drive 
$driveLetter = "Z" 
 
#Set Folder Location - Used when Mapping a Drive - Needed if not directly mapping directly to full path 
$folderLocation = "GPO" 
 
#Combine Network Drive and Folder Location - Used when Mapping a Drive 
if ($useShare -eq "No") { 
    $shareLocation = $driveLetter +":\" +$folderLocation #Used if not directly mapping directly to full path 
    #$shareLocation = $driveLetter +":\" #Used if directly mapping directly to path 
} 
 
#Get Account to copy with - Used when Mapping a Drive 
if ($useShare -eq "No") { 
    $user = Read-Host "Enter User Name" -AsString 
    $pwd = Read-Host "Enter Password" -AsSecureString 
    $mycreds = New-Object System.Management.Automation.PSCredential ($User$Pwd) 
} 
 
#Set Domain 
#$domain = $env:USERDNSDOMAIN #Full Domain Name 
#$domain = $env:USERDOMAIN #Short Domain Name 
 
#Get Date & Backup Locations 
$date = get-date -Format "yyyy-MM-dd-HH-mm" 
$backupRoot = "C:\" #Can use another drive if available 
$backupFolder = "GPOBackupByName\" 
$backupFolderPath = $backupRoot + $backupFolder 
#$backupFileName = $date + "-" + $domain  
$backupFileName = $date + "-" + $env:USERDNSDOMAIN #Full Domain Name  
#$backupFileName = $date + "-" + $env:USERDOMAIN #Short Domain Name 
#$backupPath = $backupRoot + $backupFolder + $date + "-" + $domain 
$backupPath = $backupFolderPath + $backupFileName 
 
#Configure Email notification recipient 
$email1 = "user1@test.local" 
#$email2 = "user2@test.local" 
 
#Email Function 
#function send_email ($exportPath, $email)  
function send_email ()  
{ 
    $today = Get-Date 
    $today = $today.ToString("dddd MMMM-dd-yyyy hh:mm tt") 
    $SmtpClient = new-object system.net.mail.smtpClient  
    $mailmessage = New-Object system.net.mail.mailmessage  
    #$SmtpClient.Host = "outlook.office365.com" 
    #$SmtpClient.Port = "587" 
    #$SmtpClient.EnableSsl = "True" 
    #$SmtpClient.Credentials = New-Object System.Net.NetworkCredential("User", "Password");  
    $SmtpClient.Host = "<SMTP Relay Server>" 
    $SmtpClient.Port = "25" 
    $mailmessage.from = "Sender <sender@test.local>"  
    $mailmessage.To.add($email1) 
    #$mailmessage.To.add($email2) 
    $mailmessage.Subject = "PLEASE READ: GPO's have been changed." 
    $mailmessage.IsBodyHtml = $true 
    #$mailmessage.Attachments.Add($emailFile) 
    $mailmessage.Attachments.Add($backupFolderPath +$backupFileName +"-GPOChanges.csv") 
    $mailmessage.Body = @" 
<!--<strong>GPO's have been Changed in $domain</strong><br />--> 
GPO's have been changed in <span style="background-color:yellow;color:black;"><strong>$domain</strong></span>.<br /> <br /> 
 
Generated on : $today<br /><br /> 
<br /></font></h5> 
"@ 
 
 $smtpclient.Send($mailmessage)  
} 
 
#Check if GPO Changes in last Day, Exit if no changes made in last day 
$modifiedGPOs  = @(Get-GPO -All | Where-Object {$_.ModificationTime -ge $(Get-Date).AddDays(-1)}).count 
If ($modifiedGPOs -eq "0") { 
    Write-Host "No Changes in last Day" 
    Exit   #Exit if no changes made in last day 
} 
 
#Verify GPO BackupFolder 
if ((Test-Path $backupFolderPath-eq $false) { 
    New-Item -Path $backupFolderPath -ItemType directory 
} 
 
#Generate Email List of changes 
Write-Output "Please Wait - Creating GPO Email Report" 
#Get-GPO -All | Where-Object {$_.ModificationTime -ge $(Get-Date).AddDays(-1)} | Export-csv $backupFolderPath$backupFileName-GPOChanges.csv -NoTypeInformation 
Get-GPO -All | Where-Object {$_.ModificationTime -ge $(Get-Date).AddDays(-1)} | Export-csv $backupPath-GPOChanges.csv -NoTypeInformation 
#$emailFile = $backupFolderPath +$backupFileName +"-GPOChanges.csv" 
 
#Send email Notification 
if ($moveBackups -eq "Yes") { 
    Write-Output "Please Wait - Sending Email Report" 
    send_email 
} 
 
#Export GPO List 
#Write-Host "Creating GPO List" 
Write-Output "Please Wait - Creating GPO List" 
#Get-GPO -All | Export-csv $backupFolderPath$backupFileName-GPOList.csv -NoTypeInformation 
Get-GPO -All | Export-csv $backupPath-GPOList.csv -NoTypeInformation 
 
#Export GPO Report 
#Write-Host "Creating GPO Report" 
Write-Output "Please Wait - Creating GPO Report" 
#Get-GPOReport -All -ReportType xml -Path $backupFolderPath$backupFileName-GPOReport.xml 
Get-GPOReport -All -ReportType xml -Path $backupPath-GPOReport.xml 
 
#Export GPO Properties Report 
#Write-Host "Creating GPO Properties Report" 
Write-Output "Please Wait - Creating GPO Properties Report" 
#param( 
#    [parameter(Mandatory = $False )][array]$GPOList, 
#        [parameter(Mandatory = $False )][switch]$All 
#    ) 
 
$GPOList = (Get-Gpo -All).DisplayName 
$colGPOLinks = @() 
foreach ($GPOItem in $GPOList){ 
    [xml]$gpocontent =     Get-GPOReport $GPOItem -ReportType xml 
    $LinksPaths = $gpocontent.GPO.LinksTo | Where-Object{$_.Enabled -eq $True| ForEach-Object{$_.SOMPath} 
    $Wmi = Get-GPO $GPOItem | Select-Object WmiFilter 
    $CreatedTime = $gpocontent.GPO.CreatedTime 
    $ModifiedTime = $gpocontent.GPO.ModifiedTime 
    $CompVerDir = $gpocontent.GPO.Computer.VersionDirectory 
    $CompVerSys = $gpocontent.GPO.Computer.VersionSysvol 
    $CompEnabled = $gpocontent.GPO.Computer.Enabled 
    $UserVerDir = $gpocontent.GPO.User.VersionDirectory 
    $UserVerSys = $gpocontent.GPO.User.VersionSysvol 
    $UserEnabled = $gpocontent.GPO.User.Enabled 
    $SecurityFilter = ((Get-GPPermissions -Name $GPOItem -All | Where-Object{$_.Permission -eq "GpoApply"}).Trustee | Where-Object{$_.SidType -ne "Unknown"}).name -Join ',' 
    foreach ($LinksPath in $LinksPaths){ 
        $objGPOLinks = New-Object System.Object 
        $objGPOLinks | Add-Member -type noteproperty -name GPOName -value $GPOItem 
        $objGPOLinks | Add-Member -type noteproperty -name LinksPath -value $LinksPath 
        $objGPOLinks | Add-Member -type noteproperty -name WmiFilter -value ($wmi.WmiFilter).Name 
        $objGPOLinks | Add-Member -type noteproperty -name CreatedTime -value $CreatedTime 
        $objGPOLinks | Add-Member -type noteproperty -name ModifiedTime -value $ModifiedTime 
        $objGPOLinks | Add-Member -type noteproperty -name ComputerRevisionsAD -value $CompVerDir 
        $objGPOLinks | Add-Member -type noteproperty -name ComputerRevisionsSYSVOL -value $CompVerSys 
        $objGPOLinks | Add-Member -type noteproperty -name UserRevisionsAD -value $UserVerDir 
        $objGPOLinks | Add-Member -type noteproperty -name UserRevisionsSYSVOL -value $UserVerSys 
        $objGPOLinks | Add-Member -type noteproperty -name ComputerSettingsEnabled -value $CompEnabled 
        $objGPOLinks | Add-Member -type noteproperty -name UserSettingsEnabled -value $UserEnabled 
        $objGPOLinks | Add-Member -type noteproperty -name SecurityFilter -value $SecurityFilter 
        $colGPOLinks +$objGPOLinks 
    } 
} 
#$colGPOLinks | sort-object GPOName, LinksPath | Export-Csv -Delimiter ',' -Path $backupFolderPath$backupFileName-GPOReport.csv -NoTypeInformation 
$colGPOLinks | sort-object GPOName, LinksPath | Export-Csv -Delimiter ',' -Path $backupPath-GPOReport.csv -NoTypeInformation 
 
#Export Unlinke GPO Report 
#Write-Host "Creating Unlinked GPO Properties Report" 
Write-Output "Please Wait - Creating Unlinked GPO Properties Report" 
function IsNotLinked($xmldata){ 
    If ($xmldata.GPO.LinksTo -eq $null) { 
        Return $true 
    } 
    Return $false 
} 
$unlinkedGPOs = @() 
Get-GPO -All | ForEach-Object { $gpo = $_ ; $_ | Get-GPOReport -ReportType xml | ForEach-Object { If(IsNotLinked([xml]$_)){$unlinkedGPOs +$gpo} }} 
If ($unlinkedGPOs.Count -eq 0) { 
    "No Unlinked GPO's Found" 
} 
Else{ 
    #$unlinkedGPOs | Sort-Object GpoStatus,DisplayName | Select-Object DisplayName,ID,GpoStatus,CreationTime,ModificationTime | Export-Csv -Delimiter ',' -Path $backupFolderPath$backupFileName-UnlinkedGPOReport.csv -NoTypeInformation 
    $unlinkedGPOs | Sort-Object GpoStatus,DisplayName | Select-Object DisplayName,ID,GpoStatus,CreationTime,ModificationTime | Export-Csv -Delimiter ',' -Path $backupPath-UnlinkedGPOReport.csv -NoTypeInformation 
} 
 
#Verify GPO BackupPath 
if ((Test-Path $backupPath-eq $false) { 
    New-Item -Path $backupPath -ItemType directory 
} 
 
#backup GPOs into named folders 
$allGPOs =get-gpo -all 
foreach ($gpo in $allGPOs) { 
 $foldernamejoin-path $backupPath ($gpo.displayname.Replace(" ","_"+ "_{" +$gpo.Id + "}") 
    if ((Test-Path $foldername-eq $false) { 
        New-Item -Path $foldername -ItemType directory 
    } 
    Backup-GPO -Name $gpo.displayname -Path $foldername 
} 
 
#Compress Folders 
Write-Output "Please Wait - Creating ZIP File" 
#PowerShell 5.0 
#Compress-Archive -Path $backupPath -DestinationPath $backupPath+".zip" 
#PowerShell 2.0-4.x 
$source = $backupPath 
$destination = $backupPath+".zip" 
 If(Test-path $destination) { 
    Remove-item $destination 
} 
Add-Type -assembly "system.io.compression.filesystem" 
[io.compression.zipfile]::CreateFromDirectory($Source$destination) 
 
#Delete GPO Backup Folder 
Write-Output "Please Wait - Deleting GPO Backup Folder" 
Remove-item -Path $backupPath -Recurse -Force -ErrorAction SilentlyContinue 
 
#Complete if not moving off of System 
if ($moveBackups -eq "No") { 
    Write-Output "GPO Backup - Complete" 
    Exit 
} 
 
#Map Network Drive 
if ($useShare -eq "No") { 
    #Net Use $driveLetter $networkDrive /User:$user $pwd 
    New-PSDrive -Name $driveLetter -PSProvider FileSystem -Root $networkDrive -Credential $mycreds 
} 
 
#Move GPO Backups to Network Folder 
Write-Output "Please Wait - Moving GPO Backup Files to Network Backup Folder" 
#Get-ChildItem "C:\GPOBackupByName" -Recurse | Move-Item -Destination $shareLocation 
Get-ChildItem $backupFolderPath -Recurse | Move-Item -Destination $shareLocation 
Write-Output "Please Wait - Completed Moving GPO Backup Files to Network Backup Folder" 
 
#Disconnect Network Drive 
#if ($useShare -eq "No") { 
#    Net Use $driveLetter /D 
#} 
 
#Completed Script 
Write-Output "GPO Backup - Complete"