Modules/AzureDevOpsDsc.Common/Api/Functions/Private/Helper/ACL/Merge-AzDoUnmanagedACE.ps1
|
<#
.SYNOPSIS Carries the live ACEs a resource does not manage into a serialized ACL body. .DESCRIPTION Set-AzDoPermission posts to 'accesscontrollists', which replaces the whole ACL for each token in the body: an ACE left out is deleted. ConvertTo-ACLHashtable only serializes the ACEs a resource manages, so on a token that other identities also hold ACEs on, posting its output as-is strips them. On the organization root token that would include the grants every member of the organization relies on. This adds each live ACE whose descriptor the body does not already carry, with its allow and deny masks unchanged, to the ACL with the same token. ACEs the body already carries are left as the body has them, so the managed identities still get exactly the desired masks. .PARAMETER SerializedACLs The output of ConvertTo-ACLHashtable: a hashtable with 'Count' and a 'value' list of ACL objects. .PARAMETER LiveACLs The ACLs as Get-DevOpsACL returned them: objects with 'token' and 'acesDictionary'. .OUTPUTS The SerializedACLs hashtable, with the unmanaged ACEs added. .EXAMPLE $body = ConvertTo-ACLHashtable @serializeACLParams $body = Merge-AzDoUnmanagedACE -SerializedACLs $body -LiveACLs $LookupResult.LiveACLs #> Function Merge-AzDoUnmanagedACE { [CmdletBinding()] [OutputType([System.Collections.Hashtable])] param ( [Parameter(Mandatory = $true)] [System.Collections.Hashtable]$SerializedACLs, [Parameter()] [AllowNull()] [AllowEmptyCollection()] [Object[]]$LiveACLs ) if (-not $LiveACLs) { return $SerializedACLs } foreach ($acl in $SerializedACLs.value) { # Tokens are case-insensitive in Azure DevOps. $liveACL = $LiveACLs | Where-Object { $_.token -eq $acl.token } | Select-Object -First 1 if (-not $liveACL -or -not $liveACL.acesDictionary) { continue } $liveEntries = if ($liveACL.acesDictionary -is [System.Collections.IDictionary]) { @($liveACL.acesDictionary.Values) } else { @($liveACL.acesDictionary.PSObject.Properties.Value) } foreach ($entry in $liveEntries) { $descriptor = $entry.descriptor # The body's acesDictionary is a hashtable, so this lookup is case-insensitive too. if ([String]::IsNullOrEmpty($descriptor) -or $acl.acesDictionary.ContainsKey($descriptor)) { continue } Write-Verbose "[Merge-AzDoUnmanagedACE] Keeping the unmanaged ACE for '$descriptor' on token '$($acl.token)'." $acl.acesDictionary[$descriptor] = @{ allow = [Int64]$entry.allow deny = [Int64]$entry.deny descriptor = $descriptor } } } return $SerializedACLs } |