PSPowercfg.psm1


<#
.SYNOPSIS
    PowerShell Module to interact with Powercfg
.DESCRIPTION
    PowerShell Module to interact with Powercfg
.NOTES
    Author : Simon Godefroy - Simon.Godefroy@FocusedIT.co.uk
    Version : 1.0.1
    Date : 2022.04.18
        Update : 1.0.1
                    SG - 2022.04.18
                    Minor update
        Update : 1.0.0
                    SG - 2022.04.18
                    Initial Script
.LINK
    http://www.FocusedIT.co.uk
#>


function Test-Administrator {
    $user = [Security.Principal.WindowsIdentity]::GetCurrent();
    (New-Object Security.Principal.WindowsPrincipal $user).IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator)
}

function Invoke-MultiChoice {
    <#
    .SYNOPSIS
        Generate a Multichoice from multi-valued object and return the selected object
        .DESCRIPTION
        Generate a Multichoice from multi-valued object and return the selected object (can accept pipeline input)
    .EXAMPLE
        Invoke-MultiChoice -Input $ListOfNames
    .EXAMPLE
        $ListOfComputers | Invoke-MultiChoice -Property ComputerName
    .NOTES
        Author : Simon Godefroy - Simon.Godefroy@FocusedIT.co.uk
        Version : 1.0.0
        Date : 2022.04.18
            Update : 1.0.0
                        SG - 2022.04.18
                        Initial Script
    .LINK
        http://www.FocusedIT.co.uk
    #>


    [CmdletBinding()]
    param(
        [Parameter(ValueFromPipeline=$True)]
        $Input,
        [Parameter(ValueFromPipeline=$False)]
        $Property
    )
    begin{
        $Items = @()
    }
    process{
        $Items += $Input
    }
    end{
        $InputCount = $Items.count
        $Max = $InputCount -1
        $i = 0
        while($i -le $Max){
            if($Property){
                $Current = ($Items[$i]).$Property
            }else{
                $Current = $Items[$i]
            }
            Write-Host "$i $Current "
            $i ++
        }
        $Choice = Read-Host "Enter Selection Number"
        if($Choice -match "\d{1}"){
            $Result = $Items[$Choice]
        }else{
            $Search = $Items | ?{$_ -match $Choice}
            if($Search.count -eq 1){
                $Result = $Search
            }else{
                Write-Warning "Please be more specific.."
            }
        }
        return $Result
    }
}

