Domain controllers required ports: Use PowerShell to check if they are listening

An Active Directory domain controller needs to listen on specific ports to service different client requests. For example, when a client computer needs to authenticate, it connects to a server which hosts KDC service and which is listening on the Port 88. Similarly, network ports TCP 139 and UDP 138 are required by the SYSVOL replication service that takes place between all domain controllers. At a minimum, they must listen on these required ports:

  • UDP Port 88 is required for authentication purposes. UDP Port 88 is used by clients and domain controllers to authenticate with each other.
  • Both UDP and TCP Port 135 are required for communication between domain controllers and clients to domain controllers.
  • TCP Port 139 and UDP 138 network ports are used by the SYSVOL replication service to replicate contents of SYSVOL folder.
  • UDP Port 389 for LDAP network port is used to handle normal authentication queries from client computers.
  • TCP and UDP Port 464 is used for Kerberos Password Change.
  • TCP Port 3268 and 3269 are required for Global Catalog communication from clients to domain controllers. Global catalog servers help in finding an object in the Active Directory quickly.
  • Both DNS TCP and UDP 53 network ports are used by clients and domain controllers for name resolution purposes.

Check the network port status on a domain controller

If you wish to check the network port status on a specific domain controller, you can run a simple NetStat command that will list all the network ports that a domain controller is listening on. To check the port status on a particular domain controller and to save the output to a text file, execute this command:

Netstat –an –b | find /I “’Listening” > C:\Temp\DCPorts.txt

When you execute the command, it checks all the ports that are listening on a domain controller and then saves the output to C:\Temp\DCPorts.TXT file. You can navigate through the file to ensure the domain controller is listening on the required network ports. However, it becomes difficult if you need to check network ports status on each domain controller. It might take a considerable amount of time if you use the above method to check the status of each port on each domain controller. This is where this article comes in handy. Here we provide a PowerShell script that connects to each domain controller and then collects the network port status.

Requirements for running the PowerShell script

Make sure you run the script from a Windows Server 2012 R2 member server or domain controller, and ensure to create a Temp folder on the C:\ drive as script generates a report by name “DCPortReport.CSV” under the C:\Temp folder. Apart from meeting the above requirements, there are a few other requirements that you need to meet:

  • First, download PortQry from Microsoft. The script uses the tool to collect the port status from the target domain controller.
  • Create a text file named “DCList.TXT” that contains the Active Directory domain controller names.

The script checks common domain controller ports such as UDP-389, TCP-389, UDP-135, TCP-135, UDP-88, TCP-88, UDP-445, and TCP-445. The status for each port is provided in the report generated by the script.


