private/CreateOrSetOU.ps1
function CreateOrSetOU { [CmdletBinding(DefaultParameterSetName="DistinguishedNameOnly",SupportsShouldProcess=$true)] Param ( [Parameter(ParameterSetName="DistinguishedNameOnly", ValueFromPipelineByPropertyName)] [String]$DistinguishedName, [Parameter(ParameterSetName="NameAndDescription",Mandatory, ValueFromPipelineByPropertyName)] [String]$Name, [Parameter(ValueFromPipelineByPropertyName)] [String]$Description = "---Automatically created by createOrSetOU $((get-date).ToString("yyyy.MM.dd--HH.mm"))---", [Parameter(ParameterSetName="NameAndDescription", Mandatory, ValueFromPipelineByPropertyName)] [String]$Path, [Microsoft.ActiveDirectory.Management.ADDirectoryServer]$Server = (get-addomainController -Writable -Discover) ) BEGIN { $shouldProcess = @{ Confirm = [bool]($ConfirmPreference -eq "low") Whatif = [bool]($WhatIfPreference.IsPresent) verbose = [bool]($VerbosePreference -ne "SilentlyContinue") } $CreatedOUs = [System.Collections.Generic.List[String]]::new() $RootDSE = [adsi]"LDAP://RootDSE" $DefaultOU_SDDL = (get-adobject -server $server -filter { (ldapDisplayName -eq "organizationalUnit") } -searchBase ($rootDSE.SchemaNamingContext[0]) -properties defaultSecurityDescriptor).defaultSecurityDescriptor $defaultOU_ACL = [System.DirectoryServices.ActiveDirectorySecurity]::new() $defaultOU_ACL.SetSecurityDescriptorSddlForm($defaultOU_SDDL) write-loghandler -level "Verbose" -message "Initializing OU/Container Processing (DC: $server)" } PROCESS { $thisDN = if ($distinguishedName) { $DistinguishedName } else { "OU={0},{1}" -f $Name,$Path } $LocationTable = split-LDAPPath -distinguishedName $thisDN -ashashtable write-loghandler -level "Debug" -message "Started Processing '$thisDN''" -target $LocationTable.DistinguishedName $OUParams = @{ ProtectedFromAccidentalDeletion = $false Description = $Description } # Check if parent path exists. If not, lets recursively create it. # We use `get-adobject` to account for non-ou containers (like ProgramData) # We use "Distinguishedname = $LocationTable.Parent" to avoid infinite recursion. trap { $output['Status'] ="Error" write-loghandler -level "warning" -message "Here there be dragons: $($_.exception.getType().fullname)" write-loghandler -level "error" -message ("Error updating OU {0} at {1} with Description {2}" -f $LocationTable.LeafName, $LocationTable.Parent, $Description) -target $_ throw $_ } $Output = [ordered]@{ Status = "Pending" Name = $LocationTable.LeafName Path = $LocationTable.Parent Description = $Description } try { $foundOU = @(Get-ADOrganizationalUnit -identity $LocationTable.distinguishedName) if ($foundOU.count -ne 1) { throw "Didn't find exactly 1 OU" } $PSShouldProcessMsg = $(write-logHandler -passthru -target $LocationTable.DistinguishedName -message "Set Description, Protection, and ACLs") if ($PSCmdlet.ShouldProcess.Invoke($PSShouldProcessMsg)){ Set-ADOrganizationalUnit -Identity $LocationTable.DistinguishedName @OUParams -replace @{ntSecurityDescriptor = $defaultOU_ACL} -confirm:$False | out-null $output['Status'] = "Updated" } else { $output['Status'] ="Set" } } catch [Microsoft.ActiveDirectory.Management.ADIdentityNotFoundException] { try { if ($PSCmdlet.ShouldProcess.Invoke($(write-logHandler -passthru -level "Debug" -target $LocationTable.DistinguishedName -message "Attempt to create New OU"))){ New-ADOrganizationalUnit -server $server -name $LocationTable.LeafName -path $LocationTable.Parent @OUParams -confirm:$false } } Catch [Microsoft.ActiveDirectory.Management.ADIdentityNotFoundException] { # This means a parent OU doesn't exist if ($LocationTable.Parent -ne $runtime.domain.dn -and $LocationTable.Parent -like "OU=*") { try { write-loghandler -level "warning" -message ("Parent '{0}' doesn't seem to exist; trying to create it...." -f $LocationTable.Parent) -target $LocationTable.Parent CreateOrSetOU -DistinguishedName $LocationTable.Parent -server $server New-ADOrganizationalUnit -server $server -name $LocationTable.LeafName -path $LocationTable.Parent @OUParams -confirm:$false } catch { throw $_ } } else { write-loghandler -level "Warning" -message ("Parent {0} doesn't exist and isn't an OU" -f $LocationTable.Parent) throw $_ } } $output['Status'] ="New" $CreatedOUs.add($LocationTable.DistinguishedName) } catch [Microsoft.ActiveDirectory.Management.ADException] { if ($_.exception.innerException -like "*already exists*") { # the OU already exists } else { write-loghandler -level "Debug" -message "Not sure what this error is, throw it." -target $LocationTable.DistinguishedName -indentLevel 3 $output['Status'] ="Error" throw $_ } } catch { write-loghandler -level "Debug" -message "Not sure what this is-- throw it to trap" -target $LocationTable.DistinguishedName -indentLevel 2 throw $_ } if ($WhatIfPreference.isPresent) { $output['Status'] ="{0}(Whatif)" -f $output['Status'] } [pscustomobject]$Output } END { write-progress -Activity "CreateOrSetOU" -Completed for ($i = 0; $i -lt $CreatedOUs.count; $i++) { #foreach ($OU in $CreatedOUs) { $ProgressActivity = "Waiting for creation of new OUs (total: {0} " -f $CreatedOUs.count $OU = $CreatedOUs[$i] Write-Progress -Activity $ProgressActivity -PercentComplete (($i/$createdOUs.count) * 100) try { Get-ADOrganizationalUnit -server $server -identity $OU | out-null } catch [Microsoft.ActiveDirectory.Management.ADIdentityNotFoundException] { for ($j = 0; $j -lt $Settings.AppSettings.SleepTimeout; $j+=$Settings.AppSettings.SleepLength) { $OUExists = [bool](Get-ADOrganizationalUnit -server $server -filter "distinguishedName -eq '$OU'") if ($OUExists) { break } $status = "Checking $OU (waiting for $j seconds)" Write-Progress -Activity $ProgressActivity -Status $status -CurrentOperation $status -SecondsRemaining $($Settings.AppSettings.SleepLength - $j) start-sleep -seconds $Settings.AppSettings.SleepLength } Write-Progress -Activity $ProgressActivity -completed } catch { write-warning $_.exception.getType().fullname throw $_ } Write-Progress -Activity $ProgressActivity -completed } } } |