Public/Get-ADLocalDC.ps1
|
#Requires -Modules ps_Module_ActiveDirectoryTools Function Get-ADLocalDC() { <# .SYNOPSIS This function will attempt to return an available domain controller in the same Active Directory site as the computer calling the function. It provides functionality to use either .net calls (default) or the ActiveDirectory module for Powershell cmdlet to validate the availability of the Domain Controller IMPORTANT: This function relies on the function Get-ADComputerSite which is available in this module .PARAMETER UsePsAdCommand Optional. Default = no. This will use the PowerShell module for ActiveDirectory command "Get-ADDomain" to validate the domain controller availability. This is useful for testing AD WebServices availability. If this parameter is not specified the domain controller will be validated using the .net System.DirectoryServices.DirectoryEntry class. .PARAMETER Verbose Optional. This will print the steps taken to discover the DC in the local site .DESCRIPTION This function uses the .net class System.DirectoryServices.ActiveDirectory.DomainController to discover the domain controllers in the AD site. Each DC is tested in turn until a valid Domain Controller has been discovered. .INPUTS See parameters. .OUTPUTS This function will return a string containing an available domain controller located in the same AD site as the computer calling the function. .EXAMPLE Import-Module ps_Module_ActiveDirectoryTools $sDomainController = Get-ADLocalDC .NOTES MVogwell - October 2022 - Version 1.0 Version history: 1.0 - Initial tested release 1.1 - Updated to remove .net calls to enable pester testing #> [CmdletBinding()] [OutputType([System.String])] param ( [Parameter(Mandatory=$false)][switch]$UsePsAdCommand ) $ErrorActionPreference = "Stop" # This function attempts to discover an available domain controller in the local AD site # The UsePsADCommand $sRtnDcName = "" # Get local AD site name - call function to get this. This could trigger an error $sAdSite = Get-ADComputerSite # Confirm the local AD site name could be discovered if ($null -eq $sAdSite) { throw "Failed to discover local AD site name" } # Call Get-ADDomainControllersBySite function to return the Domain Controllers within a specific site # The function will be loaded by importing the base module. $arrDomainControllers = Get-ADDomainControllersBySite -sAdSite $sAdSite # Confirm at least one DC has been returned if ($null -eq $arrDomainControllers) { throw "Failed to discover any domain controllers" } # Test the availability of the domain controllers foreach ($objDc in $arrDomainControllers) { Write-Verbose "`t=== Testing DC: $($objDc.Name)" $objAd = $null try { if ($UsePsAdCommand -eq $true) { $objAd = Get-ADDomain -Server $objDc.Name -ErrorAction "Stop" # If the search was successful if (!($null -eq $objAD)) { $sRtnDcName = $objDc.name Write-Verbose "`t`t+++ Successfully tested $($objDc.Name)" break # escape the AD loop } } else { # Validate the domain controller available - calls function Get-ADDomainControllerRootEntry which # loaded during the module import $objAD = Get-ADDomainControllerRootEntry -sDCName $objDc.Name # Confirm the returned object isn't null then confirm if the returned data contains a property called defaultNamingContext # if it does then the .net function from Get-ADDomainControllerRootEntry has discovered an available active Domain Controller if (!($null -eq $objAd)) { if ((($objAd | Get-Member -MemberType Properties | Select-Object -ExpandProperty name) -contains "defaultNamingContext") -eq $true) { $sRtnDcName = $objDc.Name # Function Test-QuickTcpConnection is available in the module and loaded when the module is imported $bADWebServicesPortAvailable = Test-QuickTcpConnection -sComputerName $objDc.Name -iPort 9389 if ($bADWebServicesPortAvailable -eq $true) { Write-Verbose "`t`t+++ SUCCESS: DC $($objDC.Name) has been validated" break # escape the AD loop - a DC has been found so no need to keep searching } else { # AD Web Services (reqd for PowerShell modules) is not available on the destination DC Write-Verbose "`t`t--- DC $($objDC.Name) is up but AD Web Services is not available" } } else { Write-Verbose "`t`t--- DC $($objDC.Name) did not respond with a valid defaultNamingContext value" } } else { Write-Verbose "`t`t--- DC $($objDC.Name) did not response with any valid data" } } } catch { $objAd = $null $sErrMsg = ("Domain Controller $($objDC.Name) not available. Error: " + (($Global:Error[0].exception).toString()).replace("`r"," ").replace("`n"," ")) Write-Verbose "`t`t--- $sErrMsg" } } # Check that a DC was discovered - throw error if not found if ([string]::IsNullOrEmpty($sRtnDcName) -eq $true) { throw "Failed to discover an available Domain Controller in the local site" } return $sRtnDcName } |