$TestCSVFile = “C:\Temp\DCPortReport.CSV”
Remove-Item $TestCSVFile -ErrorAction SilentlyContinue
$ThisString=”Domain Controller,Connection,Command Status, UDP-389, TCP-389, UDP-135, TCP-135, UDP-88, TCP-88, UDP-445, TCP-445,Final Status”
Add-Content “$TestCSVFile” $ThisString
$TestStatus=”Passed”
$TestText = “”
$sumVal=0
$ReachOrNot = “Yes”
$AnyGap = “No”
$TotNo = 0
$AnyOneOk=”No”
$IntDirNow = “C:\ReqPortTest”
mkdir $IntDirNow -Force
$PortQryExe = “C:\Temp\PortQry.exe”
Foreach ($ItemName in Get-Content “$GDCList”)
{
$IsDCGap = “No”
$ThisService=”NetLogon”
$Error.Clear()
Get-Service -Name “$ThisService” -ComputerName $ItemName
IF ($Error.Count -eq 0)
{
$AnyOneOk=”Yes”
$PortTCP389Status=”Listening”
$PortTCP135Status=”Listening”
$PortTCP88Status=”Listening”
$PortTCP445Status=”Listening”
$PortUDP389Status=”Listening”
$PortUDP135Status=”Listening”
$PortUDP88Status=”Listening”
$PortUDP445Status=”Listening”
$LookFor = “Filtered”
$ThisServer=$ItemName
$Port = “389”
$PortProtocol = “UDP”
$cmd = $PortQryExe + ” -n ” + $ThisServer + ” -p ” + $PortProtocol + ” -e ” + $port
$PortQryResultFile = “C:\Temp\ReqPortTest\”+$CurProfNowForAll+$ThisServer+”_”+$Port+”_”+$PortProtocol+”.TXT”
Remove-Item $PortQryResultFile -ErrorAction SilentlyContinue
$Output = Invoke-Expression $cmd
$Output | Out-file $PortQryResultFile
$ThisLookFor=$LookFor
$FoundOrNot=Select-String -Path $PortQryResultFile -Pattern $ThisLookFor
$TotFoundNow=$FoundOrNot.Count
$FinStatus=””
IF ($TotFoundNow -ne 0)
{
$PortUDP389Status = “Filtered”
$AnyGap = “Yes”
$IsDCGap = “Yes”
}
Remove-Item $PortQryResultFile -ErrorAction SilentlyContinue
$Port = “135”
$PortProtocol = “UDP”
$cmd = $PortQryExe + ” -n ” + $ThisServer + ” -p ” + $PortProtocol + ” -e ” + $port
$PortQryResultFile = “C:\Temp\ReqPortTest\”+$CurProfNowForAll+$ThisServer+”_”+$Port+”_”+$PortProtocol+”.TXT”
Remove-Item $PortQryResultFile -ErrorAction SilentlyContinue
$Output = Invoke-Expression $cmd
$Output | Out-file $PortQryResultFile
$ThisLookFor=$LookFor
$FoundOrNot=Select-String -Path $PortQryResultFile -Pattern $ThisLookFor
$TotFoundNow=$FoundOrNot.Count
$FinStatus=””
IF ($TotFoundNow -ne 0)
{
$PortUDP139Status = “Filtered”
$AnyGap = “Yes”
$IsDCGap = “Yes”
}
Remove-Item $PortQryResultFile -ErrorAction SilentlyContinue
$Port = “88”
$PortProtocol = “UDP”
$cmd = $PortQryExe + ” -n ” + $ThisServer + ” -p ” + $PortProtocol + ” -e ” + $port
$PortQryResultFile = “C:\Temp\ReqPortTest\”+$CurProfNowForAll+$ThisServer+”_”+$Port+”_”+$PortProtocol+”.TXT”
Remove-Item $PortQryResultFile -ErrorAction SilentlyContinue
$Output = Invoke-Expression $cmd
$Output | Out-file $PortQryResultFile
$ThisLookFor=$LookFor
$FoundOrNot=Select-String -Path $PortQryResultFile -Pattern $ThisLookFor
$TotFoundNow=$FoundOrNot.Count
$FinStatus=””
IF ($TotFoundNow -ne 0)
{
$PortUDP88Status = “Filtered”
$AnyGap = “Yes”
$IsDCGap = “Yes”
}
Remove-Item $PortQryResultFile -ErrorAction SilentlyContinue
$Port = “445”
$PortProtocol = “UDP”
$cmd = $PortQryExe + ” -n ” + $ThisServer + ” -p ” + $PortProtocol + ” -e ” + $port
$PortQryResultFile = “C:\Temp\ReqPortTest\”+$CurProfNowForAll+$ThisServer+”_”+$Port+”_”+$PortProtocol+”.TXT”
Remove-Item $PortQryResultFile -ErrorAction SilentlyContinue
$Output = Invoke-Expression $cmd
$Output | Out-file $PortQryResultFile
$ThisLookFor=$LookFor
$FoundOrNot=Select-String -Path $PortQryResultFile -Pattern $ThisLookFor
$TotFoundNow=$FoundOrNot.Count
$FinStatus=””
IF ($TotFoundNow -ne 0)
{
$PortUDP445Status = “Filtered”
$AnyGap = “Yes”
$IsDCGap = “Yes”
}
Remove-Item $PortQryResultFile -ErrorAction SilentlyContinue
$Port = “389”
$PortProtocol = “TCP”
$cmd = $PortQryExe + ” -n ” + $ThisServer + ” -p ” + $PortProtocol + ” -e ” + $port
$PortQryResultFile = “C:\Temp\ReqPortTest\”+$CurProfNowForAll+$ThisServer+”_”+$Port+”_”+$PortProtocol+”.TXT”
Remove-Item $PortQryResultFile -ErrorAction SilentlyContinue
$Output = Invoke-Expression $cmd
$Output | Out-file $PortQryResultFile
$ThisLookFor=$LookFor
$FoundOrNot=Select-String -Path $PortQryResultFile -Pattern $ThisLookFor
$TotFoundNow=$FoundOrNot.Count
$FinStatus=””
IF ($TotFoundNow -ne 0)
{
$PortTCP389Status = “Filtered”
$AnyGap = “Yes”
$IsDCGap = “Yes”
}
Remove-Item $PortQryResultFile -ErrorAction SilentlyContinue
$Port = “135”
$PortProtocol = “TCP”
$cmd = $PortQryExe + ” -n ” + $ThisServer + ” -p ” + $PortProtocol + ” -e ” + $port
$PortQryResultFile = “C:\Temp\ReqPortTest\”+$CurProfNowForAll+$ThisServer+”_”+$Port+”_”+$PortProtocol+”.TXT”
Remove-Item $PortQryResultFile -ErrorAction SilentlyContinue
$Output = Invoke-Expression $cmd
$Output | Out-file $PortQryResultFile
$ThisLookFor=$LookFor
$FoundOrNot=Select-String -Path $PortQryResultFile -Pattern $ThisLookFor
$TotFoundNow=$FoundOrNot.Count
$FinStatus=””
IF ($TotFoundNow -ne 0)
{
$PortTCP139Status = “Filtered”
$AnyGap = “Yes”
$IsDCGap = “Yes”
}
Remove-Item $PortQryResultFile -ErrorAction SilentlyContinue
$Port = “88”
$PortProtocol = “TCP”
$cmd = $PortQryExe + ” -n ” + $ThisServer + ” -p ” + $PortProtocol + ” -e ” + $port
$PortQryResultFile = “C:\Temp\ReqPortTest\”+$CurProfNowForAll+$ThisServer+”_”+$Port+”_”+$PortProtocol+”.TXT”
Remove-Item $PortQryResultFile -ErrorAction SilentlyContinue
$Output = Invoke-Expression $cmd
$Output | Out-file $PortQryResultFile
$ThisLookFor=$LookFor
$FoundOrNot=Select-String -Path $PortQryResultFile -Pattern $ThisLookFor
$TotFoundNow=$FoundOrNot.Count
$FinStatus=”Ok”
IF ($TotFoundNow -ne 0)
{
$PortTCP88Status = “Filtered”
$AnyGap = “Yes”
$IsDCGap = “Yes”
}
Remove-Item $PortQryResultFile -ErrorAction SilentlyContinue
$Port = “445”
$PortProtocol = “TCP”
$cmd = $PortQryExe + ” -n ” + $ThisServer + ” -p ” + $PortProtocol + ” -e ” + $port
$PortQryResultFile = “C:\Temp\ReqPortTest\”+$CurProfNowForAll+$ThisServer+”_”+$Port+”_”+$PortProtocol+”.TXT”
Remove-Item $PortQryResultFile -ErrorAction SilentlyContinue
$Output = Invoke-Expression $cmd
$Output | Out-file $PortQryResultFile
$ThisLookFor=$LookFor
$FoundOrNot=Select-String -Path $PortQryResultFile -Pattern $ThisLookFor
$TotFoundNow=$FoundOrNot.Count
$FinStatus=””
IF ($TotFoundNow -ne 0)
{
$PortTCP445Status = “Filtered”
$AnyGap = “Yes”
$IsDCGap = “Yes”
}
Remove-Item $PortQryResultFile -ErrorAction SilentlyContinue
IF ($PortTCP389Status -eq “Filtered” -or $PortTCP135Status -eq “Filtered” -or $PortTCP88Status -eq “Filtered” -or $PortTCP445Status -eq “Filtered” -or $PortUDP389Status -eq “Filtered” -or $PortUDP135Status -eq “Filtered” -or $PortUDP88Status -eq “Filtered” -or $PortUDP445Status -eq “Filtered”)
{
$FinStatus =”WARNING: This domain controller does not listen on required domain controller ports.”
}
$DCConError = “Ok”
$ComConError = “Ok”
$FinalStr = $ItemName+”,”+$DCConError+”,”+$ComConError+”,”+$PortUDP389Status+”,”+$PortTCP389Status+”,”+$PortUDP135Status+”,”+$PortTCP135Status+”,”+$PortUDP88Status+”,”+$PortTCP88Status+”,”+$PortUDP445Status+”,”+$PortTCP445Status+”,”+$FinStatus
Add-Content $TestCSVFile $FinalStr
IF ($IsDCGap -eq “Yes”)
{
$TotNo++
}
}
else
{
$ThisSTR = $ItemName+”,Error Connecting to Domain Controller”
Add-Content “$TestCSVFile” $ThisStr
}
}
IF ($AnyGap -eq “Yes”)
{
$TestStatus=”Critical”
$TestText = “Domain Controllers are not listening on the required ports. Please ensure all domain controllers are listening on the required ports and protocols.”
$SumVal = $TotNo
}
IF ($AnyGap -eq “No”)
{
$TestStatus=”Passed”
$TestText = “All domain controllers are listening on the required ports. Please ensure AD Health Profiler was able to execute Dynamic Pack against all domain controllers.”
$SumVal = “”
IF ($AnyOneOk -eq “No”)
{
$TestStatus=”Error”
$TestText = “Error Executing Dynamic Pack”
$SumVal = “”
}
}
$STR = $ADTestName +”,”+$TestStartTime+”,”+$TestStatus+”,”+$SumVal +”,”+$TestText


