Loading
Your Intune Compliance Is Moving to Azure Attestation… and Your Firewall Might Break it
Microsoft is Unifying the Copilot Apps… What IT Admins need to know before September 2026
Remove Device Everywhere – Because Microsoft Thought 3 Portals Was a Good Idea
I Asked Copilot To Make ASCII Art… and It Broke My Soul
AZ-140 Renewal 2025 – What Microsoft Really Tested (and what they didn’t)
Let me paint you a picture

You’re working for a customer. A big one. The kind where policies exist… not because people follow them but because Legal needs to sleep at night.
And one of those policies is:
When you leave the office… SHUT DOWN YOUR COMPUTER

Simple right? RIGHT? … no? Of course not. Because there will always be users who:
And this client of mine took this policy seriously. Like… SERIOUSLY seriously. Security… Energy… Compliance… Nightly Maintenance… the whole checklist.
So… how do you enforce it?
Easy: You create a GPO that shuts the machine down when idle.
Or… at least… that’s the theory. Because in the real world?
A computer can be idle while:
GPO sees none of that. GPO only sees:
No mouse? No keyboard? -> Must be sleeping -> KILL IT WITH FIRE

Perfect if your organization is filled exclusively with interns and psychopaths. But not perfect for a customer who has legitimate long-running workloads.
So… what do you do?
I needed something smarter, something polite, something that didn’t kill a 3D render because someone went to lunch.
So… I wrote a script. A beautiful, slightly chaotic, very Engin-Style script.
# Time in seconds for idle detection (10 hours)
$idleTime = 36000
# Countdown time in seconds (2 hours)
$countdownTime = 7200
# Define the script for the pop-up
Add-Type -AssemblyName PresentationFramework
Add-Type @"
using System;
using System.Runtime.InteropServices;
public static class IdleTime
{
[StructLayout(LayoutKind.Sequential)]
struct LASTINPUTINFO
{
public uint cbSize;
public uint dwTime;
}
[DllImport("user32.dll")]
static extern bool GetLastInputInfo(ref LASTINPUTINFO plii);
public static uint GetIdleTime()
{
LASTINPUTINFO lastInputInfo = new LASTINPUTINFO();
lastInputInfo.cbSize = (uint)Marshal.SizeOf(typeof(LASTINPUTINFO));
GetLastInputInfo(ref lastInputInfo);
return ((uint)Environment.TickCount - lastInputInfo.dwTime) / 1000;
}
}
"@
function Show-Popup {
[void][System.Reflection.Assembly]::LoadWithPartialName('System.Windows.Forms')
[void][System.Reflection.Assembly]::LoadWithPartialName('System.Drawing')
# Create form
$form = New-Object Windows.Forms.Form
$form.Text = "Idle Warning"
$form.Size = New-Object Drawing.Size(500, 200)
$form.StartPosition = "CenterScreen"
$form.TopMost = $true
# Label for the message
$label = New-Object Windows.Forms.Label
$label.Text = "The computer has been idle for 10 hours. The computer will shutdown after 2 hours."
$label.AutoSize = $true
$label.Location = New-Object Drawing.Point(10, 20)
$form.Controls.Add($label)
# Countdown label
$countdownLabel = New-Object Windows.Forms.Label
$countdownLabel.Text = "Time remaining: 02:00:00"
$countdownLabel.AutoSize = $true
$countdownLabel.Location = New-Object Drawing.Point(10, 60)
$form.Controls.Add($countdownLabel)
# Shutdown Now button
$shutdownButton = New-Object Windows.Forms.Button
$shutdownButton.Text = "Shutdown Now"
$shutdownButton.Size = New-Object Drawing.Size(100, 40)
$shutdownButton.Location = New-Object Drawing.Point(50, 100)
$shutdownButton.Add_Click({
Stop-Timer
Shutdown-Computer
$form.Close()
})
$form.Controls.Add($shutdownButton)
# Cancel Shutdown button
$cancelButton = New-Object Windows.Forms.Button
$cancelButton.Text = "Cancel Shutdown"
$cancelButton.Size = New-Object Drawing.Size(100, 40)
$cancelButton.Location = New-Object Drawing.Point(200, 100)
$cancelButton.Add_Click({
Stop-Timer
[System.Windows.Forms.MessageBox]::Show("Shutdown canceled.")
$form.Close()
})
$form.Controls.Add($cancelButton)
# Function to stop the timer
function Stop-Timer {
if ($global:timer) {
$global:timer.Stop()
$global:timer.Dispose()
}
}
# Function to shutdown the computer
function Shutdown-Computer {
Stop-Timer
Stop-Computer -Force
}
# Set up timer for countdown using System.Windows.Forms.Timer
$global:timer = New-Object Windows.Forms.Timer
$global:timer.Interval = 1000 # 1 second
$global:timer.Add_Tick({
$global:countdownTime -= 1
$timeSpan = [System.TimeSpan]::FromSeconds($global:countdownTime)
$countdownLabel.Text = "Time remaining: " + $timeSpan.ToString("hh\:mm\:ss")
if ($global:countdownTime -le 0) {
Shutdown-Computer
$form.Close()
}
})
$global:timer.Start()
# Show the form
$form.Add_Shown({$form.Activate()})
[void]$form.ShowDialog()
}
# Idle detection loop
while ($true) {
# Get the system idle time in seconds
$idleSeconds = [IdleTime]::GetIdleTime()
if ($idleSeconds -ge $idleTime) {
Show-Popup
}
# Check every 60 seconds
Start-Sleep -Seconds 60
}And this is what it does:
It’s basically a polite “Bruh… are you still there?” assistant. And let’s be honest, after 12 hours? If you still haven’t checked your machine, it deserves to be shutdown.
I call the Windows API “GetLastInputInfo” through a little C# class inside Powershell. Yes… I know… C# inside powershell.
Don’t judge me.
Because yes… people actually leave devices unattended for 10 hours.
The popup basically says:
Yo… your machine… you know… has been idle for 10 hours.
I’m giving you 2 hours to fix your life choices. We can get the plutonium somewhere else… like… lightning or something
And then… the timer starts ticking.

The red pill… or the blue pill? Wait… that’s the Matrix… we were talking about Back to the Future a minute ago. I’m confused…

If you ignore my popup for 2 hours… I assume you’re either:
Either way: PC goes off
The solution is:
Your pick
Now, I know some PowerShell gurus out there are judging my script.

Users will forever find a way to break policies. So instead of fighting them… I built something that gives them a choice
A simple PowerShell script that solves a real problem in the real world.
Thanks for reading.
Cheers,
Engin
Engin SoysalMicrosoft MVP and Microsoft Certified Trainer, sharing practical experience with Azure, Microsoft Intune and endpoint engineering.
43 stories · read them all
0 Comments