Test RPC ports via Powershell

Would you like to test whether one server can talk to another server via the (default) RPC ports? There is a very handy Powershell script that can do this.

1. Powershell script

You can use the below script to verify if the network ports are opened and one machine can connect to the other one.

Disclaimer: credits to the following blog for providing this script: Testing RPC ports with PowerShell (and yes, it’s as much fun as it sounds!) New and Improved!! – Scripting Blog (microsoft.com). I did make a few alterations in the parameters of the script.

Save the below as a Powershell script, and then run it.

# This Sample Code is provided for the purpose of illustration only and is not intended to be used in a production environment.
# THIS SAMPLE CODE AND ANY RELATED INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR
# FITNESS FOR A PARTICULAR PURPOSE.
#
#
# Script queries port 135 to get the listening ephemeral ports from the remote server
#  and verifies that they are reachable.
#
#
#  Usage:  RPCCheckv2 -Computer YourServerNameHere
#
#

<#PSScriptInfo
.VERSION 1.1
.GUID 2fda37e6-9d6d-4cff-b0ae-9f924ddf4afb
.AUTHOR Ryan Ries
.COMPANYNAME 
.COPYRIGHT 
.TAGS 
.LICENSEURI 
.PROJECTURI 
.ICONURI 
.EXTERNALMODULEDEPENDENCIES 
.REQUIREDSCRIPTS 
.EXTERNALSCRIPTDEPENDENCIES 
.RELEASENOTES
#>

<# 
.DESCRIPTION 
 This script tests TCP network connectivity to not just the RPC Endpoint Mapper on port 135, but it also checks TCP network connectivity to each of the registered endpoints returned by querying the EPM.  I wrote this because many firewall teams have a difficult time with RPC, and they will end up allowing the Endpoint Mapper on port 135, but forget to also allow the ephemeral ports through the firewall.  This script uses localhost by default, but obviously you can specify a remote machine name or IP address to test a server across the network.  The script works by P/Invoking functions exported from rpcrt4.dll to get an enumeration of registered endpoints from the endpoint mapper, so it's not just a wrapper around portqry.exe.  

 Added dictionary for return since this script needs the port numbers returned - JV 10-31-2021
#> 

Param(
[Parameter(Mandatory=$true)]
[string]$Computer
)
# 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')
    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;
            }


            // Returns a dictionary of <Uuid, port>
            public static Dictionary<int, string> QueryEPM(string host)
            {
                Dictionary<int, string> ports_and_uuids = new Dictionary<int, string>();
                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:"))
                            if (ports_and_uuids.ContainsKey(int.Parse(s.Split('[')[1].Split(']')[0])) == false) ports_and_uuids.Add(int.Parse(s.Split('[')[1].Split(']')[0]), elementIfId.Uuid.ToString());
                           
                        RpcBindingFree(ref elementBindingHandle);
                        
                    }
                    while (retCode != 1772); // RPC_X_NO_MORE_ENTRIES

                }
                catch(Exception ex)
                {
                    Console.WriteLine(ex);
                    return ports_and_uuids;
                }
                finally
                {
                    RpcBindingFree(ref bindingHandle);
                }
                
                return ports_and_uuids;
            }
        }
'@
    }
    PROCESS
    {
 
        [Bool]$EPMOpen = $False
        [Bool]$bolResult = $False
        $Socket = New-Object Net.Sockets.TcpClient
                
        Try
        {                    
            $Socket.Connect($ComputerName, 135)
            If ($Socket.Connected)
            {
                $EPMOpen = $True
            }
            $Socket.Close()                    
        }
        Catch
        {
            $Socket.Dispose()
        }
                
        If ($EPMOpen)
        {
            Add-Type $PInvokeCode
                    
            # Dictionary <Uuid, Port>
            $RPC_ports_and_uuids = [Rpc]::QueryEPM($Computer)
            $PortDeDup = ($RPC_ports_and_uuids.Keys) | Sort-Object -Unique
            Foreach ($Port In $PortDeDup)
            {
                $Socket = New-Object Net.Sockets.TcpClient
                Try
                {
                    $Socket.Connect($Computer, $Port)
                    If ($Socket.Connected)
                    {
                        Write-Output "$Port Reachable"
                    }
                    $Socket.Close()
                }
                Catch
                {
                    Write-Output "$Port Unreachable"
                    $Socket.Dispose()
                }

            }

        }

  
    }

    END
    {

    }
}

Test-RPC -ComputerName $Computer

Read-Host -Prompt “Press Enter to exit”

2. Run the script

When you run the script, it will ask for the computer name to connect to, and it will give the following output:

cmdlet RPCCheckv2.ps1 at command pipeline position 1
Supply values for the following parameters:
Computer: othermachine.local

49664 Reachable
49665 Reachable
49666 Reachable
49669 Reachable
49670 Reachable
49715 Reachable
49720 Reachable
49773 Reachable
50195 Reachable
Press Enter to exit:

The above output “reachable” indicates that the ports on the other machine are open and connection over RPC succeeded. If the output would contain “Unreachable” it means there is a firewall issue somewhere.

Hope this helped you. Good luck!

By Leendert de Borst

Freelance software architect with 10+ years of experience. Expert in translating complex technical problems into creative & simple solutions.