Viewing Net Sessions using PowerShell and PInvoke

We are all used to view net sessions on a local or remote system by calling net session to see what clients are connected to another system such as a file server or even a domain controller. This provides a nice way to determine where a user might be logged in at assuming that they have an active session or one that is just idle. The problem with net session is that it requires admin rights on the system that you are running the command against in order for it to provide the data you need.


If you are a server admin, then this really isn’t that much of a deal as you can just use PowerShell remoting to query a bunch of  systems and get the information that you need. I wanted a way to  do this without worrying about admin rights or being able to remote into a system to get the information so I decided to look beyond the usual .Net and native PowerShell approaches to see if anything was available. The next logical step was to look lower in the stack and the Win32API and see what functions were available for me to use. I’ve done a fair amount of work with PInvoke and wasn’t afraid to see what kind of fun would await me if I happened to find something that might fit what I need.

After a decent amount of research,  I came across the NetSessionEnum function which provided me exactly the type of data that I am looking for. As with many of these functions, it isn’t enough to create the method to use but also to set up the Structs and/or Enums that the functions require to support the marshaling of data in and out of managed memory. In this case,  I have to make use of the SESSION_INFO_10 structure as I am looking to only return back data on the session which provides the client, username, active time and idle time. The image below highlights the structure I picked and also the other available Structs if I wanted different types of data.


The last thing that I need to look at is adding NetApiBufferFree so I can be sure to free up the buffer and avoid any unnecessary memory leaks.

Now that we have this out of the way, we can look to put these pieces together and make a function that we can use repeatedly.

If you want to see more about using pinvoke with PowerShell and a better look at what you need to do, then check out this article I did a while back. For this article, I am going to just point out one part that  I had to do in order to allow the parameters within the NetSessionEnum to properly work with the method.

Looking at the pinvoke signature for this function out on, you can see that the first 3 parameters are a little more unique than what I typically see in that they unmanaged type of LPWStr which is a 32 bit pointer.


That means that my usual approach to dynamically building the method has to account for this, otherwise just adding a string type will result in the method throwing an error when used.

I will build the method just like I normally would and give it all of the proper parameter and return value types that it needs. Instead of proceeding by adding some custom attributes to the method, I am going to focus first on defining the parameters that have special requirements by building custom attributes for those first.


#region Custom Attribute Builder
$ctor = [System.Runtime.InteropServices.MarshalAsAttribute].GetConstructor(@([System.Runtime.InteropServices.UnmanagedType]))
$CustomAttribute = [System.Runtime.InteropServices.UnmanagedType]::LPWStr
$CustomAttributeBuilder = New-Object System.Reflection.Emit.CustomAttributeBuilder -ArgumentList $ctor, $CustomAttribute
#endregion Custom Attribute Builder


Notice here that I am defining the LPWStr unmanaged type within the custom attribute. This will be important to add to my parameters that need it. Fortunately, these happen to be the first 3 parameters of the method (Servername, UserClientName and Username).  I need to make use of the DefineParameter method that is within the method object that I created earlier. All I need is the position of the parameter, a parameter attribute and supply $Null for the last parameter. After that I use SetCustomAttribute and give the parameter the extra attribute that it needs and there will be no problems with these parameters causing issues on the method.


#Define first three parameters with custom attributes
1..3 | ForEach {
    $Parameter = $PInvokeMethod.DefineParameter(

My function, Get-NetSession will get around that limitation that we saw earlier when trying to view the sessions on a domain controller. By design, I exclude sessions that this command creates on the remote system by looking at the current user and computer and performing the exclusion. If the user happens to be on a different system also, then it will be displayed.

Get-NetSession –Computername vdc1


I can use the –IncludeSelf parameter to include my own sessions create by the command.

Get-NetSession –Computername vdc1 –IncludeSelf


I also have a UserName parameter that accepts a single string to filter for a particular user if to avoid looking at a large dump of data.

You can find the script to download below as well as the source code from my GitHub repo at the bottom.

Download Script

Source Code

About Boe Prox

Microsoft PowerShell MVP working as a Senior Systems Administrator
This entry was posted in powershell and tagged , , , . Bookmark the permalink.

2 Responses to Viewing Net Sessions using PowerShell and PInvoke

  1. Pingback: Revisiting NetSession Function using PSReflect | Learn Powershell | Achieve More

  2. Gyz says:

    Hi Boe, thanks for this great article. Lately I came across a similar function Get-NetSessions from Powerview module. Can maybe interested for you..I digged not yet deeper into it to see any differences..but I definitely see use of your tool, thanks for your great work.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s