Get idle time of machine

后端 未结 3 546
我在风中等你
我在风中等你 2020-12-15 06:25

Is there a way to get the idle time of the machine, as in the amount of time the machine has not been used for, in minutes/hours using Powershell or a batch file?

相关标签:
3条回答
  • 2020-12-15 06:34

    Here's a PowerShell solution that uses the Win32 API GetLastInputInfo.

    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;
                }
            }
        }
    }
    '@
    

    And an example usage:

    for ( $i = 0; $i -lt 10; $i++ ) {
        Write-Host ("Last input " + [PInvoke.Win32.UserInput]::LastInput)
        Write-Host ("Idle for " + [PInvoke.Win32.UserInput]::IdleTime)
        Start-Sleep -Seconds (Get-Random -Minimum 1 -Maximum 5)
    }
    
    0 讨论(0)
  • 2020-12-15 06:36
    $Last = [PInvoke.Win32.UserInput]::LastInput
    $Idle = [PInvoke.Win32.UserInput]::IdleTime
    $LastStr = $Last.ToLocalTime().ToString("MM/dd/yyyy hh:mm tt")
    Write-Host ("Last user keyboard/mouse input: " + $LastStr)
    Write-Host ("Idle for " + $Idle.Days + " days, " + $Idle.Hours + " hours, " + $Idle.Minutes + " minutes, " + $Idle.Seconds + " seconds.")
    

    Try this - although running remotely it may be running on a different session and therefore a different idle time?

    0 讨论(0)
  • 2020-12-15 06:54

    This vbscript code is inspired from the answered question to show you how we can use it for Auto-Shutdown your workstation after Idle Timeout !

    Auto-Shutdown_On_Idle_TimeOut.vbs


    '##########################################################################################################################
    '# Auto-Shutdown your workstation after Idle Timeout                                                                      #
    '# Script Name : Auto-Shutdown_On_Idle_TimeOut.vbs                                                                        #
    '# Arrêt automatique de votre poste de travail après le délai d'inactivité                                                #
    '# Idea comes from here ==>  This snippet is from http://stackoverflow.com/a/15846912                                     #
    '# https://stackoverflow.com/questions/15845508/get-idle-time-of-machine/15846912#15846912                                #
    '# https://gist.github.com/wendelb/1c364bb1a36ca5916ca4 ===> Auto-Lock your workstation after Idle-Timeout with PowerShell#
    '##########################################################################################################################
    Option Explicit
    Dim Copyright,Msg,MsgEN,MsgFR
    Copyright = "Auto-Shutdown your workstation after Idle Timeout " & ChrW(169) &" Hackoo 2020"
    
    MsgEN = Array("ATTENTION ! There is another instance running !",_
    "Save your Work because the computer will shutdown in 60 seconds")
    
    MsgFR = Array("ATTENTION ! Il y a une autre instance en cours d'exécution !",_
    "Sauvegarder votre Travail car l'ordinateur va s'éteindre dans 60 secondes")
    
    If AppPrevInstance() Then 
        If Oslang = 1036 Then
            Msg = MsgFR(0) 
        Else
            Msg = MsgEN(0)
        End If
        MsgBox Msg & VbCrLF & CommandLineLike(WScript.ScriptName),VbExclamation,Copyright
        WScript.Quit   
    Else 
        Dim Timeout_Idle,strCommand,VbsPath,ShortcutName
        If Oslang = 1036 Then
            Msg = MsgFR(1) 
        Else
            Msg = MsgEN(1)
        End If
        Timeout_Idle = "60"  '60 Minutes = 1 Heure = 1 Hour
        strCommand = "Shutdown.exe -s -t 60 -c " & DblQuote(Msg)
        VbsPath = Wscript.ScriptFullName
        ShortcutName = "Auto-Shutdown_On_Idle_TimeOut"
        Call Shortcut(VbsPath,ShortcutName)
        Call Write_Run_PScript(Timeout_Idle,strCommand)
    End If
    '---------------------------------------------------------------------------------------------------------------
    Sub Shortcut(PathApplication,ShortcutName)
        Dim objShell,StartFolder,objShortCut,MyTab
        Set objShell = CreateObject("WScript.Shell")
        MyTab = Split(PathApplication,"\")
        If ShortcutName = "" Then
            ShortcutName = MyTab(UBound(MyTab))
        End if
        StartFolder = objShell.SpecialFolders("Startup")
        Set objShortCut = objShell.CreateShortcut(StartFolder & "\" & ShortcutName & ".lnk")
        objShortCut.TargetPath = DblQuote(PathApplication)
        ObjShortCut.IconLocation = "%SystemRoot%\system32\SHELL32.dll,27"
        objShortCut.Save
    End Sub
    '---------------------------------------------------------------------------------------------------------------
    Function DblQuote(Str)
        DblQuote = Chr(34) & Str & Chr(34)
    End Function
    '---------------------------------------------------------------------------------------------------------------
    Sub Write_Run_PScript(Timeout_Idle,strCommand)
        Const ForWriting = 2
        Dim fs,Ws,ts,Ret,PSFile,ByPassPSFile
        Set fs = CreateObject("Scripting.FileSystemObject")
        Set Ws = CreateObject("WScript.Shell")
        PSFile = Ws.ExpandEnvironmentStrings("%Temp%") & fs.GetTempName & ".ps1"
        ByPassPSFile = "PowerShell -ExecutionPolicy bypass -noprofile -file "
        Set ts = fs.OpenTextFile(PSFile,ForWriting,True)
        ts.WriteLine "$idle_timeout = New-TimeSpan -Minutes "& Timeout_Idle &""
        ts.WriteLine "Add-Type @'"
        ts.WriteLine "using System;"
        ts.WriteLine "using System.Diagnostics;"
        ts.WriteLine "using System.Runtime.InteropServices;"
        ts.WriteLine "namespace PInvoke.Win32 {"
        ts.WriteLine "    public static class UserInput {"
        ts.WriteLine "        [DllImport(""user32.dll"", SetLastError=false)]"
        ts.WriteLine "        private static extern bool GetLastInputInfo(ref LASTINPUTINFO plii);"
        ts.WriteLine "        [StructLayout(LayoutKind.Sequential)]"
        ts.WriteLine "        private struct LASTINPUTINFO {"
        ts.WriteLine "            public uint cbSize;"
        ts.WriteLine "            public int dwTime;"
        ts.WriteLine "        }"
        ts.WriteLine "        public static DateTime LastInput {"
        ts.WriteLine "            get {"
        ts.WriteLine "                DateTime bootTime = DateTime.UtcNow.AddMilliseconds(-Environment.TickCount);"
        ts.WriteLine "                DateTime lastInput = bootTime.AddMilliseconds(LastInputTicks);"
        ts.WriteLine "                return lastInput;"
        ts.WriteLine "            }"
        ts.WriteLine "        }"
        ts.WriteLine "        public static TimeSpan IdleTime {"
        ts.WriteLine "            get {"
        ts.WriteLine "                return DateTime.UtcNow.Subtract(LastInput);"
        ts.WriteLine "            }"
        ts.WriteLine "        }"
        ts.WriteLine "        public static int LastInputTicks {"
        ts.WriteLine "            get {"
        ts.WriteLine "                LASTINPUTINFO lii = new LASTINPUTINFO();"
        ts.WriteLine "                lii.cbSize = (uint)Marshal.SizeOf(typeof(LASTINPUTINFO));"
        ts.WriteLine "                GetLastInputInfo(ref lii);"
        ts.WriteLine "                return lii.dwTime;"
        ts.WriteLine "            }"
        ts.WriteLine "       }"
        ts.WriteLine "    }"
        ts.WriteLine "}"
        ts.WriteLine "'@"
        ts.WriteLine "$locked = 0;"
        ts.WriteLine "Do {"
        ts.WriteLine "  $idle_time = [PInvoke.Win32.UserInput]::IdleTime;"
        ts.WriteLine "  if (($locked -eq 0) -And ($idle_time -gt $idle_timeout)) {"
        ts.WriteLine "      "&strCommand&""
        ts.WriteLine "      $locked = 1;"
        ts.WriteLine "  }"
        ts.WriteLine "  if ($idle_time -lt $idle_timeout) {"
        ts.WriteLine "      $locked = 0;"
        ts.WriteLine "  }"
        ts.WriteLine "    Start-Sleep -Seconds 10"
        ts.WriteLine "}"
        ts.WriteLine "while (1 -eq 1)"
        ts.Close
        Ret = Ws.run(ByPassPSFile & PSFile,0,True)
    End sub
    '----------------------------------------------------------------------------------------------------------------
    Function AppPrevInstance()   
        With GetObject("winmgmts:" & "{impersonationLevel=impersonate}!\\.\root\cimv2")   
            With .ExecQuery("SELECT * FROM Win32_Process WHERE CommandLine LIKE " & CommandLineLike(WScript.ScriptFullName) & _
                " AND CommandLine LIKE '%WScript%' OR CommandLine LIKE '%cscript%'")   
                AppPrevInstance = (.Count > 1)   
            End With   
        End With   
    End Function    
    '----------------------------------------------------------------------------------------------------------------
    Function CommandLineLike(ProcessPath)   
        ProcessPath = Replace(ProcessPath, "\", "\\")   
        CommandLineLike = "'%" & ProcessPath & "%'"   
    End Function
    '----------------------------------------------------------------------------------------------------------------
    Function OSLang()
        Dim dtmConvertedDate,strComputer,objWMIService,oss,os
        Set dtmConvertedDate = CreateObject("WbemScripting.SWbemDateTime")
        strComputer = "."
        Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
        Set oss = objWMIService.ExecQuery ("Select * from Win32_OperatingSystem")
        For Each os in oss
            OSLang = os.OSLanguage
        Next
    End Function
    '----------------------------------------------------------------------------------------------------------------
    
    0 讨论(0)
提交回复
热议问题