Skip to content

Instantly share code, notes, and snippets.

@timothywarner
Last active December 1, 2024 22:07
Show Gist options
  • Select an option

  • Save timothywarner/356f6346a96a242196fe2b758234b905 to your computer and use it in GitHub Desktop.

Select an option

Save timothywarner/356f6346a96a242196fe2b758234b905 to your computer and use it in GitHub Desktop.
PowerShell script that simulates random, human-generated keyboard input
[CmdletBinding()]
param(
[Parameter()]
[switch]$Force,
[Parameter()]
[switch]$TestMode
)
# Stay-Awake simulates natural human keyboard activity during work hours to prevent
# system idle states. It uses harmless keystrokes and realistic timing patterns to
# maintain system activity without interfering with normal operations.
#
# Author: Tim Warner
# GitHub: @timothywarner; @timothywarner-org
# Version: 2.1.0
# License: MIT
#
# Usage Examples:
# # Normal work hours operation (Mon-Fri, ~6am-6pm)
# .\start-stayawake.ps1
#
# # Test mode (simulates Wednesday at 2 PM)
# .\start-stayawake.ps1 -TestMode
#
# # Force mode (runs regardless of time/day)
# .\start-stayawake.ps1 -Force
#
# Features:
# - Simulates natural human keyboard patterns
# - Varies activity timing based on time of day
# - Safe, non-intrusive keystrokes
# - Detailed session reporting
# - Historical activity tracking
#
# Notes:
# - Uses only harmless keys (Shift, arrow keys)
# - Automatically adjusts for lunch hours
# - Press Ctrl+C to exit gracefully
function Start-StayAwake {
[CmdletBinding()]
param(
[Parameter()]
[switch]$Force,
[Parameter()]
[switch]$TestMode,
[Parameter()]
[switch]$Debug
)
# Initialize session variables
$script:sessionStartTime = Get-Date
$script:sessionEndTime = $script:sessionStartTime
$script:clickCount = 0
$script:terminatedByCtrlC = $false
try {
# Verify we can use Windows Forms
Add-Type -AssemblyName System.Windows.Forms -ErrorAction Stop
# Test key sending capability
try {
[System.Windows.Forms.SendKeys]::SendWait("+")
} catch {
Write-Error "Failed to send test keystroke. Script may not work on this system."
throw
}
# Define work schedule
$baseStartTime = '6:00 AM'
$baseEndTime = '6:00 PM'
# Create random number generator
$random = New-Object System.Random
# TestMode override needs to come BEFORE the time check
if ($TestMode) {
Write-Host "πŸ§ͺ Test Mode: Simulating Wednesday at 2 PM..." -ForegroundColor Magenta
$isWeekday = $true
$currentTime = Get-Date
$currentTime = $currentTime.Date.AddHours(14) # Set to 2 PM
$todayStart = $currentTime.Date.AddHours(6) # 6 AM
$todayEnd = $currentTime.Date.AddHours(18) # 6 PM
} else {
# Regular time check
$currentTime = Get-Date
$isWeekday = $currentTime.DayOfWeek -notin 'Saturday', 'Sunday'
# Generate realistic schedule variations
$startOffsetMinutes = $random.Next(-15, 31)
$endOffsetMinutes = $random.Next(-10, 45)
$todayStart = [datetime]::Parse($baseStartTime).AddMinutes($startOffsetMinutes)
$todayEnd = [datetime]::Parse($baseEndTime).AddMinutes($endOffsetMinutes)
}
# Check if we should run (note TestMode is now checked first)
if ($TestMode) {
Write-Host "πŸ§ͺ Running in Test Mode (simulated time: $($currentTime.ToString('h:mm tt')))" -ForegroundColor Magenta
}
elseif ($Force) {
Write-Host "⚠️ Force mode enabled - ignoring time restrictions" -ForegroundColor Yellow
}
elseif (-not $isWeekday -or
$currentTime -lt $todayStart -or
$currentTime -gt $todayEnd) {
Write-Host "⏸️ Outside of today's work hours ($($todayStart.ToString('h:mm tt')) to $($todayEnd.ToString('h:mm tt')))" -ForegroundColor Yellow
Write-Host "πŸ’‘ Tip: Use -Force to override work hours or -TestMode to simulate work hours" -ForegroundColor Cyan
return
}
# Define safe keys that work on all keyboards
$keys = @(
"{RIGHT}", # Safe navigation keys
"{LEFT}",
"{DOWN}",
"{UP}",
"+" # Shift key (won't affect state)
)
# Register Ctrl+C handler
$null = Register-EngineEvent -SourceIdentifier PowerShell.Exiting -Action {
$script:terminatedByCtrlC = $true
}
Write-Host "πŸ“… Today's schedule:" -ForegroundColor Cyan
Write-Host "πŸƒ Starting at: $($todayStart.ToString('h:mm tt'))" -ForegroundColor Cyan
Write-Host "🏁 Ending at: $($todayEnd.ToString('h:mm tt'))" -ForegroundColor Cyan
Write-Host "`nPress Ctrl+C to exit gracefully" -ForegroundColor Yellow
while (-not $script:terminatedByCtrlC) {
$currentTime = Get-Date
if ($Force -or $TestMode -or
($currentTime -ge $todayStart -and
$currentTime -le $todayEnd)) {
# Select two complementary keys to cancel each other
$key1 = $keys[$random.Next(0, $keys.Length)]
[System.Windows.Forms.SendKeys]::SendWait($key1)
Start-Sleep -Milliseconds 100 # Brief pause
# If using a toggle key, untoggle it
if ($key1 -in "{NUMLOCK}", "{SCROLLLOCK}") {
[System.Windows.Forms.SendKeys]::SendWait($key1)
}
$script:keyPressCount++
# Debug output
if ($Debug) {
$status = [PSCustomObject]@{
Time = Get-Date -Format "HH:mm:ss"
Key = $key1
Count = $script:keyPressCount
NextDelay = $baseDelay
}
Write-Host ($status | Format-Table | Out-String)
} else {
Write-Host "πŸ”‘ $(Get-Date -Format "HH:mm:ss") - Key: $key1" -ForegroundColor Green
}
# Calculate delay based on time of day
$hourOfDay = $currentTime.Hour
$baseDelay = switch ($hourOfDay) {
{$_ -in 6..8} { $random.Next(20, 61) } # Morning
{$_ -in 9..11} { $random.Next(10, 41) } # Peak morning
{$_ -in 12..13} { $random.Next(180, 301) } # Lunch
{$_ -in 14..16} { $random.Next(15, 46) } # Afternoon
{$_ -in 17..18} { $random.Next(30, 91) } # Evening
default { $random.Next(20, 61) }
}
Write-Host "πŸ”‘ Sent key: $key" -ForegroundColor Green
Write-Host "⏲️ Next activity in $baseDelay seconds..." -ForegroundColor Magenta
Start-Sleep -Seconds $baseDelay
} else {
break
}
}
} catch {
Write-Error "An error occurred: $($_.Exception.Message)"
Add-Content -Path "error.log" -Value "$(Get-Date): $($_.Exception.Message)`nStackTrace: $($_.Exception.StackTrace)"
} finally {
# Clean up event handler
Get-EventSubscriber -SourceIdentifier PowerShell.Exiting -ErrorAction SilentlyContinue |
Unregister-Event
# Calculate final statistics
$script:sessionEndTime = Get-Date
$sessionDuration = New-TimeSpan -Start $script:sessionStartTime -End $script:sessionEndTime
# Save session data
$csvPath = "stayawake-data.csv"
$historicalData = @()
if (Test-Path $csvPath) {
$historicalData = @(Import-Csv -Path $csvPath)
}
$newEntry = [PSCustomObject]@{
Date = $script:sessionStartTime.ToString('yyyy-MM-dd HH:mm:ss')
Clicks = $script:clickCount
Duration = [math]::Round($sessionDuration.TotalMinutes, 2)
}
$historicalData = @($historicalData) + @($newEntry)
$historicalData | Export-Csv -Path $csvPath -NoTypeInformation
# Generate report
$report = @"
πŸ“Š Session Report:
-------------------
πŸ•’ Start Time: $($script:sessionStartTime.ToString('yyyy-MM-dd HH:mm:ss'))
End Time: $($script:sessionEndTime.ToString('yyyy-MM-dd HH:mm:ss'))
⏳ Duration: $([math]::Round($sessionDuration.TotalMinutes, 2)) minutes
πŸ–±οΈ Clicks Sent: $script:clickCount
πŸ† Highest Click Count: $(($historicalData | Measure-Object -Property Clicks -Maximum).Maximum)
"@
Write-Host $report -ForegroundColor Green
if ($script:terminatedByCtrlC) {
Write-Host "πŸ›‘ Program terminated by user (Ctrl+C)." -ForegroundColor Red
}
Write-Host "πŸ‘‹ Goodbye! Have a great day! 😊" -ForegroundColor Green
}
}
# Run the function if the script is called directly
if ($MyInvocation.InvocationName -ne '.') {
# Create params hashtable from bound parameters
$params = @{}
# Only add parameters that were actually passed to the script
if ($PSBoundParameters.ContainsKey('Force')) { $params['Force'] = $Force }
if ($PSBoundParameters.ContainsKey('TestMode')) { $params['TestMode'] = $TestMode }
Start-StayAwake @params
}
# Test/Debug invocation
if ($MyInvocation.ScriptName -eq $PSCommandPath) {
# Quick test - run for 30 seconds with debug output
$params = @{
Force = $true
Debug = $true
}
Write-Host "πŸ§ͺ Running 30-second test..." -ForegroundColor Magenta
Start-StayAwake @params
Start-Sleep -Seconds 30
Write-Host "βœ… Test complete!" -ForegroundColor Green
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment