Sunday, June 10, 2012

PowerShell Script to Backup and Delete List of GPO's (with Restore Script)

One of my first tasks in cleaning up the previously referenced group policy infrastructure, was to delete all of the unused Group Policy Objects. There were a lot, so a script was definitely in order. Fortunately, PowerShell has a native cmdlet (via the Group Policy Module), delete-gpo, that can delete group policy objects. I could very easily whip up a script to loop through a file and delete policies, but when we're talking about scripts and production environments, safety always comes first. It would be irresponsible to simply delete all of the policies, without a plan to quickly recover if something went wrong. Again, PowerShell makes it easy by having native cmdlets backup-gpo and restore-gpo.

So to be safe and prepared called for two scripts: one to backup and delete the GPOs, and one to restore them if necessary. Since it best to use a Backup ID to restore a GPO, the logging in the first script gives us both the Backup ID and the GUID. To make restoring as quickly and easy as possible, the scripts are configured so that the log from the backup/delete script can simply be passed to the restore script, and it will restore everything in the log file.

One thing that is important to point out is that restoring a GPO does not restore its links. In my case, I was only deleting unlinked GPO's, so this was not an issue. However, if any GPO's were linked before being deleted, they will need to be re-linked in order to take effect.

Script #1: Delete-GPOList.ps1


# Usage: Delete-GPOList -file <path to file> -path <path for backups>
# Creates Two Log Files:
# Success Log: Delete-GPOList_<date>.log
# Error Log: Delete-GPOList_Errors_<date>.log


Param(
[parameter(Mandatory=$true)] [string] $path,
[parameter(Mandatory=$true)] [string] $file



import-module grouppolicy


#-----------------------------------------------
# Functions
#-----------------------------------------------


#Backs up a GPO and then deletes it
function BackupDelete-GPO
{
param($GPOGUID, $BackupPath)

#clears any errors
$error.clear()


#Backup policy and check for errors
write-host Backing Up:`t $GPOGUID
$GPObackup = backup-gpo -guid $GPOGUID -path $BackupPath
if ($error) { return "Backup Error" }
write-host `t Backup Completed! Backup ID: $GPOBackup.Id.ToString()


#Delete policy and check for errors
write-host Deleting:`t $GPOGUID
remove-gpo -guid $GPOGUID
if ($error) { return "Delete Error" }
write-host `t Deletion Successful
return $GPOBackup.Id.ToString()
}




#-----------------------------------------------
# Test Backup and File Path
#-----------------------------------------------
if (!(test-path $path)) { 
write-warning "Backup Path Invalid: $Path"
break
}
if (!(test-path $file)) { 
write-warning "File Not Found: $File"
break
}


#-----------------------------------------------
# Creates Log File
#-----------------------------------------------


$date = (get-date).ToString('yyyy-MM-dd')
$logfile = "Delete-GPOList_$date.log"
$errorlog = "Delete-GPOList_Errors_$date.log"


#-----------------------------------------------
# Parses file and and backs up deletes GPO's
#-----------------------------------------------
Get-Content $file | foreach {
$GPOGUID = $_
$Delete = BackupDelete-GPO $GPOGUID $path
if ($Delete -eq "Backup Error") {
"Backup Error: $GPOGUID" >> $errorlog
} elseif ($Delete -eq "Delete Error") {
"Delete Error: $GPOGUID" >> $errorlog
} else {
"$GPOGUID;$Delete" >> $logfile
}
}



Script #2: Restore-GPOList.ps1

# Usage: Restore-GPOList -file <GPO-Delete Log> -path <Backup Path>


Param(
[parameter(Mandatory=$true)] [string] $path,
[parameter(Mandatory=$true)] [string] $file



import-module grouppolicy


Get-Content $File | foreach {
$GPOGUID = ($_ -split ";")[0]
$BackupID = ($_ -split ";")[1]

$error.clear()
write-host Restoring: $GPOGUID
restore-gpo -BackupId $BackupID -path $Path

if ($error) {
write-warning Error Restoring:
write-warning `t GPO GUID:`t $GPOGUID
write-warning `t Backup ID:`t $BackupID
} else {
write-host `tComplete!
}
}

2 comments:

  1. Thanks for your script !
    It works very well ! :)

    ReplyDelete
  2. hey,

    just wondering what format the guid list needs to be in?

    ReplyDelete