Last active
December 1, 2024 22:07
-
-
Save timothywarner/356f6346a96a242196fe2b758234b905 to your computer and use it in GitHub Desktop.
PowerShell script that simulates random, human-generated keyboard input
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| [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