Reputation: 981
I wanted to automate setting the action Windows 7 takes when the lid is closed on my work laptop, as this is reset via GPO every time i login.
I know that i can use the powercfg command in a batch script to achieve this:
powercfg -setacvalueindex 5ca83367-6e45-459f-a27b-476b1d01c936 0
powercfg -setdcvalueindex 5ca83367-6e45-459f-a27b-476b1d01c936 0
However, this was a good excuse to attempt learning some powershell. My first attempt takes over 10 seconds to run.
How can i improve on the below, both in terms of runtime & in terms of cleanliness of the code. What would be the idiomatic powershell way to approach the below?
$DO_NOTHING = 0
$activePowerPlan = Get-WmiObject -Namespace "root\cimv2\power" Win32_PowerPlan | where {$_.IsActive}
$rawPowerPlanID = $activePowerPlan | select -Property InstanceID
$rawPowerPlanID -match '\\({.*})}'
$powerPlanID = $matches[1]
# The .GetRelated() method is an inefficient approach, i'm looking for a needle and this haystack is too big. Can i go directly to the object instead of searching?
$lidCloseActionOnACPower = $activePowerPlan.GetRelated("win32_powersettingdataindex") | where {$_.InstanceID -eq "Microsoft:PowerSettingDataIndex\$powerPlanID\AC\{5ca83367-6e45-459f-a27b-476b1d01c936}"}
$lidCloseActionOnBattery = $activePowerPlan.GetRelated("win32_powersettingdataindex") | where {$_.InstanceID -eq "Microsoft:PowerSettingDataIndex\$powerPlanID\DC\{5ca83367-6e45-459f-a27b-476b1d01c936}"}
$lidCloseActionOnACPower | select -Property SettingIndexValue
$lidCloseActionOnACPower.SettingIndexValue = $DO_NOTHING
$lidCloseActionOnACPower.put()
$lidCloseActionOnBattery | select -Property SettingIndexValue
$lidCloseActionOnBattery.SettingIndexValue = $DO_NOTHING
$lidCloseActionOnBattery.put()
Upvotes: 16
Views: 30934
Reputation: 1
Agree with @js2010 this worked for me on Win 7 for Power Button
powercfg -setacvalueindex scheme_current sub_buttons pbuttonaction 0
0 = Do Nothing | 1 = Sleep | 2 = Hibernate | 3 = Turn Off
also tried
powercfg -setacvalueindex scheme_current sub_buttons sbuttonaction 0
sbuttonaction succesfully changed Sleep Button for me.
0 = Do Nothing | 1 = Sleep | 2+ = Do Nothing
Worked straight out of powershell.
Thanks for this !
Upvotes: 0
Reputation: 1304
I was just trying to replicate this on current Windows, and the old solutions would not work anymore (the "Activate" method is not offered in CIM and trying to apply the changes from WMI with the Activate method throws an error the method is not defined)
The code I ended up using to check if the settings are correct on the current PowerPlan (CIM) and the easiest way to apply the changes seemed to be powercfg.exe
directly.
The powercfg
lines that are uncommented are Aliases, since this Setting had an alias, but not all settings do.
If you do not know the GUIDs for the subgroups or settings you want, you should be able to check them with powercfg /Qh
which is quite lengthy and you will probably want to view in a text file.
This will run the report and open it in a text file
powercfg /Qh > %temp%\CurrentPower Settings.txt && %temp%\CurrentPowerSettings.txt
This script below just applies the settings to the current, active, Power Plan - but if you knew directly which
$DesiredValue = 0
$SettingSubGroupID = '4f971e89-eebd-4455-a8de-9e59040e7347'
$SettingGUID = '5ca83367-6e45-459f-a27b-476b1d01c936'
# Select Current Power Plan
$currentPLan = Get-CimInstance -namespace "root\cimv2\power" -class Win32_powerplan | where {$_.IsActive}
$schemeID= $currentPLan.InstanceID -replace "^Microsoft:PowerPlan\\{(.*?)}$",'$1'
# Apply Settings to Specific Power Plan by GUID
# $specificPowerPlanID = '8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c'
# $currentPlan = Get-CimInstance -namespace "root\cimv2\power" -class Win32_powerplan | where {$_.InstanceID -match $specificPowerPlanID}
# $schemeID= $currentPLan.InstanceID -replace "^Microsoft:PowerPlan\\{(.*?)}$",'$1'
# Optionally Activate this specific Power Plan
# powercfg -SetActive $specificPowerPlanID
$currPLanLidCLoseSettings = Get-CimAssociatedInstance -InputObject $currentPLan -ResultClassName 'win32_powersettingdataindex' | where {$_.InstanceID -match $SettingGUID}
$improperSettings = $currPLanLidCLoseSettings | where {$_.settingIndexValue -ne $DesiredValue}
If ($improperSettings) {
Write-Verbose -Verbose "Found $(@($improperSettings).Count) settings in current power plan that do not match. Fixing"
# Aliases are taken from 'powercfg /Aliases'
# SubGroup GUID Alias SUB_BUTTONS = 4f971e89-eebd-4455-a8de-9e59040e7347
# SubGroup GUID Alias LIDACTION = 5ca83367-6e45-459f-a27b-476b1d01c936
powercfg -SETACVALUEINDEX $schemeID SUB_BUTTONS LIDACTION $DesiredValue
powercfg -SETDCVALUEINDEX $schemeID SUB_BUTTONS LIDACTION $DesiredValue
# powercfg -SETACVALUEINDEX $schemeID $SettingSubGroupID $SettingGUID$SettingGUID $DesiredValue
# powercfg -SETDCVALUEINDEX $schemeID $SettingSubGroupID $SettingGUID $DesiredValue
Write-Verbose -Verbose "New Values are below"
Get-CimAssociatedInstance -InputObject $currentPLan -ResultClassName 'win32_powersettingdataindex' | where {$_.InstanceID -match $SettingGUID}
}
else {
Write-Verbose -Verbose "All settings are already correct"
}
Upvotes: 1
Reputation: 1199
I found this script on Quickly change the "lid" power setting on your laptop. Asks for agreement to terms of usage. Works for W10.
@echo off
set debug=1
::*************************
:: Script Name: lid.cmd
:: author: Stephen D Arsenault
:: Creation Date: 2013-september-07
:: Modified Date: 2013-september-07
:: Description: Changes the lid action to sleep or do nothing
:: parameters: - on: sets lid action to do nothing
:: - off: sets lid action to sleep
::*************************
echo Getting current scheme GUID
::store the output of powercfg /getactivescheme in %cfg%
for /f "tokens=* USEBACKQ" %%a in (`powercfg /getactivescheme`) do @set cfg=%%a
if %debug%==1 echo Current %cfg%
::trim power config output to get GUID
set trimcfg=%cfg:~19,36%
if %debug%==1 echo %trimcfg%
::accepts arguments
if %1==off set newVal=001
if %1==OFF set newVal=001
if %1==on set newVal=000
if %1==ON set newVal=000
::make power scheme change
powercfg /setdcvalueindex %trimcfg% 4f971e89-eebd-4455-a8de-9e59040e7347 5ca83367-6e45-459f-a27b-
476b1d01c936 %newVal% >nul 2>&1
powercfg /setacvalueindex %trimcfg% 4f971e89-eebd-4455-a8de-9e59040e7347 5ca83367-6e45-459f-a27b-
476b1d01c936 %newVal% >nul 2>&1
if %errorlevel%==1 echo "Invalid Parameters"
if %errorlevel%==1 pause
if %errorlevel%==1 echo %date% %time% Invalid Parameters: %1 >>C:\tools\lid.log
echo %date% %time% %1 >>C:\tools\lid.log
::apply changes
powercfg /s %trimcfg%
Note: The script contains two hard coded references to c:\tools
. These references are for logging only so you can safely either comment them out or modify them to your file structure.
Upvotes: 4
Reputation: 27516
Powercfg with all the aliases:
powercfg -setacvalueindex scheme_current sub_buttons pbuttonaction 0
Upvotes: 1
Reputation: 71
I wanted to do the same thing et get the exact same problem. Finally, I found that you need to insert in your command line the registry keys that are superior to the one you want to modify:
powercfg -setacvalueindex 5ca83367-6e45-459f-a27b-476b1d01c936 0
powercfg -setdcvalueindex 5ca83367-6e45-459f-a27b-476b1d01c936 0
should become:
powercfg -setacvalueindex 381b4222-f694-41f0-9685-ff5bb260df2e 4f971e89-eebd-4455-a8de-9e59040e7347 5ca83367-6e45-459f-a27b-476b1d01c936 0
powercfg -setdcvalueindex 381b4222-f694-41f0-9685-ff5bb260df2e 4f971e89-eebd-4455-a8de-9e59040e7347 5ca83367-6e45-459f-a27b-476b1d01c936 0
Just put that in a BAT file and you're ready to go!
Upvotes: 7
Reputation: 45928
What I've seen in Windows 8.1 is that when the lid action is changed for a power scheme, then that power scheme must be both the active and the preferred power scheme. The active power scheme can be set by PowerCfg, and the preferred power scheme can be set by registry.
Here's a Powershell script to change them and the lid action:
#Enable High performance
$powerScheme = "High performance"
#Find selected power scheme guid
$guidRegex = "(\{){0,1}[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}(\}){0,1}"
[regex]$regex = $guidRegex
$guid = ($regex.Matches((PowerCfg /LIST | where {$_ -like "*$powerScheme*"}).ToString())).Value
#Change preferred scheme
$regGuid = "{025A5937-A6BE-4686-A844-36FE4BEC8B6D}"
$currentPreferredScheme = Get-ItemProperty -Path Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\explorer\ControlPanel\NameSpace\$regGuid -Name PreferredPlan
if ($currentPreferredScheme.PreferredPlan -ne $guid) {
Set-ItemProperty -Path Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\explorer\ControlPanel\NameSpace\$regGuid -Name PreferredPlan -Value $guid
Write-Host -ForegroundColor Green "Preferred scheme successfully changed. Preferred scheme is now '$powerScheme'."
} else {
Write-Host -ForegroundColor Yellow "Preferred scheme does not need to be changed. Preferred scheme is '$powerScheme'."
}
#Change active scheme
$currentActiveScheme = PowerCfg /GETACTIVESCHEME
if ($currentActiveScheme | where {$_ -notlike "*$guid*"}) {
PowerCfg /SETACTIVE $guid
Write-Host -ForegroundColor Green "Power scheme successfully changed. Current scheme is now '$powerScheme'."
} else {
Write-Host -ForegroundColor Yellow "Power scheme does not need to be changed. Current scheme is '$powerScheme'."
}
#Do not sleep when closing lid on AC
PowerCfg /SETACVALUEINDEX $guid SUB_BUTTONS LIDACTION 000
Write-Host -ForegroundColor Green "No action when closing lid on AC."
Upvotes: 4
Reputation: 31
This bit of PowerShell does actually change the registry settings, but it doesn't change how my laptops behave when the lid is closed. Using powercfg
does the same thing as this WMI object.
Apparently, the registry Sub Group PowerButtons and Lid
has 2 different sets of registry entries.
This script, and the identical commands within powercfg
, change this Sub Group within Power Options >> Advanced Settings
to Do Nothing
(or Sleep
, or Hibernate
, or whatever option number from 0 - 3
that you set), but within the actual Control Panel settings for Change what the power buttons do
and Change what closing the lid does
are unaffected. It is the settings within Control Panel that actually dictate actions, at least for this Sub Group.
If I use powercfg
or a similar PS script to what was written above, I can actually Change Plan Settings
to obtain the desired behavior for dimming the display (or whatever). I just can't find anything that will work for the Power Buttons and Lid
Sub Group.
Upvotes: 3
Reputation: 8650
Honestly, I don't see any reason why you shouldn't use tools that simply work... ;) Anyways: when working with WMI is usually good idea to filter as much to the left as you can. Should not make much difference here, but at times difference is huge. This is how I would do it with WMI:
$Name = @{
Namespace = 'root\cimv2\power'
}
$ID = (Get-WmiObject @Name Win32_PowerPlan -Filter "IsActive = TRUE") -replace '.*(\{.*})"', '$1'
$Lid = '{5ca83367-6e45-459f-a27b-476b1d01c936}'
Get-WmiObject @Name Win32_PowerSettingDataIndex -Filter "InstanceId LIKE '%$Id\\%C\\$Lid'" |
Set-WmiInstance -Arguments @{ SettingIndexValue = 0 }
There may be better way with more advanced WQL query, this is almost the same what you did, only bit modified.
Upvotes: 5
Reputation: 52689
Try the WMI accelerator:
$class = ([wmi] '\root\cimv2\power:Win32_PowerSettingDataIndex.InstanceID="Microsoft:PowerSettingDataIndex\\{8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c}\\DC\\{5ca83367-6e45-459f-a27b-476b1d01c936}"')
$class.SettingIndexValue = 0
$class.Put()
Upvotes: 5