Public/New-Tier0CreateOU.ps1
function New-Tier0CreateOU { <# .SYNOPSIS Creates a new Tier0 Organizational Unit (OU) structure in Active Directory. .DESCRIPTION Creates and configures the Tier0 Organizational Units structure following Microsoft's tier model. This includes: - Creating the main Admin OU at the domain root - Creating child OUs for accounts, groups, rights, PAWs, service accounts - Configuring proper inheritance and permissions for each OU - Setting appropriate descriptions based on configuration - Applying security hardening by removing unnecessary permissions This function is part of the tier model implementation and establishes the foundation for secure Active Directory administration. .PARAMETER ConfigXMLFile Full path to the XML configuration file containing all naming conventions, OU structure, and security settings. The XML file must contain required Admin section with all OU definitions. .PARAMETER DMScripts Path to all the scripts and files needed by this function. Must contain a SecTmpl subfolder with required templates. Default: C:\PsScripts\ .EXAMPLE New-Tier0CreateOU -ConfigXMLFile 'C:\PsScripts\Config.xml' Creates the Tier 0 OU structure using the specified configuration file. .EXAMPLE $params = @{ ConfigXMLFile = 'C:\PsScripts\Config.xml' DMScripts = 'D:\AdminScripts\' } New-Tier0CreateOU @params Creates Tier 0 OU structure with enhanced security hardening using a custom scripts directory. .INPUTS [System.IO.FileInfo] You can pipe the path to the XML configuration file to this function. .OUTPUTS [System.String] Returns a status message upon successful completion with count of created OUs. .NOTES Used Functions: Name ║ Module/Namespace ═══════════════════════════════════════╬════════════════════════════ Import-MyModule ║ EguibarIT New-DelegateAdOU ║ EguibarIT Set-AdInheritance ║ EguibarIT.DelegationPS Remove-AuthUser ║ EguibarIT.DelegationPS Start-AdCleanOU ║ EguibarIT.DelegationPS Remove-PreWin2000FromOU ║ EguibarIT.DelegationPS Remove-AccountOperator ║ EguibarIT.DelegationPS Remove-PrintOperator ║ EguibarIT.DelegationPS Get-FunctionDisplay ║ EguibarIT Write-Verbose ║ Microsoft.PowerShell.Utility Write-Progress ║ Microsoft.PowerShell.Utility Write-Error ║ Microsoft.PowerShell.Utility .NOTES Version: 1.3 DateModified: 28/Apr/2025 LastModifiedBy: Vicente Rodriguez Eguibar vicente@eguibar.com Eguibar IT http://www.eguibarit.com .LINK https://github.com/vreguibar/EguibarIT .LINK https://docs.microsoft.com/en-us/windows-server/identity/securing-privileged-access/securing-privileged-access-reference-material .COMPONENT Active Directory .ROLE System Administrator .FUNCTIONALITY Active Directory, Security, Tier Model, Delegation Model, Security Hardening #> [CmdletBinding( SupportsShouldProcess = $true, ConfirmImpact = 'High' )] [OutputType([System.String])] 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.Servers -or $null -eq $xml.n.Sites -or $null -eq $xml.n.NC) { throw 'XML file is missing required elements (Admin, Servers, Sites 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 # Display function header if variables exist 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 Import-MyModule -Name 'EguibarIT.DelegationPS' -Verbose:$false ############################## # Variables Definition # Parameters variable for splatting CMDlets [hashtable]$Splat = [hashtable]::New([StringComparer]::OrdinalIgnoreCase) [hashtable]$ProgressSplat = [hashtable]::New([StringComparer]::OrdinalIgnoreCase) # Load the XML configuration file try { $confXML = [xml](Get-Content $PSBoundParameters['ConfigXMLFile']) } catch { Write-Error -Message ('Error reading XML file: {0}' -f $_.Exception.Message) throw } #end Try-Catch # Define OU names from XML configuration [hashtable]$OuNames = @{ # Main Admin OU ItAdminOu = $ConfXML.n.Admin.OUs.ItAdminOU.name # Admin sub-OUs ItAdminAccountsOu = $ConfXML.n.Admin.OUs.ItAdminAccountsOU.name ItAdminGroupsOU = $ConfXML.n.Admin.OUs.ItAdminGroupsOU.name ItPrivGroupsOU = $ConfXML.n.Admin.OUs.ItPrivGroupsOU.name ItPawOu = $ConfXML.n.Admin.OUs.ItPawOU.name ItRightsOu = $ConfXML.n.Admin.OUs.ItRightsOU.name ItServiceAccountsOu = $ConfXML.n.Admin.OUs.ItServiceAccountsOU.name ItHousekeepingOu = $ConfXML.n.Admin.OUs.ItHousekeepingOU.name ItInfraOu = $ConfXML.n.Admin.OUs.ItInfraOU.name ItAdminSrvGroupsOU = $ConfXML.n.Admin.OUs.ItAdminSrvGroupsOU.name # PAW sub-OUs ItPawT0Ou = $ConfXML.n.Admin.OUs.ItPawT0OU.name ItPawT1Ou = $ConfXML.n.Admin.OUs.ItPawT1OU.name ItPawT2Ou = $ConfXML.n.Admin.OUs.ItPawT2OU.name ItPawStagingOu = $ConfXML.n.Admin.OUs.ItPawStagingOU.name # Service Accounts sub-OUs ItSAT0OU = $ConfXML.n.Admin.OUs.ItSAT0OU.name ItSAT1OU = $ConfXML.n.Admin.OUs.ItSAT1OU.name ItSAT2OU = $ConfXML.n.Admin.OUs.ItSAT2OU.name # Infrastructure sub-OUs ItInfraT0Ou = $ConfXML.n.Admin.OUs.ItInfraT0OU.name ItInfraT1Ou = $ConfXML.n.Admin.OUs.ItInfraT1OU.name ItInfraT2Ou = $ConfXML.n.Admin.OUs.ItInfraT2OU.name ItInfraStagingOu = $ConfXML.n.Admin.OUs.ItInfraStagingOU.name # Quarantine OUs ItNewComputersOU = $ConfXML.n.Admin.OUs.ItNewComputersOU.name ItNewUsersOU = $ConfXML.n.Admin.OUs.ItNewUsersOU.name } # Generate DN paths for created OUs [hashtable]$OuPaths = @{ # Main Admin OU ItAdminOuDn = ('OU={0},{1}' -f $OuNames.ItAdminOu, $Variables.AdDn) # Admin sub-OUs ItAdminAccountsOuDn = ('OU={0},OU={1},{2}' -f $OuNames.ItAdminAccountsOu, $OuNames.ItAdminOu, $Variables.AdDn) ItAdminGroupsOUDn = ('OU={0},OU={1},{2}' -f $OuNames.ItAdminGroupsOU, $OuNames.ItAdminOu, $Variables.AdDn) ItPrivGroupsOUDn = ('OU={0},OU={1},{2}' -f $OuNames.ItPrivGroupsOU, $OuNames.ItAdminOu, $Variables.AdDn) ItPawOuDn = ('OU={0},OU={1},{2}' -f $OuNames.ItPawOu, $OuNames.ItAdminOu, $Variables.AdDn) ItRightsOuDn = ('OU={0},OU={1},{2}' -f $OuNames.ItRightsOu, $OuNames.ItAdminOu, $Variables.AdDn) ItServiceAccountsOuDn = ('OU={0},OU={1},{2}' -f $OuNames.ItServiceAccountsOu, $OuNames.ItAdminOu, $Variables.AdDn) ItHousekeepingOuDn = ('OU={0},OU={1},{2}' -f $OuNames.ItHousekeepingOu, $OuNames.ItAdminOu, $Variables.AdDn) ItInfraOuDn = ('OU={0},OU={1},{2}' -f $OuNames.ItInfraOu, $OuNames.ItAdminOu, $Variables.AdDn) ItAdminSrvGroupsOUDn = ('OU={0},OU={1},{2}' -f $OuNames.ItAdminSrvGroupsOU, $OuNames.ItAdminOu, $Variables.AdDn) # PAW sub-OUs ItPawT0OuDn = ('OU={0},OU={1},OU={2},{3}' -f $OuNames.ItPawT0Ou, $OuNames.ItPawOu, $OuNames.ItAdminOu, $Variables.AdDn) ItPawT1OuDn = ('OU={0},OU={1},OU={2},{3}' -f $OuNames.ItPawT1Ou, $OuNames.ItPawOu, $OuNames.ItAdminOu, $Variables.AdDn) ItPawT2OuDn = ('OU={0},OU={1},OU={2},{3}' -f $OuNames.ItPawT2Ou, $OuNames.ItPawOu, $OuNames.ItAdminOu, $Variables.AdDn) ItPawStagingOuDn = ('OU={0},OU={1},OU={2},{3}' -f $OuNames.ItPawStagingOu, $OuNames.ItPawOu, $OuNames.ItAdminOu, $Variables.AdDn) # Service Accounts sub-OUs ItSAT0OuDn = ('OU={0},OU={1},OU={2},{3}' -f $OuNames.ItSAT0OU, $OuNames.ItServiceAccountsOu, $OuNames.ItAdminOu, $Variables.AdDn) ItSAT1OuDn = ('OU={0},OU={1},OU={2},{3}' -f $OuNames.ItSAT1OU, $OuNames.ItServiceAccountsOu, $OuNames.ItAdminOu, $Variables.AdDn) ItSAT2OuDn = ('OU={0},OU={1},OU={2},{3}' -f $OuNames.ItSAT2OU, $OuNames.ItServiceAccountsOu, $OuNames.ItAdminOu, $Variables.AdDn) # Infrastructure sub-OUs ItInfraT0OuDn = ('OU={0},OU={1},OU={2},{3}' -f $OuNames.ItInfraT0Ou, $OuNames.ItInfraOu, $OuNames.ItAdminOu, $Variables.AdDn) ItInfraT1OuDn = ('OU={0},OU={1},OU={2},{3}' -f $OuNames.ItInfraT1Ou, $OuNames.ItInfraOu, $OuNames.ItAdminOu, $Variables.AdDn) ItInfraT2OuDn = ('OU={0},OU={1},OU={2},{3}' -f $OuNames.ItInfraT2Ou, $OuNames.ItInfraOu, $OuNames.ItAdminOu, $Variables.AdDn) ItInfraStagingOuDn = ('OU={0},OU={1},OU={2},{3}' -f $OuNames.ItInfraStagingOu, $OuNames.ItInfraOu, $OuNames.ItAdminOu, $Variables.AdDn) } # Initialize progress tracking [int]$TotalSteps = 23 # Total number of OUs to create [int]$CurrentStep = 0 } #end Begin Process { if ($PSCmdlet.ShouldProcess('Active Directory', 'Create Tier0 Organizational Units')) { try { #region Create Main Admin OU $CurrentStep++ $ProgressSplat = @{ Activity = 'Creating Tier 0 OU Structure' Status = ('Step {0} of {1}: Creating {2} OU' -f $CurrentStep, $TotalSteps, $OuNames.ItAdminOu) PercentComplete = (($CurrentStep / $TotalSteps) * 100) } Write-Progress @ProgressSplat # Create main Admin OU $Splat = @{ ouName = $OuNames.ItAdminOu ouPath = $Variables.AdDn ouDescription = $ConfXML.n.Admin.OUs.ItAdminOU.description CleanACL = $true } try { New-DelegateAdOU @Splat Write-Debug -Message ('Successfully created {0} OU at {1}' -f $OuNames.ItAdminOu, $Variables.AdDn) } catch { Write-Error -Message ('Failed to create {0} OU: {1}' -f $OuNames.ItAdminOu, $_.Exception.Message) throw } #end Try-Catch # Remove inheritance and copy ACEs $Splat = @{ LDAPpath = $OuPaths.ItAdminOuDn RemoveInheritance = $true RemovePermissions = $true } Set-AdInheritance @Splat Write-Debug -Message ('Successfully configured inheritance settings for {0}' -f $OuPaths.ItAdminOuDn) # Implement security hardening if specified Write-Debug -Message ('Applying security hardening to {0}' -f $OuPaths.ItAdminOuDn) # Remove AUTHENTICATED USERS group from OU (but must retain on ACL) Remove-AuthUser -LDAPPath $OuPaths.ItAdminOuDn # Clean Ou Start-AdCleanOU -LDAPPath $OuPaths.ItAdminOuDn -RemoveUnknownSIDs -Confirm:$false -Force # Remove Pre-Windows 2000 Access group from OU Remove-PreWin2000FromOU -LDAPPath $OuPaths.ItAdminOuDn # Remove ACCOUNT OPERATORS Access group from OU Remove-AccountOperator -LDAPPath $OuPaths.ItAdminOuDn # Remove PRINT OPERATORS Access group from OU Remove-PrintOperator -LDAPPath $OuPaths.ItAdminOuDn Write-Verbose -Message ('Security hardening completed for {0}' -f $OuPaths.ItAdminOuDn) <# # Remove AUTHENTICATED USERS group from OU # # CHECK... This one should not "LIST" but must be on ACL Remove-AuthUser -LDAPPath $ItAdminOuDn # Clean Ou Start-AdCleanOU -LDAPPath $ItAdminOuDn -RemoveUnknownSIDs # Remove Pre-Windows 2000 Access group from OU Remove-PreWin2000FromOU -LDAPPath $ItAdminOuDn # Remove ACCOUNT OPERATORS 2000 Access group from OU Remove-AccountOperator -LDAPPath $ItAdminOuDn # Remove PRINT OPERATORS 2000 Access group from OU Remove-PrintOperator -LDAPPath $ItAdminOuDn #> <# Computer objects within this ares MUST have read access, otherwise GPO will not apply - TO BE DONE Manually change Authenticated Users from "This Object Only" to "This and descendant objects" then ACL will look like this: Get-AclAccessRule -LDAPpath 'OU=Admin,DC=EguibarIT,DC=local' -SearchBy 'Authenticated Users' VERBOSE: ACE (Access Control Entry) Filtered By: Authenticated Users VERBOSE: ============================================================ ACENumber : 1 DistinguishedName : OU=Admin,DC=EguibarIT,DC=local IdentityReference : Authenticated Users ActiveDirectoryRights : ReadProperty, GenericExecute AccessControlType : Allow ObjectType : GuidNULL InheritanceType : All InheritedObjectType : GuidNULL IsInherited : False #> #endregion #region Create Admin Sub-OUs Write-Verbose -Message 'Creating Sub-OUs for Admin (Tier0)...' # Create parameter for all sub-OUs $Splat = @{ ouPath = $OuPaths.ItAdminOuDn CleanACL = $true } # Create each Admin sub-OU with progress reporting $CurrentStep++ $ProgressSplat = @{ Activity = 'Creating Tier 0 OU Structure' Status = ('Step {0} of {1}: Creating {2} OU' -f $CurrentStep, $TotalSteps, $OuNames.ItAdminAccountsOu) PercentComplete = (($CurrentStep / $TotalSteps) * 100) } Write-Progress @ProgressSplat New-DelegateAdOU -ouName $OuNames.ItAdminAccountsOu -ouDescription $ConfXML.n.Admin.OUs.ItAdminAccountsOU.description @Splat $CurrentStep++ $ProgressSplat = @{ Activity = 'Creating Tier 0 OU Structure' Status = ('Step {0} of {1}: Creating {2} OU' -f $CurrentStep, $TotalSteps, $OuNames.ItAdminGroupsOU) PercentComplete = (($CurrentStep / $TotalSteps) * 100) } Write-Progress @ProgressSplat New-DelegateAdOU -ouName $OuNames.ItAdminGroupsOU -ouDescription $ConfXML.n.Admin.OUs.ItAdminGroupsOU.description @Splat $CurrentStep++ $ProgressSplat = @{ Activity = 'Creating Tier 0 OU Structure' Status = ('Step {0} of {1}: Creating {2} OU' -f $CurrentStep, $TotalSteps, $OuNames.ItPrivGroupsOU) PercentComplete = (($CurrentStep / $TotalSteps) * 100) } Write-Progress @ProgressSplat New-DelegateAdOU -ouName $OuNames.ItPrivGroupsOU -ouDescription $ConfXML.n.Admin.OUs.ItPrivGroupsOU.description @Splat $CurrentStep++ $ProgressSplat = @{ Activity = 'Creating Tier 0 OU Structure' Status = ('Step {0} of {1}: Creating {2} OU' -f $CurrentStep, $TotalSteps, $OuNames.ItPawOu) PercentComplete = (($CurrentStep / $TotalSteps) * 100) } Write-Progress @ProgressSplat New-DelegateAdOU -ouName $OuNames.ItPawOu -ouDescription $ConfXML.n.Admin.OUs.ItPawOU.description @Splat $CurrentStep++ $ProgressSplat = @{ Activity = 'Creating Tier 0 OU Structure' Status = ('Step {0} of {1}: Creating {2} OU' -f $CurrentStep, $TotalSteps, $OuNames.ItRightsOu) PercentComplete = (($CurrentStep / $TotalSteps) * 100) } Write-Progress @ProgressSplat New-DelegateAdOU -ouName $OuNames.ItRightsOu -ouDescription $ConfXML.n.Admin.OUs.ItRightsOU.description @Splat $CurrentStep++ $ProgressSplat = @{ Activity = 'Creating Tier 0 OU Structure' Status = ('Step {0} of {1}: Creating {2} OU' -f $CurrentStep, $TotalSteps, $OuNames.ItServiceAccountsOu) PercentComplete = (($CurrentStep / $TotalSteps) * 100) } Write-Progress @ProgressSplat New-DelegateAdOU -ouName $OuNames.ItServiceAccountsOu -ouDescription $ConfXML.n.Admin.OUs.ItServiceAccountsOU.description @Splat $CurrentStep++ $ProgressSplat = @{ Activity = 'Creating Tier 0 OU Structure' Status = ('Step {0} of {1}: Creating {2} OU' -f $CurrentStep, $TotalSteps, $OuNames.ItHousekeepingOu) PercentComplete = (($CurrentStep / $TotalSteps) * 100) } Write-Progress @ProgressSplat New-DelegateAdOU -ouName $OuNames.ItHousekeepingOu -ouDescription $ConfXML.n.Admin.OUs.ItHousekeepingOU.description @Splat $CurrentStep++ $ProgressSplat = @{ Activity = 'Creating Tier 0 OU Structure' Status = ('Step {0} of {1}: Creating {2} OU' -f $CurrentStep, $TotalSteps, $OuNames.ItInfraOu) PercentComplete = (($CurrentStep / $TotalSteps) * 100) } Write-Progress @ProgressSplat New-DelegateAdOU -ouName $OuNames.ItInfraOu -ouDescription $ConfXML.n.Admin.OUs.ItInfraOU.description @Splat $CurrentStep++ $ProgressSplat = @{ Activity = 'Creating Tier 0 OU Structure' Status = ('Step {0} of {1}: Creating {2} OU' -f $CurrentStep, $TotalSteps, $OuNames.ItAdminSrvGroupsOU) PercentComplete = (($CurrentStep / $TotalSteps) * 100) } Write-Progress @ProgressSplat New-DelegateAdOU -ouName $OuNames.ItAdminSrvGroupsOU -ouDescription $ConfXML.n.Admin.OUs.ItAdminSrvGroupsOU.description @Splat # Ensure inheritance is enabled for child Admin OUs $Splat = @{ RemoveInheritance = $false RemovePermissions = $true } Write-Verbose -Message 'Configuring inheritance for Admin sub-OUs...' Set-AdInheritance -LDAPpath $OuPaths.ItAdminAccountsOuDn @Splat Set-AdInheritance -LDAPpath $OuPaths.ItAdminGroupsOUDn @Splat Set-AdInheritance -LDAPpath $OuPaths.ItPrivGroupsOUDn @Splat Set-AdInheritance -LDAPpath $OuPaths.ItPawOuDn @Splat Set-AdInheritance -LDAPpath $OuPaths.ItRightsOuDn @Splat Set-AdInheritance -LDAPpath $OuPaths.ItServiceAccountsOuDn @Splat Set-AdInheritance -LDAPpath $OuPaths.ItHousekeepingOuDn @Splat Set-AdInheritance -LDAPpath $OuPaths.ItInfraOuDn @Splat Set-AdInheritance -LDAPpath $OuPaths.ItAdminSrvGroupsOUDn @Splat #endregion #region Create PAW Sub-OUs Write-Debug -Message 'Creating PAW Sub-OUs...' # Create parameter for PAW sub-OUs $Splat = @{ ouPath = $OuPaths.ItPawOuDn CleanACL = $true } # Create each PAW sub-OU with progress reporting $CurrentStep++ $ProgressSplat = @{ Activity = 'Creating Tier 0 OU Structure' Status = ('Step {0} of {1}: Creating {2} OU' -f $CurrentStep, $TotalSteps, $OuNames.ItPawT0Ou) PercentComplete = (($CurrentStep / $TotalSteps) * 100) } Write-Progress @ProgressSplat New-DelegateAdOU -ouName $OuNames.ItPawT0Ou -ouDescription $ConfXML.n.Admin.OUs.ItPawT0OU.description @Splat $CurrentStep++ $ProgressSplat = @{ Activity = 'Creating Tier 0 OU Structure' Status = ('Step {0} of {1}: Creating {2} OU' -f $CurrentStep, $TotalSteps, $OuNames.ItPawT1Ou) PercentComplete = (($CurrentStep / $TotalSteps) * 100) } Write-Progress @ProgressSplat New-DelegateAdOU -ouName $OuNames.ItPawT1Ou -ouDescription $ConfXML.n.Admin.OUs.ItPawT1OU.description @Splat $CurrentStep++ $ProgressSplat = @{ Activity = 'Creating Tier 0 OU Structure' Status = ('Step {0} of {1}: Creating {2} OU' -f $CurrentStep, $TotalSteps, $OuNames.ItPawT2Ou) PercentComplete = (($CurrentStep / $TotalSteps) * 100) } Write-Progress @ProgressSplat New-DelegateAdOU -ouName $OuNames.ItPawT2Ou -ouDescription $ConfXML.n.Admin.OUs.ItPawT2OU.description @Splat $CurrentStep++ $ProgressSplat = @{ Activity = 'Creating Tier 0 OU Structure' Status = ('Step {0} of {1}: Creating {2} OU' -f $CurrentStep, $TotalSteps, $OuNames.ItPawStagingOu) PercentComplete = (($CurrentStep / $TotalSteps) * 100) } Write-Progress @ProgressSplat New-DelegateAdOU -ouName $OuNames.ItPawStagingOu -ouDescription $ConfXML.n.Admin.OUs.ItPawStagingOU.description @Splat # Ensure inheritance is enabled for PAW sub-OUs $Splat = @{ RemoveInheritance = $false RemovePermissions = $true } Write-Verbose -Message 'Configuring inheritance for PAW sub-OUs...' Set-AdInheritance -LDAPpath $OuPaths.ItPawT0OuDn @Splat Set-AdInheritance -LDAPpath $OuPaths.ItPawT1OuDn @Splat Set-AdInheritance -LDAPpath $OuPaths.ItPawT2OuDn @Splat Set-AdInheritance -LDAPpath $OuPaths.ItPawStagingOuDn @Splat #endregion #region Create Service Accounts Sub-OUs Write-Debug -Message 'Creating Service Accounts Sub-OUs...' # Create parameter for Service Accounts sub-OUs $Splat = @{ ouPath = $OuPaths.ItServiceAccountsOuDn CleanACL = $true } # Create each Service Account sub-OU with progress reporting $CurrentStep++ $ProgressSplat = @{ Activity = 'Creating Tier 0 OU Structure' Status = ('Step {0} of {1}: Creating {2} OU' -f $CurrentStep, $TotalSteps, $OuNames.ItSAT0OU) PercentComplete = (($CurrentStep / $TotalSteps) * 100) } Write-Progress @ProgressSplat New-DelegateAdOU -ouName $OuNames.ItSAT0OU -ouDescription $ConfXML.n.Admin.OUs.ItSAT0OU.description @Splat $CurrentStep++ $ProgressSplat = @{ Activity = 'Creating Tier 0 OU Structure' Status = ('Step {0} of {1}: Creating {2} OU' -f $CurrentStep, $TotalSteps, $OuNames.ItSAT1OU) PercentComplete = (($CurrentStep / $TotalSteps) * 100) } Write-Progress @ProgressSplat New-DelegateAdOU -ouName $OuNames.ItSAT1OU -ouDescription $ConfXML.n.Admin.OUs.ItSAT1OU.description @Splat $CurrentStep++ $ProgressSplat = @{ Activity = 'Creating Tier 0 OU Structure' Status = ('Step {0} of {1}: Creating {2} OU' -f $CurrentStep, $TotalSteps, $OuNames.ItSAT2OU) PercentComplete = (($CurrentStep / $TotalSteps) * 100) } Write-Progress @ProgressSplat New-DelegateAdOU -ouName $OuNames.ItSAT2OU -ouDescription $ConfXML.n.Admin.OUs.ItSAT2OU.description @Splat # Ensure inheritance is enabled for Service Accounts sub-OUs $Splat = @{ RemoveInheritance = $false RemovePermissions = $true } Write-Verbose -Message 'Configuring inheritance for Service Accounts sub-OUs...' Set-AdInheritance -LDAPpath $OuPaths.ItSAT0OuDn @Splat Set-AdInheritance -LDAPpath $OuPaths.ItSAT1OuDn @Splat Set-AdInheritance -LDAPpath $OuPaths.ItSAT2OuDn @Splat #endregion #region Create Infrastructure Sub-OUs Write-Debug -Message 'Creating Infrastructure Sub-OUs...' # Create parameter for Infrastructure sub-OUs $Splat = @{ ouPath = $OuPaths.ItInfraOuDn CleanACL = $true } # Create each Infrastructure sub-OU with progress reporting $CurrentStep++ $ProgressSplat = @{ Activity = 'Creating Tier 0 OU Structure' Status = ('Step {0} of {1}: Creating {2} OU' -f $CurrentStep, $TotalSteps, $OuNames.ItInfraT0Ou) PercentComplete = (($CurrentStep / $TotalSteps) * 100) } Write-Progress @ProgressSplat New-DelegateAdOU -ouName $OuNames.ItInfraT0Ou -ouDescription $ConfXML.n.Admin.OUs.ItInfraT0OU.description @Splat $CurrentStep++ $ProgressSplat = @{ Activity = 'Creating Tier 0 OU Structure' Status = ('Step {0} of {1}: Creating {2} OU' -f $CurrentStep, $TotalSteps, $OuNames.ItInfraT1Ou) PercentComplete = (($CurrentStep / $TotalSteps) * 100) } Write-Progress @ProgressSplat New-DelegateAdOU -ouName $OuNames.ItInfraT1Ou -ouDescription $ConfXML.n.Admin.OUs.ItInfraT1OU.description @Splat $CurrentStep++ $ProgressSplat = @{ Activity = 'Creating Tier 0 OU Structure' Status = ('Step {0} of {1}: Creating {2} OU' -f $CurrentStep, $TotalSteps, $OuNames.ItInfraT2Ou) PercentComplete = (($CurrentStep / $TotalSteps) * 100) } Write-Progress @ProgressSplat New-DelegateAdOU -ouName $OuNames.ItInfraT2Ou -ouDescription $ConfXML.n.Admin.OUs.ItInfraT2OU.description @Splat $CurrentStep++ $ProgressSplat = @{ Activity = 'Creating Tier 0 OU Structure' Status = ('Step {0} of {1}: Creating {2} OU' -f $CurrentStep, $TotalSteps, $OuNames.ItInfraStagingOu) PercentComplete = (($CurrentStep / $TotalSteps) * 100) } Write-Progress @ProgressSplat New-DelegateAdOU -ouName $OuNames.ItInfraStagingOu -ouDescription $ConfXML.n.Admin.OUs.ItInfraStagingOU.description @Splat # Ensure inheritance is enabled for Infrastructure sub-OUs $Splat = @{ RemoveInheritance = $false RemovePermissions = $true } Write-Debug -Message 'Configuring inheritance for Infrastructure sub-OUs...' Set-AdInheritance -LDAPpath $OuPaths.ItInfraT0OuDn @Splat Set-AdInheritance -LDAPpath $OuPaths.ItInfraT1OuDn @Splat Set-AdInheritance -LDAPpath $OuPaths.ItInfraT2OuDn @Splat Set-AdInheritance -LDAPpath $OuPaths.ItInfraStagingOuDn @Splat #endregion # Ensure Authenticated Users have proper permissions to enable GPO application Write-Debug -Message 'Configuring Authenticated Users permissions for GPO application...' # Complete progress bar Write-Progress -Activity 'Creating Tier 0 OU Structure' -Completed } catch { Write-Error -Message ('Error creating Tier 0 OU structure: {0}' -f $_.Exception.Message) throw } finally { # Ensure progress bar is removed on error Write-Progress -Activity 'Creating Tier 0 OU Structure' -Completed } #end Try-Catch-Finally } #end If ShouldProcess } #end Process End { # Display function footer if variables exist if ($null -ne $Variables -and $null -ne $Variables.Footer) { $txt = ($Variables.Footer -f $MyInvocation.InvocationName, 'creating Tier0 Organizational Units.' ) 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 # Return status message with count of created OUs and root OU path return ('Tier 0 OU structure successfully created with {0} OUs. Root: {1}' -f $OuPaths.Count, $OuPaths.ItAdminOuDn) } #end End } #end Function New-Tier0CreateOU |