Friday 3 May 2024

GPO - Searching for a string in backed up GPO files

Housekeeping abandoned

GPOs or Group Policy Objects can be unwieldy at the best of times. I walked into an organisation and was landed in the middle of a quagmire of chaos with over a thousand GPOs, some first created over 16 years ago.

There is no guessing that basic housekeeping was the furthest from the mind of the administrators of that estate, an Aegean stable of egregious compromise and mismanagement awaits, but what to do?

Get an understanding of what has been done, and work to give a form of sanity to the infrastructure with the view to an eventual cleanup and the preparation of ingesting the best parts of this setup into EntraID. It would seem like a pipedream.

Just the shock, I decided to backup all the GPOs, which took just under 7 hours. Now that I had a backup, it would be easier to search the GPReport.XML files in my backup folder for historical information than to search the live environment.

ChatGPT does the heavylifting

So, I offered ChatGPT-4 an extensive prompt of requirements to read the files, find the string, and output the result to a CSV file, but also just because the GPO might be linked to several containers, Domain level or OUs, there is a separate output file for if the GPO is linked.

I guess, manipulating an XML file can be fun to extract the information you need, but this is not about XML gymnastics, just getting useful information out of GPOs.

The Code:


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
<#	
	====================================================================================
	 Created with: 	ChatGPT-4 and PowerShell ISE
	 Created on:   	03/05/2024 00:46 AM
	 Curated by:   	Akin Akintayo
	 Filename:     	Search-StringInGPOXML.ps1

	------------------------------------------------------------------------------------

	 Purpose: This is created as a time-saving script to search through backed-up GPOs
     in a folder specified for a string and output first to a CSV file, all occurrences
     of the string and in a separate LinksTo file list all the links to the GPO

	====================================================================================
	
#>


# Define the path to the directory containing GPO backups
$BackupDirectory = "C:\Repository\GPO\GPOBackup\Backup-02-05-2024"

# Define the output path for the CSV file
$OutputPath = "C:\Repository\GPO\GPResults"

# Prompt for the search string
$searchString = Read-Host "Please enter the string to search for"

# Create a filename for the CSV based on the current date and the search string
$UniqueFile = "$(Get-Date -Format 'yy-MMM-dd-HH-mm-ss')-$($searchString -replace ' ', '')"
$csvFileName = "$($UniqueFile)-GPOReport.csv"
$csvFileFullPath = Join-Path $OutputPath $csvFileName
$LinkInfoFilename = "$($UniqueFile)-LinksTo.Log"
$LinksToFullPath = Join-Path $OutputPath $LinkInfoFilename

# Import the GroupPolicy module
Import-Module GroupPolicy

# Get all GPReport.xml files from the specified directory
$xmlFiles = Get-ChildItem -Path $BackupDirectory -Filter "GPReport.xml" -Recurse -Depth 1

# Prepare an array to hold the results
$results = @()

# Loop through each XML file to search for the specified string
foreach ($file in $xmlFiles) {
    # Load the XML content
    [xml]$xmlContent = Get-Content -Path $file.FullName

    # Check if the XML content contains the search string
    if ($xmlContent.OuterXml.Contains($searchString)) {
        # Extract GPO details
        # $gpoDetails = Get-GPO -Guid $xmlContent.GPO.Identifier -All

        # Create a custom object to hold the necessary details
        $result = [PSCustomObject]@{
            Name = $xmlContent.GPO.Name
            GUID = $xmlContent.GPO.Identifier.Identifier.'#text'
            Linked = $xmlContent.GPO.LinksTo.Enabled
            GPOFolder = $file.Directory.Name
        }

        If ($xmlContent.GPO.LinksTo.Enabled) {
            "$($xmlContent.GPO.Name) `n`n  $($xmlContent.GPO.LinksTo.SOMPath)`n`n`n`n" | Out-File -FilePath $LinksToFullPath -Append -Width 200
        }

        # Add the custom object to the results array
        $results += $result
    }
}

# Export the results to a CSV file
$results | Export-Csv -Path $csvFileFullPath -NoTypeInformation

# Output the name of the CSV file created
Write-Host "CSV file created: $csvFileFullPath"