We help IT Professionals succeed at work.

script

109 Views
Last Modified: 2020-10-13
Hello,

I'm looking for help to write a script to find out who are on the RDS and sign some of them off.  I like to use Task Schedule to run this script.  Currently, I run shutdown.exe /f /l to sign out individual user.  There must be a way to find out a list of users on the server and loop-through one by one to force them off the server.  Thank you.
Comment
Watch Question

CERTIFIED EXPERT

Commented:
psloggedon ( which you can download from the technet ) will display such a list remotely. i believe you can loop through the output and logout whoever you want using your existing command.

there is also a powershell way as well, and most likely something using the output of the existing "net" command. those should be rather easy to find online. i'll help with the crafting if you go that way.

also note that the windows management console has a snippet that allows to do such tasks graphically, though i'm unsure you can filter and logout a list of users easily
CERTIFIED EXPERT
Most Valuable Expert 2019
Most Valuable Expert 2018

Commented:
Try this PowerShell script; works remotely, can process multiple servers.
It's in test mode, the actual logoff part is commented out so that you can test it.
Function Get-UserSession {
[CmdletBinding()]
Param(
	[Parameter(Position=0, ValueFromPipeline=$true)]
	[String[]]$ComputerName = $ENV:ComputerName
)
	Process {
		$ComputerName | ForEach-Object {
			Try {
				Write-Verbose "Processing $($_) ..."
				$out = [ordered]@{}
				$out['ComputerName'] = $_
				$out['IPAddress'] = ([System.Net.Dns]::GetHostAddresses($_) | Where-Object {$_.AddressFamily -eq 'InterNetwork'})[0].IPAddressToString
				$output = & 'C:\Windows\system32\query.exe' user /server:$_ 2>&1
				If ($output -like '*No User exists*') {
					Write-Warning "[$($_)] $($output -join ' ')"
				} ElseIf ($output -like '*Error*') {
					Throw "[$($_)] $($output -join ' ')"
				} Else {
					$output |
						Select-Object -Skip 1 |
						Where-Object {$_ -match '(?<Current>.)(?<UserName>.{20})(?<SessionName>.{16})(?<ID>.{7})(?<State>.{8})\s+(?<IdleTime>\S+)\s+(?<LogonTime>.*)'} |
							ForEach-Object {
								ForEach ($prop in 'UserName', 'SessionName', 'ID', 'State', 'IdleTime', 'LogonTime') {$out[$prop] = $Matches[$prop].Trim()}
								[PSCustomObject]$out
							}
				}
			} Catch {
				$PSCmdlet.WriteError($_)
			}
		}
	}
}

$servers = "Server1", "Server2", "Server3"
$servers |
	Get-UserSession |
	ForEach-Object {
		Write-Host "Logging off $($_.UserName) from $($_.ComputerName)"
	#	& logoff.exe $_.SessionName /SERVER:$_.ComputerName
	}

Open in new window

Hiep NguyenIT Director

Author

Commented:
I copied to notepad and saved to logoff.vbs, then run it but I got error.
CERTIFIED EXPERT
Most Valuable Expert 2019
Most Valuable Expert 2018

Commented:
Again: this is a PowerShell script.
Save as .ps1 and run from a PowerShell console.
Jose Gabriel Ortega CastroCEO Faru Bonon IT&Agency /Top-Rated Freelancer (Upwork)/Photographer
CERTIFIED EXPERT
Awarded 2018
Distinguished Expert 2018

