Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PowerPlan: Powercfg.exe instead of WMI and allow GUID as power plan name #202

Merged
merged 7 commits into from
Mar 28, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@

## Unreleased

- PowerPlan:
- Added support to specify the desired power plan either as name or guid.
Fixes [Issue #59](https://github.com/PowerShell/ComputerManagementDsc/issues/59)
- Changed the resource so it uses powercfg.exe instead of WMI/CIM
(Workaround fo rServer 2012R2 Core, Nano Server, Server 2019 and Windows 10).
Fixes [Issue #155](https://github.com/PowerShell/ComputerManagementDsc/issues/155)
and [Issue #65](https://github.com/PowerShell/ComputerManagementDsc/issues/65)

## 6.1.0.0

- Updated LICENSE file to match the Microsoft Open Source Team standard.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ $script:localizedData = Get-LocalizedData `
Specifies the resource is a single instance, the value must be 'Yes'.

.PARAMETER Name
Specifies the name of the power plan to assign to the node.
Specifies the name or GUID of the power plan to assign to the node.

.EXAMPLE
Get-TargetResource -IsSingleInstance 'Yes' -Name 'High performance'
Expand All @@ -46,21 +46,7 @@ function Get-TargetResource
$Name
)

$getCimInstanceArguments = @{
Name = 'root\cimv2\power'
Class = 'Win32_PowerPlan'
Filter = "ElementName = '$Name'"
}

try
{
$plan = Get-CimInstance @getCimInstanceArguments
}
catch
{
New-InvalidOperationException `
-Message ($script:localizedData.PowerPlanCimError -f $getCimInstanceArguments.Class)
}
$plan = Get-PowerPlan -Name $Name

if ($plan)
{
Expand Down Expand Up @@ -94,7 +80,7 @@ function Get-TargetResource
Specifies the resource is a single instance, the value must be 'Yes'.

.PARAMETER Name
Specifies the name of the power plan to assign to the node.
Specifies the name or GUID of the power plan to assign to the node.

.EXAMPLE
Set-TargetResource -IsSingleInstance 'Yes' -Name 'High performance'
Expand All @@ -118,30 +104,16 @@ function Set-TargetResource

Write-Verbose -Message ($script:localizedData.PowerPlanIsBeingActivated -f $Name)

$getCimInstanceArguments = @{
Name = 'root\cimv2\power'
Class = 'Win32_PowerPlan'
Filter = "ElementName = '$Name'"
}

try
{
$plan = Get-CimInstance @getCimInstanceArguments
}
catch
{
New-InvalidOperationException `
-Message ($script:localizedData.PowerPlanCimError -f $getCimInstanceArguments.Class)
}
$plan = Get-PowerPlan -Name $Name

try
if($plan)
{
$plan | Invoke-CimMethod -MethodName Activate
Set-PowerPlan -Guid $plan.Guid
}
catch
else
{
New-InvalidOperationException `
-Message ($script:localizedData.PowerPlanWasUnableToBeSet -f $Name, $_.Exception.Message)
-Message ($script:localizedData.PowerPlanNotFound -f $Name)
}
}

Expand All @@ -153,7 +125,7 @@ function Set-TargetResource
Specifies the resource is a single instance, the value must be 'Yes'.

.PARAMETER Name
Specifies the name of the power plan to assign to the node.
Specifies the name or GUID of the power plan to assign to the node.

.EXAMPLE
Test-TargetResource -IsSingleInstance 'Yes' -Name 'High performance'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@
class MSFT_PowerPlan : OMI_BaseResource
{
[Key, Description("Specifies the resource is a single instance, the value must be 'Yes'."), ValueMap{"Yes"}, Values{"Yes"}] String IsSingleInstance;
[Required, Description("The name of the power plan to activate.")] String Name;
[Required, Description("The name or GUID of the power plan to activate.")] String Name;
[Read, Description("Determines if the power plan is active.")] Boolean IsActive;
};
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@
class MSFT_PowerPlan : OMI_BaseResource
{
[Key, Description("Specifies the resource is a single instance, the value must be 'Yes'.") : Amended] String IsSingleInstance;
[Description("The name of the power plan to activate.") : Amended] String Name;
[Description("The name or GUID of the power plan to activate.") : Amended] String Name;
};
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,4 @@ ConvertFrom-StringData @'
PowerPlanNotFound = Unable to find the power plan '{0}'.
PowerPlanIsBeingActivated = Activating power plan '{0}'.
PowerPlanIsBeingValidated = Validating power plan '{0}'.
PowerPlanWasUnableToBeSet = Unable to set the power plan '{0}' to the active plan. Error message: {1}
PowerPlanCimError = Could not get the Common Information Model (CIM) instances of class '{0}'.
'@
Original file line number Diff line number Diff line change
Expand Up @@ -491,11 +491,114 @@ function Set-TimeZoneUsingDotNet
[Microsoft.PowerShell.TimeZone.TimeZone]::Set($TimeZoneId)
} # function Set-TimeZoneUsingDotNet

<#
.SYNOPSIS
This function gets a power plans/schemes specified by its friendly name or GUID.
It returns a custom object with the properties of the power plan or
nothing if the powerplan does not exist on the computer.

.PARAMETER Name
Friendly name or GUID of a power plan to get.

.NOTES
The powercfg.exe utility is used here because the Win32_PowerPLan class has
issues on some platforms (e.g Server 2012 R2 core or Nano Server).
This function is used by the PowerPlan resource.
#>
function Get-PowerPlan {
[CmdletBinding()]
param
(
[Parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[System.String]
$Name
)

# Set to stop so that the errors from powercfg.exe are terminating
$ErrorActionPreference = 'Stop'

try {
$powercfgOutPut = & powercfg.exe /L
}
catch {
New-InvalidOperationException -ErrorRecord $_
}

if(($null -eq $powercfgOutPut) -or ('' -eq $powercfgOutPut))
{
New-InvalidOperationException -Message $script:localizedData.UnableToGetPowerPlans
}

$allPlans = @()

foreach($line in $powercfgOutPut)
{

if($line -match "^.*?:[ ]*(?'guid'.*?)[ ]*\((?'name'.*?)\)")
{
$plan = [PSCustomObject]@{
Name = [String]$Matches.name
Guid = [Guid]$Matches.guid
IsActive = $false
}

if($line -match "\*$")
{
$plan.IsActive = $true
}

$allPlans += $plan
}
}

$selectedPlan = $allPlans | Where-Object -FilterScript {
($_.Name -eq $Name) -or
($_.Guid -eq $Name)
}

$selectedPlan
}

<#
.SYNOPSIS
This function activates the desired power plan (specified by its GUID).

.PARAMETER Guid
GUID of a power plan to activate.

.NOTES
The powercfg.exe utility is used here because the Win32_PowerPLan class has
issues on some platforms (e.g Server 2012 R2 core or Nano Server).
This function is used by the PowerPlan resource.
#>
function Set-PowerPlan {
[CmdletBinding()]
param
(
[Parameter(Mandatory = $true)]
[System.Guid]
$Guid
)

# Set to stop so that the errors from powercfg.exe are terminating
$ErrorActionPreference = 'Stop'

try {
& powercfg.exe /S $Guid
}
catch {
New-InvalidOperationException -ErrorRecord $_
}
}

Export-ModuleMember -Function `
Test-DscParameterState, `
Test-DscObjectHasProperty, `
Test-Command, `
Get-TimeZoneId, `
Test-TimeZoneId, `
Set-TimeZoneId, `
Set-TimeZoneUsingDotNet
Set-TimeZoneUsingDotNet, `
Get-PowerPlan, `
Set-PowerPlan
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,5 @@ ConvertFrom-StringData @'
SettingTimeZoneMessage = Setting time zone to '{0}' using {1}.
TimeZoneUpdatedMessage = Time zone has been updated to '{0}'.
AddingSetTimeZoneDotNetTypeMessage = Adding .NET Set time zone Type.
UnableToGetPowerPlans = Unable to get available power plans with powercfg.exe /l. Unexpected empty output from powercfg.exe.
'@
Loading