Public/Miscellaneous/Get-ExtendedRightHashTable.ps1
Function Get-ExtendedRightHashTable { <# .SYNOPSIS Gets all Extended Rights GUIDs from Active Directory and stores them in a hashtable. .DESCRIPTION This function queries the Active Directory Configuration partition and retrieves all Extended Rights GUIDs, creating a hashtable that maps display names to their corresponding GUIDs. The hashtable is stored in the $Variables.ExtendedRightsMap variable for later use. This function is essential for performing extended rights operations in Active Directory, particularly for security descriptors and permission management. .PARAMETER Force Forces the function to rebuild the Extended Rights map even if it already exists. .PARAMETER Server Specifies the domain controller to use for the query. If not provided, the function will use the default domain controller. .EXAMPLE Get-ExtendedRightHashTable Retrieves all Extended Rights GUIDs and stores them in $Variables.ExtendedRightsMap. .EXAMPLE Get-ExtendedRightHashTable -Force Forces the function to rebuild the Extended Rights map even if it already exists. .EXAMPLE Get-ExtendedRightHashTable -Server 'DC01.EguibarIT.local' Retrieves all Extended Rights GUIDs from the specified domain controller. .OUTPUTS System.Collections.Hashtable A hashtable mapping DisplayName of extended rights to their corresponding GUIDs. .NOTES Used Functions: Name ║ Module/Namespace ═══════════════════════════════════════════╬══════════════════════════════ Get-ADObject ║ ActiveDirectory Write-Progress ║ Microsoft.PowerShell.Utility Write-Verbose ║ Microsoft.PowerShell.Utility Write-Error ║ Microsoft.PowerShell.Utility Write-Debug ║ Microsoft.PowerShell.Utility Write-Warning ║ Microsoft.PowerShell.Utility .NOTES Version: 1.1 DateModified: 21/Mar/2025 LastModifiedBy: Vicente Rodriguez Eguibar vicente@eguibar.com Eguibar IT http://www.eguibarit.com .LINK https://github.com/vreguibar/EguibarIT.DelegationPS/blob/main/Public/Get-ExtendedRightHashTable.ps1 #> [CmdletBinding( SupportsShouldProcess = $false, ConfirmImpact = 'Low' )] [OutputType([System.Collections.Hashtable])] Param( [Parameter(Mandatory = $false, ValueFromPipeline = $false, ValueFromPipelineByPropertyName = $false, ValueFromRemainingArguments = $false, Position = 0, HelpMessage = 'Forces the function to rebuild the Extended Rights map even if it already exists.' )] [Alias('Rebuild')] [switch]$Force, [Parameter(Mandatory = $false, ValueFromPipeline = $false, ValueFromPipelineByPropertyName = $false, ValueFromRemainingArguments = $false, Position = 1, HelpMessage = 'Specifies the domain controller to use for the query.' )] [ValidateNotNullOrEmpty()] [Alias('DC', 'DomainController')] [string]$Server ) Begin { Set-StrictMode -Version Latest # Display function header if variables exist if ($null -ne $Variables -and $null -ne $Variables.HeaderDelegation) { $txt = ($Variables.HeaderDelegation -f (Get-Date).ToString('dd/MMM/yyyy'), $MyInvocation.Mycommand, (Get-FunctionDisplay -HashTable $PsBoundParameters -Verbose:$False) ) Write-Verbose -Message $txt } #end if ############################## # Variables Definition [hashtable]$TmpMap = [hashtable]::New([StringComparer]::OrdinalIgnoreCase) [hashtable]$Splat = [hashtable]::New([StringComparer]::OrdinalIgnoreCase) [int32]$i = 0 [bool]$FillUp = $false [hashtable]$ProgressSplat = [hashtable]::New([StringComparer]::OrdinalIgnoreCase) [int32]$ProcessedItems = 0 [bool]$NeedToFillExtendedRightsMap = $false [int32]$BatchSize = 1000 # Optimized batch size for AD queries $Splat = @{ SearchBase = ('CN=Extended-Rights,{0}' -f $Variables.configurationNamingContext) LDAPFilter = '(objectclass=controlAccessRight)' Properties = 'DisplayName', 'rightsGuid' } # Add server if specified if ($PSBoundParameters.ContainsKey('Server')) { $ADSplat.Add('Server', $Server) Write-Debug -Message ('Using specified server: {0}' -f $Server) } #end If } #end Begin Process { # Check if $Variables.ExtendedRightsMap is Null or Empty If ($Force -or [string]::IsNullOrEmpty($Variables.ExtendedRightsMap) -or $Variables.ExtendedRightsMap.Count -eq 0) { # We have to fill it up $FillUp = $true Write-Debug -Message 'The Extended Rights map is null, empty, or Force parameter was specified.' } else { Write-Debug -Message 'Extended Rights map already exists. Use -Force to rebuild it.' } #end If-Else If ( $FillUp ) { try { Write-Debug -Message 'Getting the GUID value of each Extended Right' # Add pagination parameters for large environments $ADSplat.Add('ResultPageSize', $BatchSize) # Execute the AD query with optimized filter Write-Debug -Message ('Executing AD query with parameters: {0}' -f ($ADSplat | ConvertTo-Json -Compress)) $AllExtended = Get-ADObject @Splat $ExtendedRightsCount = ($AllExtended | Measure-Object).Count Write-Debug -Message ('Found {0} Extended Rights objects' -f $ExtendedRightsCount) # Process Extended Rights objects ForEach ($Item in $AllExtended) { $ProcessedItems++ # Update progress bar $ProgressSplat = @{ Activity = 'Adding Extended Rights to Hashtable' Status = ('Processing: {0}/{1} ({2:P2} complete)' -f $ProcessedItems, $ExtendedRightsCount, ($ProcessedItems / $ExtendedRightsCount)) PercentComplete = [math]::Round(($ProcessedItems / $ExtendedRightsCount) * 100, 2) CurrentOperation = ('Processing Extended Right: {0}' -f $Item.DisplayName) } Write-Progress @ProgressSplat # Convert rightsGuid to string GUID format and add to hashtable try { $GuidValue = ([System.GUID]$ExtendedItem.rightsGuid).GUID # Check if the DisplayName already exists in the hashtable if (-not $TmpMap.ContainsKey($ExtendedItem.DisplayName)) { $TmpMap.Add($Item.DisplayName, $GuidValue) Write-Debug -Message ('Added {0}: {1}' -f $Item.DisplayName, $GuidValue) } else { Write-Warning -Message (' Duplicate DisplayName found: {0}. Using first occurrence only.' -f $Item.DisplayName ) } #end If-Else } catch { Write-Warning -Message (' Error processing Extended Right {0}: {1}' -f $Item.DisplayName, $_.Exception.Message ) } #end Try-Catch } #end Foreach # Add the "All" entry with null GUID if (-not [string]::IsNullOrEmpty($Constants.guidNull)) { $TmpMap.Add('All', $Constants.guidNull) Write-Debug -Message ('Added All: {0}' -f $Constants.guidNull) } else { # Add a null GUID if $Constants.guidNull is not defined $TmpMap.Add('All', '00000000-0000-0000-0000-000000000000') Write-Debug -Message 'Added All: 00000000-0000-0000-0000-000000000000' } #end If-Else # Update the module-level variable with our new hashtable Write-Verbose -Message 'Updating $Variables.ExtendedRightsMap with new values' $Variables.ExtendedRightsMap = $TmpMap } catch [System.DirectoryServices.ActiveDirectory.ActiveDirectoryOperationException] { Write-Error -Message ('Active Directory operation error: {0}' -f $_.Exception.Message) throw } catch [System.UnauthorizedAccessException] { Write-Error -Message ('Access denied error: {0}' -f $_.Exception.Message) throw } catch { Write-Error -Message ('Error filling Extended Rights map: {0}' -f $_.Exception.Message) throw } Finally { # Complete the progress bar $ProgressSplat = @{ Activity = 'Adding Extended Rights to Hashtable' Status = 'Completed' CurrentOperation = 'Finished' PercentComplete = 100 Completed = $true } Write-Progress @ProgressSplat } #end Try-Catch-Finally } #end If } #end Process End { # Display function footer if variables exist if ($null -ne $Variables -and $null -ne $Variables.FooterDelegation) { $txt = ($Variables.FooterDelegation -f $MyInvocation.InvocationName, 'filling up ExtendedRightsMap variable.' ) Write-Verbose -Message $txt } #end if } #end END } #end Function Get-ExtendedRightHashTable |