PowerShell: GPO Report & Backup Scripts

PowerShell: GPO Report & Backup Scripts

Regularly I'm faced with the need to document Group Policies in place on a domain. Luckily, Microsoft makes it pretty easy to do this using PowerShell as shown below.

Generate a Single Report of All Domain GPO's

PS> Get-GPOReport -All -Domain $Domain -ReportType HTML -Path $Directory

While the Get-GPOReport cmdlet with the -All switch, works well, opening the report it creates can be problematic. Because the browser needs to load the entire report containing every GPO setting in the domain in to memory before it can be viewed, you may find yourself waiting... and waiting for the report to render, only to have IE crash.

To work around this problem the script below will create a dated directory in My Documents, then generate a single HTML based report for each GPO located within the specified domain.

Generate a separate report for each GPO in a Domain

# Create individual report for each GPO in a domain.

$Today = Get-Date -UFormat "%Y%m%d"
$Profile = $env:USERPROFILE
$Directory = $Profile + "\Documents\GPOReports_" + $Today
$Domain = Write-Host "FQDN"

if (Test-Path -Path $Directory)
{
    Write-Host -ForegroundColor Red "Directory Exists. Existing reports in the directory may be overwritten if GPO's have the same name."
}
else
{
    Write-Host "Directory Not Found"
    New-Item -ItemType Directory -Path $Directory
}

Import-Module GroupPolicy

$GPOList = Get-GPO -All -Domain $Domain
ForEach ($Id in $GPOList)
{
    $GUID = $Id.Id
    $DisplayName = $Id.DisplayName
    Get-GPOReport -GUID $GUID -ReportType HTML -Path $Directory\$DisplayName.html
}

As you can see, the script above isn't very complicated. If you skip down to the secton after Import-Module GroupPolicy, we're quering for a list of GPO's then saving that to a PowerShell object.

Next, we loop through the new GPOList object, and run the Get-GPOReport cmdlet, for each of the GPO's in the GPOList object we created. All the rest is really just window dressing.

Cmdlet to Backup All GPO's

Backup-GPO -All -Domain "domain.com" -Path "\\server\share"



Function to Generate an HTML Report of each Domain GPO, and optionally, Backup each GPO at the same time.

Expanding on this a little further, I decided there are times when I might want to also backup each GPO at the same time the report is generated.
The script below, generates a single report for each GPO in a domain, then immediately creates a backup of each GPO. The script can be scheduled to run daily. Each day it will generate a new directory for reports and backups using the days date in a YYYYMMDD format.

Function fn-GPOSave
{
<#
.Synopsis
Function used to backup and generate HTML based reports of each GPO in a domain.
.Description
The primary intent of this to create an individual report of all GPO's in the domain to be used 
for a variety of documentation purposes. The function was created because generating a single
report containing all GPO objects in a large domain environment, would result in issues being
able to open and view the report.

As an added benefit, the script will optionally backup each GPO after generating a report. This
ensures your GPO's are both documented and protected.

The reports & backup files are stored in a directory, created by the script if it yet exists.
Any contents of the directory will be overwritten when the script runs, so only one report/backup
can be created per Path per day. The date is appended to the "Reports_", and "Backup_" directories.
  BP140031201
CREATED BY: England, Matthew (http://pmibluepapers.blogspot.com/2014/03/BP14031201.html)

.Example
fn-GPOSave -Domain "myaddomain.com" -Path "\\fileshare.myaddomain.com\share" -BackupDesired $True
This example will generate an HTML report of each GPO and save it to 
"\\fileshare.myaddomina.com\share\GPOReports_$Today\". It will then create a backup of each GPO saving it to
the same share in a directory called GPOBackups_$Today\, where $Today represents todays date.
.Parameter Domain
This parameter is required and is positional. (Position 1)
The fully qualified domain name for the domain containing the desired GPO's should be entered, as in the examples.
.Parameter Path
This parameter is optional, and is positional. (Position 2)
If no path is specified, the default value of "My Documents" is used, for the user running the script.
.Parameter BackupDesired
This parameter is optional, and is positional. (Position 3)
This is a Bool value. You can enter $TRUE or 1, if you desire backups.
If you only want to generate HTML reports, supply a value of $FALSE or 0.
If no option is specified, then no backups are run, and only reports will be generated.
#>

    [CmdletBinding()]
    Param(
        [Parameter(Mandatory=$True,Position=1)]
        [string]$Domain,
        [Parameter(Mandatory=$False,Position=2)]
        [string]$Path = $env:USERPROFILE+"\Documents",
        [Parameter(Mandatory=$False,Position=3)]
        [bool]$BackupDesired = $False
    )


$Today = Get-Date -UFormat "%Y%m%d"
$ReportPath = $Path + "\GPOReports_" + $Today


if (Test-Path -Path $ReportPath)
{
    Write-Host -ForegroundColor Red "Directory Exists. Existing reports in the directory may be overwritten if GPO's have the same name."
}
else
{
    Write-Host "Directory Not Found"
    New-Item -ItemType Directory -Path $ReportPath
}

Import-Module GroupPolicy

$GPOList = Get-GPO -All -Domain $Domain
ForEach ($Id in $GPOList)
{
    $GUID = $Id.Id
    $DisplayName = $Id.DisplayName
    Get-GPOReport -GUID $GUID -ReportType HTML -Path $ReportPath\$DisplayName.html

}

##### GPO BACKUP SECTION

if ($BackupDesired)
{
    $BackupPath = $Path + "\GPOBackups_" + $Today
    if (Test-Path -Path $BackupPath)
    {
        Write-Host -ForegroundColor Red "Directory Exists. Existing reports in the directory may be overwritten if GPO's have the same name."
    }
    else
    {
        Write-Host "Directory Not Found"
        New-Item -ItemType Directory -Path $BackupPath
    }

    ForEach ($Id in $GPOList)
    {
        $GUID = $Id.Id
        Backup-GPO -GUID $GUID -Path $BackupPath
    }
}
}


After Thoughts

As I mentioned, my original goal here was simply to document, the GPO's, using the GPO-Report cmdlet. Because adding backup came later, it's not ideal, but still it gets the job done.
Once I was finished writing this script, I immediately began to think of how it could be improved by ensuring the Backup & Report names are easily associated with each other. As I learn more, I may come back and update this script, or post a link to an updated version.

I'd love to hear your feedback. Perhaps I can try to incorporate some of your ideas.