Once the script has been executed successfully, a report file named DCPortReport.CSV file will be created under “C:\Temp” folder. The report includes the port status for each domain controller as shown in the report below:

Domain controllers required ports

As you can see in the report, the script connected to each domain controller, ran thePortQry tool, and then collected the port status for each domain controller. As is indicated in the “Final Status” column of the report, DC3.TechGenix.com and DC4.TechGenix.com domain controllers are not listening on one or more ports. All you need to do is just check the output and make sure nothing on the operating system is preventing a domain controller from listening on the required network ports.

You may find this PowerShell script handy in case you wish to check the domain controllers port status in an Active Directory forest. While you can check the port status on a single domain controller by using the NetStat command as explained above, using the script will save you a lot of time. You can include the PowerShell script in your Active Directory Health Procedure and have the script run every month to ensure the domain controllers are listening on the required ports.

About The Author

14 thoughts on “Domain controllers required ports: Use PowerShell to check if they are listening”

  1. – no need to use portqry, use system.Net.Sockets instead
    – why the test for netogon? in fact that test means you need admin access on the DC’s, which you wouldn’t need for just testing ports. Worse, every Windows box will have netlogon service; so the test adds a security requirement for no benefit
    – don’t create a file on disk as you go, create a PS Object and just output it to the pipeline
    – you can dynamically get the DC list, or better still write an advanced function that either determines them, or takes a list
    – way too many unneeded variables, often assigned and then just used once on next line
    – The variable ‘ReachOrNot’ is assigned but never used
    – The variable ‘PortUDP139Status’ is assigned but never used.
    – The variable ‘PortTCP139Status’ is assigned but never used.
    – The variable ‘STR’ is assigned but never used
    – refactor the code using functions, you have the same code over and over testing each port
    – $CurProfNowForAll has no definition?

  2. I would use get-addomaincontroller or get-adcomputer to get the DC list no need for an advanced function. Agree using .Net to query the ports is cleaner and will perform much better.

  3. James Magalona

    Anyone where can place the DClist file? I got this error below:

    Get-Content : Cannot bind argument to parameter ‘Path’ because it is an empty string.
    At line:15 char:35
    + Foreach ($ItemName in Get-Content “$GDCList”)

  4. Nirmal Sharma

    DCList file can be in C:\Temp directory, but it needs to contain the list of domain controllers that to be checked by the script.

    /Nirmal

  5. stephen tretakis

    I have the same issue and txt file dclist in in c:\temp I get the same error ,
    Get-Content : Cannot bind argument to parameter ‘Path’ because it is an empty string.
    At line:15 char:35
    + Foreach ($ItemName in Get-Content “$GDCList”). I even have the ps1 in that folder
    steve

  6. Nirmal.

    Thank you for the script.
    I have the same issue – file DClist.txt is in c:\temp
    I got the same error:
    Get-Content : Cannot bind argument to parameter ‘Path’ because it is an empty string.
    At line:15 char:35

    My DClist. txt has 2 domain controller NETBIOS names – one name per line.

  7. Same error for me as well. Your script is not working!

    PS C:\Temp> .\Ports_check.ps1

    Directory: C:\

    Mode LastWriteTime Length Name
    —- ————- —— —-
    d—– 6/20/2019 9:37 AM ReqPortTest
    Get-Content : Cannot bind argument to parameter ‘Path’ because it is an empty string.
    At C:\Temp\Ports_check.ps1:15 char:35
    + Foreach ($ItemName in Get-Content “$GDCList”)
    + ~~~~~~~~~~
    + CategoryInfo : InvalidData: (:) [Get-Content], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationErrorEmptyStringNotAllowed,Microsoft.PowerShell.Commands.GetC
    ontentCommand

  8. variable $GDCList has no value

    Edit powershell script and

    set it as $GDCList=(Get-ADForest).GlobalCatalogs
    or $GDCList=”c:\Temp\DCList.TXT”

    before line 16 Foreach ($ItemName in Get-Content “$GDCList”)

  9. This seems like a very convoluted way of checking…. If you have Win8.1/Server 2012 R2 and above you can do it in 2 lines:

    $ports = “135”,”88″,”139″,”389″,”464″,”3268,””3269″,”53″
    $ports | % { tnc COMPUTERNAME -port $_ }

  10. I am getting below error while executing the script, any help on this?

    Get-Service : Cannot find any service with service name ‘NetLogon’.
    At C:\temp\PortQuery.ps1:21 char:1
    + Get-Service -Name “$ThisService” -ComputerName $ItemName
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : ObjectNotFound: (NetLogon:String) [Get-Service], ServiceCommandException
    + FullyQualifiedErrorId : NoServiceFoundForGivenName,Microsoft.PowerShell.Commands.GetServiceCommand

Leave a Comment

Your email address will not be published. Required fields are marked *

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

Scroll to Top