Commented:
Yeah, you need to save the text file with the PS1 extension (it's not a .vbs) because the solution given by odba is Powershell and not a visual basic script).

https://prnt.sc/sjqxo8
CERTIFIED EXPERT

Commented:
... or run "ps c:\path\to\whatever"
Hiep NguyenIT Director

Author

Commented:
Thank you for your help.

How I debug or pause at each user to examine?
Should I run this on domain controller or on each RDS?
CERTIFIED EXPERT

Commented:
Not my script but it seems to process a list of rdp servers so it should work pretty much anywhere on a domain providing you have adequate (admin ) privileges
CERTIFIED EXPERT
Most Valuable Expert 2019
Most Valuable Expert 2018

Commented:
You can run that on any machine remotely against a list of other machines.
Define the list of servers to run it against in line 35.
You can enter a line like
		Read-Host 'Return to continue'

Open in new window

between lines 39 and 40 to stop for each user.

And as I said, the script is in test mode and will not logoff anyone as long as line 40 stays commented.
Hiep NguyenIT Director

Author

Commented:
Try "ps logoff.ps1"
ps : Cannot find a process with the name "logoff.ps1". Verify the process name and call the cmdlet again.
At line:1 char:1
+ ps logoff.ps1
+ ~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (logoff.ps1:String) [Get-Process], ProcessCommandException
    + FullyQualifiedErrorId : NoProcessFoundForGivenName,Microsoft.PowerShell.Commands.GetProcessCommand

then try ".\logoff.ps1"
Get-UserSession : Exception calling "GetHostAddresses" with "1" argument(s): "No such host is known"
At C:\Users\Administrator\Desktop\logoff.ps1:37 char:2
+     Get-UserSession |
+     ~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [Get-UserSession], MethodInvocationException
    + FullyQualifiedErrorId : SocketException,Get-UserSession
Hiep NguyenIT Director

Author

Commented:
Is there a command (from cmd) to list all users currently on the server?  I don't need to do this remotely.
CERTIFIED EXPERT
Most Valuable Expert 2019
Most Valuable Expert 2018

Commented:
You don't pass a server name to the function:
Function Get-UserSession {
[CmdletBinding()]
Param(
	[Parameter(Position=0, ValueFromPipeline=$true)]
	[String[]]$ComputerName = $ENV:ComputerName
)
	Process {
		$ComputerName | ForEach-Object {
			Try {
				Write-Verbose "Processing $($_) ..."
				$out = [ordered]@{}
				$out['ComputerName'] = $_
				$out['IPAddress'] = ([System.Net.Dns]::GetHostAddresses($_) | Where-Object {$_.AddressFamily -eq 'InterNetwork'})[0].IPAddressToString
				$output = & 'C:\Windows\system32\query.exe' user /server:$_ 2>&1
				If ($output -like '*No User exists*') {
					Write-Warning "[$($_)] $($output -join ' ')"
				} ElseIf ($output -like '*Error*') {
					Throw "[$($_)] $($output -join ' ')"
				} Else {
					$output |
						Select-Object -Skip 1 |
						Where-Object {$_ -match '(?<Current>.)(?<UserName>.{20})(?<SessionName>.{16})(?<ID>.{7})(?<State>.{8})\s+(?<IdleTime>\S+)\s+(?<LogonTime>.*)'} |
							ForEach-Object {
								ForEach ($prop in 'UserName', 'SessionName', 'ID', 'State', 'IdleTime', 'LogonTime') {$out[$prop] = $Matches[$prop].Trim()}
								[PSCustomObject]$out
							}
				}
			} Catch {
				$PSCmdlet.WriteError($_)
			}
		}
	}
}

Get-UserSession |
	ForEach-Object {
		Write-Host "Logging off $($_.UserName) from $($_.ComputerName)"
	#	& logoff.exe $_.SessionName /SERVER:$_.ComputerName
	}

Open in new window

Hiep NguyenIT Director

Author

Commented:
Thanks everyone.  I'm going to write a simple program to do this using 2 DOS commands:

query user
logoff

With shutdown /f /l, it will close all opening programs/files log off the user without any warning.
Can I really do the same with logoff command?
CERTIFIED EXPERT

Commented:
shutdown can display a warning and allow a grace time. just use /t DELAY in the command. i am unsure logoff can do the same.

the tool i pointed above allows to list users locally or remotely. the output should be reasonably easy to process in a batch file
Hiep NguyenIT Director

Author

Commented:
https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/query-user 

Does any one know the size for each column "query user" returns?
CERTIFIED EXPERT

Commented:
i would expect it to change based on the length of the  user names. let's hope i am wrong ;)
the psloggedon tool i mentionned above should be more script-friendly if you can use it
odba's script seems ok to me as well
CERTIFIED EXPERT
Most Valuable Expert 2019
Most Valuable Expert 2018

Commented:
Why do you want to reinvent the wheel? My function above already parses this exact output.
Hiep NguyenIT Director

Author

Commented:
I'm not allow to run .ps1/.bat/.vbs (a lot more) on our system.
CERTIFIED EXPERT

Commented:
How do you expect to run anything ? Better tell us what IS available. From above comments, i was assuming you wanted a batch script.

Btw, whoever expects to achieve security with such limitations should probably get a different job asap.
IT Director
Commented:
This one is on us!
(Get your first solution completely free - no credit card required)
UNLOCK SOLUTION
CERTIFIED EXPERT
Most Valuable Expert 2019
Most Valuable Expert 2018

Commented:
So you are not allowed to run scripts, but you're expected to administer the RDS servers? And you can introduce and run your own executables? Wow. Just ... wow.
Anyway, PowerShell can easily send mails using Send-MailMessage.
And if whatever language you're using to create the program supports RegEx, you can just use the one from line 22.
Or try to "compile" your PowerShell scripts: https://github.com/MScholtes/PS2EXE

Can you successfully run something like the following:
powershell.exe -NoExit -Command "gci C:\Windows"

Open in new window

CERTIFIED EXPERT

Commented:
try .cmd with a batch file syntax. it will likely work.

use a dummy extension such as zzz and open it with "cmd". i am unsure but this probably also works with powershell.

you can also try various hacks such as spawning your script using the start command in a separate window, using an autoexec file in a regular directory, creating a shell extension if you can access the registry ...

windows execution protection by extension name is something you can bypass easily if you just mess a little around.

worst case scenario, you can install a separate interpreter such as bash or perl.
Hiep NguyenIT Director

Author

Commented:
As an admin, of course I can run anything but the plan is to give the *program* to user to run probably in task scheduler.  Another concern is user can modify any script and it becomes a security issue.  That's reason why I don't want to use script in this case.  I really appreciate your help and input.
CERTIFIED EXPERT

Commented:
Non admin users will no be able to modify the script if you setup adequate privileges. But they wont be able to run it as admin either unless you both code something and give them special privileges. My windows days are old but i recall impersonate client from thread.

If your users can run preconfigured scheduled tasks as admin, that should work. Likewise a service can do the trick if they are allowed to start them. Just make sure they cannot edit the script or run a different one.
Hiep NguyenIT Director

Author

Commented:
I got it to work the way that I wanted.  Thank you.
CERTIFIED EXPERT

Commented:
selected solution adds complexity, a false assertion, and does not answer the initial question in any way. mostly, it is a repetition of the question.

Gain unlimited access to on-demand training courses with an Experts Exchange subscription.

Get Access
Why Experts Exchange?

Experts Exchange always has the answer, or at the least points me in the correct direction! It is like having another employee that is extremely experienced.

Jim Murphy
Programmer at Smart IT Solutions

When asked, what has been your best career decision?

Deciding to stick with EE.

Mohamed Asif
Technical Department Head

Being involved with EE helped me to grow personally and professionally.

Carl Webster
CTP, Sr Infrastructure Consultant
Empower Your Career
Did You Know?

We've partnered with two important charities to provide clean water and computer science education to those who need it most. READ MORE

Ask ANY Question

Connect with Certified Experts to gain insight and support on specific technology challenges including:

  • Troubleshooting
  • Research
  • Professional Opinions
Unlock the solution to this question.
Join our community and discover your potential

Experts Exchange is the only place where you can interact directly with leading experts in the technology field. Become a member today and access the collective knowledge of thousands of technology experts.

*This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

OR

Please enter a first name

Please enter a last name

8+ characters (letters, numbers, and a symbol)

By clicking, you agree to the Terms of Use and Privacy Policy.