function Get-PowercfgSettings{
    $CurrentScheme = Powercfg -getactivescheme
    $CurrentScheme = $currentScheme.split("()")
    $CurrentGuid = ($currentScheme[0]).trim().split(" ")[-1]
    $CurrentName = $currentScheme[1]



    $CurrentSettings = Powercfg /Q
    $RawSettings = $CurrentSettings[2..$CurrentSettings.Count]  -join [System.Environment]::NewLine

    #Possible alternative:
    #$RawSettings = $CurrentQuery[2..$CurrentQuery.Count] | Out-String

    $SplitSettings = $RawSettings -split '(?:\r?\n){2,}'

    $SettingsArray = @()

    foreach($Setting in $SplitSettings){
        $IndexCount = -1
        $LinedSetting = (($Setting -split '(?:\r?\n)').trim() | ?{$_ -notlike "GUID Alias:*" -and $_ -notlike ""}).Trim()
        if($SubgroupGuid){
            #Remove-Variable SubgroupGuid -ErrorAction SilentlyContinue
        }
        if($SubgroupName){
            #Remove-Variable SubgroupName -ErrorAction SilentlyContinue
        }
        if($PowerSettingGuid){
            Remove-Variable PowerSettingGuid -ErrorAction SilentlyContinue
        }
        if($MinSettingHex){
            Remove-Variable MinSettingHex -ErrorAction SilentlyContinue
        }
        if($MinSetting){
            Remove-Variable MinSetting -ErrorAction SilentlyContinue
        }
        if($MaxSettingHex){
            Remove-Variable MaxSettingHex -ErrorAction SilentlyContinue
        }
        if($MaxSetting){
            Remove-Variable MaxSetting -ErrorAction SilentlyContinue
        }
        if($IncrementHex){
            Remove-Variable IncrementHex -ErrorAction SilentlyContinue
        }
        if($Increment){
            Remove-Variable Increment -ErrorAction SilentlyContinue
        }
        if($Units){
            Remove-Variable Units -ErrorAction SilentlyContinue
        }
        if($CurrentACHex){
            Remove-Variable CurrentACHex -ErrorAction SilentlyContinue
        }
        if($CurrentAC){
            Remove-Variable CurrentAC -ErrorAction SilentlyContinue
        }
        if($CurrentDCHex){
            Remove-Variable CurrentDCHex -ErrorAction SilentlyContinue
        }
        if($CurrentDC){
            Remove-Variable CurrentDC -ErrorAction SilentlyContinue
        }
        foreach($Line in $LinedSetting){
            if($Line -like "Subgroup GUID: *"){
                $SubgroupGuid = ($Line.split(" ",3)[-1]).split(" ")[0]
                $SubgroupName = ($Line.split(" ",1)[-1]).split("()")[1]
            }elseif($Line -like "Power Setting GUID: *"){
                $PowerSettingGuid = ($Line.split(" ",4)[-1]).split(" ")[0]
                $PowerSettingName = ($Line.split(" ",1)[-1]).split("()")[1]
            }elseif($Line -like "Minimum Possible Setting: *"){
                $MinSettingHex = ($Line.split(":")[-1]).trim()
                $MinSetting = [Convert]::ToString($MinSettingHex,10)
            }elseif($Line -like "Maximum Possible Setting: *"){
                $MaxSettingHex = ($Line.split(":")[-1]).trim()
                $MaxSetting = [Convert]::ToString($MaxSettingHex,10)
            }elseif($Line -like "Possible Settings increment: *"){
                $IncrementHex = ($Line.split(":")[-1]).trim()
                $Increment = [Convert]::ToString($IncrementHex,10)
            }elseif($Line -like "Possible Settings units: *"){
                $Units = ($Line.split(":")[-1]).trim()
            }elseif($Line -like "Current AC Power Setting Index: *"){
                $CurrentACHex = ($Line.split(":")[-1]).trim()
                $CurrentAC = [Convert]::ToString($CurrentACHex,10)
            }elseif($Line -like "Current DC Power Setting Index: *"){
                $CurrentDCHex = ($Line.split(":")[-1]).trim() #($Line.split(" ",3)[-1]).split(" ")[3]
                $CurrentDC = [Convert]::ToString($CurrentDCHex,10)
            }elseif($Line -like "Possible Setting Index: *"){
                $IndexCount ++
            }elseif($Line -like "Possible Setting Friendly Name: *"){
                #use Index
                $IndexName = ($Line.split(":")[-1]).trim()
                New-Variable -Name IndexTemp$IndexCount -Value $IndexName
            }
        }
        $SettingObj = New-Object psobject
        if($SubgroupGuid){
            $SettingObj | Add-Member NoteProperty SubgroupGuid $SubgroupGuid
            $SettingObj | Add-Member NoteProperty SubgroupName $SubgroupName
        }else{
            #$SettingObj | Add-Member NoteProperty SubgroupGuid $null
            #$SettingObj | Add-Member NoteProperty SubgroupName $null
        }
        if($PowerSettingGuid){
            $SettingObj | Add-Member NoteProperty PowerSettingGuid $PowerSettingGuid
            $SettingObj | Add-Member NoteProperty PowerSettingName $PowerSettingName
        }else{
            $SettingObj | Add-Member NoteProperty PowerSettingGuid $null
            $SettingObj | Add-Member NoteProperty PowerSettingName $null
        }
        if($MaxSetting){
            $SettingObj | Add-Member NoteProperty MaxSetting $MaxSetting
        }else{
            #$SettingObj | Add-Member NoteProperty MaxSetting $null
        }
        if($MinSetting){
            $SettingObj | Add-Member NoteProperty MinSetting $MinSetting
        }else{
            #$SettingObj | Add-Member NoteProperty MinSetting $null
        }
        if($Increment){
            $SettingObj | Add-Member NoteProperty Increment $Increment
        }else{
            #$SettingObj | Add-Member NoteProperty Increment $null
        }
        if($Units){
            $SettingObj | Add-Member NoteProperty Units $Units
        }else{
            #$SettingObj | Add-Member NoteProperty Units $null
        }
        if($CurrentAC){
            $SettingObj | Add-Member NoteProperty CurrentAC $CurrentAC
        }else{
            $SettingObj | Add-Member NoteProperty CurrentAC $null
        }
        if($CurrentDC){
            $SettingObj | Add-Member NoteProperty CurrentDC $CurrentDC
        }else{
            $SettingObj | Add-Member NoteProperty CurrentDC $null
        }
        $IndexesLoop = -1
        while($IndexesLoop -lt $IndexCount){
            $IndexesLoop ++
            if($CurrentIndex = (Get-Variable IndexTemp$IndexesLoop -ErrorAction SilentlyContinue).Value){
                $SettingObj | Add-Member NoteProperty Index$IndexesLoop $CurrentIndex
            }else{
                $SettingObj | Add-Member NoteProperty Index$IndexesLoop $null
            }
        }
        if($SettingObj.Index0){
            $IndexACText = "Index$CurrentAC"
            $CurrentACText = $SettingObj.$IndexACText
            $IndexDCText = "Index$CurrentDC"
            $CurrentDCText = $SettingObj.$IndexDCText
        }else{
            $CurrentACText = "$CurrentAC $Units"
            $CurrentDCText = "$CurrentDC $Units"
        }
        $SettingObj | Add-Member NoteProperty ACValue $CurrentACText
        $SettingObj | Add-Member NoteProperty DCValue $CurrentDCText
        $SettingsArray += $SettingObj 
        Remove-Variable IndexTemp* -ErrorAction SilentlyContinue
    }

    $SettingsArray
    
}

