Created
October 11, 2019 09:05
-
-
Save changbowen/391fcc71c48fc3079eba0055d91d3dd4 to your computer and use it in GitHub Desktop.
modified version of the Test-RPC from Ryan Ries
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # Author: Ryan Ries [MSFT] | |
| # Origianl date: 15 Feb. 2014 | |
| #Requires -Version 3 | |
| Function Test-RPC { | |
| [CmdletBinding(SupportsShouldProcess = $True)] | |
| Param( | |
| [Parameter(ValueFromPipeline = $True)][String[]]$ComputerName = 'localhost', | |
| [int[]]$Ports = $null | |
| ) | |
| BEGIN { | |
| Set-StrictMode -Version Latest | |
| $PInvokeCode = @' | |
| using System; | |
| using System.Collections.Generic; | |
| using System.Runtime.InteropServices; | |
| public class Rpc | |
| { | |
| // I found this crud in RpcDce.h | |
| [DllImport("Rpcrt4.dll", CharSet = CharSet.Auto)] | |
| public static extern int RpcBindingFromStringBinding(string StringBinding, out IntPtr Binding); | |
| [DllImport("Rpcrt4.dll")] | |
| public static extern int RpcBindingFree(ref IntPtr Binding); | |
| [DllImport("Rpcrt4.dll", CharSet = CharSet.Auto)] | |
| public static extern int RpcMgmtEpEltInqBegin(IntPtr EpBinding, | |
| int InquiryType, // 0x00000000 = RPC_C_EP_ALL_ELTS | |
| int IfId, | |
| int VersOption, | |
| string ObjectUuid, | |
| out IntPtr InquiryContext); | |
| [DllImport("Rpcrt4.dll", CharSet = CharSet.Auto)] | |
| public static extern int RpcMgmtEpEltInqNext(IntPtr InquiryContext, | |
| out RPC_IF_ID IfId, | |
| out IntPtr Binding, | |
| out Guid ObjectUuid, | |
| out IntPtr Annotation); | |
| [DllImport("Rpcrt4.dll", CharSet = CharSet.Auto)] | |
| public static extern int RpcBindingToStringBinding(IntPtr Binding, out IntPtr StringBinding); | |
| public struct RPC_IF_ID | |
| { | |
| public Guid Uuid; | |
| public ushort VersMajor; | |
| public ushort VersMinor; | |
| } | |
| public static HashSet<int> QueryEPM(string host) | |
| { | |
| var ports = new HashSet<int>(); | |
| int retCode = 0; // RPC_S_OK | |
| IntPtr bindingHandle = IntPtr.Zero; | |
| IntPtr inquiryContext = IntPtr.Zero; | |
| IntPtr elementBindingHandle = IntPtr.Zero; | |
| RPC_IF_ID elementIfId; | |
| Guid elementUuid; | |
| IntPtr elementAnnotation; | |
| try | |
| { | |
| retCode = RpcBindingFromStringBinding("ncacn_ip_tcp:" + host, out bindingHandle); | |
| if (retCode != 0) | |
| throw new Exception("RpcBindingFromStringBinding: " + retCode); | |
| retCode = RpcMgmtEpEltInqBegin(bindingHandle, 0, 0, 0, string.Empty, out inquiryContext); | |
| if (retCode != 0) | |
| throw new Exception("RpcMgmtEpEltInqBegin: " + retCode); | |
| do | |
| { | |
| IntPtr bindString = IntPtr.Zero; | |
| retCode = RpcMgmtEpEltInqNext (inquiryContext, out elementIfId, out elementBindingHandle, out elementUuid, out elementAnnotation); | |
| if (retCode != 0) | |
| if (retCode == 1772) | |
| break; | |
| retCode = RpcBindingToStringBinding(elementBindingHandle, out bindString); | |
| if (retCode != 0) | |
| throw new Exception("RpcBindingToStringBinding: " + retCode); | |
| string s = Marshal.PtrToStringAuto(bindString).Trim().ToLower(); | |
| if(s.StartsWith("ncacn_ip_tcp:")) { | |
| var portNum = int.Parse(s.Split('[')[1].Split(']')[0]); | |
| if (!ports.Contains(portNum)) | |
| ports.Add(portNum); | |
| } | |
| RpcBindingFree(ref elementBindingHandle); | |
| } | |
| while (retCode != 1772); // RPC_X_NO_MORE_ENTRIES | |
| } | |
| catch(Exception ex) | |
| { | |
| Console.WriteLine(ex); | |
| return ports; | |
| } | |
| finally | |
| { | |
| RpcBindingFree(ref bindingHandle); | |
| } | |
| return ports; | |
| } | |
| } | |
| '@ | |
| function TestConnect { | |
| param ( | |
| [Parameter(Mandatory = $true)] | |
| [string]$computer, | |
| [Parameter(Mandatory = $true)] | |
| [string]$protocol, | |
| [Parameter(Mandatory = $true)] | |
| [int]$port | |
| ) | |
| $protocol = $protocol.Trim().ToLowerInvariant() | |
| $result = $False | |
| switch ($protocol) { | |
| 'tcp' { | |
| $client = New-Object System.Net.Sockets.TcpClient | |
| try { | |
| $result = $client.ConnectAsync($computer, $port).Wait([System.TimeSpan]::FromSeconds(4)) | |
| } | |
| catch { | |
| # Write-Host $_.Exception | |
| } | |
| finally { | |
| $client.Close() | |
| $client.Dispose() | |
| $client = $null; | |
| } | |
| break | |
| } | |
| 'udp' { | |
| # this is not reliable because even if the port is open, server doesn't always send back a reply. | |
| $client = New-Object System.Net.Sockets.UdpClient | |
| $client.Client.SendTimeout = 2000 | |
| $client.Client.ReceiveTimeout = 2000 | |
| try { | |
| $endPoint = New-Object System.Net.IPEndPoint -ArgumentList @([System.Net.IPAddress]::Any, 0) | |
| $data = [System.Text.Encoding]::ASCII.GetBytes('!') | |
| $client.Connect($computer, $port) | |
| $client.Send($data, $data.Length) > $null | |
| if ($null -ne $client.Receive([ref]$endPoint)) { | |
| $result = $true | |
| } | |
| } | |
| catch { | |
| # Write-Host $_.Exception | |
| } | |
| finally { | |
| $client.Close() | |
| $client.Dispose() | |
| $client = $null; | |
| } | |
| break | |
| } | |
| Default { throw 'Unsupported protocol. Use tcp or udp.' } | |
| } | |
| return $result | |
| } | |
| } | |
| PROCESS { | |
| ForEach ($Computer In $ComputerName) { | |
| if (!$PSCmdlet.ShouldProcess($Computer)) { continue } | |
| if ($null -ne $Ports -and $Ports.Count -gt 0) { | |
| for ($i = 0; $i -lt $Ports.Count; $i++) { | |
| $port = $Ports[$i] | |
| $portInfo = [PSCustomObject]@{ | |
| ComputerName = $Computer; | |
| PortNumber = $port; | |
| TcpReachable = $null; | |
| UdpReachable = $null; | |
| } | |
| Write-Progress -Activity "Host address: $computer" -PercentComplete (($i + 0.5) / $Ports.Count * 100) -Status "Testing TCP port $port..." | |
| $portInfo.TcpReachable = (TestConnect $Computer 'tcp' $port) | |
| Write-Progress -Activity "Host address: $computer" -PercentComplete (($i + 1) / $Ports.Count * 100) -Status "Testing UDP port $port..." | |
| $portInfo.UdpReachable = (TestConnect $Computer 'udp' $port) | |
| $portInfo | |
| } | |
| } | |
| else { | |
| [Bool]$EPMOpen = $False | |
| $EPMOpen = TestConnect $Computer 'tcp' 135 | |
| If ($EPMOpen) { | |
| Add-Type $PInvokeCode | |
| Write-Progress -Activity "Host address: $computer" -Status "Querying EPM on port 135..." | |
| $RPCPorts = [Rpc]::QueryEPM($Computer) | |
| Foreach ($port In $RPCPorts) { | |
| $portInfo = [PSCustomObject]@{ | |
| ComputerName = $Computer; | |
| EndPointMapperOpen = $EPMOpen; | |
| PortNumber = $port; | |
| TcpReachable = $null; | |
| UdpReachable = $null; | |
| } | |
| Write-Progress -Activity "Host address: $computer" -PercentComplete (($i + 0.5) / $RPCPorts.Count * 100) -Status "Testing TCP port $port..." | |
| $portInfo.TcpReachable = (TestConnect $Computer 'tcp' $port) | |
| Write-Progress -Activity "Host address: $computer" -PercentComplete (($i + 1) / $RPCPorts.Count * 100) -Status "Testing UDP port $port..." | |
| $portInfo.UdpReachable = (TestConnect $Computer 'udp' $port) | |
| $portInfo | |
| } | |
| } | |
| Else { | |
| [PSCustomObject]@{ | |
| ComputerName = $Computer; | |
| EndPointMapperOpen = $EPMOpen; | |
| } | |
| } | |
| } | |
| } | |
| } | |
| END { | |
| } | |
| } |
Author
To be honest, I don't even remember I've ever worked on this...
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi there, just wondering if you remember why you modified the original code. I'm seeing that the original Test-RPC function crashes PowerShell in one of the environments where I am using it, and I'm trying to track down a possible fix. Thanks!