During a recent PowerShell training class we naturally covered PowerShell remoting. During the discussion I explained that a remote PSSession is essentially transparent to any currently logged on user. Unless of course you reboot the computer! One way you can identify a remote session is by the presence of the wsmprovhost process. You should see this process whenever there is a remote PSSession to the computer. So then the discussion turned to tracking who might have sessions across multiple computers which is especially helpful when dealing with disconnected sessions since you can only see your own sessions. I don't have a perfect solution, but let's see if this helps. Here is Get-PSRemoteSession.
ManageEngine ADManager Plus - Download Free Trial
Exclusive offer on ADManager Plus for US and UK regions. Claim now!
#requires -version 3.0
Function Get-PSRemoteSession {
<#
.SYNOPSIS
Get remote PSSession processes.
.DESCRIPTION
This command uses CIM to retrieve the wsmprovhost process that might be running
on a remote computer. You can use this information to determine how long a
session has been running and by what user. By default the command shows a
summary. If you want to see the full detail, use the -Full parameter. The
process owner and runtime will be added to the object in either case.
.PARAMETER Computername
This parameter has aliases of CN, Name and PSComputername
.PARAMETER Full
Write the full process object to the pipeline instead of the summary.
.EXAMPLE
PS C:\> Get-PSRemoteSession lon-dc1
ProcessID : 7016
CreationDate : 4/3/2014 1:25:32 PM
Runtime : 23:36:38.0799372
Owner : MYDOMAIN\Jeff
PSComputername : lon-dc1
ProcessID : 4676
CreationDate : 4/4/2014 12:23:41 PM
Runtime : 00:38:28.9568735
Owner : MYDOMAIN\Administrator
PSComputername : lon-dc1
.EXAMPLE
PS C:\> Get-PSRemoteSession lon-dc1 -full | select Owner,ProcessID,VM,WS,runtime
Owner : MYDOMAIN\Jeff
ProcessID : 7016
VM : 163262464
WS : 44392448
Runtime : 23:47:39.0140240
Owner : MYDOMAIN\Administrator
ProcessID : 4676
VM : 180445184
WS : 46551040
Runtime : 00:49:29.8899602
Get full process information and select some key properties
.EXAMPLE
PS C:\> get-remotesession chi-dc04,chi-dc01 | Group Owner -NoElement
Count Name
----- ----
1 GLOBOMANTICS\jeff
2 GLOBOMANTICS\Administr...
Display what user accounts are using remote sessions on the specified computers.
.EXAMPLE
PS C:\> Get-Content c:\work\computers.txt | Get-PSRemoteSession | where {$_.Runtime -gt "16:00:00"}
For a list of computers, get remote PSSessions that have been running longer
than 16 hours.
.EXAMPLE
PS C:\> get-remotesession chi-dc04,chi-dc01,chi-app01 | sort PSComputername | format-table -GroupBy PSComputername -Property CreationDate,Runtime,Owner
PSComputerName: chi-app01
CreationDate Runtime Owner
------------ ------- -----
4/11/2014 9:58:16 AM 00:04:29.8719959 GLOBOMANTICS\Administrator
PSComputerName: chi-dc01
CreationDate Runtime Owner
------------ ------- -----
4/11/2014 9:46:24 AM 00:16:21.2699348 GLOBOMANTICS\Administrator
PSComputerName: chi-dc04
CreationDate Runtime Owner
------------ ------- -----
4/11/2014 9:43:06 AM 00:19:36.8797428 GLOBOMANTICS\jeff
4/11/2014 9:47:25 AM 00:15:18.0563043 GLOBOMANTICS\Administrator
.NOTES
Version : 1.0
Last Updated : April 11, 2014
Learn more:
PowerShell in Depth: An Administrator's Guide (http://www.manning.com/jones2/)
PowerShell Deep Dives (http://manning.com/hicks/)
Learn PowerShell 3 in a Month of Lunches (http://manning.com/jones3/)
Learn PowerShell Toolmaking in a Month of Lunches (http://manning.com/jones4/)
****************************************************************
* DO NOT USE IN A PRODUCTION ENVIRONMENT UNTIL YOU HAVE TESTED *
* THOROUGHLY IN A LAB ENVIRONMENT. USE AT YOUR OWN RISK. IF *
* YOU DO NOT UNDERSTAND WHAT THIS SCRIPT DOES OR HOW IT WORKS, *
* DO NOT USE IT OUTSIDE OF A SECURE, TEST SETTING. *
****************************************************************
.LINK
Get-CimInstance
about_PSSessions
#>
[cmdletbinding()]
Param(
[Parameter(Position=0,
ValueFromPipeline=$True,
ValueFromPipelineByPropertyName=$True)]
[ValidateNotNullorEmpty()]
[Alias("CN","Name","PSComputername")]
[string[]]$Computername,
[switch]$Full
)
Begin {
Write-Verbose "Starting Get-PSRemoteSession"
} #begin
Process {
foreach ($computer in $computername) {
#test connection
Write-Verbose "Testing if computer $computer is pingable"
#do a single ping to verify computer is up
If (Test-Connection -ComputerName $computer -count 1 -Quiet) {
Write-Verbose "Querying $computer"
Try {
#use CIM to remotely query the computer
$data = Get-CimInstance win32_process -filter "name='wsmprovhost.exe'" `
-ComputerName $computer -ErrorAction Stop -ErrorVariable MyErr
if ($data) {
Write-verbose "Found sessions on $computer"
Write-verbose ($data[0] | out-string)
#add some custom properties
$data | Add-Member -membertype ScriptProperty -Name Runtime -value {
(Get-Date) - $this.creationdate}
$data | Add-Member -MemberType ScriptProperty -Name Owner -Value {
$owner = $this | Invoke-CimMethod -MethodName GetOwner
#write the owner information
"$($owner.domain)\$($owner.user)"
}
if ($Full) {
#write the full process object with additions to the pipeline
$data
}
else {
#get process summary
$data | Select ProcessID,CreationDate,RunTime,Owner,PSComputername
}
} #if $data
} #try
Catch {
Write-Warning "Could not query $computer"
Write-Warning $myErr.ErrorRecord.Exception.Message
Write-Debug "Suspend script to debug `$myErr exception"
} #catch
} #if test-connection works
else {
Write-Warning "Failed to ping $computer"
}
} #foreach computer
} #process
End {
Write-verbose "Ending Get-PSRemoteSession"
} #end
} #end function
This function takes a computername as a parameter. It does a quick ping to verify the computer is running. I probably should have made that optional, but I needed it at the time. The function then queries the computer using Get-CimInstance for all instances of the wsmprovhost.exe process. I'm using CIM because datetime values are automatically formatted which makes it much easier to add a custom property indicating how long the process, and presumably the remote session, have been running. I also add a custom property to get the process Owner. Due to a quirk (bug?) in the CIM cmdlets, I can even query a remote computer running PowerShell 2.0. When using a filter, the CIM cmdlets work with a v2 computer. I won't question it but will take advantage of it.
By default, the function writes a summary object to the pipeline.
The one thing I have yet to figure out is a way to show what computer each session is connected from. Although even if I could make the correlation with an active network connection, I'm not sure that would help in the event of a disconnected session. Nor can I tell the state of the session from the process.
I included an option to get the full process object so you could run commands like this:
But I suspect for many of you the summary will suffice. Here are some examples.
Get-Content c:\work\chi.txt | get-psremotesession | out-gridview -title "Remote Sessions"
If you kill the wsmprovhost process, that will break the PSSession so be careful. But at least now you have a way of identifying what sessions might be open. I hope you'll let me know what you think. Enjoy!






Reading through the script, one thing confuses me… $this. I don’t see it set anywhere, so is it a special variable?
Good eyes. Probably should have mentioned that. I am using Add-Member to define a new property. But instead of a NoteProperty I am creating a ScriptProperty. The value is the result of a scriptblock. In this context you use $this to indicate the current object in the pipeline. I could have taken extra steps to create my own object and type extension, in which case I would have used this same type of code to define the property, but in an XML file. My script does it all on the fly using Add-Member. So yeah, this is a special case.
So, it sounds kind of like $_, but for scriptblocks? I found it searching through about_Automatic_Variables, but the description seems a little vague and hard to wrap my head around.
Sorry, I know this is a bit off topic for what you were posting; I’d just never seen that one yet.
That is kinda correct. But as I said this is a special use case. I may have to write an article on this.
When we use the -Filter the CIM Cmdlets it does work with the machine having PowerShell v2…..So does it fall back to using DCOM when the remote machine doesn’t has winrm configured?
Just wanted to get little insight on this one…..this bug is helpful 🙂
That is the only explanation I can think of.