function Set-PowercfgSetting{
    [cmdletbinding(SupportsShouldProcess,DefaultParameterSetName='Main',ConfirmImpact = 'High')]    
    param(
        [Parameter(ValueFromPipelineByPropertyName=$false)]
        [alias("PowerSettingName")]
        [string]$Setting,
        [Parameter(ValueFromPipeline=$false)]
        $Value,
        [Parameter(ValueFromPipeline=$false)]
        $Category,
        [Parameter(ParameterSetName='ACOnly', Mandatory=$false)]
        [switch]$ACOnly,
        [Parameter(ParameterSetName='DCOnly', Mandatory=$false)]
        [switch]$DCOnly,
        [Parameter(ParameterSetName='ACDC', Mandatory=$false)]
        [switch]$ACDC,
        [switch]$Force
    )
    begin{
        try{
            if(!(Test-Administrator)){
                throw "Must be run as Administrator"
            }
        }catch{
            Write-Error $Global:Error[0] -ErrorAction Stop
        }
        #Set Default to AC Only:
        if($($PSCmdlet.ParameterSetName) -like "Main"){
            $ACOnly = $true
        }
        if ($Force){
            $ConfirmPreference = 'None'
        }
        
        $CurrentScheme = Powercfg -getactivescheme
        $CurrentScheme = $currentScheme.split("()")
        $CurrentGuid = ($currentScheme[0]).trim().split(" ")[-1]
        $CurrentName = $currentScheme[1]

        $AllSettings = Get-PowercfgSettings
        
        $FoundSettings = @()
        $Values =@()
        
    }
    process{
        if($ACOnly){
            $Mode = "AC Only"
            $ChangeAC = $true
        }elseif($DCOnly){
            $Mode = "DC Only"
            $ChangeDC = $true
        }elseif($ACDC){
            $Mode = "AC & DC"
            $ChangeAC = $true
            $ChangeDC = $true
        }
        Write-Host "Mode: $Mode"
        
        if($Category){
            $CatSettings = $AllSettings | ?{$_.SubgroupName -like "*$Category*"}
            if($CatSettings){
                $AllSettings = @()
                $AllSettings += $CatSettings
            }
            
        }
        if($Setting){
            $MatchedSettings =@()
            $MatchedSettings += $AllSettings | ?{$_.PowerSettingName -like "*$Setting*"}
        }else{
            $MatchedSettings += $AllSettings
        }
        $FoundSettings += $MatchedSettings
        if($Value.count){
            $Values += $Value
        }
    }
    end{
        while($FoundSettings.count -gt 1){
            Write-Host "Select Setting:"
            $FoundSettings = $FoundSettings | Invoke-MultiChoice -Property PowerSettingName
        }

        
        $ChosenSetting = $FoundSettings
        $ChosenString = $ChosenSetting | FT SubgroupName,PowerSettingName,ACValue,DCValue | Out-String
        Write-Host "Chosen Setting:"
        Write-Host "$ChosenString"
        if($ChosenSetting.MaxSetting){
            $ValidateString = "Integers between $($ChosenSetting.MinSetting) and $($ChosenSetting.MaxSetting), Units: $($ChosenSetting.Units)"
            $ChosenMin = $ChosenSetting.MinSetting
            $ChosenMax = $ChosenSetting.MaxSetting
        }
        
        if($ChosenSetting.Index0){
            $Indexes = ($ChosenSetting |Get-Member -Name Index*).Name
            $IndexArray = @()
            $IndexCount = -1
            foreach($Index in $Indexes){
                $IndexCount ++
                $IndexObject = New-Object PSObject
                $IndexObject | Add-Member ID  $IndexCount
                $IndexObject | Add-Member Name $ChosenSetting."Index$IndexCount"
                $IndexArray += $IndexObject
            }
            $ValidateArray = $IndexArray | FT -Hide |out-string
            $ValidateString = "Integers between 0 and $IndexCount matching array options:"
            $ChosenMin = 0
            $ChosenMax = $IndexCount
        }
        
        Write-Host "Validation: $ValidateString"
        if($ValidateArray){
            Write-Host "$ValidateArray"
        }
        $Values = $Values | sort | Select -Unique
        while($Values.count -gt 1){
            $Values = $Values | Invoke-MultiChoice
        }
        
        while($Values -lt $ChosenMin -or $Values -gt $ChosenMax){
            [int32]$Values = Read-Host "Enter Value $ChosenMin-$ChosenMax"
        }
                
        $ChosenValue = $Values
        if($ValidateArray){
            $ChosenText = $ChosenSetting."Index$ChosenValue"
        }else{
            $ChosenText = "$ChosenValue"
        }
        Write-Host "Selected Value: $ChosenValue"
        
        if ($PSCmdlet.ShouldProcess($ChosenSetting.PowerSettingName,"Set $Mode Value to: $ChosenText $($ChosenSetting.Units)")){
            #Set powercfg
            if($ChangeDC){
                powercfg /SETDCVALUEINDEX $CurrentGuid $ChosenSetting.SubgroupGuid $ChosenSetting.PowerSettingGuid $ChosenValue
            }
            if($ChangeAC){
                powercfg /SETACVALUEINDEX $CurrentGuid $ChosenSetting.SubgroupGuid $ChosenSetting.PowerSettingGuid $ChosenValue
            }
            Write-Host "Set: $($Mode): '$($ChosenSetting.PowerSettingName)' to '$ChosenText' $($ChosenSetting.Units)"
        }
        
        #Check:
        Write-Host "Updated Settings:"
        Get-PowercfgSettings| ?{$_.PowerSettingName -like $ChosenSetting.PowerSettingName} | FT SubgroupName,PowerSettingName,ACValue,DCValue #Until Formatfiles
    }
}




###
<#
Usage Examples:
 
Get-PowercfgSettings | Select SubgroupName,PowerSettingName,ACValue,DCValue #Until Formatfiles
 
 
 
$SettingsToChangeAC = ConvertFrom-CSV -delim ';' -Input @"
"Setting"; "Value"
"Turn off hard disk after"; 120
"Hibernate after"; 0
"Sleep after"; 0
"System cooling policy"; 1
"Minimum processor state"; 100
"@
 
foreach($STC in $SettingsToChangeAC){
    Set-PowercfgSetting -Setting $STC.Setting -Value $STC.Value -Force
}
 
#>


Write-Host "Functions available:" -ForegroundColor Magenta
Write-Host "Get-PowercfgSettings" -NoNewLine
Write-Host " (List all Power Settings)" -ForegroundColor Cyan
Write-Host "Set-PowercfgSetting" -NoNewLine
Write-Host " (Change a setting, prompted for selections as required, requires Admin)" -ForegroundColor Cyan