functions/groups/Export-TmfGroup.ps1
|
<#
.SYNOPSIS Exports Azure AD groups into TMF configuration objects or JSON. .DESCRIPTION Retrieves groups via Microsoft Graph (v1.0 by default; beta when -ForceBeta) and converts them to the TMF shape. Returns objects unless -OutPath is supplied, in which case JSON is written to groups/groups.json. .PARAMETER SpecificResources Optional list of group display names, IDs or wildcards (comma separated accepted) to filter. .PARAMETER Scope Scope on security groups, M365 groups or all group types. Default: Security .PARAMETER OutPath Root folder to write the export. When omitted, objects are returned instead of writing files. Legacy alias -OutPutPath is deprecated. .PARAMETER ForceBeta Use beta Graph endpoint for retrieval (may expose additional properties). .PARAMETER Append Add content to an existing file .PARAMETER Cmdlet Internal pipeline parameter; do not supply manually. .EXAMPLE Export-TmfGroup -OutPath C:\temp\tmf .EXAMPLE Export-TmfGroup -SpecificResources "HR Group","1234-5678" | ConvertTo-Json -Depth 15 #> function Export-TmfGroup { [CmdletBinding()] param( [string[]] $SpecificResources, [ValidateSet("Security", "M365", "All")] [string] $Scope = "Security", [Alias('OutPutPath')] [string] $OutPath, [switch] $Append, [switch] $ForceBeta, [System.Management.Automation.PSCmdlet] $Cmdlet = $PSCmdlet ) begin { Test-GraphConnection -Cmdlet $Cmdlet $resourceName = 'groups' $tenant = (Invoke-MgGraphRequest -Method GET -Uri ("$($script:graphBaseUrl)/organization?`$select=displayname,id")).value $groupsExport = @() $select = 'id,displayName,description,groupTypes,securityEnabled,isAssignableToRole,mailEnabled,membershipRule,assignedLicenses,mailNickname' function Convert-Group { param([object]$g, [object]$PAGs) $groupDetails = [ordered]@{displayName = $g.displayName; description = $g.description; groupTypes = $g.groupTypes; securityEnabled = $g.securityEnabled; mailEnabled = $g.mailEnabled; mailNickname = $g.mailNickname} if ($g.isAssignableToRole) { $groupDetails["isAssignableToRole"] = $g.isAssignableToRole } if ($g.membershipRule) { $groupDetails["membershipRule"] = $g.membershipRule } if ($g.assignedLicenses) { $groupDetails["assignedLicenses"] = $g.assignedLicenses } if ($g.id -in $PAGs.externalId) { $groupDetails["privilegedAccess"] = $true } $groupDetails["present"] = $true return $groupDetails } function Get-AllGroups { param( [Parameter(Mandatory=$true)] [string]$Scope, [string[]] $SpecificResourceNames, [string[]] $SpecificResourceIDs, [string[]] $SpecificResourceSearches ) switch ($Scope) { "Security" {$filter="&`$filter=mailEnabled eq false AND securityEnabled eq true"} "M365" {$filter="&`$filter=groupTypes/any(c:c+eq+'Unified')"} "All" {$filter=""} } $list = @() if ($SpecificResourceNames -or $SpecificResourceIDs -or $SpecificResourceSearches) { if ($SpecificResourceNames) { $loops = [math]::ceiling($SpecificResourceNames.count/15) $start = 0 $end = 14 for ($i=1; $i -le $loops; $i++) { $specificFilter = if ($filter) {"$filter AND displayName in ['$($SpecificResourceNames[$start..$end] -join "','")']"} else {"&`$filter=displayName in ['$($SpecificResourceNames[$start..$end] -join "','")']"} $response = (Invoke-MgGraphRequest -Method GET -Uri "$(if ($ForceBeta) { $script:graphBaseUrlbeta } else { $script:graphBaseUrl1 })/groups?`$top=999&`$select=$select$($specificFilter)").value foreach ($item in $response) { $list += $item } $start += 15 $end += 15 } } if ($SpecificResourceIDs) { $loops = [math]::ceiling($SpecificResourceIDs.count/15) $start = 0 $end = 14 for ($i=1; $i -le $loops; $i++) { $specificFilter = if ($filter) {"$filter AND id in ['$($SpecificResourceIDs[$start..$end] -join "','")']"} else {"&`$filter=id in ['$($SpecificResourceIDs[$start..$end] -join "','")']"} $response = (Invoke-MgGraphRequest -Method GET -Uri "$(if ($ForceBeta) { $script:graphBaseUrlbeta } else { $script:graphBaseUrl1 })/groups?`$top=999&`$select=$select$($specificFilter)").value foreach ($item in $response) { $list += $item } $start += 15 $end += 15 } } $SpecificResourceSearches | ForEach-Object { $specificFilter = if ($filter) {"$filter&`$search=`"displayname:$($_)`""} else {"&`$search=`"displayname:$($_)`""} $response = (Invoke-MgGraphRequest -Method GET -Uri "$(if ($ForceBeta) { $script:graphBaseUrlbeta } else { $script:graphBaseUrl1 })/groups?`$top=999&`$select=$select$($specificFilter)" -Headers @{"ConsistencyLevel"="eventual"}).value foreach ($item in $response) { $list += $item } } } else { $resp = Invoke-MgGraphRequest -Method GET -Uri "$(if ($ForceBeta) { $script:graphBaseUrlbeta } else { $script:graphBaseUrl1 })/groups?`$top=999&`$select=$select$($filter)" if ($resp.keys -contains '@odata.nextLink') { do { $list += $resp.value; $resp = Invoke-MgGraphRequest -Method GET -Uri $resp.'@odata.nextLink' } while ($resp.'@odata.nextLink') } else { $list += $resp.value } } return $list } } process { $PAGs=(Invoke-MgGraphRequest -Method GET -Uri "$script:graphBaseUrl/privilegedAccess/aadGroups/resources?`$select=externalId&`$top=999").value if ($SpecificResources) { $SpecificResourceIDs = @() $SpecificResourceNames = @() $SpecificResourceSearches = @() foreach ($SpecificResource in $SpecificResources) { if ($SpecificResource -match $script:guidRegex) { $SpecificResourceIDs += $SpecificResource } elseif ($SpecificResource -match "\*") { $SpecificResourceSearches += $SpecificResource.replace("*","") } else { $SpecificResourceNames += $SpecificResource } } $allGroups = Get-AllGroups -Scope $Scope -SpecificResourceNames $SpecificResourceNames -SpecificResourceIDs $SpecificResourceIDs -SpecificResourceSearches $SpecificResourceSearches foreach ($g in $allGroups) { $groupsExport += Convert-Group $g $PAGs } } else { foreach ($g in (Get-AllGroups -Scope $Scope)) { $groupsExport += Convert-Group $g $PAGs } } } end { Write-PSFMessage -Level Verbose -FunctionName 'Export-TmfGroup' -Message "Exporting $($groupsExport.Count) group(s). ForceBeta=$ForceBeta" if ($OutPath) { if ($groupsExport) { if ($Append) { Write-TmfExportFile -OutPath $OutPath -ResourceName $resourceName -Data $groupsExport -Append } else { Write-TmfExportFile -OutPath $OutPath -ResourceName $resourceName -Data $groupsExport } } } else { return $groupsExport } } } |