PowerShell Test-Port: Een Gids voor Aangepast Gereedschap

Laten we eens kijken hoe we een PowerShell-testpoortgereedschap kunnen bouwen dat u in staat stelt om open poorten te testen op poortnummer en label.

Om een robuust script te bouwen dat niet halverwege uw servers zal falen, is het belangrijk om er eerst voor te zorgen dat aan de vereisten die nodig zijn om uw eindresultaat te behalen, wordt voldaan.

Wat zijn deze vereisten? Vereisten zijn services zoals FTP, HTTP, DCOM, WMI, WSMAN, enzovoort. De verbinding die u probeert te maken met een server is typisch afhankelijk van dergelijke services.

Er is een hiërarchie van verschillende lagen controles die u kunt uitvoeren op uw servers voordat u een verbinding probeert te maken, afhankelijk van hoe grondig u wilt zijn.

Om te beginnen heeft u de volledige OSI-stack om te doorlopen aan de netwerkkant. Dat is exclusief services op het host-systeem waarvan u het script uitvoert, en alles op het externe host-systeem.

Een van de eerste tests die u moet uitvoeren bij het bevragen van een externe server, is controleren of de juiste netwerkpoorten open en toegankelijk zijn. Afhankelijk van de services die op de externe server worden uitgevoerd, zijn verschillende poorten vereist.

I always used to either not even attempting to test port connections or fumbling around with finding that latest Test-Port script I had scavenged somewhere. Once I found it to figure out what ports I actually needed to a test ahead of time. Today was the final straw.

I needed to query a set of domain controllers before running some CIM queries against them. I went about my normal fumbling around and decided enough was enough and sat down and built my own, fully featured port testing script.

Met behulp van dit Technet-script slaagde ik erin om een vrij goede set PowerShell-functies te maken die u niet alleen in staat stellen om TCP- en UDP-poorten te testen, maar ook om poortgroepen te testen op basis van serverrol. Geen eindeloos googelen meer om te achterhalen welke poorten welke service gebruikt!

Toegekend, vooral voor Active Directory, kunnen de poorten variëren per serverbesturingssysteem, verschillende services op een domeincontroller, enz. Voel je vrij om ze aan te passen zoals nodig is voor jouw omgeving.

Hier is een schermopname van een gebruiksvoorbeeld:

Testing ports with PowerShell

Zoals je kunt zien, kun je zoveel servers specificeren als je wilt en het zal een mooie lijst van objecten genereren, opgesplitst per servicepoortgroep en de poort voor elke computer. Tot nu toe is het erg handig gebleken! Ik hoop dat je er net zoveel gebruik van zult maken als ik!

function Test-ServerRolePortGroup {
	<#
	.SYNOPSIS
		Deze functie test open TCP/UDP-poorten per serversysteemrol.
	.DESCRIPTION
		Deze functie test alle juiste TCP/UDP-poorten per serversysteemrol, zodat je niet alle poorten hoeft te onthouden of telkens hoeft op te zoeken die moeten worden getest telkens wanneer je de externe connectiviteit van een specifieke serversysteemrol wilt verifiëren.
	.NOTES
		Link naar poortverwijzingen:
		http://technet.microsoft.com/en-us/library/dd772723(v=ws.10).aspx
		http://en.wikipedia.org/wiki/Server_Message_Block
		http://technet.microsoft.com/en-us/library/cc940063.aspx
	.PARAMETER Computernaam
		Een of meer externe computernamen, gescheiden door komma's
	.PARAMETER Serverrol
		De services op de computer waarvoor je open poorten wilt vinden. Dit kunnen gangbare services zijn zoals WinRm, Smb, Dns, Active Directory en NetBIOS
	.EXAMPLE
		PS> Test-ServerRolePortGroup -Computernaam 'LABDC','LABDC2' -Serverrol NetBIOS,WinRm,Dns
		
		Dit voorbeeld test de netwerkpoorten die nodig zijn voor NetBIOS, WinRm en Dns om te functioneren op de servers LABDC en LABDC2.
	#>
	
	[CmdletBinding()]
	[OutputType([System.Management.Automation.PSCustomObject])]
	param (
		[Parameter(Mandatory)]
		[ValidateScript({ Test-Connection -ComputerName $_ -Count 1 -Quiet})]
		[string[]]$Computername,
		[Parameter(Mandatory)]
		[ValidateSet('WinRm','Smb','Dns','ActiveDirectoryGeneral','ActiveDirectoryGlobalCatalog','NetBios')]
		[string[]]$ServerRole
	)
	begin {
		$PortGroups = @{
			'WinRm' = @{ 'TCP' = 5985}
			'Smb' = @{ 'TCP' = 445; 'UDP' = 445 }
			'Dns' = @{ 'TCP' = 53; 'UDP' = 53 }
			'ActiveDirectoryGeneral' = @{ 'TCP' = 25, 88, 389, 464, 636, 5722, 9389; 'UDP' = 88,123,389,464 }
			'ActiveDirectoryGlobalCatalog' = @{ 'TCP' = 3268, 3269 }
			'NetBios' = @{ 'TCP' = 135, 137, 138, 139; 'UDP' = 137,138,139 }
		}
	}
	process {
		foreach ($Computer in $Computername) {
			Write-Verbose "Beginning port tests on computer '$Computer'"
			try {
				$TestPortGroups = $PortGroups.GetEnumerator() | where { $ServerRole -contains $_.Key }
				Write-Verbose "Found '$($TestPortGroups.Count)' port group(s) to test"
				foreach ($PortGroup in $TestPortGroups) {
					$PortGroupName = $PortGroup.Key
					$PortGroupValues = $PortGroup.Value
					foreach ($Value in $PortGroupValues.GetEnumerator()) {
						$Protocol = $Value.Key
						$Ports = $Value.Value
						$TestResult = Test-Port -ComputerName $Computer -Protocol $Protocol -Port $Ports
						$TestResult | Add-Member -MemberType 'NoteProperty' -Name 'PortSet' -Value $PortGroupName
						$TestResult
					}
				}
			} catch {
				Write-Verbose "$($MyInvocation.MyCommand.Name) - Computer: $Computer - Error: $($_.Exception.Message) - Line Number: $($_.InvocationInfo.ScriptLineNumber)"
				$false
			}
		}
	}
}

