qwinsta /server:somesrv equivalent in Powershell? - powershell

When I run the qwinsta /server:somesrv command in cmd I can get a listing of all the current RDP sessions that are logged into a particular Windows server.
SESSIONNAME USERNAME ID STATE TYPE DEVICE
console 0 Conn wdcon
rdp-tcp 65536 Listen rdpwd
rdp-tcp#594 tom1 1 Active rdpwd
rdp-tcp#595 bob1 2 Active rdpwd
Is it possible to get a list like this on a remote server from Powershell so that the data can be used elsewhere?

There are multiple alternatives:
Use the Terminal Services PowerShell Module. Easy solution.
Writing a powershell wrapper that parses the output of qwinsta to objects. Easy solution. See example below
Use the Cassia.DLL .Net wrapper to access the native APIs that qwinsta runs behind the scene. This is the class that the TS Module uses. More difficult, but will have the benefit of being customized to your needs.
Go crazy and use the Native Methods that Cassia.DLL accesses using P/Invoke (wtsapi32.dll, kernel32.dll, winsta.dll). Hard and overcomplicated.
PowerShell-wrapper for qwinsta
function Get-TSSessions {
param(
$ComputerName = "localhost"
)
qwinsta /server:$ComputerName |
#Parse output
ForEach-Object {
$_.Trim() -replace "\s+",","
} |
#Convert to objects
ConvertFrom-Csv
}
Get-TSSessions -ComputerName "localhost" | ft -AutoSize
SESSIONNAME USERNAME ID STATE TYPE DEVICE
----------- -------- -- ----- ---- ------
services 0 Disc
console Frode 1 Active
rdp-tcp 65537 Listen
#This is objects, so we can manipulate the results to get the info we want. Active sessions only:
Get-TSSessions -ComputerName "localhost" | ? { $_.State -eq 'Active' } | ft -AutoSize SessionName, UserName, ID
SESSIONNAME USERNAME ID
----------- -------- --
console Frode 1

I used to use Terminal Services PowerShell Module (now in codeplex archive), but it was two years ago. I can't put my hand on it, but it also exists a function on gitshub or another site that embeded QWinsta/RmWinsta.

Related

Tracking the entire history of RDP sessions

We are trying to get the entire history of rdp servers via powershell.
I already looked at some example's like Qwinsta, quser, query user;
but that is not exactly what I am looking for.
I am looking for something I can write in Powershell to give me the entire history of it. from the day the machine is up.
example :
lets say I have a server I created last year.
I want to know who are the users that has logged into this server in the last year, which one is diss or active (kind of like query user or qwinsta) and when was the last time someone connected to this server.
NAME_OF_SERVER
SESSIONNAME USERNAME ID STATE DEVICE LAST_LOGIN
services 0 Disc
console 1 Conn
rdp-tcp#29 user1 2 Active
user2 3 Disc
appreciate any kind of help.
You can find the history by querying for RDP event logs. There's a handful of different events that will denote an RDP logon, but I'm going to use the RemoteConnectionManager log here:
$RDPAuths = Get-WinEvent -LogName 'Microsoft-Windows-TerminalServices-RemoteConnectionManager/Operational' -FilterXPath #'
<QueryList><Query Id="0"><Select>
*[System[EventID=1149]]
</Select></Query></QueryList>
'#
# Get specific properties from the event XML
[xml[]]$xml=$RDPAuths|Foreach{$_.ToXml()}
$EventData = Foreach ($event in $xml.Event) {
# Create custom object for event data
New-Object PSObject -Property #{
TimeCreated = (Get-Date ($event.System.TimeCreated.SystemTime) -Format 'yyyy-MM-dd hh:mm:ss K')
User = $event.UserData.EventXML.Param1
Domain = $event.UserData.EventXML.Param2
Client = $event.UserData.EventXML.Param3
}
}
$EventData | FT
You could pretty easily sort by user and find the last time they logged in using the output in $EventData:
TimeCreated User Domain Client
----------- ---- ------ ------
2021-09-23 12:02:03 -04:00 User01 MyDomain 10.10.10.10
2021-09-23 12:00:42 -04:00 User01 MyDomain 10.10.10.10
2021-09-21 11:39:08 -04:00 User02 MyDomain 10.10.10.20
There's an obvious limitation here that you can only search as far back as your event log goes, so "from the day the machine is up." may not be possible depending on how your event logs are configured.
Another option here can be to just check C:\users\* for which users have ever logged in.
For checking current sessions, I mostly use quser. If your server is running Terminal Services, you can use the RemoteDesktop module and run commands like Get-RDUserSession.

List all services in PowerShell

There are some services in Windows (such as http and USBStor) which are not listed when you view Services, or when running the Get-Service cmdlet. What is the simplest way to list all services, even the hidden or unlisted ones?
For example, the http and USBStor services are not enumerated when listing services, but they can be accessed directly by name:
PS C:\Windows\System32> Get-Service | Where-Object {"http","usbstor","spooler" -contains $_.Name}
Status Name DisplayName
------ ---- -----------
Running Spooler Print Spooler
PS C:\Windows\System32> Get-Service "http","usbstor","spooler"
Status Name DisplayName
------ ---- -----------
Running http HTTP Service
Running spooler Print Spooler
Stopped usbstor USB Mass Storage Driver
This might not be the most elegant way of getting all the services (hidden per say), but this will give you all the services along with ones these are dependent on.
Get-Service -RequiredServices | select -Unique DisplayName | ? {$_.DisplayName -like "Http*" }
Try 'Get-CimInstance'.
Such functions (Get-Service) delivered by Microsoft rely on and use CIM/Win32 classes.
(Get-Service only shows Windows services. 'HTTP' is a system driver.)
Get-CimInstance 'CIM_Service'

Fetching values from Net Use command using powershell

I am trying to get network mapped drives using below commands.
Get-WmiObject -Class Win32_MappedLogicalDisk | %{$_.Name}
Get-WmiObject -Class Win32_MappedLogicalDisk | %{$_.ProviderName}
This works in some system however does not in other systems(may be powershell version issue) So I thought of using net use command. However, I am unable to fetch the values or not sure how to get the values displays when i type 'net use'
when I type net use I get status, Local, Remote and Network column. I tried to use the below command to get the field values.
net use | select local.
but I get blank or nothing
Used below command.
net use | select local.
Need to get Local and Remote values from net use command.
See this for parsing legacy console output ---
How to Convert Text Output of a Legacy Console Application to PowerShell Objects
Yet, along with what LotPings gave you already. Your query could be a duplicate of this ...
Equivalent of net use (to list computer's connections) in powershell?
... and it's accepted answer
# For the mapped logical drive you can use WMI class Win32_MappedLogicalDisk :
Get-WmiObject Win32_MappedLogicalDisk
# Here is another way with Win32_LogicalDisk :
PS C:\> Get-WmiObject -Query "Select * From Win32_LogicalDisk Where DriveType = 4"
DeviceID : V:
DriveType : 4
ProviderName : \\jpbdellf1\c$
FreeSpace :
Size :
VolumeName :
# Edited
# You are right, you can get what you need with Win32_NetworkConnection :
Get-WmiObject Win32_NetworkConnection
LocalName RemoteName ConnectionState Status
--------- ---------- --------------- ------
\\jpbasusf1\temp Connected OK
# On Seven or W2K8 be careful to call this with the same user that run the NET USE because it's a session information.
How about using get-psdrive (the root header actually matches the displayroot property)?
get-psdrive | where displayroot -like '\\*'
Name Used (GB) Free (GB) Provider Root
---- --------- --------- -------- ----
Y 91.84 7.82 FileSystem \\server....
Depending on the PowerShell versions available you might encounter similar problems with
Get-SmbMapping which wraps the CimClass: ROOT/Microsoft/Windows/SMB:MSFT_SmbMapping.
But has otherwise an output resembling net use.
To process the real net use output and convert to an object with properties,
you may use:
$SmbMapping = (net use) -like '* \\*' | ForEach-Object {
$Status,$Local,$Remote,$Null = $_ -split ' +',4
[PSCustomObject]#{
Status = $Status
Local = $Local
Remote = $Remote
}
}
This works at least in my German locale Win10.
(Not sure about different status messages in other locales.)

Get username for PID (ProcessId)

I have a PID for which I want to check its username. I knew that we can use GetOwner(), but it is the valid method for Get-WmiObject Win32_Process. I am using Get-WmiObject -Class Win32_PerfRawData_PerfProc_Process in which there is no way to get username (as per I search online). So, I think to check PID separately is the only way to resolve this.
Can you please tell me how can I get the username of PID or get username inside Win32_PerfRawData_PerfProc_Process?
As it is described in this technet article :Technet you can use the code below.
In the last line you can put the process you want after the get-process command.
e.g. Get-Process outlook | select processname,Id,#{l="Owner";e={$owners[$_.id.tostring()]}}
$owners = #{}
gwmi win32_process |% {$owners[$_.handle] = $_.getowner().user}
Get-Process | select processname,Id,#{l="Owner";e={$owners[$_.id.tostring()]}}
The time it takes depends on how many services are currently running.
Your output will be like:
ProcessName Id Owner
----------- -- -----
OUTLOOK 13128 UserName
Hope that helps.
Kind regards.

How to check if a server is running windows 2003 or Windows 2008 by checking its RDP screen, through script?

We have recently acquired a small firm having 1500 servers on which our team doesn't has access as of now although they are in domain. We need to find out how many servers are running Windows 2k3 and how many are Windows 2k8.
I know the RDP screen of both of these versions are different , for example: if we RDP a Win2k3 machine, it gives a warning notice first and once we click Ok, it takes us to the credentials screen , but in case of Win2k8, it directly takes us to Crendentials which is a proof of the OS on the server. Doing this manually for 1500 servers is a time consuming task.
Can we implement this RDP screen logic using a script to find out the Windows OS version.
I can imagine an Algorithm something like that:
Enter server name.
Invoke mstsc for that server
Verify if the dialogue box is a direct prompt for credentials or not?
If so, print Windows 2k8, else 2k3/2k.
If this logic successful on one server, I can use it in a foreach loop for all servers and export in in Excel.
With 1500 servers I'm going to assume that you have an Active Directory in place. In that case you should be able to simply run a query against AD to retrieve the desired information:
Import-Module ActiveDirectory
$server = 'somehostname'
$dc = '...' # domain controller of trusted domain
$fltr = "OperatingSystem -like '*server*'"
Get-ADComputer -Filter $fltr -Property OperatingSystem -Server $dc |
Where-Object { $_.Enabled } |
Select-Object Name, OperatingSystem |
Sort-Object OperatingSystem, Name
Pipe the result into Export-Csv to create a CSV file that you can import into Excel.