Reputation: 281
$idle_timout = New-TimeSpan -minutes 1
Add-Type @'
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace PInvoke.Win32 {
public static class UserInput {
[DllImport("user32.dll", SetLastError=false)]
private static extern bool GetLastInputInfo(ref LASTINPUTINFO plii);
[StructLayout(LayoutKind.Sequential)]
private struct LASTINPUTINFO {
public uint cbSize;
public int dwTime;
}
public static DateTime LastInput {
get {
DateTime bootTime = DateTime.UtcNow.AddMilliseconds(-Environment.TickCount);
DateTime lastInput = bootTime.AddMilliseconds(LastInputTicks);
return lastInput;
}
}
public static TimeSpan IdleTime {
get {
return DateTime.UtcNow.Subtract(LastInput);
}
}
public static int LastInputTicks {
get {
LASTINPUTINFO lii = new LASTINPUTINFO();
lii.cbSize = (uint)Marshal.SizeOf(typeof(LASTINPUTINFO));
GetLastInputInfo(ref lii);
return lii.dwTime;
}
}
}
}
'@
$userId = (Get-Process -PID $pid).SessionID
echo $userID
$loggedOff = 0
foreach ($user in $userid){
do
{
$idle_time = [PInvoke.Win32.UserInput]::IdleTime
if (($loggedOff -eq 0) -And ($idle_time -gt $idle_timout))
{
logoff $user
$loggedOff = 1
}
if ($idle_time -lt $idle_timout)
{
$loggedOff = 0
}
}
while (1 -eq 1)
}
What I am trying to do its log off all users in our conference rooms after a given idle time. What I am trying to do is find all session id's and log off all active sessions. I am not worried about losing work as these are conference room computers. The problem I have is that I can get the session id for the current logged in user but not for all the users logged in. If anyone has any insight it would be greatly appreciated.
Upvotes: 3
Views: 5994
Reputation: 53
I realize that I'm several years late on this. However, I recently worked on a similar script.
That being said, your original PowerShell Script would have worked just fine, if you simply got rid of the Foreach Loop, thereby formatting it as follows, and ran it as a User Logon/Startup Script (so that it runs under the User Context).
$idle_timout = New-TimeSpan -minutes 1
Add-Type @'
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace PInvoke.Win32 {
public static class UserInput {
[DllImport("user32.dll", SetLastError=false)]
private static extern bool GetLastInputInfo(ref LASTINPUTINFO plii);
[StructLayout(LayoutKind.Sequential)]
private struct LASTINPUTINFO {
public uint cbSize;
public int dwTime;
}
public static DateTime LastInput {
get {
DateTime bootTime = DateTime.UtcNow.AddMilliseconds(-Environment.TickCount);
DateTime lastInput = bootTime.AddMilliseconds(LastInputTicks);
return lastInput;
}
}
public static TimeSpan IdleTime {
get {
return DateTime.UtcNow.Subtract(LastInput);
}
}
public static int LastInputTicks {
get {
LASTINPUTINFO lii = new LASTINPUTINFO();
lii.cbSize = (uint)Marshal.SizeOf(typeof(LASTINPUTINFO));
GetLastInputInfo(ref lii);
return lii.dwTime;
}
}
}
}
'@
$loggedOff = 0
do
{
$idle_time = [PInvoke.Win32.UserInput]::IdleTime
if (($loggedOff -eq 0) -And ($idle_time -gt $idle_timout))
{
logoff
$loggedOff = 1
}
if ($idle_time -lt $idle_timout)
{
$loggedOff = 0
}
}
while ($LoggedOff -eq 0)
EXIT 0
Upvotes: 0
Reputation: 281
The script I used to achieve this can be found here https://github.com/NebulaCyberSolutions/PowershellScripts/blob/master/logoffdual.ps1. I paired this with a scheduled task that ran at any logon event that would auto log off the oldest user logged in. Effectively only allowing one login at a time to conference room pc's
Upvotes: 0
Reputation: 437688
Building on Anthony Stringer's helpful answer:
To get an array of all session names associated with users:
$userSessionNames = query user | Select-Object -Skip 1 | % { (-split $_)[2] }
((Get-Process).SessionId | Sort-Object -Unique
would give you all distinct session IDs, but that would include sessions not associated with users. That said, if non-user sessions - such as 0
for services
and 65537
for rdp-tcp
- are all well-known, they could be filtered out.)
Note, however, that your foreach ($user in $userid)
loop (where $user
really refers to a user session):
GetLastInputInfo
does not provide system-wide user input information across all running sessions. Rather, GetLastInputInfo provides session-specific user input information for only the session that invoked the function." - see https://msdn.microsoft.com/en-us/library/windows/desktop/ms646302(v=vs.85).aspxUpvotes: 1
Reputation: 1016
you can better do it with remote desktop session host configuration idle time limit to your desired time.
Upvotes: 2
Reputation: 2001
here are some options that may be of use
powershell way
$computer = 'localhost'
$owners = @{}
Get-WmiObject win32_process -ComputerName $computer -Filter 'name = "explorer.exe"' | % {$owners[$_.handle] = $_.getowner().user}
Get-Process -ComputerName $computer explorer | % {$owners[$_.id.tostring()]}
or these
$server = 'localhost'
(quser /server:$server) -replace '\s{2,}', ',' | ConvertFrom-Csv
# IDENTICAL
query session /server:$server
qwinsta /server:$server
# IDENTICAL
query user /server:$server
quser /server:$server
qprocess explorer.exe /server:$server
Upvotes: 3