ADEssentials.psm1
function Get-WinADForestReplication { [CmdletBinding()] param([switch] $Extended, [Array] $DomainControllers) if (-not $DomainControllers) { $DomainControllers = Get-WinADForestControllers } $ProcessErrors = [System.Collections.Generic.List[PSCustomObject]]::new() $Replication = foreach ($DC in $DomainControllers) { try { Get-ADReplicationPartnerMetadata -Target $DC.HostName -Partition * -ErrorAction Stop } catch { Write-Warning -Message "Get-WinADForestReplication - Error on server $($_.Exception.ServerName): $($_.Exception.Message)" $ProcessErrors.Add([PSCustomObject] @{Server = $_.Exception.ServerName; StatusMessage = $_.Exception.Message }) } } foreach ($_ in $Replication) { $ServerPartner = (Resolve-DnsName -Name $_.PartnerAddress -Verbose:$false -ErrorAction SilentlyContinue) $ServerInitiating = (Resolve-DnsName -Name $_.Server -Verbose:$false -ErrorAction SilentlyContinue) $ReplicationObject = [ordered] @{Server = $_.Server ServerIPV4 = $ServerInitiating.IP4Address ServerPartner = $ServerPartner.NameHost ServerPartnerIPV4 = $ServerPartner.IP4Address LastReplicationAttempt = $_.LastReplicationAttempt LastReplicationResult = $_.LastReplicationResult LastReplicationSuccess = $_.LastReplicationSuccess ConsecutiveReplicationFailures = $_.ConsecutiveReplicationFailures LastChangeUsn = $_.LastChangeUsn PartnerType = $_.PartnerType Partition = $_.Partition TwoWaySync = $_.TwoWaySync ScheduledSync = $_.ScheduledSync SyncOnStartup = $_.SyncOnStartup CompressChanges = $_.CompressChanges DisableScheduledSync = $_.DisableScheduledSync IgnoreChangeNotifications = $_.IgnoreChangeNotifications IntersiteTransport = $_.IntersiteTransport IntersiteTransportGuid = $_.IntersiteTransportGuid IntersiteTransportType = $_.IntersiteTransportType UsnFilter = $_.UsnFilter Writable = $_.Writable Status = if ($_.LastReplicationResult -ne 0) { $false } else { $true } StatusMessage = "Last successful replication time was $($_.LastReplicationSuccess), Consecutive Failures: $($_.ConsecutiveReplicationFailures)" } if ($Extended) { $ReplicationObject.Partner = $_.Partner $ReplicationObject.PartnerAddress = $_.PartnerAddress $ReplicationObject.PartnerGuid = $_.PartnerGuid $ReplicationObject.PartnerInvocationId = $_.PartnerInvocationId $ReplicationObject.PartitionGuid = $_.PartitionGuid } [PSCustomObject] $ReplicationObject } foreach ($_ in $ProcessErrors) { if ($null -ne $_.Server) { $ServerInitiating = (Resolve-DnsName -Name $_.Server -Verbose:$false -ErrorAction SilentlyContinue) } else { $ServerInitiating = [PSCustomObject] @{IP4Address = '127.0.0.1' } } $ReplicationObject = [ordered] @{Server = $_.Server ServerIPV4 = $ServerInitiating.IP4Address ServerPartner = 'Unknown' ServerPartnerIPV4 = '127.0.0.1' LastReplicationAttempt = $null LastReplicationResult = $null LastReplicationSuccess = $null ConsecutiveReplicationFailures = $null LastChangeUsn = $null PartnerType = $null Partition = $null TwoWaySync = $null ScheduledSync = $null SyncOnStartup = $null CompressChanges = $null DisableScheduledSync = $null IgnoreChangeNotifications = $null IntersiteTransport = $null IntersiteTransportGuid = $null IntersiteTransportType = $null UsnFilter = $null Writable = $null Status = $false StatusMessage = $_.StatusMessage } if ($Extended) { $ReplicationObject.Partner = $null $ReplicationObject.PartnerAddress = $null $ReplicationObject.PartnerGuid = $null $ReplicationObject.PartnerInvocationId = $null $ReplicationObject.PartitionGuid = $null } [PSCustomObject] $ReplicationObject } } Function Get-WinADGPOMissingPermissions { <# .SYNOPSIS Short description .DESCRIPTION Long description .PARAMETER Domain Parameter description .EXAMPLE An example .NOTES Based on https://secureinfra.blog/2018/12/31/most-common-mistakes-in-active-directory-and-domain-services-part-1/ #> [cmdletBinding()] param([string] $Domain = $Env:USERDNSDOMAIN) $GPOs = Get-GPO -All -Domain $Domain $MissingPermissions = @(foreach ($GPO in $GPOs) { If ($GPO.User.Enabled) { $GPOPermissionForAuthUsers = Get-GPPermission -Guid $GPO.Id -All | Select-Object -ExpandProperty Trustee | Where-Object { $_.Name -eq "Authenticated Users" } $GPOPermissionForDomainComputers = Get-GPPermission -Guid $GPO.Id -All | Select-Object -ExpandProperty Trustee | Where-Object { $_.Name -eq "Domain Computers" } If (-not $GPOPermissionForAuthUsers -and -not $GPOPermissionForDomainComputers) { $GPO } } }) $MissingPermissions } function Get-WinADLastBackup { <# .SYNOPSIS Gets Active directory forest or domain last backup time .DESCRIPTION Gets Active directory forest or domain last backup time .PARAMETER Domain Optionally you can pass Domains by hand .EXAMPLE $LastBackup = Get-WinADLastBackup $LastBackup | Format-Table -AutoSize .EXAMPLE $LastBackup = Get-WinADLastBackup -Domain 'ad.evotec.pl' $LastBackup | Format-Table -AutoSize .NOTES General notes #> [cmdletBinding()] param([string[]] $Domains) $NameUsed = [System.Collections.Generic.List[string]]::new() [DateTime] $CurrentDate = Get-Date if (-not $Domains) { try { $Forest = Get-ADForest -ErrorAction Stop $Domains = $Forest.Domains } catch { Write-Warning "Get-WinADLastBackup - Failed to gather Forest Domains $($_.Exception.Message)" } } foreach ($Domain in $Domains) { try { [string[]]$Partitions = (Get-ADRootDSE -Server $Domain -ErrorAction Stop).namingContexts [System.DirectoryServices.ActiveDirectory.DirectoryContextType] $contextType = [System.DirectoryServices.ActiveDirectory.DirectoryContextType]::Domain [System.DirectoryServices.ActiveDirectory.DirectoryContext] $context = New-Object System.DirectoryServices.ActiveDirectory.DirectoryContext($contextType, $Domain) [System.DirectoryServices.ActiveDirectory.DomainController] $domainController = [System.DirectoryServices.ActiveDirectory.DomainController]::FindOne($context) } catch { Write-Warning "Get-WinADLastBackup - Failed to gather partitions information for $Domain with error $($_.Exception.Message)" } $Output = ForEach ($Name in $Partitions) { if ($NameUsed -contains $Name) { continue } else { $NameUsed.Add($Name) } $domainControllerMetadata = $domainController.GetReplicationMetadata($Name) $dsaSignature = $domainControllerMetadata.Item("dsaSignature") $LastBackup = [DateTime] $($dsaSignature.LastOriginatingChangeTime) [PSCustomObject] @{Domain = $Domain NamingContext = $Name LastBackup = $LastBackup LastBackupDaysAgo = - (Convert-TimeToDays -StartTime ($CurrentDate) -EndTime ($LastBackup)) } } $Output } } Function Get-WinADPriviligedObjects { [cmdletbinding()] param([switch] $LegitimateOnly, [switch] $OrphanedOnly, [switch] $Unique, [switch] $SummaryOnly) $Forest = Get-ADForest $Domains = $Forest.Domains $UsersWithAdminCount = foreach ($domain in $Domains) { $Objects = Get-ADObject -filter 'admincount -eq 1 -and iscriticalsystemobject -notlike "*"' -server $domain -properties whenchanged, whencreated, admincount, isCriticalSystemObject, "msDS-ReplAttributeMetaData", samaccountname foreach ($_ in $Objects) { [PSCustomObject] @{Domain = $Domain distinguishedname = $_.distinguishedname whenchanged = $_.whenchanged whencreated = $_.whencreated admincount = $_.admincount SamAccountName = $_.SamAccountName objectclass = $_.objectclass isCriticalSystemObject = $_.isCriticalSystemObject adminCountDate = ($_.'msDS-ReplAttributeMetaData' | ForEach-Object { ([XML]$_.Replace("`0", "")).DS_REPL_ATTR_META_DATA | Where-Object { $_.pszAttributeName -eq "admincount" } }).ftimeLastOriginatingChange | Get-Date -Format MM/dd/yyyy } } } $CriticalGroups = foreach ($domain in $Domains) { Get-ADGroup -filter 'admincount -eq 1 -and iscriticalsystemobject -eq $true' -server $domain | Select-Object @{name = 'Domain'; expression = { $domain } }, distinguishedname } $AdminCountLegitimate = [System.Collections.Generic.List[PSCustomObject]]::new() $AdminCountOrphaned = [System.Collections.Generic.List[PSCustomObject]]::new() $AdminCountAll = foreach ($object in $UsersWithAdminCount) { $DistinguishedName = ($object).distinguishedname $Results = foreach ($Group in $CriticalGroups) { $IsMember = if (Get-ADGroup -Filter { Member -RecursiveMatch $DistinguishedName } -searchbase $Group.DistinguishedName -server $Group.Domain) { $True } else { $False } $User = [PSCustomObject] @{DistinguishedName = $Object.DistinguishedName Domain = $Object.domain IsMember = $IsMember Admincount = $Object.admincount AdminCountDate = $Object.adminCountDate Whencreated = $Object.whencreated ObjectClass = $Object.objectclass GroupDomain = if ($IsMember) { $Group.Domain } else { $null } GroupDistinguishedname = if ($IsMember) { $Group.DistinguishedName } else { $null } } if ($User.IsMember) { $AdminCountLegitimate.Add($User) $User } if ($User.IsMember -eq $false -and $AdminCountLegitimate.DistinguishedName -notcontains $User.DistinguishedName -and $AdminCountOrphaned.DistinguishedName -notcontains $User.DistinguishedName) { $Properties = @('distinguishedname' 'domain' 'IsMember' 'admincount' 'adminCountDate' 'whencreated' 'objectclass') $AdminCountOrphaned.Add(($User | Select-Object -Property $Properties)) $User } } $Results } $Output = @(if ($OrphanedOnly) { $AdminCountOrphaned } elseif ($LegitimateOnly) { if ($Unique) { $AdminCountLegitimate | Select-Object -Property DistinguishedName, Domain, IsMember, Admincount, AdminCountDate, Whencreated, ObjectClass -Unique } else { $AdminCountLegitimate } } else { if ($Unique) { $AdminCountAll | Select-Object -Property DistinguishedName, Domain, IsMember, Admincount, AdminCountDate, Whencreated, ObjectClass -Unique } else { $AdminCountAll } }) if ($SummaryOnly) { $Output | Group-Object ObjectClass | Select-Object -Property Name, Count } else { $Output } } function Get-WinADSiteConnections { [CmdletBinding()] param([alias('Joiner')][string] $Splitter, [string] $Formatted) [Flags()] enum ConnectionOption { None IsGenerated TwoWaySync OverrideNotifyDefault = 4 UseNotify = 8 DisableIntersiteCompression = 16 UserOwnedSchedule = 32 RodcTopology = 64 } $NamingContext = (Get-ADRootDSE).configurationNamingContext $Connections = Get-ADObject –Searchbase $NamingContext -LDAPFilter "(objectCategory=ntDSConnection)" -Properties * $FormmatedConnections = foreach ($_ in $Connections) { if ($null -eq $_.Options) { $Options = 'None' } else { $Options = ([ConnectionOption] $_.Options) -split ', ' } if ($Formatted) { $Dictionary = [PSCustomObject] @{'CN' = $_.CN 'Description' = $_.Description 'Display Name' = $_.DisplayName 'Enabled Connection' = $_.enabledConnection 'Server From' = if ($_.fromServer -match '(?<=CN=NTDS Settings,CN=)(.*)(?=,CN=Servers,)') { $Matches[0] } else { $_.fromServer } 'Server To' = if ($_.DistinguishedName -match '(?<=CN=NTDS Settings,CN=)(.*)(?=,CN=Servers,)') { $Matches[0] } else { $_.fromServer } 'Site From' = if ($_.fromServer -match '(?<=,CN=Servers,CN=)(.*)(?=,CN=Sites,CN=Configuration)') { $Matches[0] } else { $_.fromServer } 'Site To' = if ($_.DistinguishedName -match '(?<=,CN=Servers,CN=)(.*)(?=,CN=Sites,CN=Configuration)') { $Matches[0] } else { $_.fromServer } 'Options' = if ($Splitter -ne '') { $Options -Join $Splitter } else { $Options } 'When Created' = $_.WhenCreated 'When Changed' = $_.WhenChanged 'Is Deleted' = $_.IsDeleted } } else { $Dictionary = [PSCustomObject] @{CN = $_.CN Description = $_.Description DisplayName = $_.DisplayName EnabledConnection = $_.enabledConnection ServerFrom = if ($_.fromServer -match '(?<=CN=NTDS Settings,CN=)(.*)(?=,CN=Servers,)') { $Matches[0] } else { $_.fromServer } ServerTo = if ($_.DistinguishedName -match '(?<=CN=NTDS Settings,CN=)(.*)(?=,CN=Servers,)') { $Matches[0] } else { $_.fromServer } SiteFrom = if ($_.fromServer -match '(?<=,CN=Servers,CN=)(.*)(?=,CN=Sites,CN=Configuration)') { $Matches[0] } else { $_.fromServer } SiteTo = if ($_.DistinguishedName -match '(?<=,CN=Servers,CN=)(.*)(?=,CN=Sites,CN=Configuration)') { $Matches[0] } else { $_.fromServer } Options = if ($Splitter -ne '') { $Options -Join $Splitter } else { $Options } WhenCreated = $_.WhenCreated WhenChanged = $_.WhenChanged IsDeleted = $_.IsDeleted } } $Dictionary } $FormmatedConnections } function Get-WinADSiteLinks { [CmdletBinding()] param([alias('Joiner')][string] $Splitter, [string] $Formatted) [Flags()] enum SiteLinksOptions { None = 0 UseNotify = 1 TwoWaySync = 2 DisableCompression = 4 } $NamingContext = (Get-ADRootDSE).configurationNamingContext $SiteLinks = Get-ADObject -LDAPFilter "(objectCategory=sitelink)" –Searchbase $NamingContext -Properties * foreach ($_ in $SiteLinks) { if ($null -eq $_.Options) { $Options = 'None' } else { $Options = ([SiteLinksOptions] $_.Options) -split ', ' } if ($Formatted) { [PSCustomObject] @{Name = $_.CN Cost = $_.Cost 'Replication Frequency In Minutes' = $_.ReplInterval Options = if ($Splitter -ne '') { $Options -Join $Splitter } else { $Options } Created = $_.WhenCreated Modified = $_.WhenChanged 'Protected From Accidental Deletion' = $_.ProtectedFromAccidentalDeletion } } else { [PSCustomObject] @{Name = $_.CN Cost = $_.Cost ReplicationFrequencyInMinutes = $_.ReplInterval Options = if ($Splitter -ne '') { $Options -Join $Splitter } else { $Options } Created = $_.WhenCreated Modified = $_.WhenChanged ProtectedFromAccidentalDeletion = $_.ProtectedFromAccidentalDeletion } } } } function Get-WinADUsersForeignSecurityPrincipalList { [alias('Get-WinADUsersFP')] param([string] $Domain) $ForeignSecurityPrincipalList = Get-ADObject -Filter { ObjectClass -eq 'ForeignSecurityPrincipal' } -Properties * -Server $Domain foreach ($FSP in $ForeignSecurityPrincipalList) { Try { $Translated = (([System.Security.Principal.SecurityIdentifier]::new($FSP.objectSid)).Translate([System.Security.Principal.NTAccount])).Value } Catch { $Translated = $null } Add-Member -InputObject $FSP -Name 'TranslatedName' -Value $Translated -MemberType NoteProperty -Force } $ForeignSecurityPrincipalList } function Set-WinADReplication { [CmdletBinding()] param([int] $ReplicationInterval = 15, [switch] $Instant) $NamingContext = (Get-ADRootDSE).configurationNamingContext Get-ADObject -LDAPFilter "(objectCategory=sitelink)" –Searchbase $NamingContext -Properties options | ForEach-Object { if ($Instant) { Set-ADObject $_ -replace @{replInterval = $ReplicationInterval } Set-ADObject $_ –replace @{options = $($_.options -bor 1) } } else { Set-ADObject $_ -replace @{replInterval = $ReplicationInterval } } } } function Set-WinADReplicationConnections { [CmdletBinding()] param([switch] $Force) [Flags()] enum ConnectionOption { None IsGenerated TwoWaySync OverrideNotifyDefault = 4 UseNotify = 8 DisableIntersiteCompression = 16 UserOwnedSchedule = 32 RodcTopology = 64 } $NamingContext = (Get-ADRootDSE).configurationNamingContext $Connections = Get-ADObject –Searchbase $NamingContext -LDAPFilter "(objectCategory=ntDSConnection)" -Properties * foreach ($_ in $Connections) { $OptionsTranslated = [ConnectionOption] $_.Options if ($OptionsTranslated -like '*IsGenerated*' -and -not $Force) { Write-Verbose "Set-WinADReplicationConnections - Skipping $($_.CN) automatically generated link" } else { Write-Verbose "Set-WinADReplicationConnections - Changing $($_.CN)" Set-ADObject $_ –replace @{options = $($_.options -bor 8) } } } } function Sync-DomainController { [CmdletBinding()] param([string] $Domain = $Env:USERDNSDOMAIN) $DistinguishedName = (Get-ADDomain -Server $Domain).DistinguishedName (Get-ADDomainController -Filter * -Server $Domain).Name | ForEach-Object { Write-Verbose -Message "Sync-DomainController - Forcing synchronization $_" repadmin /syncall $_ $DistinguishedName /e /A | Out-Null } } function Test-ADRolesAvailability { [cmdletBinding()] param([string] $Domain) $ADModule = Import-Module PSWinDocumentation.AD -PassThru $Roles = & $ADModule { param($Domain); Get-WinADForestRoles -Domain $Domain } $Domain if ($Domain -ne '') { [PSCustomObject] @{PDCEmulator = $Roles['PDCEmulator'] PDCEmulatorAvailability = if ($Roles['PDCEmulator']) { (Test-NetConnection -ComputerName $Roles['PDCEmulator']).PingSucceeded } else { $false } RIDMaster = $Roles['RIDMaster'] RIDMasterAvailability = if ($Roles['RIDMaster']) { (Test-NetConnection -ComputerName $Roles['RIDMaster']).PingSucceeded } else { $false } InfrastructureMaster = $Roles['InfrastructureMaster'] InfrastructureMasterAvailability = if ($Roles['InfrastructureMaster']) { (Test-NetConnection -ComputerName $Roles['InfrastructureMaster']).PingSucceeded } else { $false } } } else { [PSCustomObject] @{SchemaMaster = $Roles['SchemaMaster'] SchemaMasterAvailability = if ($Roles['SchemaMaster']) { (Test-NetConnection -ComputerName $Roles['SchemaMaster']).PingSucceeded } else { $false } DomainNamingMaster = $Roles['DomainNamingMaster'] DomainNamingMasterAvailability = if ($Roles['DomainNamingMaster']) { (Test-NetConnection -ComputerName $Roles['DomainNamingMaster']).PingSucceeded } else { $false } } } } function Test-ADSiteLinks { [cmdletBinding()] param([string] $Splitter) [Array] $SiteLinks = Get-WinADSiteConnections $Collection = @($SiteLinks).Where( { $_.Options -notcontains 'IsGenerated' -and $_.EnabledConnection -eq $true }, 'Split') $LinksManual = foreach ($Link in $Collection[0]) { "$($Link.ServerFrom) to $($Link.ServerTo)" } $LinksAutomatic = foreach ($Link in $Collection[1]) { "$($Link.ServerFrom) to $($Link.ServerTo)" } $CollectionNotifications = @($SiteLinks).Where( { $_.Options -notcontains 'UseNotify' -and $_.EnabledConnection -eq $true }, 'Split') $LinksNotUsingNotifications = foreach ($Link in $CollectionNotifications[0]) { "$($Link.ServerFrom) to $($Link.ServerTo)" } $LinksUsingNotifications = foreach ($Link in $CollectionNotifications[1]) { "$($Link.ServerFrom) to $($Link.ServerTo)" } [ordered] @{SiteLinksManual = if ($Splitter -eq '') { $LinksManual } else { $LinksManual -join $Splitter } SiteLinksAutomatic = if ($Splitter -eq '') { $LinksAutomatic } else { $LinksAutomatic -join $Splitter } SiteLinksUseNotify = if ($Splitter -eq '') { $LinksUsingNotifications } else { $LinksUsingNotifications -join $Splitter } SiteLinksNotUsingNotify = if ($Splitter -eq '') { $LinksNotUsingNotifications } else { $LinksNotUsingNotifications -join $Splitter } SiteLinksUseNotifyCount = $CollectionNotifications[1].Count SiteLinksNotUsingNotifyCount = $CollectionNotifications[0].Count SiteLinksManualCount = $Collection[0].Count SiteLinksAutomaticCount = $Collection[1].Count SiteLinksTotalCount = ($SiteLinks | Where-Object { $_.EnabledConnection -eq $true }).Count } } function Test-DNSNameServers { [cmdletBinding()] param([string] $DomainController, [string] $Domain) if ($DomainController) { $AllDomainControllers = (Get-ADDomainController -Server $Domain -Filter { IsReadOnly -eq $false }).HostName try { $Hosts = Get-DnsServerResourceRecord -ZoneName $Domain -ComputerName $DomainController -RRType NS -ErrorAction Stop $NameServers = (($Hosts | Where-Object { $_.HostName -eq '@' }).RecordData.NameServer) -replace ".$" $Compare = ((Compare-Object -ReferenceObject $AllDomainControllers -DifferenceObject $NameServers -IncludeEqual).SideIndicator -notin @('=>', '<=')) [PSCustomObject] @{DomainControllers = $AllDomainControllers NameServers = $NameServers Status = $Compare Comment = "Name servers found $($NameServers -join ', ')" } } catch { [PSCustomObject] @{DomainControllers = $AllDomainControllers NameServers = $null Status = $false Comment = $_.Exception.Message } } } } function Test-FSMORolesAvailability { [cmdletBinding()] param([string] $Domain = $Env:USERDNSDOMAIN) $DC = Get-ADDomainController -Server $Domain -Filter * $Output = foreach ($S in $DC) { if ($S.OperationMasterRoles.Count -gt 0) { $Status = Test-Connection -ComputerName $S.HostName -Count 2 -Quiet } else { $Status = $null } foreach ($_ in $S.OperationMasterRoles) { [PSCustomObject] @{Role = $_ HostName = $S.HostName Status = $Status } } } $Output } Function Test-LDAP { [CmdletBinding()] param ([alias('Server', 'IpAddress')][Parameter(Mandatory = $True)][string[]]$ComputerName, [int] $GCPortLDAP = 3268, [int] $GCPortLDAPSSL = 3269, [int] $PortLDAP = 389, [int] $PortLDAPS = 636) foreach ($Computer in $ComputerName) { [Array] $ADServerFQDN = (Resolve-DnsName -Name $Computer -ErrorAction SilentlyContinue) if ($ADServerFQDN) { if ($ADServerFQDN.NameHost) { $ServerName = $ADServerFQDN[0].NameHost } else { [Array] $ADServerFQDN = (Resolve-DnsName -Name $Computer -ErrorAction SilentlyContinue) $FilterName = $ADServerFQDN | Where-Object { $_.QueryType -eq 'A' } $ServerName = $FilterName[0].Name } } else { $ServerName = '' } $GlobalCatalogSSL = Test-LDAPPorts -ServerName $ServerName -Port $GCPortLDAPSSL $GlobalCatalogNonSSL = Test-LDAPPorts -ServerName $ServerName -Port $GCPortLDAP $ConnectionLDAPS = Test-LDAPPorts -ServerName $ServerName -Port $PortLDAPS $ConnectionLDAP = Test-LDAPPorts -ServerName $ServerName -Port $PortLDAP $PortsThatWork = @(if ($GlobalCatalogNonSSL) { $GCPortLDAP } if ($GlobalCatalogSSL) { $GCPortLDAPSSL } if ($ConnectionLDAP) { $PortLDAP } if ($ConnectionLDAPS) { $PortLDAPS }) | Sort-Object [pscustomobject]@{Computer = $Computer ComputerFQDN = $ServerName GlobalCatalogLDAP = $GlobalCatalogNonSSL GlobalCatalogLDAPS = $GlobalCatalogSSL LDAP = $ConnectionLDAP LDAPS = $ConnectionLDAPS AvailablePorts = $PortsThatWork -join ',' } } } function Test-LDAPPorts { [CmdletBinding()] param([string] $ServerName, [int] $Port) if ($ServerName -and $Port -ne 0) { try { $LDAP = "LDAP://" + $ServerName + ':' + $Port $Connection = [ADSI]($LDAP) $Connection.Close() return $true } catch { if ($_.Exception.ToString() -match "The server is not operational") { Write-Warning "Can't open $ServerName`:$Port." } elseif ($_.Exception.ToString() -match "The user name or password is incorrect") { Write-Warning "Current user ($Env:USERNAME) doesn't seem to have access to to LDAP on port $Server`:$Port" } else { Write-Warning -Message $_ } } return $False } } Export-ModuleMember -Function @('Get-WinADForestReplication', 'Get-WinADGPOMissingPermissions', 'Get-WinADLastBackup', 'Get-WinADPriviligedObjects', 'Get-WinADSiteConnections', 'Get-WinADSiteLinks', 'Get-WinADUsersForeignSecurityPrincipalList', 'Set-WinADReplication', 'Set-WinADReplicationConnections', 'Sync-DomainController', 'Test-ADRolesAvailability', 'Test-ADSiteLinks', 'Test-DNSNameServers', 'Test-FSMORolesAvailability', 'Test-LDAP') -Alias @('Get-WinADUsersFP') |