Skip to content

Instantly share code, notes, and snippets.

@changbowen
Created October 11, 2019 09:05
Show Gist options
  • Select an option

  • Save changbowen/391fcc71c48fc3079eba0055d91d3dd4 to your computer and use it in GitHub Desktop.

Select an option

Save changbowen/391fcc71c48fc3079eba0055d91d3dd4 to your computer and use it in GitHub Desktop.
modified version of the Test-RPC from Ryan Ries
# 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 {
}
}
@franklesniak
Copy link
Copy Markdown

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!

@changbowen
Copy link
Copy Markdown
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