functions/Show-Domain.ps1
Function Show-DomainTree { [cmdletbinding()] [OutputType("String")] [alias("dt")] Param( [Parameter(Position = 0, HelpMessage = "Specify the domain name. The default is the user domain.")] [ValidateNotNullOrEmpty()] [string]$Name = $env:USERDOMAIN, [Parameter(HelpMessage = "Specify a domain controller to query.")] [alias("dc", "domaincontroller")] [string]$Server, [Parameter(HelpMessage = "Specify an alternate credential.")] [alias("RunAs")] [PSCredential]$Credential, [Parameter(HelpMessage = "Display the domain tree using distinguished names.")] [alias("dn")] [switch]$UseDN, [Parameter(HelpMessage = "Include containers and non-OU elements. Items with a GUID in the name will be omitted.")] [alias("cn")] [switch]$Containers ) Write-Verbose "Starting $($myinvocation.MyCommand)" Function Get-OUTree { [cmdletbinding()] Param( [string]$Path = (Get-ADDomain).DistinguishedName, [string]$Server, [Parameter(HelpMessage = "Specify an alternate credential")] [PSCredential]$Credential, [Parameter(HelpMessage = "Display the distinguishedname")] [switch]$UseDN, [Parameter(HelpMessage = "Include containers")] [alias("cn")] [switch]$Containers, [Parameter(HelpMessage = "Used in recursion only. You don't need to specify anything")] [Int]$Indent = 1, [Parameter(HelpMessage = "Used in recursion only. You don't need to specify anything")] [switch]$Children ) Write-Verbose "Searching path $path" function GetIndentString { [CmdletBinding()] Param([int]$Indent) $charHash = @{ upperLeft = [char]0x250c upperRight = [char]0x2510 lowerRight = [char]0x2518 lowerLeft = [char]0x2514 horizontal = [char]0x2500 vertical = [char]0x2502 join = [char]0x251c } if ($Children) { if ($indent -eq 5) { $indent += 2 } elseif ($indent -eq 7) { $indent += 4 } $pad = " " * ($Indent) if ($script:IsLast) { #write-Host "LAST" -ForegroundColor magenta $str += " $pad{0}{1} " -f $charHash.join, ([string]$charHash.horizontal * 2 ) } else { $str += "{0}$pad{1}{2} " -f $charHash.vertical, $charHash.join, ([string]$charHash.horizontal * 2 ) } } else { if ($script:IsLast) { $c = $charHash.lowerleft } else { $c = $charHash.join } $str = "{0}{1} " -f $c, ([string]$charHash.horizontal * 2 ) } $str } #GUID Regex [regex]$Guid = "\w{8}-(\w{4}-){3}\w{12}" #parameters to splat for the search if ($Containers) { $filter = "(|(objectclass=container)(objectclass=organizationalUnit))" } else { $filter = "objectclass=organizationalUnit" } $search = @{ LDAPFilter = $filter SearchScope = "OneLevel" SearchBase = $path Properties = "ProtectedFromAccidentalDeletion" } "Server", "Credential" | ForEach-Object { if ($PSBoundParameters.ContainsKey($_)) { $search.Add($_, $PSBoundParameters[$_]) } } $data = Get-ADObject @search | Sort-Object -Property DistinguishedName if ($Containers) { #filter out GUID named entries $data = $data | Where-Object { $_.name -notmatch $GUID } } if ($path -match "^DC\=") { $top = $data $last = $top[-1].distinguishedname $script:IsLast = $False Write-Verbose "Last top level is $last" } if ($data ) { $data | ForEach-Object { if ($UseDN) { $name = $_.distinguishedname } else { $name = $_.name } if ($script:IsLast) { Write-Verbose "Processing last items" } else { $script:IsLast = $_.distinguishedname -eq $last } if ($_.ProtectedFromAccidentalDeletion) { #display protected OUs in color $nameValue = "$($ADReportingToolsOptions.Protected)$name$([char]0x1b)[0m" } elseif ($_.objectclass -eq 'container') { $nameValue = "$($ADReportingToolsOptions.Container)$name$([char]0x1b)[0m" } elseif ($_.objectclass -eq 'organizationalUnit') { #display non-OU and non-Container in a different color $nameValue = "$($ADReportingToolsOptions.OrganizationalUnit)$name$([char]0x1b)[0m" } else { $nameValue = "$($ADReportingToolsOptions.Other)$name$([char]0x1b)[0m" } "{0}{1}" -f (GetIndentString -indent $indent), $nameValue $PSBoundParameters["Path"] = $_.DistinguishedName $PSBoundParameters["Indent"] = $Indent + 2 $PSBoundParameters["children"] = $True #call the nested function recursively Get-OUTree @PSBoundParameters } } #if $data } if ($host.name -match 'ConsoleHost') { $getAD = @{ ErrorAction = "stop" Identity = $Name } "Server", "Credential" | ForEach-Object { if ($PSBoundParameters.ContainsKey($_)) { $getAD.Add($_, $PSBoundParameters[$_]) } } Try { Write-Verbose "Getting distinguished name for $($Name.toUpper())" $getAD | Out-String | Write-Verbose [string]$Path = (Get-ADDomain @getAD).DistinguishedName #Passing these bound parameters to another function which needs the Path $PSBoundParameters.add("Path", $Path) [void]($PSBoundParameters.remove("Name")) } Catch { Throw $_ } #display to top level container and then get children $top = @" $($ADReportingToolsOptions.DomainDNS)$Path$([char]0x1b)[0m $([char]0x2502) "@ $top #get child OUs Get-OUTree @PSBoundParameters #display a footer $tz = Get-TimeZone if ((Get-Date).IsDaylightSavingTime()) { $tzname = $tz.daylightName } else { $tzname = $tz.StandardName } $date = Get-Date -Format g $footer = @" $($ADReportingToolsOptions.OrganizationalUnit)Organizational Units$([char]0x1b)[0m $($ADReportingToolsOptions.Protected)Protected from Deletion$([char]0x1b)[0m $($ADReportingToolsOptions.Container)Containers$([char]0x1b)[0m $($ADReportingToolsOptions.Other)Other$([char]0x1b)[0m $date $tzname "@ $footer } else { Write-Host "This command should be run in a PowerShell Console host. It will NOT run in the PowerShell ISE or VS Code." -ForegroundColor magenta } Write-Verbose "Ending $($myinvocation.MyCommand)" } |