internal/functions/resolve/Resolve-Group.ps1

function Resolve-Group {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [string[]] $InputReference,
        [switch] $DontFailIfNotExisting,
        [switch] $SearchInDesiredConfiguration,
        [switch] $Expand,
        [switch] $DisplayName,
        [System.Management.Automation.PSCmdlet] $Cmdlet = $PSCmdlet
    )
    begin {
        if ($InputReference.Count -gt 1) {
            $InputReference = $InputReference | ForEach-Object { Resolve-String -Text $_ }
        } else {
            $InputReference = Resolve-String -Text $InputReference[0]
        }
        if (-not $script:groupDetailCache) {
            $script:groupDetailCache = @{}
        }
    }
    process {
        if ($InputReference -is [array] -and $InputReference.Count -gt 1) {
            if (Test-TmfInputsCached -CacheName 'groupDetailCache' -Inputs $InputReference -SkipValues @('All')) {
                $results = foreach ($i in $InputReference) {
                    if ($i -eq 'All') {
                        'All'
                    } elseif ($script:groupDetailCache.ContainsKey($i)) {
                        if ($Expand) {
                            $script:groupDetailCache[$i]
                        } elseif ($DisplayName) {
                            $script:groupDetailCache[$i].displayName
                        } else {
                            $script:groupDetailCache[$i].id
                        }
                    } else {
                        $i
                    }
                }
                return , $results
            }
            $prefetch = {
                param($all)
                $requests = @(); $idMap = @{}; $rid = 0
                # 1. GUID inputs
                $guidIds = $all | Where-Object { $_ -match $script:guidRegex }
                if ($guidIds.Count -gt 0) {
                    if ($DisplayName) {
                        try {
                            $objs = Resolve-DirectoryObject -InputReference ($guidIds | Where-Object { -not $script:groupDetailCache.ContainsKey($_) }) -Types group -ReturnObjects -DontFailIfNotExisting
                            foreach ($g in $objs) {
                                if ($g -and $g.id) {
                                    $detail = [pscustomobject]@{ id = $g.id; displayName = $g.displayName; mailNickname = $g.mailNickname }
                                    foreach ($k in @($detail.id, $detail.displayName, $detail.mailNickname)) {
                                        if ($k -and -not $script:groupDetailCache.ContainsKey($k)) {
                                            $script:groupDetailCache[$k] = $detail
                                        }
                                    }
                                }
                            }
                        } catch {
                            Write-PSFMessage -Level Verbose -Message ("Resolve-DirectoryObject bulk failed for groups: {0}" -f $_.Exception.Message) -Tag 'prefetch', 'group' -ErrorRecord $_
                        }
                    } else {
                        foreach ($gid in $guidIds | Where-Object { -not $script:groupDetailCache.ContainsKey($_) }) {
                            $rid++; $reqId = "g$rid"; $requests += @{ id = $reqId; method = 'GET'; url = "/groups/$gid?`$select=id,displayName,mailNickname" }; $idMap[$reqId] = $gid
                        }
                    }
                }
                # 2. Non-GUID inputs (displayName or mailNickname)
                $toResolve = $all | Where-Object { -not $script:groupDetailCache.ContainsKey($_) -and ($_ -notmatch $script:guidRegex) }
                foreach ($dn in $toResolve) {
                    $rid++; $reqId = "d$rid"
                    $escaped = $dn -replace "'", "''"
                    # choose filter type by pattern
                    if ($dn -match $script:mailNicknameRegex) {
                        $requests += @{ id = $reqId; method = 'GET'; url = "/groups?`$filter=mailNickname eq '$escaped'&`$select=id,displayName,mailNickname" }
                    } else {
                        $requests += @{ id = $reqId; method = 'GET'; url = "/groups?`$filter=displayName eq '$escaped'&`$select=id,displayName,mailNickname" }
                    }
                    $idMap[$reqId] = $dn
                }
                # Submit in chunks
                for ($i = 0; $i -lt $requests.Count; $i += 20) {
                    $chunk = $requests[$i..([Math]::Min($i + 19, $requests.Count - 1))]
                    try {
                        $body = @{ requests = $chunk } | ConvertTo-Json -Depth 6
                        # Escape $ in $batch to call proper Graph batch endpoint
                        $resp = Invoke-MgGraphRequest -Method POST -Uri ("$script:graphBaseUrl/`$batch") -Body $body -ContentType 'application/json'
                        if ($resp -and $resp.responses) {
                            foreach ($r in $resp.responses) {
                                if ($r.status -ge 200 -and $r.status -lt 300 -and $r.body) {
                                    $match = $null
                                    if ($r.body.value) {
                                        $match = $r.body.value | Select-Object -First 1
                                    } else {
                                        $match = $r.body
                                    }
                                    if ($match) {
                                        $detail = [pscustomobject]@{ id = $match.id; displayName = $match.displayName; mailNickname = $match.mailNickname }; Add-TmfCacheEntries -CacheName 'groupDetailCache' -Objects @($detail) -KeyProperties id, displayName, mailNickname
                                    }
                                }
                            }
                        }
                    } catch {
                        Write-PSFMessage -Level Warning -Message ("Group batch prefetch failed chunk starting index {0}: {1}" -f $i, $_.Exception.Message) -Tag 'batch', 'failed' -ErrorRecord $_
                    }
                }
            }
            $single = {
                param($one)
                if ($script:groupDetailCache.ContainsKey($one)) {
                    if ($Expand) {
                        return $script:groupDetailCache[$one]
                    } elseif ($DisplayName) {
                        return ($script:groupDetailCache[$one].displayName)
                    } else {
                        return $script:groupDetailCache[$one].id
                    }
                }
                return (Resolve-Group -InputReference $one -DontFailIfNotExisting -Expand:$Expand -DisplayName:$DisplayName -SearchInDesiredConfiguration:$SearchInDesiredConfiguration -Cmdlet $Cmdlet)
            }
            return Invoke-TmfArrayResolution -Inputs $InputReference -Prefetch $prefetch -ResolveSingle $single
        }
        try {
            if (-not $Expand -and -not $DisplayName -and $script:groupDetailCache.ContainsKey($InputReference)) {
                return $script:groupDetailCache[$InputReference].id
            }
            if (-not $Expand -and $DisplayName -and $script:groupDetailCache.ContainsKey($InputReference)) {
                return ($script:groupDetailCache[$InputReference].displayName)
            }
            if ($InputReference -eq 'All') {
                if ($Expand) {
                    return [pscustomobject]@{ id = 'All'; displayName = 'All'; mailNickname = 'All' }
                } return 'All'
            }
            $fullObj = $null; $resolvedId = $null
            if ($InputReference -match $script:guidRegex) {
                if ($script:groupDetailCache.ContainsKey($InputReference)) {
                    if ($Expand) {
                        return $script:groupDetailCache[$InputReference]
                    } elseif ($DisplayName) {
                        return ($script:groupDetailCache[$InputReference].displayName)
                    } else {
                        return $script:groupDetailCache[$InputReference].id
                    }
                }
                $fullObj = Invoke-MgGraphRequest -Method GET -Uri ("$script:graphBaseUrl/groups/{0}?`$select=id,displayName,mailNickname" -f $InputReference)
                $resolvedId = $fullObj.id
            } elseif ($InputReference -match $script:mailNicknameRegex) {
                $fullObj = (Invoke-MgGraphRequest -Method GET -Uri ("$script:graphBaseUrl/groups/?`$filter=mailNickname eq '{0}'&`$select=id,displayName,mailNickname" -f $InputReference)).value | Select-Object -First 1
                $resolvedId = $fullObj.id
            } else {
                $InputReference = $InputReference -replace "'","''"
                if ($InputReference -notmatch "'") {
                    $InputReference = [System.Web.HttpUtility]::UrlEncode($InputReference)
                }
                $fullObj = (Invoke-MgGraphRequest -Method GET -Uri ("$script:graphBaseUrl/groups/?`$filter=displayName eq '{0}'&`$select=id,displayName,mailNickname" -f $InputReference)).value | Select-Object -First 1
                $resolvedId = $fullObj.id
            }
            # Undo Url encoding for returns
            $InputReference = [System.Web.HttpUtility]::UrlDecode($InputReference)
            if (-not $resolvedId -and $SearchInDesiredConfiguration) {
                if ($InputReference -in $script:desiredConfiguration['groups'].displayName) {
                    $resolvedId = $InputReference
                }
            }
            if (-not $resolvedId) {
                if ($DontFailIfNotExisting) {
                    return $InputReference
                } else {
                    throw "Cannot find group $InputReference"
                }
            }
            if (-not $Expand) {
                if ($DisplayName) {
                    return ($fullObj.displayName)
                }; return $resolvedId
            }
            $detail = [pscustomobject]@{ id = $resolvedId; displayName = $fullObj.displayName; mailNickname = $fullObj.mailNickname }
            foreach ($k in @($detail.id, $detail.displayName, $detail.mailNickname)) {
                if ($k -and -not $script:groupDetailCache.ContainsKey($k)) {
                    $script:groupDetailCache[$k] = $detail
                }
            }
            return $detail
        } catch {
            if ($DontFailIfNotExisting) {
                Write-PSFMessage -Level Warning -Message ("Cannot resolve Group resource for input '{0}'. Error: {1}" -f ($InputReference -join ","), $_.Exception.Message) -Tag failed -ErrorRecord $_; return $InputReference
            } else {
                Write-PSFMessage -Level Warning -Message ("Cannot resolve Group resource for input '{0}'. Error: {1}" -f ($InputReference -join ","), $_.Exception.Message) -Tag failed -ErrorRecord $_; $Cmdlet.ThrowTerminatingError($_)
            }
        }
    }
}