Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- # ==============================================================================
- # PABS: Powerplan And Brightness Selector (v1.31)
- # A lightweight utility to automate Windows Power Plans and Brightness levels.
- # written by MaxK https://www.reddit.com/user/Glad-Journalist-4807/
- # on ThinkPad X390/T14s gen 1 hybrid
- # Please keep the credits intact :)
- #
- # Changes in v1.31:
- # 1. Added verification when loading power plans from config file in case some of them were deleted
- # 2. Added a bit more logging
- # 3. Replaced Start-Process "powercfg.exe" with direct call - it's faster.
- # Changes in v1.3:
- # 1. Added "PABS_Config.txt" – automated generation and parsing of configuration file.
- # 2. Dynamic Power Plan Discovery – automatically finds all system GUIDs (including hidden ones).
- # 3. Critical Performance Optimization
- # – refactored process scanning using .NET and SessionID filtering.
- # - CPU usage reduction – achieved 3x lower CPU usage by eliminating WMI overhead and exceptions.
- # 4. High-resolution stopwatch for internal performance monitoring and Measure-Command for critical path monitoring (when $logCriticalPath=1)
- # 5. UI Optimization – tray icon and status updates are now event-driven (only on actual change).
- # 6. Added logging to file (when $logToFile=1)
- # Changes in v1.2:
- # 1. PS 7 compatibility corrections: replaced ContextMenu with ContextMenuStrip, MenuItems -> Items and MenuItem ->ToolStripMenuItem.
- # ==============================================================================
- # CONFIGURATION
- $PABSversion = "1.31"
- $ConfigFile = Join-Path $PSScriptRoot "PABS_Config.txt"
- $logCriticalPath = 0
- $logToFile = 0
- $logFile = Join-Path $PSScriptRoot "PABS_Log.txt"
- function Write-Log ($msg, $color = "White") {
- $timestamp = Get-Date -Format "HH:mm:ss:fff"
- $logLine = "[$timestamp] $msg"
- Write-Host $logLine -ForegroundColor $color
- if ($logToFile -eq 1) {
- try {
- $logLine | Out-File $logFile -Append -Encoding utf8
- } catch {
- }
- }
- }
- function Initialize-PABSConfig {
- if (Test-Path $ConfigFile) { return }
- Write-Log "First run: Generating PABS_Config.txt..." -ForegroundColor Yellow
- $output = @(
- "# PABS CONFIGURATION FILE",
- "# =======================",
- "# 1. PowerPlan Definition: PowerPlan=Name,GUID",
- "# 2. Default Plans: DefaultAC=Name | DefaultBat=Name",
- "# 3. Watchlist Rules: Mode | Path | PlanName",
- ""
- )
- $sysPlans = powercfg /l | Where-Object { $_ -match "GUID:" }
- $foundPlans = @()
- foreach ($line in $sysPlans) {
- if ($line -match "GUID:\s+([\w-]+)\s+\((.+)\)") {
- $guid = $matches[1]; $name = $matches[2].Replace("*", "").Trim()
- $output += "PowerPlan=$name,$guid"
- $foundPlans += $name
- }
- }
- $output += @(
- "",
- "# DEFAULTS",
- "DefaultAC=Balanced",
- "DefaultBat=Power Saver",
- "",
- "# WATCHLIST RULES (First match wins)",
- "# Format: AC/Bat | Path | PlanName",
- "AC | C:\Games\* | Ultimate Performance",
- "AC | C:\Program Files\Mozilla Firefox\* | High Performance",
- "Bat | C:\Games\* | Balanced",
- "Bat | C:\Program Files\* | Power Saver"
- )
- $output | Out-File $ConfigFile -Encoding utf8
- }
- $PowerPlans = @{}
- $WatchListAC = @()
- $WatchListBattery = @()
- $DefaultPPAC = "Balanced"
- $DefaultPPBattery = "Power Saver"
- Initialize-PABSConfig
- # get config
- if (Test-Path $ConfigFile) {
- Get-Content $ConfigFile | ForEach-Object {
- $line = $_.Trim()
- if ($line -match "^PowerPlan=(.+),(.+)") {
- $PowerPlans[$matches[1].Trim()] = $matches[2].Trim()
- }
- elseif ($line -match "^DefaultAC=(.+)") {
- $DefaultPPAC = $matches[1].Trim()
- }
- elseif ($line -match "^DefaultBat=(.+)") {
- $DefaultPPBattery = $matches[1].Trim()
- }
- elseif ($line -match "^(AC|Bat)\s*\|\s*(.+)\s*\|\s*(.+)") {
- $mode = $matches[1].Trim()
- $rule = @{ Path = $matches[2].Trim(); Plan = $matches[3].Trim() }
- if ($mode -eq "AC") { $WatchListAC += $rule } else { $WatchListBattery += $rule }
- }
- }
- }
- # verify plans
- $Aliases = @($PowerPlans.Keys)
- foreach ($alias in $Aliases) {
- $guid = $PowerPlans[$alias]
- $check = powercfg /l | Select-String $guid
- if (-not $check) {
- Write-Log "WARNING: Power Plan '$alias' ($guid) not found! Removing from list." "Red"
- $PowerPlans.Remove($alias)
- }
- }
- $Global:PABS_Timer = [System.Diagnostics.Stopwatch]::StartNew()
- # When set to 1, the current brightness level is preserved and set after switching plans
- $AutoInheritBrightness = 1
- # Interval for checking running processes and switching plans (in seconds)
- $ProcessCheckInterval = 5
- # Interval for polling keyboard state (Ctrl+Shift+B) in milliseconds
- $KeyCheckInterval = 80
- # Standard Windows GUID for the Video/Display subgroup
- $DisplaySubGroup = "7516b95f-f776-4464-8c53-06167f40cc99"
- # end of CONFIGURATION
- #WIN32 API&UTILS
- $WinFuncs = @"
- [DllImport("user32.dll")] public static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);
- [DllImport("user32.dll")] public static extern bool EnableMenuItem(IntPtr hMenu, uint uIDEnableItem, uint uEnable);
- [DllImport("user32.dll")] public static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);
- [DllImport("user32.dll")] public static extern bool IsWindowVisible(IntPtr hWnd);
- [DllImport("user32.dll")] public static extern short GetAsyncKeyState(int vKey);
- [DllImport("powrprof.dll")] public static extern uint PowerGetActiveScheme(IntPtr UserRootPowerKey, out IntPtr ActivePolicyGuiPtr);
- "@
- $Win32 = Add-Type -MemberDefinition $WinFuncs -Name "Win32Utils" -Namespace Win32 -PassThru
- # get console window
- $ConsolePtr = (Get-Process -Id $PID).MainWindowHandle
- # disable the "X" (Close) button to prevent accidental exit
- function Disable-CloseButton {
- $hMenu = [Win32.Win32Utils]::GetSystemMenu($ConsolePtr, $false)
- [void][Win32.Win32Utils]::EnableMenuItem($hMenu, 0xF060, 0x00000001)
- }
- # start the script hidden and lock the close button
- [void][Win32.Win32Utils]::ShowWindowAsync($ConsolePtr, 0) # 0 = SW_HIDE
- Disable-CloseButton
- # find the GUID of the "Display brightness"
- $BrightGUID = $null
- $query = powercfg /q SCHEME_CURRENT SUB_VIDEO
- foreach ($line in $query) {
- if ($line -match "GUID:\s+([\w-]+).+\(Display brightness\)") {
- $BrightGUID = $matches[1].Trim(); break
- }
- }
- Write-Log "BrightGUID $BrightGUID"
- # tray icon
- Add-Type -AssemblyName System.Windows.Forms, System.Drawing
- [System.Windows.Forms.Application]::EnableVisualStyles()
- $TrayIcon = New-Object System.Windows.Forms.NotifyIcon
- $TrayIcon.Icon = [System.Drawing.Icon]::ExtractAssociatedIcon((Get-Process -Id $PID).Path)
- $TrayIcon.Visible = $true
- $ContextMenu = New-Object System.Windows.Forms.ContextMenuStrip
- $StatusItem = New-Object System.Windows.Forms.ToolStripMenuItem -Property @{ Enabled = $false; Text = "Plan: Init..." }
- # dashboard
- $ToggleItem = New-Object System.Windows.Forms.ToolStripMenuItem
- $ToggleItem.Text = "Show Dashboard"
- $ToggleItem.add_Click({
- if ([Win32.Win32Utils]::IsWindowVisible($ConsolePtr)) {
- [void][Win32.Win32Utils]::ShowWindowAsync($ConsolePtr, 0) # Hide
- $ToggleItem.Text = "Show Dashboard"
- } else {
- [void][Win32.Win32Utils]::ShowWindowAsync($ConsolePtr, 5) # Show
- Disable-CloseButton
- $ToggleItem.Text = "Minimize to tray"
- }
- })
- $ExitItem = New-Object System.Windows.Forms.ToolStripMenuItem -Property @{ Text = "Exit" }
- $ExitItem.add_Click({ $TrayIcon.Visible = $false; [void](Stop-Process -Id $PID) })
- [void]$ContextMenu.Items.Add($StatusItem)
- [void]$ContextMenu.Items.Add("-")
- [void]$ContextMenu.Items.Add($ToggleItem)
- [void]$ContextMenu.Items.Add($ExitItem)
- $TrayIcon.ContextMenuStrip = $ContextMenu
- # get currebnt brightness
- function Get-CurrentBrightness {
- $bObj = Get-CimInstance -Namespace root/WMI -ClassName WmiMonitorBrightness | Select-Object -First 1
- return $bObj.CurrentBrightness
- }
- # set brightness level for both AC and DC modes for a target plan
- function Set-PlanBrightness ($targetGuid, $brightness) {
- if ($null -eq $BrightGUID) { return }
- [void](Start-Process "powercfg.exe" -ArgumentList "/setacvalueindex $targetGuid $DisplaySubGroup $BrightGUID $brightness" -WindowStyle Hidden -Wait)
- [void](Start-Process "powercfg.exe" -ArgumentList "/setdcvalueindex $targetGuid $DisplaySubGroup $BrightGUID $brightness" -WindowStyle Hidden -Wait)
- }
- function Get-IsOnAC {
- $battery = Get-CimInstance -ClassName Win32_Battery -ErrorAction SilentlyContinue
- if ($null -eq $battery) { return $true }
- return $battery.BatteryStatus -eq 2
- }
- function Get-ActivePlanGuid {
- $ptr = [IntPtr]::Zero
- [void][Win32.Win32Utils]::PowerGetActiveScheme([IntPtr]::Zero, [ref]$ptr)
- if ($ptr -ne [IntPtr]::Zero) {
- return ([System.Runtime.InteropServices.Marshal]::PtrToStructure($ptr, [type][Guid])).ToString().ToLower()
- }
- return ""
- }
- # main loop
- $lastProcessCheck = [DateTime]::MinValue
- $lastMode = $null
- Write-Log "PABS v$PABSversion Online - Monitoring started" "Cyan"
- $ActiveGUID = Get-ActivePlanGuid
- $ActiveAlias = "Unknown"
- foreach ($key in $PowerPlans.Keys) {
- if ($PowerPlans[$key].ToLower() -eq $ActiveGUID.ToLower()) {
- $ActiveAlias = $key
- break
- }
- }
- Write-Log "--- System State ---" "Gray"
- Write-Log "Current power plan: $ActiveAlias ($ActiveGUID)" "Cyan"
- while ($true) {
- [System.Windows.Forms.Application]::DoEvents()
- # Ctrl+Shift+B monitoring
- if ([Win32.Win32Utils]::GetAsyncKeyState(17) -band 0x8000) {
- if (([Win32.Win32Utils]::GetAsyncKeyState(16) -band 0x8000) -and ([Win32.Win32Utils]::GetAsyncKeyState(66) -band 0x8000)) {
- $currB = Get-CurrentBrightness
- Write-Log "Syncing brightness: $currB% to ALL defined plans. It may take a while..." "Magenta"
- foreach ($guid in $PowerPlans.Values) { Set-PlanBrightness $guid $currB }
- & powercfg.exe /setactive (Get-ActivePlanGuid)
- Start-Sleep -Milliseconds 500
- Write-Log "Syncing brightness: Finished" "Magenta"
- }
- }
- # monitoring and AC/battery logic
- $now = [DateTime]::Now
- if ($now -gt $lastProcessCheck.AddSeconds($ProcessCheckInterval)) {
- $sw = [System.Diagnostics.Stopwatch]::StartNew()
- $IsOnAC = Get-IsOnAC
- $currentModeStr = if($IsOnAC){"AC"}else{"BAT"}
- $CurrentWL = if($IsOnAC){$WatchListAC}else{$WatchListBattery}
- $TargetAlias = if($IsOnAC){$DefaultPPAC}else{$DefaultPPBattery}
- $time = Measure-Command {
- $currentSessionID = [System.Diagnostics.Process]::GetCurrentProcess().SessionId
- $procPaths = Get-CimInstance -ClassName Win32_Process -Filter "SessionId=$currentSessionID" |
- Select-Object -ExpandProperty ExecutablePath | Where-Object { $_ }
- }
- if ($logCriticalPath -eq 1 ) {
- Write-Log "Get process list: $($time.TotalMilliseconds) ms"
- }
- $time = Measure-Command {
- $TriggeringPath = "Default"
- :OuterLoop foreach ($item in $CurrentWL) {
- foreach ($path in $procPaths) {
- if ($path -like $item.Path) {
- $TargetAlias = $item.Plan
- $TriggeringPath = $path
- break OuterLoop
- }
- }
- }
- }
- if ($logCriticalPath -eq 1 ) {
- Write-Log "OuterLoop: $($time.TotalMilliseconds) ms"
- }
- $ActiveGUID = Get-ActivePlanGuid
- if ($logCriticalPath -eq 1) {
- $ActiveAlias = "Unknown"
- foreach ($key in $PowerPlans.Keys) {
- if ($PowerPlans[$key].ToLower() -eq $ActiveGUID.ToLower()) {
- $ActiveAlias = $key
- break
- }
- }
- Write-Log "--- System State ---" "Gray"
- Write-Log "Current Active: $ActiveAlias ($ActiveGUID)" "Cyan"
- Write-Log "Target Plan: $TargetAlias" "White"
- }
- if ($PowerPlans.ContainsKey($TargetAlias)) {
- $TargetGUID = $PowerPlans[$TargetAlias].ToLower()
- if ($ActiveGUID -ne $TargetGUID -or $currentModeStr -ne $lastMode) {
- $StatusItem.Text = "Plan: $TargetAlias [$currentModeStr]"
- $TrayIcon.Text = "PABS: $TargetAlias ($currentModeStr)"
- $lastMode = $currentModeStr
- }
- if ($ActiveGUID -ne $TargetGUID) {
- # inherit current brightness to the target plan if enabled
- if ($AutoInheritBrightness -eq 1) {
- $currB = Get-CurrentBrightness
- Write-Log "Inheriting brightness: $currB% for $TargetAlias" "Gray"
- Set-PlanBrightness $TargetGUID $currB
- }
- # apply the target power plan
- & powercfg.exe /setactive $TargetGUID
- [void](Start-Process "powercfg.exe" -ArgumentList "/setactive $TargetGUID" -WindowStyle Hidden -Wait)
- Write-Log "Switching to $TargetAlias ($currentModeStr). Triggered by: $TriggeringPath" "Yellow"
- }
- }
- $lastProcessCheck = $now
- }
- Start-Sleep -Milliseconds $KeyCheckInterval
- }
Advertisement
Add Comment
Please, Sign In to add comment