Functions/Find-AzResourceGroup.ps1

function Find-AzResourceGroup {
    <#
    .SYNOPSIS
        Finds Azure Resource Groups across subscriptions using Azure Resource Graph.
 
    .DESCRIPTION
        This function searches for Azure Resource Groups across one or more subscriptions using Azure Resource Graph queries.
        It supports exact or partial name matching, filtering by subscription and location, and optionally including resources within the resource groups.
 
    .PARAMETER ResourceGroupName
        The name of the Resource Group to search for. Supports exact or partial matching based on the ExactMatch parameter.
 
    .PARAMETER ExactMatch
        If specified, performs an exact name match. Otherwise, performs a partial match (contains).
 
    .PARAMETER IncludeResources
        If specified, includes all resources within the matching resource groups in the results.
 
    .PARAMETER SubscriptionIds
        Optional. Array of subscription IDs to search within. If not specified, searches all accessible subscriptions.
 
    .PARAMETER Locations
        Optional. Array of Azure locations to filter by. If not specified, searches all locations.
 
    .PARAMETER ShowSubscriptionSummary
        If specified, displays a summary of results grouped by subscription.
 
    .EXAMPLE
        Find-AzResourceGroup -ResourceGroupName "myapp" -ExactMatch
 
        Finds resource groups with the exact name "myapp".
 
    .EXAMPLE
        Find-AzResourceGroup -ResourceGroupName "prod" -IncludeResources
 
        Finds all resource groups containing "prod" in their name and includes all resources within them.
 
    .EXAMPLE
        Find-AzResourceGroup -ResourceGroupName "network" -SubscriptionIds @("sub-id-1", "sub-id-2") -ShowSubscriptionSummary
 
        Finds resource groups containing "network" in the specified subscriptions and shows a summary.
 
    .INPUTS
        Input is from command line or called from a script.
 
    .OUTPUTS
        Outputs resource group information with subscription details to the pipeline.
 
    .NOTES
        Author: Lars Panzerbjørn
        Creation Date: 2026.01.29
    #>


    [CmdletBinding()]
    param(
        [Parameter(Mandatory, Position = 0)]
        [string]$ResourceGroupName,

        [Parameter()]
        [switch]$ExactMatch,

        [Parameter()]
        [switch]$IncludeResources,

        [Parameter()]
        [string[]]$SubscriptionIds,

        [Parameter()]
        [string[]]$Locations,

        [Parameter()]
        [switch]$ShowSubscriptionSummary
    )

    BEGIN{
        Write-Verbose "Starting search for resource group: $ResourceGroupName"
    }

    PROCESS{
        # Build where clause based on match type
        IF($ExactMatch) {
            $WhereClause = "name == '$ResourceGroupName'"
            Write-Verbose "Using exact match search"
        } else {
            $WhereClause = "name contains '$ResourceGroupName'"
            Write-Verbose "Using partial match search"
        }

        # Build the base query
        IF($IncludeResources) {
            $Query = @"
Resources
| where resourceGroup $($WhereClause -replace 'name','resourceGroup')
| project subscriptionId, resourceGroup, name, type, location
"@

        Write-Verbose "Query will include resources within resource groups"
        } else {
            $Query = @"
ResourceContainers
| where type == 'microsoft.resources/subscriptions/resourcegroups'
| where $WhereClause
| project subscriptionId, resourceGroup = name, location
"@

        }

        # Add subscription filtering if specified
        IF($SubscriptionIds -and $SubscriptionIds.Count -gt 0) {
            $SubsList = $SubscriptionIds -join "', '"
            $Query = $Query + "`n| where subscriptionId in ('$SubsList')"
            Write-Verbose "Filtering to specific subscriptions: $($SubscriptionIds -join ', ')"
        }

        # Add location filtering if specified
        IF($Locations -and $Locations.Count -gt 0) {
            $LocationsList = $Locations -join "', '"
            $Query = $Query + "`n| where location in ('$LocationsList')"
            Write-Verbose "Filtering to specific locations: $($Locations -join ', ')"
        }

        TRY{
            Write-Verbose "Executing Azure Resource Graph query"
            $Results = Search-AzGraph -Query $Query

            IF($Results.Count -eq 0) {
                Write-Warning "No resource groups found matching the pattern '$ResourceGroupName'"
                return
            }

            # Format output with subscription names
            $FormattedResults = @()
            $SubscriptionCache = @{}

            foreach ($Result in $Results) {
                # Cache subscription names to avoid repeated lookups
                IF(-not $SubscriptionCache.ContainsKey($Result.subscriptionId)) {
                    $SubName = (Get-AzSubscription -SubscriptionId $Result.subscriptionId -ErrorAction SilentlyContinue).Name
                    IF(-not $SubName) { $SubName = "Unknown" }
                    $SubscriptionCache[$Result.subscriptionId] = $SubName
                }

                IF($IncludeResources) {
                    $FormattedResults += [PSCustomObject]@{
                        SubscriptionName = $SubscriptionCache[$Result.subscriptionId]
                        SubscriptionId = $Result.subscriptionId
                        ResourceGroupName = $Result.resourceGroup
                        ResourceName = $Result.name
                        ResourceType = $Result.type
                        Location = $Result.location
                    }
                } else {
                    $FormattedResults += [PSCustomObject]@{
                        SubscriptionName = $SubscriptionCache[$Result.subscriptionId]
                        SubscriptionId = $Result.subscriptionId
                        ResourceGroupName = $Result.resourceGroup
                        Location = $Result.location
                    }
                }
            }

            # Show summary if requested
            IF($ShowSubscriptionSummary) {
                Write-Host "`nSubscription Summary:" -ForegroundColor Green
                $FormattedResults | Group-Object SubscriptionName | ForEach-Object {
                    Write-Host " $($_.Name): $($_.Count) resource group(s)" -ForegroundColor Cyan
                }
            }

            return $FormattedResults
        }
        CATCH{
            Write-Error "Failed to search for resource group: $($_.Exception.Message)"
        }
    }

    END{
        Write-Verbose "Search completed"
    }
}