Public/New-Tier0NestingGroup.ps1
function New-Tier0NestingGroup { <# .SYNOPSIS Creates and applies nesting for Tier0 administration groups. .DESCRIPTION This function establishes and configures the nested group structure required for Tier0 security model. It configures which accounts/groups are denied from being replicated to Read-Only Domain Controllers (RODC). It configures group nesting for built-in groups with the correct delegated rights groups. It extends rights through the delegation model by nesting security groups appropriately. The function relies on pre-existing group variables that must be defined before calling this function. .PARAMETER ConfigXMLFile [System.IO.FileInfo] Full path to the XML configuration file. Contains all naming conventions, OU structure, and security settings. Must be a valid XML file with required schema elements. Default: C:\PsScripts\Config.xml .PARAMETER DMScripts [System.String] Path to all the scripts and files needed by this function. The path must exist and contain a 'SecTmpl' subfolder. Default: C:\PsScripts\ .EXAMPLE New-Tier0NestingGroup Creates the nesting structure for Tier0 administration groups using existing group variables. .INPUTS None. This function does not accept pipeline input. .OUTPUTS None. This function does not generate any output. .NOTES Used Functions: Name ║ Module/Namespace ══════════════════════════════════╬══════════════════════════════ Import-MyModule ║ EguibarIT Get-FunctionDisplay ║ EguibarIT Add-AdGroupNesting ║ EguibarIT Get-ADGroup ║ ActiveDirectory New-ADGroup ║ ActiveDirectory Write-Verbose ║ Microsoft.PowerShell.Utility Write-Error ║ Microsoft.PowerShell.Utility .NOTES Version: 1.1 DateModified: 29/Apr/2025 LastModifiedBy: Vicente Rodriguez Eguibar vicente@eguibar.com Eguibar IT http://www.eguibarit.com .LINK https://github.com/vreguibar/EguibarIT .COMPONENT Active Directory .ROLE Security Administration .FUNCTIONALITY Tier 0 Security Group Management #> [CmdletBinding( SupportsShouldProcess = $true, ConfirmImpact = 'High' )] [OutputType([System.Void])] param ( [Parameter( Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, ValueFromRemainingArguments = $false, HelpMessage = 'Full path to the configuration.xml file', Position = 0 )] [ValidateScript({ if (-Not ($_ | Test-Path -PathType Leaf) ) { throw ('File not found: {0}' -f $_) } if ($_.Extension -ne '.xml') { throw ('File must be XML: {0}' -f $_) } try { [xml]$xml = Get-Content -Path $_ -ErrorAction Stop # Verify required XML elements are present if ($null -eq $xml.n.Admin -or $null -eq $xml.n.Admin.GG -or $null -eq $xml.n.Admin.gMSA -or $null -eq $xml.n.Admin.OUs -or $null -eq $xml.n.NC) { throw 'XML file is missing required elements (Admin, GG, gMSA, OUs or NC section)' } return $true } catch { throw ('Invalid XML file: {0}' -f $_.Exception.Message) } })] [PSDefaultValue( Help = 'Default Value is "C:\PsScripts\Config.xml"', Value = 'C:\PsScripts\Config.xml' )] [Alias('Config', 'XML', 'ConfigXml')] [System.IO.FileInfo] $ConfigXMLFile, [Parameter(Mandatory = $false, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, ValueFromRemainingArguments = $false, HelpMessage = 'Path to all the scripts and files needed by this function', Position = 1)] [PSDefaultValue( Help = 'Default Value is "C:\PsScripts\"', Value = 'C:\PsScripts\' )] [Alias('ScriptPath')] [string] $DMScripts = 'C:\PsScripts\', [Parameter(Mandatory = $false, ValueFromPipeline = $false, ValueFromPipelineByPropertyName = $false, ValueFromRemainingArguments = $false, HelpMessage = 'Start transcript logging to DMScripts path with function name', Position = 2)] [Alias('Transcript', 'Log')] [switch] $EnableTranscript ) Begin { Set-StrictMode -Version Latest If (-not $PSBoundParameters.ContainsKey('ConfigXMLFile')) { $PSBoundParameters['ConfigXMLFile'] = 'C:\PsScripts\Config.xml' } #end If If (-not $PSBoundParameters.ContainsKey('DMScripts')) { $PSBoundParameters['DMScripts'] = 'C:\PsScripts\' } #end If # If EnableTranscript is specified, start a transcript if ($EnableTranscript) { # Ensure DMScripts directory exists if (-not (Test-Path -Path $DMScripts -PathType Container)) { try { New-Item -Path $DMScripts -ItemType Directory -Force | Out-Null Write-Verbose -Message ('Created transcript directory: {0}' -f $DMScripts) } catch { Write-Warning -Message ('Failed to create transcript directory: {0}' -f $_.Exception.Message) } #end try-catch } #end if # Create transcript filename using function name and current date/time $TranscriptFile = Join-Path -Path $DMScripts -ChildPath ('{0}_{1}.LOG' -f $MyInvocation.MyCommand.Name, (Get-Date -Format 'yyyyMMdd_HHmmss')) try { Start-Transcript -Path $TranscriptFile -Force -ErrorAction Stop Write-Verbose -Message ('Transcript started: {0}' -f $TranscriptFile) } catch { Write-Warning -Message ('Failed to start transcript: {0}' -f $_.Exception.Message) } #end try-catch } #end if # Initialize logging if ($null -ne $Variables -and $null -ne $Variables.Header) { $txt = ($Variables.Header -f (Get-Date).ToString('dd/MMM/yyyy'), $MyInvocation.Mycommand, (Get-FunctionDisplay -HashTable $PsBoundParameters -Verbose:$False) ) Write-Verbose -Message $txt } #end If ############################## # Module imports Import-MyModule -Name 'ActiveDirectory' -Verbose:$false Import-MyModule -Name 'EguibarIT' -Verbose:$false ############################## # Variables Definition # parameters variable for splatting CMDlets [hashtable]$Splat = [hashtable]::New([StringComparer]::OrdinalIgnoreCase) #$ArrayList = [System.Collections.ArrayList]::new() [System.Collections.Generic.List[object]]$ArrayList = [System.Collections.Generic.List[object]]::New() # Load the XML configuration file try { [xml]$confXML = [xml](Get-Content -Path $PSBoundParameters['ConfigXMLFile'] -ErrorAction Stop) } catch { Write-Error -Message ('Error reading XML file: {0}' -f $_.Exception.Message) throw } #end Try-Catch # Load naming conventions from XML [hashtable]$NC = @{ 'sl' = $confXML.n.NC.LocalDomainGroupPreffix 'sg' = $confXML.n.NC.GlobalGroupPreffix 'su' = $confXML.n.NC.UniversalGroupPreffix 'Delim' = $confXML.n.NC.Delimiter 'T0' = $confXML.n.NC.AdminAccSufix0 'T1' = $confXML.n.NC.AdminAccSufix1 'T2' = $confXML.n.NC.AdminAccSufix2 } #region Users Variables $AdminName = Get-SafeVariable -Name 'AdminName' -CreateIfNotExist { try { Get-ADUser -Filter * | Where-Object { $_.SID -like 'S-1-5-21-*-500' } } catch { Write-Debug -Message ('Failed to retrieve Administrator name: {0}' -f $_.Exception.Message) $null } } $NewAdminExists = Get-SafeVariable -Name 'NewAdminExists' -CreateIfNotExist { $newAdminName = $confXML.n.Admin.users.NEWAdmin.Name if (-not [string]::IsNullOrEmpty($newAdminName)) { Get-AdObjectType -Identity $newAdminName } else { $null } } #endregion Users Variables #region Well-Known groups Variables $DomainAdmins = Get-SafeVariable -Name 'DomainAdmins' -CreateIfNotExist { try { Get-ADGroup -Filter * | Where-Object { $_.SID -like 'S-1-5-21-*-512' } } catch { Write-Debug -Message ('Failed to retrieve Domain Admins group: {0}' -f $_.Exception.Message) $null } } $EnterpriseAdmins = Get-SafeVariable -Name 'EnterpriseAdmins' -CreateIfNotExist { try { Get-ADGroup -Filter * | Where-Object { $_.SID -like 'S-1-5-21-*-519' } } catch { Write-Debug -Message ('Failed to retrieve Enterprise Admins group: {0}' -f $_.Exception.Message) $null } } $CryptoOperators = Get-SafeVariable -Name 'CryptoOperators' -CreateIfNotExist { try { Get-ADGroup -Filter * | Where-Object { $_.SID -like 'S-1-5-32-569' } } catch { Write-Debug -Message ('Failed to retrieve Cryptographic Operators group: {0}' -f $_.Exception.Message) $null } } $ServerOperators = Get-SafeVariable -Name 'ServerOperators' -CreateIfNotExist { try { Get-ADGroup -Identity 'S-1-5-32-549' } catch { Write-Debug -Message ('Failed to retrieve Server Operators group: {0}' -f $_.Exception.Message) $null } } $RemoteMngtUsers = Get-SafeVariable -Name 'RemoteMngtUsers' -CreateIfNotExist { try { Get-ADGroup -Filter * | Where-Object { $_.SID -like 'S-1-5-32-580' } } catch { Write-Debug -Message ('Failed to retrieve Remote Management Users group: {0}' -f $_.Exception.Message) $null } } $RemoteDesktopUsers = Get-SafeVariable -Name 'RemoteDesktopUsers' -CreateIfNotExist { try { Get-ADGroup -Filter * | Where-Object { $_.SID -like 'S-1-5-32-555' } } catch { Write-Debug -Message ('Failed to retrieve Remote Desktop Users group: {0}' -f $_.Exception.Message) $null } } $EvtLogReaders = Get-SafeVariable -Name 'EvtLogReaders' -CreateIfNotExist { try { Get-ADGroup -Filter * | Where-Object { $_.SID -like 'S-1-5-32-573' } } catch { Write-Debug -Message ('Failed to retrieve Event Log Readers group: {0}' -f $_.Exception.Message) $null } } $NetConfOperators = Get-SafeVariable -Name 'NetConfOperators' -CreateIfNotExist { try { Get-ADGroup -Filter * | Where-Object { $_.SID -like 'S-1-5-32-556' } } catch { Write-Debug -Message ('Failed to retrieve Network Configuration Operators group: {0}' -f $_.Exception.Message) $null } } $PerfLogUsers = Get-SafeVariable -Name 'PerfLogUsers' -CreateIfNotExist { try { Get-ADGroup -Filter * | Where-Object { $_.SID -like 'S-1-5-32-559' } } catch { Write-Debug -Message ('Failed to retrieve Performance Log Users group: {0}' -f $_.Exception.Message) $null } } $PerfMonitorUsers = Get-SafeVariable -Name 'PerfMonitorUsers' -CreateIfNotExist { try { Get-ADGroup -Filter * | Where-Object { $_.SID -like 'S-1-5-32-558' } } catch { Write-Debug -Message ('Failed to retrieve Performance Monitor Users group: {0}' -f $_.Exception.Message) $null } } #endregion Well-Known groups Variables #region Global groups Variables $SG_InfraAdmins = Get-SafeVariable -Name 'SG_InfraAdmins' -CreateIfNotExist { $groupName = ('{0}{1}{2}' -f $NC['sg'], $NC['Delim'], $confXML.n.Admin.GG.InfraAdmins.Name) Get-AdObjectType -Identity $groupName } $SG_AdAdmins = Get-SafeVariable -Name 'SG_AdAdmins' -CreateIfNotExist { $groupName = ('{0}{1}{2}' -f $NC['sg'], $NC['Delim'], $confXML.n.Admin.GG.AdAdmins.Name) Get-AdObjectType -Identity $groupName } $SG_GpoAdmins = Get-SafeVariable -Name 'SG_GpoAdmins' -CreateIfNotExist { $groupName = ('{0}{1}{2}' -f $NC['sg'], $NC['Delim'], $confXML.n.Admin.GG.GpoAdmins.Name) Get-AdObjectType -Identity $groupName } $SG_Tier0Admins = Get-SafeVariable -Name 'SG_Tier0Admins' -CreateIfNotExist { $groupName = ('{0}{1}{2}' -f $NC['sg'], $NC['Delim'], $confXML.n.Admin.GG.Tier0Admins.Name) Get-AdObjectType -Identity $groupName } $SG_Tier1Admins = Get-SafeVariable -Name 'SG_Tier1Admins' -CreateIfNotExist { $groupName = ('{0}{1}{2}' -f $NC['sg'], $NC['Delim'], $confXML.n.Admin.GG.Tier1Admins.Name) Get-AdObjectType -Identity $groupName } $SG_Tier2Admins = Get-SafeVariable -Name 'SG_Tier2Admins' -CreateIfNotExist { $groupName = ('{0}{1}{2}' -f $NC['sg'], $NC['Delim'], $confXML.n.Admin.GG.Tier2Admins.Name) Get-AdObjectType -Identity $groupName } $SG_Operations = Get-SafeVariable -Name 'SG_Operations' -CreateIfNotExist { $groupName = ('{0}{1}{2}' -f $NC['sg'], $NC['Delim'], $confXML.n.Servers.GG.Operations.Name) Get-AdObjectType -Identity $groupName } $SG_ServerAdmins = Get-SafeVariable -Name 'SG_ServerAdmins' -CreateIfNotExist { $groupName = ('{0}{1}{2}' -f $NC['sg'], $NC['Delim'], $confXML.n.Servers.GG.ServerAdmins.Name) Get-AdObjectType -Identity $groupName } $SG_AllSiteAdmins = Get-SafeVariable -Name 'SG_AllSiteAdmins' -CreateIfNotExist { $groupName = ('{0}{1}{2}' -f $NC['sg'], $NC['Delim'], $confXML.n.Admin.GG.AllSiteAdmins.Name) Get-AdObjectType -Identity $groupName } $SG_AllGALAdmins = Get-SafeVariable -Name 'SG_AllGALAdmins' -CreateIfNotExist { $groupName = ('{0}{1}{2}' -f $NC['sg'], $NC['Delim'], $confXML.n.Admin.GG.AllGalAdmins.Name) Get-AdObjectType -Identity $groupName } $SG_GlobalUserAdmins = Get-SafeVariable -Name 'SG_GlobalUserAdmins' -CreateIfNotExist { $groupName = ('{0}{1}{2}' -f $NC['sg'], $NC['Delim'], $confXML.n.Admin.GG.GlobalUserAdmins.Name) Get-AdObjectType -Identity $groupName } $SG_GlobalPcAdmins = Get-SafeVariable -Name 'SG_GlobalPcAdmins' -CreateIfNotExist { $groupName = ('{0}{1}{2}' -f $NC['sg'], $NC['Delim'], $confXML.n.Admin.GG.GlobalPCAdmins.Name) Get-AdObjectType -Identity $groupName } $SG_GlobalGroupAdmins = Get-SafeVariable -Name 'SG_GlobalGroupAdmins' -CreateIfNotExist { $groupName = ('{0}{1}{2}' -f $NC['sg'], $NC['Delim'], $confXML.n.Admin.GG.GlobalGroupAdmins.Name) Get-AdObjectType -Identity $groupName } $SG_ServiceDesk = Get-SafeVariable -Name 'SG_ServiceDesk' -CreateIfNotExist { $groupName = ('{0}{1}{2}' -f $NC['sg'], $NC['Delim'], $confXML.n.Admin.GG.ServiceDesk.Name) Get-AdObjectType -Identity $groupName } $DnsAdmins = Get-SafeVariable -Name 'DnsAdmins' -CreateIfNotExist { Get-AdObjectType -Identity 'DnsAdmins' } $ProtectedUsers = Get-SafeVariable -Name 'ProtectedUsers' -CreateIfNotExist { Get-AdObjectType -Identity 'Protected Users' } #endregion Global groups Variables #region Local groups Variables $SL_AdRight = Get-SafeVariable -Name 'SL_AdRight' -CreateIfNotExist { $groupName = ('{0}{1}{2}' -f $NC['sl'], $NC['Delim'], $confXML.n.Admin.LG.AdRight.Name) Get-AdObjectType -Identity $groupName } $SL_InfraRight = Get-SafeVariable -Name 'SL_InfraRight' -CreateIfNotExist { $groupName = ('{0}{1}{2}' -f $NC['sl'], $NC['Delim'], $confXML.n.Admin.LG.InfraRight.Name) Get-AdObjectType -Identity $groupName } $SL_DnsAdminRight = Get-SafeVariable -Name 'SL_DnsAdminRight' -CreateIfNotExist { $groupName = ('{0}{1}{2}' -f $NC['sl'], $NC['Delim'], $confXML.n.Admin.LG.DnsAdminRight.Name) Get-AdObjectType -Identity $groupName } $SL_GpoAdminRight = Get-SafeVariable -Name 'SL_GpoAdminRight' -CreateIfNotExist { $groupName = ('{0}{1}{2}' -f $NC['sl'], $NC['Delim'], $confXML.n.Admin.LG.GpoAdminRight.Name) Get-AdObjectType -Identity $groupName } $SL_PGM = Get-SafeVariable -Name 'SL_PGM' -CreateIfNotExist { $groupName = ('{0}{1}{2}' -f $NC['sl'], $NC['Delim'], $confXML.n.Admin.LG.PGM.Name) Get-AdObjectType -Identity $groupName } $SL_PUM = Get-SafeVariable -Name 'SL_PUM' -CreateIfNotExist { $groupName = ('{0}{1}{2}' -f $NC['sl'], $NC['Delim'], $confXML.n.Admin.LG.PUM.Name) Get-AdObjectType -Identity $groupName } $SL_GM = Get-SafeVariable -Name 'SL_GM' -CreateIfNotExist { $groupName = ('{0}{1}{2}' -f $NC['sl'], $NC['Delim'], $confXML.n.Admin.LG.GM.Name) Get-AdObjectType -Identity $groupName } $SL_UM = Get-SafeVariable -Name 'SL_UM' -CreateIfNotExist { $groupName = ('{0}{1}{2}' -f $NC['sl'], $NC['Delim'], $confXML.n.Admin.LG.UM.Name) Get-AdObjectType -Identity $groupName } $SL_PSAM = Get-SafeVariable -Name 'SL_PSAM' -CreateIfNotExist { $groupName = ('{0}{1}{2}' -f $NC['sl'], $NC['Delim'], $confXML.n.Admin.LG.PSAM.Name) Get-AdObjectType -Identity $groupName } $SL_PAWM = Get-SafeVariable -Name 'SL_PAWM' -CreateIfNotExist { $groupName = ('{0}{1}{2}' -f $NC['sl'], $NC['Delim'], $confXML.n.Admin.LG.PAWM.Name) Get-AdObjectType -Identity $groupName } $SL_PISM = Get-SafeVariable -Name 'SL_PISM' -CreateIfNotExist { $groupName = ('{0}{1}{2}' -f $NC['sl'], $NC['Delim'], $confXML.n.Admin.LG.PISM.Name) Get-AdObjectType -Identity $groupName } $SL_SAGM = Get-SafeVariable -Name 'SL_SAGM' -CreateIfNotExist { $groupName = ('{0}{1}{2}' -f $NC['sl'], $NC['Delim'], $confXML.n.Admin.LG.SAGM.Name) Get-AdObjectType -Identity $groupName } $SL_DcManagement = Get-SafeVariable -Name 'SL_DcManagement' -CreateIfNotExist { $groupName = ('{0}{1}{2}' -f $NC['sl'], $NC['Delim'], $confXML.n.Admin.LG.DcManagement.Name) Get-AdObjectType -Identity $groupName } $SL_TransferFSMOright = Get-SafeVariable -Name 'SL_TransferFSMOright' -CreateIfNotExist { $groupName = ('{0}{1}{2}' -f $NC['sl'], $NC['Delim'], $confXML.n.Admin.LG.TransferFSMOright.Name) Get-AdObjectType -Identity $groupName } $SL_PromoteDcRight = Get-SafeVariable -Name 'SL_PromoteDcRight' -CreateIfNotExist { $groupName = ('{0}{1}{2}' -f $NC['sl'], $NC['Delim'], $confXML.n.Admin.LG.PromoteDcRight.Name) Get-AdObjectType -Identity $groupName } $SL_DirReplRight = Get-SafeVariable -Name 'SL_DirReplRight' -CreateIfNotExist { $groupName = ('{0}{1}{2}' -f $NC['sl'], $NC['Delim'], $confXML.n.Admin.LG.DirReplRight.Name) Get-AdObjectType -Identity $groupName } $SL_SvrOpsRight = Get-SafeVariable -Name 'SL_SvrOpsRight' -CreateIfNotExist { $groupName = ('{0}{1}{2}' -f $NC['sl'], $NC['Delim'], $confXML.n.Servers.LG.SvrOpsRight.Name) Get-AdObjectType -Identity $groupName } $SL_SvrAdmRight = Get-SafeVariable -Name 'SL_SvrAdmRight' -CreateIfNotExist { $groupName = ('{0}{1}{2}' -f $NC['sl'], $NC['Delim'], $confXML.n.Servers.LG.SvrAdmRight.Name) Get-AdObjectType -Identity $groupName } $SL_GlobalGroupRight = Get-SafeVariable -Name 'SL_GlobalGroupRight' -CreateIfNotExist { $groupName = ('{0}{1}{2}' -f $NC['sl'], $NC['Delim'], $confXML.n.Servers.LG.GlobalGroupRight.Name) Get-AdObjectType -Identity $groupName } $SL_GlobalAppAccUserRight = Get-SafeVariable -Name 'SL_GlobalAppAccUserRight' -CreateIfNotExist { $groupName = ('{0}{1}{2}' -f $NC['sl'], $NC['Delim'], $confXML.n.Servers.LG.GlobalAppAccUserRight.Name) Get-AdObjectType -Identity $groupName } #endregion Local groups Variables $AllGlobalGroupVariables = @( $DomainAdmins, $SG_InfraAdmins, $SG_AdAdmins, $SG_GpoAdmins, $SG_Tier0Admins, $SG_Tier1Admins, $SG_Tier2Admins, $SG_Operations, $SG_ServerAdmins, $SG_AllSiteAdmins, $SG_AllGALAdmins, $SG_GlobalUserAdmins, $SG_GlobalPcAdmins, $SG_GlobalGroupAdmins, $SG_ServiceDesk ) $AllLocalGroupVariables = @( $SL_AdRight, $SL_InfraRight, $SL_DnsAdminRight, $SL_GpoAdminRight, $SL_PGM, $SL_PUM, $SL_GM, $SL_UM, $SL_PSAM, $SL_PAWM, $SL_PISM, $SL_SAGM, $SL_DcManagement, $SL_TransferFSMOright, $SL_PromoteDcRight, $SL_DirReplRight, $SL_SvrOpsRight, $SL_SvrAdmRight, $SL_GlobalGroupRight, $SL_GlobalAppAccUserRight ) $ItAdminOu = $ConfXML.n.Admin.OUs.ItAdminOU.name $ItRightsOu = $ConfXML.n.Admin.OUs.ItRightsOU.name $ItRightsOuDn = ('OU={0},OU={1},{2}' -f $ItRightsOu, $ItAdminOu, $Variables.AdDn) } #end Begin Process { # Progress parameters that will be reused [hashtable]$ProgressSplat = @{ Activity = 'Configuring Tier 0 Nesting Structure' Status = 'Starting operation...' PercentComplete = 0 Id = 1 } # Total number of operations for progress calculation $TotalOperations = 3 $CurrentOperation = 0 # Avoid having privileged or semi-privileged groups copy to RODC if ($PSCmdlet.ShouldProcess('Nesting Denied RODC groups')) { $CurrentOperation++ $ProgressSplat['Status'] = ('Operation {0}/{1}: Configuring groups denied replication to RODC...' -f $CurrentOperation, $TotalOperations) $ProgressSplat['PercentComplete'] = ($CurrentOperation / $TotalOperations * 100) Write-Progress @ProgressSplat Write-Verbose -Message 'Configuring groups denied replication to RODC...' $ArrayList.Clear() foreach ($Item in $AllGlobalGroupVariables) { if ($null -ne $Item) { [void]$ArrayList.Add($Item) } else { Write-Error -Message ('Group not found: {0}' -f $Item) } #end If GroupName } #end ForEach # Include Enterprise Admins [void]$ArrayList.Add($EnterpriseAdmins) foreach ($Item in $AllLocalGroupVariables) { if ($null -ne $Item) { [void]$ArrayList.Add($Item) } else { Write-Error -Message ('Group not found: {0}' -f $Item) } #end If GroupName } #end ForEach # Add groups Add-AdGroupNesting -Identity $DeniedRODC -Members $ArrayList Write-Verbose -Message 'Successfully added groups to DeniedRODC' # Add Users $ArrayList.Clear() if ($null -ne $AdminName) { [void]$ArrayList.Add($AdminName) } if ($null -ne $NewAdminExists) { [void]$ArrayList.Add($NewAdminExists) } Add-AdGroupNesting -Identity $DeniedRODC -Members $ArrayList Write-Verbose -Message 'Successfully added admin users to DeniedRODC' } #end If ShouldProcess # Nest Groups - Delegate Rights through Builtin groups # https://docs.microsoft.com/en-us/windows/security/identity-protection/access-control/active-directory-security-groups # http://blogs.technet.com/b/lrobins/archive/2011/06/23/quot-admin-free-quot-active-directory-and-windows-part-1-understanding-privileged-groups-in-ad.aspx # http://blogs.msmvps.com/acefekay/2012/01/06/using-group-nesting-strategy-ad-best-practices-for-group-strategy/ if ($PSCmdlet.ShouldProcess('Delegate rights through nesting Builtin groups')) { $CurrentOperation++ $ProgressSplat['Status'] = ('Operation {0}/{1}: Configuring builtin group membership...' -f $CurrentOperation, $TotalOperations) $ProgressSplat['PercentComplete'] = ($CurrentOperation / $TotalOperations * 100) Write-Progress @ProgressSplat Write-Verbose -Message 'Configuring builtin group membership...' Add-AdGroupNesting -Identity $CryptoOperators -Members $SG_AdAdmins Add-AdGroupNesting -Identity $DnsAdmins -Members $SG_AdAdmins, $SG_Tier0Admins Add-AdGroupNesting -Identity $EvtLogReaders -Members $SG_AdAdmins, $SG_Operations Add-AdGroupNesting -Identity $NetConfOperators -Members $SG_AdAdmins, $SG_Tier0Admins Add-AdGroupNesting -Identity $PerfLogUsers -Members $SG_AdAdmins, $SG_Operations, $SG_Tier0Admins Add-AdGroupNesting -Identity $PerfMonitorUsers -Members $SG_AdAdmins, $SG_Operations, $SG_Tier0Admins Add-AdGroupNesting -Identity $RemoteDesktopUsers -Members $SG_AdAdmins Add-AdGroupNesting -Identity $ServerOperators -Members $SG_AdAdmins Add-AdGroupNesting -Identity $RemoteMngtUsers -Members $SG_AdAdmins, $SG_Tier0Admins # Create and configure WinRMRemoteWMIUsers group if it doesn't exist $RemoteWMI = Get-ADGroup -Filter { SamAccountName -like 'WinRMRemoteWMIUsers*' } -ErrorAction SilentlyContinue If (-not $RemoteWMI) { $Splat = @{ GroupScope = 'DomainLocal' GroupCategory = 'Security' Name = 'WinRMRemoteWMIUsers__' Path = $ItRightsOuDn } New-ADGroup @Splat $RemoteWMI = Get-ADGroup 'WinRMRemoteWMIUsers__' Write-Verbose -Message 'Created WinRMRemoteWMIUsers__ group' } Add-AdGroupNesting -Identity $RemoteWMI -Members $SG_AdAdmins, $SG_Tier0Admins # Configure Protected Users group membership # https://technet.microsoft.com/en-us/library/dn466518(v=ws.11).aspx $ArrayList.Clear() if ($null -ne $AdminName) { [void]$ArrayList.Add($AdminName) } if ($null -ne $NewAdminExists) { [void]$ArrayList.Add($NewAdminExists) } Add-AdGroupNesting -Identity $ProtectedUsers -Members $ArrayList $ArrayList.Clear() foreach ($Item in $AllGlobalGroupVariables) { if (($null -ne $Item) -and ($item -ne 'Enterprise Admins')) { [void]$ArrayList.Add($Item) } else { Write-Error -Message ('Group not found: {0}' -f $Item) } #end If GroupName } #end ForEach Add-AdGroupNesting -Identity $ProtectedUsers -Members $ArrayList Write-Verbose -Message 'Successfully configured builtin group membership' } #end If ShouldProcess # Nest Groups - Extend Rights through delegation model groups # http://blogs.msmvps.com/acefekay/2012/01/06/using-group-nesting-strategy-ad-best-practices-for-group-strategy/ if ($PSCmdlet.ShouldProcess('Extend Rights through delegation model group nesting')) { $CurrentOperation++ $ProgressSplat['Status'] = ('Operation {0}/{1}: Configuring delegation model group nesting...' -f $CurrentOperation, $TotalOperations) $ProgressSplat['PercentComplete'] = ($CurrentOperation / $TotalOperations * 100) Write-Progress @ProgressSplat # InfraAdmins as member of InfraRight $Splat = @{ Identity = $SL_InfraRight Members = $SG_InfraAdmins } Add-AdGroupNesting @Splat # InfraAdmins as member of PUM $Splat = @{ Identity = $SL_PUM Members = $SG_InfraAdmins } Add-AdGroupNesting @Splat # InfraAdmins as member of PGM $Splat = @{ Identity = $SL_PGM Members = $SG_InfraAdmins } Add-AdGroupNesting @Splat # InfraAdmins as member of PISM $Splat = @{ Identity = $SL_PISM Members = $SG_InfraAdmins } Add-AdGroupNesting @Splat # InfraAdmins as member of PAWM $Splat = @{ Identity = $SL_PAWM Members = $SG_InfraAdmins } Add-AdGroupNesting @Splat # InfraAdmins as member of PSAM $Splat = @{ Identity = $SL_PSAM Members = $SG_InfraAdmins } Add-AdGroupNesting @Splat # InfraAdmins as member of Tier0Admins $Splat = @{ Identity = $SG_Tier0Admins Members = $SG_InfraAdmins } Add-AdGroupNesting @Splat # InfraAdmins as member of DirReplRight $Splat = @{ Identity = $SL_DirReplRight Members = $SG_InfraAdmins } Add-AdGroupNesting @Splat # InfraAdmins as member of AdAdmins $Splat = @{ Identity = $SG_AdAdmins Members = $SG_InfraAdmins } Add-AdGroupNesting @Splat Write-Verbose -Message 'Successfully configured InfraAdmins nesting' # AdAdmins as member of AdRight $Splat = @{ Identity = $SL_AdRight Members = $SG_AdAdmins } Add-AdGroupNesting @Splat # AdAdmins as member of UM $Splat = @{ Identity = $SL_UM Members = $SG_AdAdmins } Add-AdGroupNesting @Splat # AdAdmins as member of GM $Splat = @{ Identity = $SL_GM Members = $SG_AdAdmins } Add-AdGroupNesting @Splat # AdAdmins as member of GpoAdmins $Splat = @{ Identity = $SG_GpoAdmins Members = $SG_AdAdmins } Add-AdGroupNesting @Splat # AdAdmins as member of AllSiteAdmins $Splat = @{ Identity = $SG_AllSiteAdmins Members = $SG_AdAdmins } Add-AdGroupNesting @Splat # AdAdmins as member of ServerAdmins $Splat = @{ Identity = $SG_ServerAdmins Members = $SG_AdAdmins } Add-AdGroupNesting @Splat # AdAdmins as member of DcManagement $Splat = @{ Identity = $SL_DcManagement Members = $SG_AdAdmins } Add-AdGroupNesting @Splat # AdAdmins as member of Tier0Admins $Splat = @{ Identity = $SG_Tier0Admins Members = $SG_AdAdmins } Add-AdGroupNesting @Splat # Tier0Admins as member of DcManagement $Splat = @{ Identity = $SL_DcManagement Members = $SG_Tier0Admins } Add-AdGroupNesting @Splat Write-Verbose -Message 'Successfully configured Tier0Admins nesting' # GpoAdmins nesting $Splat = @{ Identity = $SL_GpoAdminRight Members = $SG_GpoAdmins } Add-AdGroupNesting @Splat Write-Verbose -Message 'Successfully configured GpoAdmins nesting' # AllSiteAdmins and AllGalAdmins nesting $Splat = @{ Identity = $SG_AllGALAdmins Members = $SG_AllSiteAdmins } Add-AdGroupNesting @Splat # AllGalAdmins as member of ServiceDesk $Splat = @{ Identity = $SG_ServiceDesk Members = $SG_AllGALAdmins } Add-AdGroupNesting @Splat Write-Verbose -Message 'Successfully configured AllSiteAdmins and AllGalAdmins nesting' # ServerAdmins as member of SvrAdmRight $Splat = @{ Identity = $SL_SvrAdmRight Members = $SG_ServerAdmins } Add-AdGroupNesting @Splat # Operations as member of SvrOpsRight $Splat = @{ Identity = $SL_SvrOpsRight Members = $SG_Operations } Add-AdGroupNesting @Splat # ServerAdmins as member of Operations $Splat = @{ Identity = $SG_Operations Members = $SG_ServerAdmins } Add-AdGroupNesting @Splat Write-Verbose -Message 'Successfully configured ServerAdmins and Operations nesting' } #end If ShouldProcess # Complete the progress bar $ProgressSplat['Status'] = 'Completed all operations' $ProgressSplat['PercentComplete'] = 100 Write-Progress @ProgressSplat # Finally, clean up the progress bar Write-Progress -Id 1 -Activity 'Configuring Tier 0 Nesting Structure' -Completed } #end Process End { if ($null -ne $Variables -and $null -ne $Variables.Footer) { $txt = ($Variables.Footer -f $MyInvocation.InvocationName, 'Nesting Tier0 Groups.' ) Write-Verbose -Message $txt } #end If # Stop transcript if it was started if ($EnableTranscript) { try { Stop-Transcript -ErrorAction Stop Write-Verbose -Message 'Transcript stopped successfully' } catch { Write-Warning -Message ('Failed to stop transcript: {0}' -f $_.Exception.Message) } #end Try-Catch } #end If } #end End } #end Function New-Tier0NestingGroup |