Providers/Authentik/Public/New-AuthentikGroup.ps1
|
function New-AuthentikGroup { <# .EXTERNALHELP TestEnvironment-Help.xml .SYNOPSIS Creates the seeded Authentik groups, nested as Data\AuthentikGroups.csv describes #> [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'Medium')] [OutputType([PSCustomObject])] param( [Parameter()] [string[]]$GroupName, [Parameter()] [ValidateSet('Core', 'Bulk')] [string[]]$Tier, [Parameter()] [switch]$ShowProgress, [Parameter()] [switch]$PassThru ) $connection = Get-AuthentikConnection $marker = Get-AuthentikSeedMarker -Connection $connection $csvPath = Join-Path -Path (Get-AuthentikDataPath) -ChildPath 'AuthentikGroups.csv' $allRows = @(Import-Csv -Path $csvPath -Encoding UTF8) $rows = $allRows if ($Tier) { $rows = @($rows | Where-Object { $Tier -contains $_.Tier }) } if ($GroupName) { $rows = @($allRows | Where-Object { $GroupName -contains $_.Name }) $unknown = @($GroupName | Where-Object { $rows.Name -notcontains $_ }) if ($unknown) { throw "No definition in $csvPath for: $($unknown -join ', ')" } } # Depth from the full CSV, not the selection, so a partial rebuild still creates a parent # before its child when both are selected. A group can name more than one parent, so the # depth is the longest path up, and the walk is bounded in case the CSV ever holds a cycle. $parentsOf = @{} foreach ($row in $allRows) { $parentsOf[$row.Name] = @($row.Parent -split ';' | Where-Object { $_ }) } $depthOf = { param($key) $depth = 0 $frontier = @($parentsOf[$key]) while ($frontier.Count -gt 0 -and $depth -lt 20) { $depth++ $frontier = @($frontier | ForEach-Object { if ($parentsOf.ContainsKey($_)) { $parentsOf[$_] } }) } $depth } $rows = @($rows | Sort-Object -Property @{ Expression = { & $depthOf $_.Name } }, Name) $result = [PSCustomObject]@{ TotalGroups = $rows.Count CreatedGroups = 0 UpdatedGroups = 0 Groups = @() Errors = @() } # Groups that already exist, keyed by CSV key, so a parent created in an earlier run or # earlier in this loop resolves to its pk. $pkByKey = @{} foreach ($existing in (Get-AuthentikSeededObject -Type Groups -Connection $connection)) { if ($existing.attributes.PSObject.Properties['labKey']) { $pkByKey[[string]$existing.attributes.labKey] = [string]$existing.pk } } $groups = [System.Collections.Generic.List[object]]::new() $index = 0 foreach ($row in $rows) { $name = '{0}{1}' -f $marker.Prefix, $row.DisplayName $index++ Write-TestProgress -Activity 'Seeding groups' -Status "$index of $($rows.Count): $name" ` -PercentComplete ([int](100 * $index / [Math]::Max(1, $rows.Count))) -ShowProgress:$ShowProgress if (-not $PSCmdlet.ShouldProcess($name, 'Create Authentik group')) { continue } try { $parents = @() foreach ($parentKey in $parentsOf[$row.Name]) { if ($pkByKey.ContainsKey($parentKey)) { $parents += $pkByKey[$parentKey] } else { Write-Warning "Group '$name' names parent '$parentKey', which does not exist yet. Created without it." } } $attributes = [ordered]@{} $attributes[$marker.Attribute] = $marker.Tag $attributes['labKey'] = $row.Name $attributes['labCategory'] = $row.Category $attributes['labDescription'] = $row.Description $body = @{ name = $name is_superuser = $false parents = $parents attributes = $attributes } $group = $null if ($pkByKey.ContainsKey($row.Name)) { $group = Invoke-AuthentikRequest -Method PATCH -Path "/core/groups/$($pkByKey[$row.Name])/" -Body $body -Connection $connection $result.UpdatedGroups++ Write-Verbose "Updated group $name" } else { $group = Invoke-AuthentikRequest -Method POST -Path '/core/groups/' -Body $body -Connection $connection $result.CreatedGroups++ Write-Verbose "Created group $name" } $pkByKey[$row.Name] = [string]$group.pk $groups.Add([PSCustomObject]@{ Id = [string]$group.pk Key = $row.Name Name = $name Parent = $row.Parent Category = $row.Category }) } catch { $message = "Failed to create group '$name': $($_.Exception.Message)" $result.Errors += $message Write-Error $message } } $result.Groups = $groups.ToArray() Write-TestProgress -Activity 'Seeding groups' -Completed -ShowProgress:$ShowProgress Write-Verbose ("Groups: $($result.CreatedGroups) created, $($result.UpdatedGroups) updated, " + "$($result.Errors.Count) problems") if ($PassThru) { return $result } } |