URAMIRAIKAN

1020のなれの果て (since 2005.6.19)

無操作が一定時間継続したときにログオフするPowerShellスクリプト

 お仕事での課題対応のための試作。
 共有PCやVDIでログインしたまま環境を占有しないようにするためとかの対応ですが、サードパーティ製品の利用が許可されなかった場合や、ロックがかかって一定時間経ったらのようなステップを踏むような場合のパーツとして。

 そんなわけでWindows標準のPowerShell、OSは最近のWindows 10が対象。それ以外の環境でも動くと思うけど動作確認はしていないです。

# Parameters Param ( [Parameter(HelpMessage="Timeout minutes until logoff")][alias("Timeout","t")][ValidateRange(1,1440)][Int]$TimeoutMin = 1, [alias("Force","f")][Switch]$ForceFlag ) $ActionInt = 0 if ($ForceFlag) { $ActionInt = $ActionInt + 4 } # Modules 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; } } } } '@ # Main Routine $Timeout = [TimeSpan]::FromMinutes($TimeoutMin) $Interval = [TimeSpan]::FromMilliseconds(850) do { Start-Sleep -Milliseconds 1000 $IdleTime = [PInvoke.Win32.UserInput]::IdleTime $TimeoutPercent = ($IdleTime.TotalSeconds / $Timeout.TotalSeconds) * 100 Write-Progress -Activity "Idle Timeout until Logoff" -Status ([String][Math]::Round($IdleTime.Totalseconds, 2) + " seconds") -PercentComplete $TimeoutPercent if ($IdleTime -gt $Timeout) { Write-Host "See you again!" (Get-WmiObject -Class Win32_OperatingSystem -ComputerName .).Win32Shutdown($ActionInt) } } while ($IdleTime -gt $Interval) exit

 TimeSpanオブジェクトを作成する方法を"New-TimeSpan"にしなかった理由はミリ秒を使いたかったからです。体感時間として1秒は結構タイムラグを感じるんですよね。あと、最初に取得するアイドルタイムが"Start-Sleep"に与えた時間より短くなるので、微調整したかったというのもあります。

 実行時のオプションはタイムアウト値 (分) と強制のスイッチ。"Write-Progress"を使っているのは個人的に試してみたかっただけで意味はないです。動作確認とかで視覚的にわかりやすいくらいですね。
 実際の実行方法は、タスクスケジューラでセッション切断時やロック時をトリガーに起動するようなケースを想定しています。