Skip to content

Instantly share code, notes, and snippets.

@JohnLBevan
Created April 27, 2017 11:27
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JohnLBevan/8173b2b8aeb84b0c0f4b48900e43a478 to your computer and use it in GitHub Desktop.
Save JohnLBevan/8173b2b8aeb84b0c0f4b48900e43a478 to your computer and use it in GitHub Desktop.
Find all RDP sessions on servers using a PowerShell function to wrap the Query Session logic. NB: Alternate Credentials not yet implemented
function Get-RdpSessions {
[CmdletBinding()]
param (
[Parameter(Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)]
$ComputerName
,
[Parameter()]
[switch]$Force
<# not yet implememnted
,
[Parameter()]
[System.Management.Automation.Credential()]
[System.Management.Automation.PSCredential]$Credential = [System.Management.Automation.PSCredential]::Empty
#>
)
process {
#force logic
[bool]$forced = $false
[string]$previousValue = '' #hold as string in case this property's held as something other than int; i.e. we don't want to cause side effects
if ($Force.IsPresent) {
try {
$previousValue = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine', $ComputerName).OpenSubKey('SYSTEM\CurrentControlSet\Control\Terminal Server').GetValue('AllowRemoteRPC')
write-verbose "$ComputerName's AllowRDP = $previousValue"
if($previousValue -ne '1') {
[Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine', $ComputerName).OpenSubKey('SYSTEM\CurrentControlSet\Control\Terminal Server',$true).SetValue('AllowRemoteRPC', 1)
$forced = $true
write-verbose "$ComputerName's AllowRDP Forced to 1"
}
} catch {
write-verbose "$ComputerName's AllowRDP failed to use the force :("
#even if we fail here, we still proceed; as we may be able to see sessions on the remote machine even if we can't read from its registry
}
}
#query session logic
try {
#https://ss64.com/nt/query-session.html
#pull the results into a variable
[string[]]$querySessionResult = (qwinsta "/server:$ComputerName")
#it would be nice to figute out the fixed-width column sizes automatically, in case they vary; but as the ID column is right aligned, that's not so easy:
#[string]$regex = '^' + (($querySessionResult[0] -split '\s\b' | select -skip 1 | %{"(?<$($_.trim())>.{$($_.Length+1)}"}) -join ')') + '.*)$'
#so instead using a fixed defintion:
[string]$regex = '^(?<SESSIONNAME>.{18})(?<USERNAME>.{18})(?<ID>.{11})(?<STATE>.{8})(?<TYPE>.{7})(?<DEVICE>.*)$' #column sizes from https://superuser.com/a/1000089/156700
$querySessionResult | select -skip 1 | ?{$_ -match $regex} | %{
$matches.remove(0)
$properties = @{}
$Matches.Keys | %{$properties[$_] = "$($Matches[$_])".Trim()}
(New-Object -TypeName PSObject -Property $properties)
}
} finally { #regardless of whether the above works, ensure that if we forced things, we put them back how they were
if($forced) {
[Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine', $ComputerName).OpenSubKey('SYSTEM\CurrentControlSet\Control\Terminal Server',$true).SetValue('AllowRemoteRPC', $previousValue)
write-verbose "$ComputerName's AllowRDP reset to $previousValue"
}
}
}
}
#demo for one computer
Get-RdpSessions -ComputerName $MyComputer -Force -Verbose
#demo for all servers in AD:
#uses Test-ConnectionQuickly workflow from here to avoid running against offline machines https://codereview.stackexchange.com/questions/97726/powershell-to-quickly-ping-a-number-of-machines
$servers = Get-AdComputer {(OperatingSystem -like "*server*") -and (Enabled -eq $true)}
$servers = Test-ConnectionQuickly $servers | ? Online
$servers | Get-RdpSessions -Force -Verbose | ? Username
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment