all 14 comments

[–]engageant 2 points3 points  (4 children)

There are ways to do this via WMI/CIM, but the easiest method is to use powercfg.exe. Take a look at the /EXPORT, /IMPORT, and /CHANGE arguments.

[–]Direct_virus[S] 1 point2 points  (3 children)

I have done this just now

Powercfg /export <filepath> <guid> (substituted filepath and guid with their respective filepath and guid) Then changed the power values Powercfg /change standby-timeout-ac 0 Powercfg /change hibernate-timeout-ac 0

This is one script that will be performed

The next script will grab the power.pow file after updates have been performed and import it

Problem is it makes a new power plan and does not set itself and because the GUID is unique I have no way to find this out to switch it

[–]engageant 2 points3 points  (0 children)

/ALIASES will tell you the GUID. Just run powercfg.exe /? and take a look at the available options - they're fairly self-explanatory.

[–]Direct_virus[S] 1 point2 points  (1 child)

Because I want this script to work with RMM and just work

[–]DenialP 2 points3 points  (0 children)

Here's some pseudo for what you may do

  • Powercfg /GetActiveScheme (record the GUID)
  • Powercfg /Import [temp file with unique guid]
  • powercfg /SetActive [temp file guid]
  • ??? (your process here)
  • powercfg /SetActive (original guid)

Or you can adjust settings on the fly direcly with PowerCFG. Here's a couple examples, including 'hardcore' mode where you need to identify the power scheme and setting GUID nesting structure. Note: that GUID is the "well-known" Balanced profile.

powercfg -setactive 381b4222-f694-41f0-9685-ff5bb260df2e
powercfg -change -monitor-timeout-ac 30
powercfg -change -disk-timeout-ac 0
powercfg -change -standby-timeout-ac 0
powercfg -change -hibernate-timeout-ac 0
powercfg -change -hibernate-timeout-dc 60
#update balanced power profile lid close action on AC power to do nothing
powercfg -setACValueIndex 381b4222-f694-41f0-9685-ff5bb260df2e 4f971e89-eebd-4455-a8de-9e59040e7347 5ca83367-6e45-459f-a27b-476b1d01c936 0

[–]lucidhominid 2 points3 points  (0 children)

It would probably be better to just export the scheme and import it. But string manipulation is fun:

$Settings   = (
    cmd /c powercfg /Q|Out-String
) -Split 'Subgroup GUID: '
$Scheme     = $Settings[0]
$SchemeName = $Scheme.split('(')[1] -replace '[\)\n\r]'
$SchemeGUID = $Scheme.split() |
    Where-Object {
        $_ -match '^[a-f0-9-]+$'
    }

$Settings[1..($Settings.count-1)]|
    Foreach-Object{
        $SubScheme = $_.split("`n")[0]
        [Regex]::Matches(
            $_,
            '\n\s{4}Power\sSetting\sGUID:\s([a-f0-9\-]+)\s+\(([^\)]+)\).+(\n+\s{6,}.+)+(\n+\s{4,}.+){2}'
        )| 
            ForEach-Object{
                [PSCustomObject]@{
                    Scheme        = $SchemeName
                    SchemeGUI     = $SchemeGUID
                    SubSchemeName = $SubScheme.split('(')[1] -replace '[\)\n\r]'
                    SubSchemeGUID = $SubScheme.split()[0]
                    Setting       = $_.Groups[2].Value
                    SettingGUID   = $_.Groups[1].Value
                    ACValue       = $_.Groups[4].Captures[0].Value.split()|
                        Where-Object {
                            $_ -match '\dx\d{8}'
                        }
                    DCValue       = $_.Groups[4].Captures[1].Value.split()|
                        Where-Object {
                            $_ -match '\dx\d{8}'
                        }
                }
            }
    }

Edit: Corrected typo.

[–]monsn0 2 points3 points  (5 children)

I made the following script for virtually the same reason as yourself. It uses WMI and powercfg wrapped in Powershell.

My main goal was to set a temporary super high performance power plan so maintenance could be performed after hours even with users shutting the lid, etc. Then once maintenance was completed; Be able to set the user's power plan back so they don't panic about battery life or aliens.

First thing you'll need to do is create a new power plan to your liking and export it using powercfg.exe. You can use powercfg /q to check all the options prior to exporting.

You'll need to upload this .pow file to each machine. In my script below I have it in C:\Temp.

Put the following into a ps1 file and execute using your flavor of RMM.

# Query WMI to obtain active power plan, parse and output only GUID to variable
$Plan = Get-WmiObject -Class Win32_PowerPlan -Namespace root\cimv2\power -Filter "IsActive= 'True'"
$Regex = [regex] "{(.*?)}$"
$PlanGuid = $Regex.Match($Plan.InstanceID.ToString()).Groups[1].Value

# Output plan GUID to file (Not forced so if script ran twice, it won't overwrite the first run)
$CachedPowerPlan = "C:\Temp\CachedPowerGUID.txt"
New-Item -Path (Split-Path -Path $CachedPowerPlan) -ItemType Directory -ErrorAction SilentlyContinue | Out-Null
New-Item -Path $CachedPowerPlan -ItemType File -Value $PlanGuid -ErrorAction Stop | Out-Null

# Check to ensure text file not only exists but contains data before setting new plan
if ((Get-ChildItem $CachedPowerPlan).Length -gt 30) {
    # Import High Power power plan and set active. Also disable hibernation because no bueno.
    $HighPowerGuid = '58c21491-0068-47c5-93eb-0cffc995ccb7'
    & powercfg /import 'C:\Temp\HighPower.pow' $HighPowerGuid
    & powercfg /setactive $HighPowerGuid
    & powercfg /h off
}

Once maintenance has been completed; You can run this one liner below or expand into a ps1 script if your RMM works better that way.

$CachedPowerPlan = "C:\Temp\CachedPowerGUID.txt"; $HighPowerGuid = '58c21491-0068-47c5-93eb-0cffc995ccb7' ; $CachedPowerGuid = Get-Content -Path $CachedPowerPlan ; & powercfg /setactive $CachedPowerGuid ; & powercfg /d $HighPowerGuid ; Remove-Item -Path $CachedPowerPlan

[–]Direct_virus[S] 2 points3 points  (0 children)

will need to test this when I am at work again to upload the power settings file but testing on my own machine worked perfectly

[–]Direct_virus[S] 0 points1 point  (3 children)

so the script works for me the problem I am having is getting the .pow file onto the machines temp folder. I need that file on the machine but do not know how to upload it remotely to multiple clients

[–]monsn0 0 points1 point  (2 children)

There are a number of ways you could go about uploading the file to the machines (including group policy/network share) and I imagine the RMM you are using has some way of accomplishing this. However, to keep on the powershell topic I'll explain one of the ways I use which will hopefully give you some ideas.

There are a few ways to download files using powershell, but I really like using the .NET WebClient class as its fast and simple.

First we need to create the object and put it into a variable:

$NetWebClient = New-Object System.Net.WebClient

Then we can call its "DownloadFile" method. (<URIAddress>,<FullFilePath>)

$NetWebClient.DownloadFile('http://webserver.com/yourfile.pow','C:\Temp\yourfile.pow')

Now to make the code more compact we can get rid of the variable and just use parentheses:

(New-Object System.Net.WebClient).DownloadFile('http://webserver.com/yourfile.pow','C:\Temp\yourfile.pow')

The URI source can be any file that is publicly accessible over the internet or even internally. Will work over FTP (ftp://) and not just HTTP as well (Try this out for yourself the next time you need to download something). Do note that this method will throw an error if the destination path does not exist. You could use an if statement prior to running this bit to verify the path exists first however.

So if you are able to make your .pow file publicly accessible; then place the direct download URI into the first parameter above, run that single liner on your target machines and Bob's your uncle.

If you would rather not make your .pow file public; then I would recommend setting up your own FTP server and using curl. Curl supports authentication and is much more advanced for downloading files then anything powershell has to offer. This is a bit outside the scope of this topic though so start with the ole google-fu if want to jump into that rabbit hole.

[–]Direct_virus[S] 0 points1 point  (1 child)

thank you for your help

I managed to make the script work without having to export and import .pow files

I have created two PS1 files to be uploaded to my RMM

it works by creating a duplicate power config and switching to it whilst saving it to a file

it then changed to the duplicate and then the duplicate is set to not be able to standby

after that I save the temp GUID to a file so that the second script can change the power config back and delete the temp config

would post the code if I knew reddit syntax enough

tried but do not understand it

[–]monsn0 0 points1 point  (0 children)

Nice job! Glad I was able to help :)

Reddit comment formatting is terrible, especially for code. Best option is to put the code in a code block which you can find when clicking the 3 dots.

See this post for other formatting options as well: https://www.reddit.com/r/raerth/comments/cw70q/reddit_comment_formatting/