function Test-Port {
	<#
	.SYNOPSIS
		Deze functie test open TCP/UDP-poorten.
	.DESCRIPTION
		Deze functie test elke TCP/UDP-poort om te zien of deze open of gesloten is.
	.NOTES
		Bekend probleem: Als deze functie binnen 10-20 opeenvolgende keren wordt aangeroepen op dezelfde poort en computer, zal de UDP-poortcontrole $false uitvoeren wanneer dit $true zou moeten zijn. Ik heb nog niet uitgevonden waarom dit gebeurt.
	.PARAMETER Computernaam
		Een of meer externe computernamen, gescheiden door komma's
	.PARAMETER Poort
		Een of meer door komma's gescheiden poortnummers die je wilt testen.
	.PARAMETER Protocol
		Het protocol (UDP of TCP) dat je wilt testen
	.PARAMETER TcpTimeout
		Het aantal milliseconden dat de functie zal wachten voordat de TCP-poort wordt gesloten verklaard.
	.PARAMETER UdpTimeout
		Het aantal milliseconden dat de functie zal wachten voordat de UDP-poort wordt gesloten verklaard.
	.EXAMPLE
		PS> Test-Port -Computernaam 'LABDC','LABDC2' -Protocol TCP 80,443
		
		Dit voorbeeld test de TCP-netwerkpoorten 80 en 443 op zowel de LABDC- als LABDC2-servers.
	#>
	[CmdletBinding(DefaultParameterSetName='TCP')]
	[OutputType([System.Management.Automation.PSCustomObject])]
	param (
		[Parameter(Mandatory)]
		[string[]]$ComputerName,
		[Parameter(Mandatory)]
		[int[]]$Port,
		[Parameter(Mandatory)]
		[ValidateSet('TCP', 'UDP')]
		[string]$Protocol,
		[Parameter(ParameterSetName='TCP')]
		[int]$TcpTimeout = 1000,
		[Parameter(ParameterSetName = 'UDP')]
		[int]$UdpTimeout = 1000
	)
	process {
		foreach ($Computer in $ComputerName) {
			foreach ($Portx in $Port) {
				$Output = @{ 'Computername' = $Computer; 'Port' = $Portx; 'Protocol' = $Protocol; 'Result' = '' }
				Write-Verbose "$($MyInvocation.MyCommand.Name) - Beginning port test on '$Computer' on port '$Protocol<code>:$Portx'"
				if ($Protocol -eq 'TCP') {
					$TcpClient = New-Object System.Net.Sockets.TcpClient
					$Connect = $TcpClient.BeginConnect($Computer, $Portx, $null, $null)
					$Wait = $Connect.AsyncWaitHandle.WaitOne($TcpTimeout, $false)
					if (!$Wait) {
						$TcpClient.Close()
						Write-Verbose "$($MyInvocation.MyCommand.Name) - '$Computer' failed port test on port '$Protocol</code>:$Portx'"
						$Output.Result = $false
					} else {
						$TcpClient.EndConnect($Connect)
						$TcpClient.Close()
						Write-Verbose "$($MyInvocation.MyCommand.Name) - '$Computer' passed port test on port '$Protocol<code>:$Portx'"
						$Output.Result = $true
					}
					$TcpClient.Close()
					$TcpClient.Dispose()
				} elseif ($Protocol -eq 'UDP') {
					$UdpClient = New-Object System.Net.Sockets.UdpClient
					$UdpClient.Client.ReceiveTimeout = $UdpTimeout
					$UdpClient.Connect($Computer, $Portx)
					Write-Verbose "$($MyInvocation.MyCommand.Name) - Sending UDP message to computer '$Computer' on port '$Portx'"
					$a = new-object system.text.asciiencoding
					$byte = $a.GetBytes("$(Get-Date)")
					[void]$UdpClient.Send($byte, $byte.length)
					#Het IPEndPoint-object stelt ons in staat datagrammen te lezen die vanuit elke bron zijn verzonden.
					Write-Verbose "$($MyInvocation.MyCommand.Name) - Creating remote endpoint"
					$remoteendpoint = New-Object system.net.ipendpoint([system.net.ipaddress]::Any, 0)
					try {
						#Blokkeert totdat er een bericht op deze socket terugkeert vanaf een externe host.
						Write-Verbose "$($MyInvocation.MyCommand.Name) - Waiting for message return"
						$receivebytes = $UdpClient.Receive([ref]$remoteendpoint)
						[string]$returndata = $a.GetString($receivebytes)
						If ($returndata) {
							Write-Verbose "$($MyInvocation.MyCommand.Name) - '$Computer' passed port test on port '$Protocol</code>:$Portx'"
							$Output.Result = $true
						}
					} catch {
						Write-Verbose "$($MyInvocation.MyCommand.Name) - '$Computer' failed port test on port '$Protocol`:$Portx' with error '$($_.Exception.Message)'"
						$Output.Result = $false
					}
					$UdpClient.Close()
					$UdpClient.Dispose()
				}
				[pscustomobject]$Output
			}
		}
	}
}

Source:
https://adamtheautomator.com/powershell-test-port/