# # ConnectivityCheck.ps1 # param ( [parameter(Mandatory=$true)] [string] $NameResolutionFileName, [parameter(Mandatory=$true)] [string] $TcpEndpointsFileName, [parameter(Mandatory=$false)] [string] $OutDir = $Env:Temp, [parameter(Mandatory=$false)] [string] $CheckHostsFile ) $BlnCheckHostsFile = $false if ($CheckHostsFile) { if ($CheckHostsFile -ine "false" -and $CheckHostFile -ine "no" -and $CheckHostFile -ne "0") { $BlnCheckHostsFile = $true } } # Functions # # Override the built-in cmdlet with a custom version function Write-ErrorMsg($Message) { [Console]::ForegroundColor = 'red' Write-Output $Message [Console]::ResetColor() } function Convert-ByteArrayToHex { [cmdletbinding()] param( [parameter(Mandatory=$true)] [Byte[]] $Bytes ) #$HexString = [System.Text.StringBuilder]::new($Bytes.Length * 2) $HexString = New-Object System.Text.StringBuilder($Bytes.Length * 2) ForEach($Byte in $Bytes){ $HexString.AppendFormat("{0:x2}", $Byte) | Out-Null } $HexString.ToString() } function Convert-HexToByteArray { [cmdletbinding()] param( [parameter(Mandatory=$true)] [String] $HexString) # $Bytes = [byte[]]::new($HexString.Length / 2) $Bytes = New-Object byte[]($HexString.Length / 2) For($i=0; $i -lt $HexString.Length; $i+=2){ $Bytes[$i/2] = [convert]::ToByte($HexString.Substring($i, 2), 16) } $Bytes } function IsPortOpen { param( [parameter(Mandatory=$true)] [string] $HostName, [parameter(Mandatory=$true)] [int] $Port, [parameter(Mandatory=$false)] [int] $Timeout = 5000) $Result = $null # REMOVED: TCPClient's ConnectAsync not available in older powershell # $Client = New-Object System.Net.Sockets.TCPClient # $Timeout = # $IsOpen = $Client.ConnectAsync($HostName, $Port).Wait($Timeout) $Client = New-Object System.Net.Sockets.TCPClient $IsOpen = $false try { $AsyncResult = $Client.BeginConnect($HostName, $Port, $null, $null) if (!$AsyncResult.AsyncWaitHandle.WaitOne($Timeout, $false)) { throw [System.TimeoutException]::new(); } $Client.EndConnect($AsyncResult) | Out-Null $IsOpen = $Client.Connected } catch { $IsOpen = $false } finally { $Client.Close(); } if ($IsOpen) { $Result = "Success" } else { $Result = "Fail" } "$($Result): $($HostName):$($Port)" } function Read-Hosts-File-To-Hash { Param ( [string] $FileName, [int] $IncludeCommentedLines) $HostHash = @{} if (-not (Test-Path -Path $FileName)) { Write-ErrorMsg "Error: file not found: $($FileName)" return $null } # $Lines = Get-Content -Path $FileName $Lines = [IO.File]::ReadAllLines($FileName) foreach ($Line in $Lines) { $Line = $Line.Trim() if ($Line.Length -lt 9) { continue } $Chars = $Line.ToCharArray() if ($Chars[0] -eq '#') { if ($IncludeCommentedLines -eq 0) { continue } } $Line = $Line.Trim('#') if ($Line.Length -lt 9) { continue } $ix = $Line.IndexOf('#') if ($ix -gt 0) { if ($ix -lt 9) { continue } $Line = $Line.Substring(0, $ix) } $Words = ($Line -split ' ') if ($Words.Count -lt 2) { continue } $Ip = $Words[0] try { [IPAddress]$Ip > $null } catch { continue } $Names = New-Object System.Collections.Generic.List[String] for ($i = 1; $i -lt $Words.Count; ++$i) { $Word = $Words[$i].Trim() if ($Word) { $Names.Add($Words[$i]) } } if ($HostHash.ContainsKey($Ip)) { foreach ($Name in $Names) { $HostHash[$Ip].Add($Name) } } else { $HostHash.Add($Ip, $Names) } } $HostHash } function Read-TcpEndpoints-File-To-Hash { Param ( [string] $FileName, [int] $IncludeCommentedLines) $TcpEndpointsHash = @{} if (-not (Test-Path -Path $FileName)) { Write-ErrorMsg "Error: file not found: $($FileName)" return $null } # $Lines = Get-Content -Path $FileName $Lines = [IO.File]::ReadAllLines($FileName) foreach ($Line in $Lines) { $Line = $Line.Trim() if ($Line.Length -lt 9) { continue } $Chars = $Line.ToCharArray() if ($Chars[0] -eq '#') { if ($IncludeCommentedLines -eq 0) { continue } } $Line = $Line.Trim('#') if ($Line.Length -lt 9) { continue } $ix = $Line.IndexOf('#') if ($ix -gt 0) { if ($ix -lt 9) { continue } $Line = $Line.Substring(0, $ix) } $Parts = ($Line -split ' ') if ($Parts.Count -lt 2) { continue } $Ip = $Parts[0] try { [IPAddress]$Ip > $null } catch { continue } $PortsCsv = $Parts[1] $PortsArr = ($PortsCsv -split ',') $Ports = New-Object System.Collections.Generic.List[String] for ($i = 0; $i -lt $PortsArr.Count; ++$i) { $Port = $PortsArr[$i] $Port = $Port.Trim() if ($Port) { $Ports.Add($Port) } } if ($TcpEndpointsHash.ContainsKey($Ip)) { foreach ($Port in $Ports) { $TcpEndpointsHash[$Ip] = $Ports } } else { $TcpEndpointsHash.Add($Ip, $Ports) } } $TcpEndpointsHash } # Set Up # $DateStringPrefix = Get-Date -Format "yyyy-MM-dd_HHmmss__" if (-not (Test-Path -Path $OutDir)) { New-Item -ItemType Directory -Force -Path $OutDir >$null } $OutFileName = Join-Path -Path $OutDir -ChildPath "$($DateStringPrefix)ConnectivityCheck.log" $ErrorActionPreference="SilentlyContinue" Stop-Transcript | out-null $ErrorActionPreference = "Continue" Start-Transcript -path $OutFileName Write-Host # Retrieve IPs and host names from file for name resolution check. $HostsFileName = "$($Env:windir)\system32\drivers\etc\hosts" if (Test-Path -Path $NameResolutionFileName) { Write-Host "Retrieving IPs and host names from $NameResolutionFileName..." $NameResolutionTable = Read-Hosts-File-To-Hash $NameResolutionFileName 0 } else { Write-ErrorMsg "Name resolution file missing: $NameResolutionFileName" $NameResolutionTable = $null } if (Test-Path -Path $HostsFileName) { $NameResolutionTable = Read-Hosts-File-To-Hash $HostsFileName.ToString() 0 } else { Write-ErrorMsg "System hosts file missing: $HostsFileName" $NameResolutionTable = $null } # Retrieve TCP endpoints from file for connectivity check. if (Test-Path -Path $TcpEndpointsFileName) { Write-Host "Retrieving TCP endpoints from $TcpEndpointsFileName..." $TcpEndpointMap = Read-TcpEndpoints-File-To-Hash $TcpEndpointsFileName } else { Write-ErrorMsg "TCP endpoints file missing: $TcpEndpointsFileName" $TcpEndpointMap = $null } # Name Resolution Check # Write-Output "`r`n`r`nNAME RESOLUTION TEST ($NameResolutionFileName):`r`n" if ($null -ne $NameResolutionTable) { foreach ($IpCorrect in $NameResolutionTable.Keys) { $Names = $NameResolutionTable[$IpCorrect] foreach ($Name in $Names) { if (!$Name) { continue } $AddressList = $null try { $AddressList = [System.Net.Dns]::GetHostAddresses($Name) } catch { Write-ErrorMsg "Error: $($Name) doesn't resolve." continue } $IpList = New-Object 'System.Collections.Generic.List[string]' foreach ($Ip in $AddressList) { if ($Ip.AddressFamily -ne "InterNetwork") { continue } if ($IpList.Contains($Ip.IPAddressToString)) { continue } $IpList.Add($Ip.IPAddressToString) > $null } if ($IpList.Count -eq 0) { Write-ErrorMsg "Error: $($Name) doesn't resolve to any IPv4 addresses." continue } if ($IpList.Count -gt 1) { Write-ErrorMsg "Error: $($Name) resolves to multiple IP addresses: $($IpList -join ', ')" continue } $Ip = $IpList[0] if ($IpCorrect -eq $Ip) { #Write-Output "Success: $($Name) resolves to $($IpCorrect)" Write-Output "Success: $($IpCorrect) resolved from $($Name)" } else { Write-ErrorMsg "Error: $($Name) resolves to $($Ip) instead of $($IpCorrect)." } } } } # Hosts file check # if ($BlnCheckHostsFile) { Write-Output "`r`n`r`nHOSTS FILE CHECK ($($HostsFileName)):`r`n" if ($null -ne $NameResolutionTable -and $null -ne $NameResolutionTable) { foreach ($Ip in $NameResolutionTable.Keys) { $SourceNames = $NameResolutionTable[$Ip] $SourceNamesStr = $SourceNames -join " " $SourceEntryStr = "$($Ip) $($SourceNamesStr)" if (-not $NameResolutionTable.ContainsKey($Ip)) { Write-ErrorMsg "Error: missing entry equivalent to '$($SourceEntryStr)'" continue } $MissingNames = @() $Names = $NameResolutionTable[$Ip] foreach ($SourceName in $SourceNames) { if (-not ($Names -contains $SourceName)) { $MissingNames += $SourceName } } if (0 -lt $MissingNames.count) { Write-ErrorMsg "Error: entry or entries for $($Ip) missing the following names: $($MissingNames -join ' ')" } else { foreach ($SourceName in $SourceNames) { Write-Output "Success: found $($Ip) $($SourceName)" } } } } } # TCP connectivity check # $EndPoints = New-Object System.Collections.Generic.List[Object] Write-Output "`r`n`r`nTCP CONNECTIVITY TEST:`r`n" if ($null -ne $TcpEndpointMap) { foreach ($Ip in $TcpEndpointMap.Keys) { $Ports = $TcpEndpointMap[$Ip] foreach ($Port in $Ports) { $ThisEndPoint = New-Object PSObject -Property @{ Host = [string]$Ip Port = [int]$Port } $EndPoints.Add($ThisEndPoint) } } } foreach ($EndPoint in $EndPoints) { IsPortOpen -hostName $EndPoint.Host -port $EndPoint.Port } # Clean up # Stop-Transcript