Private/Start-InterruptibleSleep.ps1

function Start-InterruptibleSleep {
    [CmdletBinding()]
    Param(
        [int]$Seconds
    )

    $deadline = (Get-Date).AddSeconds($Seconds)
    $PollMs = (($Seconds * 100), 3000 | Measure-Object -Minimum).Minimum
    Start-Sleep -Milliseconds (100)

    while ((Get-Date) -lt $deadline) {
        Start-Sleep -Milliseconds $PollMs

        if ((Get-UserIdleMilliseconds) -lt $PollMs) {
            return $false
        }
    }

    return $true
}

function Get-UserIdleMilliseconds {
    if (-not ("Win32.UserInputNative" -as [type])) {
        Add-Type -TypeDefinition @"
using System.Runtime.InteropServices;

namespace Win32 {
    public static class UserInputNative {
        [StructLayout(LayoutKind.Sequential)]
        public struct LASTINPUTINFO {
            public uint cbSize;
            public uint dwTime;
        }

        [DllImport("user32.dll")]
        public static extern bool GetLastInputInfo(ref LASTINPUTINFO plii);
    }
}
"@

    }

    $lii = New-Object Win32.UserInputNative+LASTINPUTINFO
    $lii.cbSize = [Runtime.InteropServices.Marshal]::SizeOf($lii)
    $ok = [Win32.UserInputNative]::GetLastInputInfo([ref]$lii)
    if (-not $ok) {
        throw "GetLastInputInfo failed."
    }

    $now = [uint32][Environment]::TickCount
    $last = [uint32]$lii.dwTime
    return [long]([uint32]($now - $last))
}