BAMCIS.Networking.psm1
Function Test-Port { <# .SYNOPSIS Tests if a TCP or UDP is listening on a computer. .DESCRIPTION The Test-Port cmdlet tests for the availability of a TCP or UDP port on a local or remote server. .PARAMETER Port The port number to test. This must be between 1 and 65535. .PARAMETER ComputerName The IP or DNS name of the computer to test. This defaults to "localhost". .PARAMETER ReceiveTimeout The timeout in milliseconds to wait for a response. This defaults to 1000. .PARAMETER Source The source IP address the test should originate from on the local machine. If this is not specified, the Windows networking stack chooses the source interface. The first available port between 49152 and 65535 is used for the source port. .PARAMETER Tcp Indicates that TCP should be used. This is the default .PARAMETER Udp Indicates that UDP should be used. .PARAMETER Payload The byte array payload to send for a UDP connection test. .EXAMPLE Test-Port -Port 443 -ComputerName RemoteServer.test.local -Tcp Tests for the availability of port 443 via TCP on RemoteServer.test.local .EXAMPLE Test-Port -Port 123 -ComputerName dc1.contoso.com -Udp -Payload @(0x00, 0x01) Tests for the availability of port 123 (NTP) via UDP on dc1.contoso.com. The payload to send via UDP is also specified. .INPUTS None .OUTPUTS System.Boolean .NOTES AUTHOR: Michael Haken LAST UPDATE: 10/26/2017 #> [CmdletBinding(DefaultParameterSetName = "tcp")] [OutputType()] Param( [Parameter(Position = 0, Mandatory = $true)] [ValidateRange(1, 65535)] [System.Int32]$Port, [Parameter(Position = 1)] [ValidateNotNullOrEmpty()] [System.String]$ComputerName = "localhost", [Parameter(Position = 2)] [ValidateScript({ $_ -gt 0 })] [System.Int32]$ReceiveTimeout = 1000, [Parameter()] [ValidateNotNull()] [System.Net.IPAddress]$Source = $null, [Parameter(ParameterSetName = "tcp")] [Switch]$Tcp, [Parameter(ParameterSetName = "udp")] [Switch]$Udp, [Parameter(ParameterSetName = "udp")] [ValidateNotNull()] [System.Byte[]]$Payload = $null ) Begin { } Process { $Success = $false [System.Collections.Hashtable]$Splat = @{} # If a source was specified, choose a source port to use if ($Source -ne $null) { [System.Collections.Hashtable]$SourceSplat = @{} if ($PSCmdlet.ParameterSetName -eq "tcp") { $SourceSplat.Add("Tcp", $true) } else { $SourceSplat.Add("Udp", $true) } [System.Int32]$LocalPort = Get-InUsePorts -ReturnAvailable @SourceSplat | Select-Object -First 1 [System.Net.IPEndPoint]$LocalEndpoint = New-Object -TypeName System.Net.IPEndPoint($Source, $LocalPort) $Splat.Add("ArgumentList", @($LocalEndpoint)) } if ($PSCmdlet.ParameterSetName -eq "tcp") { # Create the TCP client [System.Net.Sockets.TcpClient]$TcpClient = New-Object -TypeName System.Net.Sockets.TcpClient @Splat try { # Begin the connection and wait for a response $Connection = $TcpClient.BeginConnect($ComputerName, $Port, $null, $null) [System.Boolean]$Wait = $Connection.AsyncWaitHandle.WaitOne($ReceiveTimeout, $false) # If the response was successful, close the connection if ($Wait) { $TcpClient.EndConnect($Connection) | Out-Null $Success = $true } } catch [System.Net.Sockets.SocketException] { Write-Log -ErrorRecord $_ -Level VERBOSEERROR } finally { $TcpClient.Close() $TcpClient.Dispose() } } else { # Create the UDP client [System.Net.Sockets.UdpClient]$UdpClient = New-Object -TypeName System.Net.Sockets.UdpClient @Splat $UdpClient.Client.ReceiveTimeout = $ReceiveTimeout Write-Log -Message "Connecting to $ComputerName." -Level VERBOSE try { $UdpClient.Connect($ComputerName, $Port) if ($Payload -ne $null) { # Create a default payload to send $Payload = [System.Byte[]](0x00) } Write-Log -Message "Sending data." -Level VERBOSE [System.Int32]$SentBytes = $UdpClient.Send($Bytes, $Bytes.Length) [System.Byte[]]$Buffer = New-Object -TypeName System.Byte[](512) [System.Int32]$ReceivedBytes = $UdpClient.Client.Receive($Buffer) $Success = $ReceivedBytes > 0 } catch [System.Net.Sockets.SocketException] { if (@([System.Net.Sockets.SocketError]::Success, [System.Net.Sockets.SocketError]::TimedOut, [System.Net.Sockets.SocketError]::IsConnected, [System.Net.Sockets.SocketError]::IOPending) -contains $_.Exception.SocketErrorCode) { $Success = $true } else { Write-Log -ErrorRecord $_ -Level VERBOSEERROR } } finally { $UdpClient.Close() $UdpClient.Dispose() } } Write-Output -InputObject $Success } End { } } Function Get-InUsePorts { <# .SYNPOSIS Gets the ports currently in use by TCP or UDP connections. .DESCRIPTION The cmdlet gets the ports that are currently in use by active TCP or UDP connections or listeners. The ports can be limited to either IPv4 or IPv6 connections, but default to including both IPv4 and IPv6. Additionally, the cmdlet can provide the available ports between 49152 and 65535 instead of all in use ports. .PARAMETER IPv4 This specifies that only ports being used for IPv4 connections are utilized. .PARAMETER IPv6 This specifies that only ports being used for IPv6 connections are utilized. .PARAMETER ReturnAvailable This specifies that available ports between 49152 and 65535 are returned instead of all in use ports. .PARAMETER Tcp Specifies that ports in use for TCP connections will be returned. This is the default. .PARAMETER Udp Specifies that ports in use for UDP connections will be returned. .EXAMPLE Get-InUsePorts -IPv4 The cmdlet will return a list of in use IPv4 TCP ports. .EXAMPLE Get-InUsePorts -Udp The cmdlet will return a list of in use IPv4 and IPv6 UDP ports. .INPUTS None .OUTPUTS System.Int32[] .NOTES AUTHOR: Michael Haken LAST UPDATE: 10/25/2017 #> [CmdletBinding()] Param( [Parameter()] [Switch]$IPv4, [Parameter()] [Switch]$IPv6, [Parameter()] [Switch]$ReturnAvailable, [Parameter(ParameterSetName = "tcp")] [Switch]$Tcp, [Parameter(ParameterSetName = "udp")] [Switch]$Udp ) Begin { } Process { $IPTypes = @() if (-not $IPv4 -and -not $IPv6) { $IPTypes = @([System.Net.Sockets.AddressFamily]::InterNetwork, [System.Net.Sockets.AddressFamily]::InterNetworkV6) } else { if ($IPv4) { $IPTypes += [System.Net.Sockets.AddressFamily]::InterNetwork } if ($IPv6) { $IPTypes += [System.Net.Sockets.AddressFamily]::InterNetworkV6 } } [System.Net.IPEndpoint[]]$Listeners = $null if ($PSCmdlet.ParameterSetName -eq "tcp") { $Listeners = ([System.Net.NetworkInformation.IPGlobalProperties]::GetIPGlobalProperties()).GetActiveTcpListeners() } else { $Listeners = ([System.Net.NetworkInformation.IPGlobalProperties]::GetIPGlobalProperties()).GetActiveUdpListeners() } [System.Int32[]]$UsedPorts = $Listeners | Where-Object {$IPTypes -contains $_.AddressFamily} | Select-Object -ExpandProperty Port if ($ReturnAvailable) { [System.Int32[]]$Temp = 49152..65535 # Add comma so the array isn't unrolled [System.Collections.ArrayList]$List = New-Object -TypeName System.Collections.ArrayList(,$Temp) foreach ($Port in $UsedPorts) { $List.Remove($Port) } Write-Output -InputObject ([System.Int32[]]$List | Sort-Object) } else { Write-Output -InputObject ($UsedPorts | Sort-Object) } } End{ } } Function Set-NetAdapterDnsSuffix { <# .SYNOPSIS Sets the DNS suffix search order for TCP/IP. .DESCRIPTION This cmdlet allows you to specify either a list of DNS suffixes, a single DNS suffix that should be at the top of the ordering and optionally replace all other entries, or revert to using the primary and connection specific suffixes with optional domain name devolution (the "append parent suffixes of the primary dns suffix" option). .PARAMETER Domains The domains to set as the DNS suffix search list. .PARAMETER DefaultDomain The domain that should appear at the top of the search list. If it does not currently exist in the list it will be added, otherwise it will be moved to the top. .PARAMETER Replace Indicates whether the default domain should replace all of the current entries in the list. This is equivalent to specifying the parameter -Domains @("my.newdomain.com"). .PARAMETER AppendPrimaryAndConnectionSpecificSuffixes This parameter removes all entries from the Search List and uses provided primary and connection specific DNS suffixes when resolving unqualified domain names. .PARAMETER UseDomainNameDevolution This parameter indiciates that domain name devolution will be used. The resolver performs name devolution on the primary DNS suffix. It strips off the leftmost label and tries the resulting domain name until only two labels remain. For example, if your primary DNS suffix is mfg.fareast.isp01-ext.com, and then queried for the unqualified, single-label name "coffee," the resolver queries in order the following FQDNs: coffee.fareast.isp01-ext.com. coffee.isp01-ext.com. .PARAMETER ReturnStringErrorMessage If this is specified, instead of an integer return value, the string representation of the error code is returned. .EXAMPLE $Result = Set-NetAdapterDnsSuffix -Domains @("contoso.com", "tailspintoys.com") This sets the DNS suffix search list to the domains provided. The Result indicates the success or failure code of the operation. .EXAMPLE $Result = Set-NetAdapterDnsSuffix -DefaultDomain "contoso.com" This sets contoso.com to be the first entry in the search list and does not modify any existing entries. .EXAMPLE $Result = Set-NetAdapterDnsSuffix -AppendPrimaryAndConnectionSpecificSuffixes This removes all items in the Search List and uses primary and connection specific suffixes (like those received from DHCP). .INPUTS System.String[] .OUTPUTS System.Int32 The output is 0 for success and non-zero for failure. The exit code may correspond to a known error message that can be accessed through the Get-NetAdapterErrorCode cmdlet. .NOTES AUTHOR: Michael Haken LAST UPDATE: 10/2/2017 #> [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = "HIGH")] [OutputType([System.Int32])] Param( [Parameter(Mandatory = $true, ValueFromPipeline = $true, ParameterSetName = "Domains")] [ValidateNotNullOrEmpty()] [System.String[]]$Domains = @(), [Parameter(Mandatory = $true, ParameterSetName = "UpdateDefault")] [ValidateNotNullOrEmpty()] [System.String]$DefaultDomain, [Parameter(ParameterSetName = "UpdateDefault")] [System.Boolean]$Replace = $false, [Parameter(ParameterSetName = "AppendPrimary", Mandatory = $true)] [Switch]$AppendPrimaryAndConnectionSpecificSuffixes, [Parameter(ParameterSetName = "AppendPrimary")] [System.Boolean]$UseDomainNameDevolution, [Parameter()] [Switch]$ReturnStringErrorMessage, [Parameter()] [Switch]$Force ) Begin { if (-not (Test-IsLocalAdmin)) { throw "You must run this cmdlet with admin credentials." } } Process { $Result = 65 # Unknown failure switch ($PSCmdlet.ParameterSetName) { "AppendPrimary" { $Path = "HKLM:\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters" Write-Log -Message "Updating registry at $Path." -Level VERBOSE $Prop = Get-ItemProperty -Path $Path -Name SearchList if ($Prop -eq $null) { New-ItemProperty -Path $Path -Name SearchList -Value "" -PropertyType ([Microsoft.Win32.RegistryValueKind]::String) | Out-Null } else { # This will create the value if it doesn't exist, or update the existing property, # but we can't specify a property type with it Set-ItemProperty -Path $Path -Name SearchList -Value "" | Out-Null } if ($PSBoundParameters.ContainsKey("UseDomainNameDevolution")) { $Prop = Get-ItemProperty -Path $Path -Name UseDomainNameDevolution if ($Prop -eq $null) { New-ItemProperty -Path $Path -Name UseDomainNameDevolution ([System.Int32]$UseDomainNameDevolution) -PropertyType ([Microsoft.Win32.RegistryValueKind]::DWord) | Out-Null } else { Set-ItemProperty -Path $Path -Name UseDomainNameDevolution -Value ([System.Int32]$UseDomainNameDevolution) | Out-Null } } $Result = 0 break } {$_ -in @("UpdateDefault", "Domains")} { $NewDns = @() # Just set the new domains to the provided ones if ($PSCmdlet.ParameterSetName -eq "Domains") { $NewDns = $Domains } # Otherwise, if we're replacing, only add the new default domain elseif ($Replace) { $NewDns += $DefaultDomain } # Otherwise, we got a default domain, but we want to move it to the top else { [System.String[]]$Dns = (Get-CimClass -ClassName Win32_NetworkAdapterConfiguration).CimClassProperties["DNSDomainSuffixSearchOrder"].Value $Index = [System.Array]::IndexOf($Dns, $DefaultDomain) # Index will be -1 if not found, otherwise, we found it, so move it first if ($Index -ge 0) { $NewDns += $Dns[$Index] } for ($i = 0; $i -lt $Dns.Length; $i++) { if ($i -ne $Index) { $NewDns += $Dns[$i] } } } Write-Log -Message "Calling SetDNSSuffixSearchOrder CIM method." -Level VERBOSE $Result = (Invoke-CimMethod -ClassName Win32_NetworkAdapterConfiguration -MethodName SetDNSSuffixSearchOrder -Arguments @{"DNSDomainSuffixSearchOrder" = $NewDns}).ReturnValue break } } if ($ReturnStringErrorMessage) { if ($script:NicErrorMessages.ContainsKey([System.UInt32]$Result) ) { Write-Output -InputObject ($script:NicErrorMessages[[System.UInt32]$Result]) } else { Write-Output -InputObject "$Result" } } else { Write-Output -InputObject $Result } } End { } } Function Get-NetAdapterErrorCode { <# .SYNOPSIS Returns the string error message from a net adapter WMI method return value for the Win32_NetworkAdapterConfiguration class. .DESCRIPTION Attempts the find the string error message corresponding to the SetDNSSuffixSearchOrder method call on the Win32_NetworkAdapterConfiguration class. If the error message is not found, the error code is returned as a string. This cmdlet can be used with the Set-NetAdapterDnsSuffix cmdlet to translate the return code. .PARAMETER ErrorCode The error code returned by the Win32_NetworkAdapterConfiguration class method. .EXAMPLE Get-NetAdapterErrorCode -ErrorCode 73 This returns the string "Invalid domain name". .INPUTS System.Int32 .OUTPUTS System.String .NOTES AUTHOR: Michael Haken LAST UPDATE: 10/2/2017 #> [CmdletBinding()] [OutputType([System.String])] Param( [Parameter(Mandatory = $true, ValueFromPipeline = $true, Position = 0)] [System.UInt32]$ErrorCode ) Begin { } Process { if ($script:NicErrorMessages.ContainsKey($ErrorCode)) { Write-Output -InputObject $script:NicErrorMessages[$ErrorCode] } else { Write-Output -InputObject "$ErrorCode" } } End { } } $script:IPv6Configs = @( [PSCustomObject]@{Name="IPv6 Disabled On All Interfaces";Value="0xFFFFFFFF"}, [PSCustomObject]@{Name="IPv6 Enabled only on tunnel interfaces";Value="0xFFFFFFFE"}, [PSCustomObject]@{Name="IPv6 Disabled On Tunnel Interfaces, Enabled On All Others";Value="0xFFFFFFEF"}, [PSCustomObject]@{Name="IPv6 Disabled On Loopback Interface, Enabled On All Others";Value="0xFFFFFFEE"}, [PSCustomObject]@{Name="IPv6 Disabled, Prefer IPv6 over IPv4";Value="0xFFFFFFDF"}, [PSCustomObject]@{Name="IPv6 Enabled Only On Tunnel Interfaces, Prefer IPv6 of IPv4";Value="0xFFFFFFDE"}, [PSCustomObject]@{Name="IPv6 Enabled On All Non Tunnel Interfaces, Prefer IPv6 over IPv4";Value="0xFFFFFFCF"}, [PSCustomObject]@{Name="IPv6 Disabled On Loopback Interface, Prefer IPv6 over IPv4";Value="0xFFFFFFCE"}, [PSCustomObject]@{Name="IPv6 Disabled On All Interfaces";Value="0x000000FF"}, [PSCustomObject]@{Name="IPv6 Prefer IPv4 over IPv6 by changing entries in prefix policy table";Value="0x00000020"}, [PSCustomObject]@{Name="IPv6 Disabled on LAN and PPP interfaces ";Value="0x00000010"}, [PSCustomObject]@{Name="Disable Teredo";Value="0x00000008"}, [PSCustomObject]@{Name="Disable ISATAP";Value="0x00000004"}, [PSCustomObject]@{Name="Disable 6to4";Value="0x00000002"}, [PSCustomObject]@{Name="IPv6 Disabled on Tunnel Interfaces including ISATAP, 6to4 and Teredo";Value="0x00000001"} ) $script:NicErrorMessages = @{ [System.UInt32]0 = "Successful completion, no reboot required"; [System.UInt32]1 = "Successful completion, reboot required"; [System.UInt32]64 = "Method not supported on this platform"; [System.UInt32]65 = "Unknown failure"; [System.UInt32]66 = "Invalid subnet mask"; [System.UInt32]67 = "An error occurred while processing an Instance that was returned"; [System.UInt32]68 = "Invalid input parameter"; [System.UInt32]69 = "More than 5 gateways specified"; [System.UInt32]70 = "Invalid IP address"; [System.UInt32]71 = "Invalid gateway IP address"; [System.UInt32]72 = "An error occurred while accessing the Registry for the requested information"; [System.UInt32]73 = "Invalid domain name"; [System.UInt32]74 = "Invalid host name"; [System.UInt32]75 = "No primary/secondary WINS server defined"; [System.UInt32]76 = "Invalid file"; [System.UInt32]77 = "Invalid system path"; [System.UInt32]78 = "File copy failed"; [System.UInt32]79 = "Invalid security parameter"; [System.UInt32]80 = "Unable to configure TCP/IP service"; [System.UInt32]81 = "Unable to configure DHCP service"; [System.UInt32]82 = "Unable to renew DHCP lease"; [System.UInt32]83 = "Unable to release DHCP lease"; [System.UInt32]84 = "IP not enabled on adapter"; [System.UInt32]85 = "IPX not enabled on adapter"; [System.UInt32]86 = "Frame/network number bounds error"; [System.UInt32]87 = "Invalid frame type"; [System.UInt32]88 = "Invalid network number"; [System.UInt32]89 = "Duplicate network number"; [System.UInt32]90 = "Parameter out of bounds"; [System.UInt32]91 = "Access denied"; [System.UInt32]92 = "Out of memory"; [System.UInt32]93 = "Already exists"; [System.UInt32]94 = "Path, file or object not found"; [System.UInt32]95 = "Unable to notify service"; [System.UInt32]96 = "Unable to notify DNS service"; [System.UInt32]97 = "Interface not configurable"; [System.UInt32]98 = "Not all DHCP leases could be released/renewed"; [System.UInt32]100 = "DHCP not enabled on adapter"; [System.UInt32]2147786788 = "Write lock not enabled"; [System.UInt32]2147749891 = "Must be run with admin privileges" } |