CraigJPerry
CraigJPerry

Reputation: 981

Powershell Set Lid Close Action

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

Answers (9)

Marko S
Marko S

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

PsychoData
PsychoData

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

Stephen Boston
Stephen Boston

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

js2010
js2010

Reputation: 27516

Powercfg with all the aliases:

powercfg -setacvalueindex scheme_current sub_buttons pbuttonaction 0

Upvotes: 1

Vandal
Vandal

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

Even Mien
Even Mien

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

Brian
Brian

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

BartekB
BartekB

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

Andy Arismendi
Andy Arismendi

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

Related Questions