Although Powershell in its latest version has literally a huge number of cmdlets (1602 under Windows 2012 R2) and the .Net Framework exposes almost anything a system administrator could dream of, there are times you are stuck and either fall back to what I inappropriately call 'legacy' executables, or call unmanaged APIs from within your code.
For example, a simple task like finding out which Windows process is holding which socket open is almost an impossible task for any beginner to intermediate Powershell developer.
Of course there is a cmdlet to find out the list of the running processes. It's called Get-Process and exposes many process properties: Process Id (PID), Process name, Handles, Non Paged Memory (NPM), Paged Memory (PM), Working Set (WS), Virtual Memory (VM) and many others, but not the number of the corresponding open port.
Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName ------- ------ ----- ----- ----- ------ -- ----------- 56 7 1796 7424 53 3.20 292 conhost 201 11 1532 3612 42 1.98 344 csrss 89 9 1260 3484 39 0.75 400 csrss
And of course, as the Scripting Guy explains, Powershell 4.0 has a cmdlet, named Get-NetTCPConnection, to show each TCP connection property, such as the local or remote IP address, the local or remote port, and the connection state. But unfortunately the information containing the ID of the process that set up each connection is not fetched.
LocalAddress LocalPort RemoteAddress RemotePort State AppliedSetting ------------ --------- ------------- ---------- ----- --------------
192.168.44.12 58849 192.168.44.14 389 Established Datacenter 192.168.44.12 58845 192.168.44.15 389 Established Datacenter ::1 54765 ::1 135 Established Datacenter
So, as far as I have found, if we stick to out-of-the-box Powershell cmdlets, there is no way to find the link between a process and a socket.
Looking into .Net, inside the System.Net.NetworkInformation namespace we can find an interesting class to explore: IPGlobalProperties. This class provides information about the network connectivity of the local computer and has:
- a method GetActiveTcpConnections() that returns a TCPConnectionInformation array holding three properties: LocalEndpoint, RemoteEndPoint and State
- a method GetActiveTcpListeners() which returns the IP address of the EndPoint as well as the Port number
Under Powershell you can query them straight away. Notice the we have to use :: to indicate to PowerShell that we want to work with a static method or property, like GetIPGlobalProperties:
[System.Net.NetworkInformation.IPGlobalProperties] | Get-Member -static
TypeName: System.Net.NetworkInformation.IPGlobalProperties
Name MemberType Definition
---- ---------- ----------
Equals Method static bool Equals(System.Object objA, System.Object objB)
GetIPGlobalProperties Method static System.Net.Netwo...ion.IPGlobalProperties GetIPGlobalProperties()
ReferenceEquals Method static bool ReferenceEquals(System.Object objA, System.Object objB)
[System.Net.NetworkInformation.IPGlobalProperties]::GetIPGlobalProperties().GetActiveTcpConnections()
[System.Net.NetworkInformation.IPGlobalProperties]::GetIPGlobalProperties().GetActiveTcpListeners()
Unfortunately the PID of the process opening the socket is still missing. Too bad.At this point, there are two options left. The first one is to fall back to using good old Netstat.exe and parse the result as Shay Levy did in an old post. You can check his function on PoshCode.
Parsing the output of netstat is not an easy task, and Shay does a brilliant job of splitting the text output and objectify it while adding the result of Get-Process to each connection, so that the PID is shown. The resulting PSObject can be filtered, sorted and formatted to best suit our needs. The function code is explained on his blog, so I won't delve more in it. I just invite you to have a look at it since its a great workaround (if not a full extent solution).
But how comes that we can't retrieve the same information netstat does when used with the -ano parameters? Well, the answer is simple: on a Windows Systems there is managed code and unmanaged code.
![]() |
Output of netstat -ano, with PID |
One of these functions, GetExtendedTCpTable, which exists inside the Internet Protocol Helper (IP Helper) API, is the one that Netstat probably use to find out the hidden link between processes and sockets.
These Win32 API functions can't be accessed directly from inside Powershell because there is no wrapper for them in the .Net Framework.
Fortunately there is the possibility to call Win32 and other unmanaged APIs from managed code (like C#) by using a Platform Invoke (P/Invoke), which is the operation the Common Language Runtime does when it finds and loads the required Win32 API DLL in memory, then invokes the desired function.
As Lee Holmes explains on his blog, there are a few ways to access a Win32 API from Powershell. One of them consists in using the Add-Type cmdlet, which takes in the C# signature of a function (GetExtendedTCpTable in our case, whose signature is here), and building a new class on it.
This is a pretty complex process, which goes well beyond the perimeter of this system administration blog, but I want all the same share the link to Justin blog who did an excellent job of importing the iphlpapi.dll and writing a Get-Netstat wrapper function.
![]() |
Add-Type cmdlet and C# signature |
Accessing a function inside an unmanaged API is a rewarding but dangerous task, since you are exiting the comfort zone your Powershell interpreter provides, so be careful, since you shouldn't be doing that unless you have very good Windows Internals and C# skills.
Shay's approach is brilliant, since it shows how strong Powershell is in handling raw text and beautifying it to a manageable object. I liked in particular the way he checks for a string being an IPV6 address inside an IF block:
if (($la = $item[1] -as [ipaddress]).AddressFamily -eq ‘InterNetworkV6′) { }I really like Powershell, because I never stop learning. Stay tuned for more!
No comments:
Post a Comment