Scripts/Search-GPO.ps1

function Search-GPO {

    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [string]$SearchString,

        [string]$CachePath =
            "$env:ProgramData\GPOCache",

        [switch]$RebuildCache
    )

    $RequiredCacheVersion = 1

    $CacheFile =
        Join-Path $CachePath "cache.json"

    $IndexFile =
        Join-Path $CachePath "SearchIndex.json"

    #
    # Validation
    #
    $BuildNeeded = $false

    if (!(Test-Path $CacheFile)) {
        $BuildNeeded = $true
    }

    if (!(Test-Path $IndexFile)) {
        $BuildNeeded = $true
    }

    if (!$BuildNeeded) {

        try {

            $Cache =
                Get-Content `
                    $CacheFile `
                    -Raw |
                ConvertFrom-Json

            if (
                $Cache.CacheVersion -ne
                $RequiredCacheVersion
            ) {
                $BuildNeeded = $true
            }

            if (
                !(Test-Path $IndexFile)
            ) {
                $BuildNeeded = $true
            }
        }
        catch {

            $BuildNeeded = $true
        }
    }

    if (
        $BuildNeeded -or
        $RebuildCache
    ) {

        Write-Host `
            "Creating cache..." `
            -ForegroundColor Yellow

        New-GPOCache `
            -CachePath $CachePath
    }

    if ($BuildNeeded) {

        Write-Host `
            "Creating cache..." `

        New-GPOCache `
            -CachePath $CachePath
    }
    elseif ($RebuildCache) {

        Write-Host `
            "Updating cache..." `

        Update-GPOCache `
            -CachePath $CachePath
    }

        $MaxCacheAgeDays = 7

    $Age =
        ((Get-Date) -
        [datetime]$Cache.CreatedDate).TotalDays

    if ($Age -ge $MaxCacheAgeDays) {

        Update-GPOCache `
            -CachePath $CachePath
    }

    #
    # Load index
    #
    try {

        $Index =
            Get-Content `
                $IndexFile `
                -Raw |
            ConvertFrom-Json

    }
    catch {

        throw "SearchIndex.json is corrupt."
    }

    #
    # Search
    #
    $Matches =
        $Index |
        Where-Object {

            $_.Value -like
            "*$SearchString*"
        }

    #
    # Group by GPO
    #
    $Results =
        $Matches |
        Group-Object Guid |
        ForEach-Object {

            $First =
                $_.Group[0]

            $UniqueMatches = @(
                $_.Group |
                Sort-Object `
                    MatchType,
                    Value `
                    -Unique
            )

            [PSCustomObject]@{
                DisplayName =
                    $First.DisplayName

                Guid =
                    $First.Guid

                MatchCount =
                    $UniqueMatches.Count

                Matches = @(
                    $UniqueMatches |
                    Select-Object `
                        -First 20 |
                    ForEach-Object {

                        "$($_.MatchType): $($_.Value)"
                    }
                ) -join "`r`n"
            }
        }

    $Results |
        Sort-Object DisplayName

}