Find Out How To Get Idle Time from a Group of PCs

Adam Bertram

Adam Bertram

Read more posts by this author.

The time comes when a manager walks into your office and says “We’re tightening the belt this year. One way we’re looking to save money is to remove unused PCs from 1 area and move it into another area. Give me a list of all PCs that haven’t been used in X days.” You agree to do it without thinking as usual and think no big deal. After a few minutes of looking into it you then think “…ummm, what really does “unused” mean anyway?” Does “unused” mean users aren’t working on it and just use it as a Facebook machine? Does “unused” mean X application isn’t being executed on it or does it simply mean no keyboard or mouse activity at all?

After you grill the manager a little bit you find out that he wants all PCs that haven’t had any kind of keyboard or mouse activity for 1 week. Fine. Game on.

I came across this awesome StackOverflow question which did 90% of the work for me.

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
        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;

$(([PInvoke.Win32.UserInput]::IdleTime).TotalMinutes)" | Add-Content -Path "\\SERVER\C$\FOLDER\$($env:COMPUTERNAME)-idletime.txt"

This is nearly exactly the same as the author example but I needed to modify it for a mass deployment. All I’m doing it executing the script on a workstation and getting the total idle time in minutes.

I’m then adding this to a file called PCNAME-idletime.txt on a server. I’m using SCCM so the deployment of the script was trivial.

After all workstations completed and I had a whole bunch of text files in the server’s folder I then merged them all into 1 single CSV and voila!, the manager got what he wanted!

Get-ChildItem '\\SERVER\C$\FOLDER' | select @{n='PCName';e={$_.BaseName.Replace('-idletime.txt','')}},@{n='IdleTime';e={(Get-Content $_.FullName)}} | Export-Csv -NoTypeInformation -Append -Path CSVFILE.csv

This one-liner lists all the text files and using calculated properties creates a name to idle time reference which I then export out into a CSV. What I end up with is something like this:

PCName,Idletime PC1,345 PC2,123 PC3,0

I hope this helps the next time you want to get unused PCs!

Subscribe to Adam the Automator

Get the latest posts delivered right to your inbox

Looks like you're offline!