Created
July 30, 2025 07:56
-
-
Save gourytch/4dacfc15b38a15976df9bc45c78483f8 to your computer and use it in GitHub Desktop.
Set power saving scheme when workstation is locked
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
| <# | |
| # How to enable 4800..4803 events | |
| * run `gpedit.msc` | |
| * goto: | |
| ->`Computer Configuration` | |
| ->`Windows Settings` | |
| ->`Security Settings` | |
| ->`Advanced Audit Policy Configuration` | |
| ->`System Audit Policies - Local Group Policy Object` | |
| ->`Logon/Logoff` | |
| * enable: `Audit Other Logon/Logoff Events` | |
| # How to add CMD-wrapper | |
| * create LockWatcher.cmd | |
| * add: powershell -ExecutionPolicy Bypass -File "%~dp0\LockWatcher.ps1" | |
| #> | |
| # Check and Run with elevated privileges | |
| if (!([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) { | |
| Start-Process powershell.exe "-NoProfile -ExecutionPolicy Bypass -File `"$PSCommandPath`"" -Verb RunAs | |
| exit | |
| } | |
| $logPath = "C:\Temp\LockWatcher.log" | |
| # Ensure log directory exists | |
| $logDirectory = Split-Path $logPath -Parent | |
| if (-not (Test-Path $logDirectory)) { | |
| New-Item -ItemType Directory -Path $logDirectory | Out-Null | |
| } | |
| function Log($message) { | |
| try { | |
| Write-Host $message # Add console output for debugging | |
| $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss" | |
| "$timestamp $message" | Out-File $logPath -Append | |
| } | |
| catch { | |
| Write-Host "... Log error: $_" | |
| } | |
| } | |
| # Power Scheme Functions | |
| function Get-PowerSchemes { | |
| try { | |
| $schemes = @() | |
| $output = powercfg /list 2>&1 | |
| foreach ($line in $output) { | |
| if ($line -match 'Power Scheme GUID: ([\d\w-]+)\s+\((.*?)\)\s*(\*)?') { | |
| $schemes += [PSCustomObject]@{ | |
| Guid = $matches[1] | |
| Name = $matches[2] | |
| Active = [bool]$matches[3] | |
| } | |
| } | |
| } | |
| return $schemes | |
| } | |
| catch { | |
| Log "Error retrieving power schemes: $_" | |
| return $null | |
| } | |
| } | |
| function Set-PowerScheme($guid) { | |
| try { | |
| $result = powercfg /setactive $guid 2>&1 | |
| if ($LASTEXITCODE -ne 0) { | |
| throw $result | |
| } | |
| Log "Switched to power scheme: $((Get-PowerSchemes | Where-Object Guid -eq $guid).Name)" | |
| return $true | |
| } | |
| catch { | |
| Log "Error switching power scheme: $_" | |
| return $false | |
| } | |
| } | |
| # Initialize power schemes with validation | |
| try { | |
| $schemes = Get-PowerSchemes | |
| $powerSaverGuid = ($schemes | Where-Object Name -match 'Power saver').Guid | |
| $balancedGuid = ($schemes | Where-Object Name -match 'Balanced').Guid | |
| if (-not $powerSaverGuid) { throw "Power saver scheme not found" } | |
| if (-not $balancedGuid) { throw "Balanced scheme not found" } | |
| } | |
| catch { | |
| Log "Initialization failed: $_" | |
| exit 1 | |
| } | |
| # Event Handler Functions | |
| function global:SetPowerSavingScheme { | |
| Log "set power saving scheme." | |
| Set-PowerScheme $powerSaverGuid | Out-Null | |
| } | |
| function global:SetBalancedScheme { | |
| Log "set balanced scheme." | |
| Set-PowerScheme $balancedGuid | Out-Null | |
| } | |
| # Powered by Active Audit Policy: "Audit Other Logon/Logoff Events" enabled | |
| $ids = @(4800, 4801, 4802, 4803) | |
| Log "--- start ---" | |
| try { | |
| $initial = Get-WinEvent -FilterHashtable @{LogName='Security'; Id=$ids} -MaxEvents 1 -Oldest:$false -ErrorAction Stop | |
| $seen = $initial.RecordId | |
| Log "Set baseline to $seen." | |
| } catch { | |
| # No existing events found | |
| $seen = 0 | |
| Log "No existing events found — Set baseline to $seen." | |
| } | |
| Log "Starting polling for Event IDs $($ids -join ', ') from $seen ..." | |
| while ($true) { | |
| try { | |
| $events = Get-WinEvent -FilterHashtable @{LogName='Security'; Id=$ids} -MaxEvents 1 -ErrorAction Stop | |
| } | |
| catch { | |
| if ($_.FullyQualifiedErrorId -like '*NoMatchingEventsFound*') { | |
| # No new relevant events, skip logging | |
| Start-Sleep -Seconds 1 | |
| continue | |
| } | |
| else { | |
| # Unexpected error, display and break | |
| Log "Error reading events: $($_.Exception.Message)" | |
| break | |
| } | |
| } | |
| foreach ($evt in $events | Sort-Object RecordId) { | |
| $rec_id = $evt.RecordId | |
| $evt_id = $evt.Id | |
| if ($rec_id -le $seen) { continue } | |
| $seen = $reC_id | |
| $ts = $evt.TimeCreated.ToString("yyyy-MM-dd HH:mm:ss") | |
| Log "I has got the new event: ctime: [$ts], record ID: $rec_id, event ID: $evt_id" | |
| switch ($evt_id) { | |
| 4800 { | |
| Log "4800: The workstation was locked." | |
| SetPowerSavingScheme | |
| } | |
| 4801 { | |
| Log "4801: The workstation was unlocked." | |
| SetBalancedScheme | |
| } | |
| 4802 { | |
| Log "4802: The screen saver was invoked." | |
| SetPowerSavingScheme | |
| } | |
| 4803 { | |
| Log "4803: The screen saver was dismissed." | |
| SetBalancedScheme | |
| } | |
| } | |
| } | |
| Start-Sleep -Seconds 1 | |
| } | |
| Log "--- finish ---" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment