DSCResources/cPowerPlan/cPowerPlan.psm1

$script:DataPath = Join-path $PSScriptRoot '\DATA'
$script:PlanListPath = Join-path $DataPath '\GUID_LIST_PLAN'
$script:PowerPlanAliases = Get-Content $PlanListPath -Raw | ConvertFrom-StringData

function Get-TargetResource {
    [CmdletBinding()]
    [OutputType([System.Collections.Hashtable])]
    param
    (
        [ValidateSet("Present", "Absent")]
        [string]
        $Ensure = 'Present',

        [parameter(Mandatory = $true)]
        [string]
        $GUID,

        [parameter(Mandatory = $true)]
        [string]
        $Name,

        [parameter()]
        [string]
        $Description,

        [bool]
        $Active = $false
    )
    $ErrorActionPreference = 'Stop'

    Write-Verbose "Retrieving Power Plan. { GUID: $GUID }"
    if ($PowerPlanAliases -and $PowerPlanAliases.ContainsKey($GUID)) {
        $GUID = $PowerPlanAliases.$GUID
    }

    $Plan = @(Get-PowerPlan -GUID $GUID -Verbose:$false)[0]
    if (-not $Plan) {
        $Ensure = 'Absent'
        $Name = ''
        $Description = ''
        $Active = $false
    }
    else {
        $Ensure = 'Present'
        $Name = $Plan.ElementName
        $Description = $Plan.Description
        $Active = $Plan.IsActive
    }

    $returnValue = @{
        Ensure      = [string]$Ensure
        GUID        = [string]$GUID
        Name        = [string]$Name
        Description = [string]$Description
        Active      = [bool]$Active
    }

    Write-Verbose ("Current state ( Ensure: {0} | GUID: {1} | Name: {2} | Description: {3} | Active: {4} )" -f $returnValue.Ensure, $returnValue.GUID, $returnValue.Name, $returnValue.Description, $returnValue.Active)
    $returnValue
} # end of Get-TargetResource

function Set-TargetResource {
    [CmdletBinding()]
    param
    (
        [ValidateSet("Present", "Absent")]
        [string]
        $Ensure = 'Present',

        [parameter(Mandatory = $true)]
        [string]
        $GUID,

        [parameter(Mandatory = $true)]
        [string]
        $Name,

        [parameter()]
        [string]
        $Description,

        [bool]
        $Active = $false
    )
    $ErrorActionPreference = 'Stop'

    if ($PowerPlanAliases -and $PowerPlanAliases.ContainsKey($GUID)) {
        $GUID = $PowerPlanAliases.$GUID
    }

    try {
        # Ensure = "Absent"
        if ($Ensure -eq 'Absent') {
            $Plan = Get-PowerPlan $GUID -Verbose:$false
            $PlanGUID = $Plan.InstanceId.Split('\')[1] -replace '[{}]'
            Write-Verbose ('Removing PowerPlan ({0})' -f $PlanGUID)
            if ($Plan.IsActive) {
                $NonActivePlan = Get-CimInstance -Name root\cimv2\power -Class win32_PowerPlan -Verbose:$false | where {-not $_.IsActive} | select -First 1
                if (-not $NonActivePlan) {
                    Write-Error "Couldn't deactivate the powerplan"
                }
                $ExitCode = (Start-Command -FilePath 'Powercfg.exe' -ArgumentList ('/SETACTIVE {0}' -f ($NonActivePlan.InstanceId.Split('\')[1] -replace '[{}]'))).ExitCode
                if ($ExitCode -ne 0) {
                    Write-Error "Couldn't deactivate the powerplan"
                }
            }
            $ExitCode = (Start-Command -FilePath 'Powercfg.exe' -ArgumentList ('/D {0}' -f $PlanGUID)).ExitCode
            if ($ExitCode -ne 0) {
                Write-Error 'Error occured'
            }
            else {
                Write-Verbose 'Power Plan removed successfully'
            }
        }
        else {
            # Ensure = "Present"
            if ($Plan = Get-PowerPlan $GUID -Verbose:$false) {
                $PlanGUID = $Plan.InstanceId.Split('\')[1] -replace '[{}]'
                if ($Plan.ElementName -ne $Name) {
                    if ($PSBoundParameters.ContainsKey('Description')) {
                        $ExitCode = (Start-Command -FilePath 'Powercfg.exe' -ArgumentList ('/CHANGENAME {0} "{1}" "{2}"' -f $PlanGUID, $Name, $Description)).ExitCode
                    }
                    else {
                        $ExitCode = (Start-Command -FilePath 'Powercfg.exe' -ArgumentList ('/CHANGENAME {0} "{1}"' -f $PlanGUID, $Name)).ExitCode
                    }
                    if ($ExitCode -ne 0) {
                        Write-Error 'Error occured when changing the name of Power Plan'
                    }
                    Write-Verbose 'The Name of Power Plan has been changed successfully.'
                }

                if ($Active) {
                    $ExitCode = (Start-Command -FilePath 'Powercfg.exe' -ArgumentList ('/SETACTIVE {0}' -f $PlanGUID)).ExitCode
                    if ($ExitCode -ne 0) {
                        Write-Error "Couldn't activate the powerplan"
                    }
                    Write-Verbose 'The Power Plan activated.'
                }
                elseif ($Plan.IsActive) {
                    $NonActivePlan = Get-CimInstance -Name root\cimv2\power -Class win32_PowerPlan -Verbose:$false | where {-not $_.IsActive} | select -First 1
                    if (-not $NonActivePlan) {
                        Write-Error "Couldn't deactivate the powerplan"
                    }
                    $ExitCode = (Start-Command -FilePath 'Powercfg.exe' -ArgumentList ('/SETACTIVE {0}' -f ($NonActivePlan.InstanceId.Split('\')[1] -replace '[{}]'))).ExitCode
                    if ($ExitCode -ne 0) {
                        Write-Error "Couldn't deactivate the powerplan"
                    }
                    Write-Verbose 'The Power Plan deactivated.'
                }
            }
            else {
                if ($GUID -notmatch '^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$') {
                    Write-Error 'Invalid GUID format'
                }
                $BasePlan = Get-PowerPlan -Verbose:$false
                $BaseGuid = $BasePlan.InstanceId.Split('\')[1] -replace '[{}]'
                $ExitCode = (Start-Command -FilePath 'Powercfg.exe' -ArgumentList ('/DUPLICATESCHEME {0} {1}' -f $BaseGuid, $GUID)).ExitCode
                if ($ExitCode -ne 0) {
                    Write-Error "Couldn't create the Power Plan"
                }

                $ExitCode = (Start-Command -FilePath 'Powercfg.exe' -ArgumentList ('/CHANGENAME {0} "{1}" "{2}"' -f $GUID, $Name, $Description)).ExitCode
                if ($ExitCode -ne 0) {
                    Write-Error 'Error occured when changing the name of Power Plan'
                }

                if ($Active) {
                    $ExitCode = (Start-Command -FilePath 'Powercfg.exe' -ArgumentList ('/SETACTIVE {0}' -f $GUID)).ExitCode
                    if ($ExitCode -ne 0) {
                        Write-Error "Couldn't activate the Power Plan"
                    }
                }

                Write-Verbose 'New Power Plan created.'
            }
        }
    }
    catch {
        Write-Error $_.Exception.Message
    }

} # end of Set-TargetResource

function Test-TargetResource {
    [CmdletBinding()]
    [OutputType([System.Boolean])]
    param
    (
        [ValidateSet("Present", "Absent")]
        [string]
        $Ensure = 'Present',

        [parameter(Mandatory = $true)]
        [string]
        $GUID,

        [parameter(Mandatory = $true)]
        [string]
        $Name,

        [parameter()]
        [string]
        $Description,

        [bool]
        $Active = $false
    )

    Write-Verbose "Test started. { Ensure: $Ensure | GUID: $GUID | Name: $Name | Description: $Description | Active: $Active }"
    if ($PowerPlanAliases -and $PowerPlanAliases.ContainsKey($GUID)) {
        $GUID = $PowerPlanAliases.$GUID
    }

    $Result = $false
    try {
        $cState = (Get-TargetResource @PSBoundParameters)
        if ($Ensure -ne $cState.Ensure) {
            $Result = $false
        }
        elseif ($Ensure -eq 'Present') {
            $Result = (($Active -eq $cState.Active) -and ($Name.Equals($cState.Name)))
            if ($PSBoundParameters.ContainsKey('Description')) {
                $Result = ($Result -and ($Description.Equals($cState.Description)))
            }
        }
        else {
            $Result = $true
        }
    }
    catch {
        Write-Error $_.Exception.Message
    }

    if ($Result) {
        Write-Verbose ('Test Passed')
    }
    else {
        Write-Verbose ('Test Failed')
    }
    $Result
} # end of Test-TargetResource

function Get-PowerPlan {
    [CmdletBinding()]
    Param(
        [Parameter(Position = 0, ValueFromPipeline)]
        [Alias('PlanGuid')]
        [AllowEmptyString()]
        [string]$GUID
    )

    if ($PowerPlanAliases.ContainsKey($GUID)) {
        $GUID = $PowerPlanAliases.$GUID
    }

    if ($GUID -eq 'ALL') {
        Get-CimInstance -Name root\cimv2\power -Class win32_PowerPlan
    }
    elseif ($GUID) {
        Get-CimInstance -Name root\cimv2\power -Class win32_PowerPlan | Where-Object {$_.InstanceID -match $GUID}
    }
    else {
        Get-CimInstance -Name root\cimv2\power -Class win32_PowerPlan | Where-Object {$_.IsActive}
    }
}

function Start-Command {
    [CmdletBinding()]
    Param(
        [Parameter(Mandatory = $true, Position = 0)]
        [string] $FilePath,
        [Parameter(Mandatory = $false, Position = 1)]
        [string[]]$ArgumentList,
        [int]$Timeout = [int]::MaxValue
    )
    $ProcessInfo = New-Object System.Diagnostics.ProcessStartInfo
    $ProcessInfo.FileName = $FilePath
    $ProcessInfo.UseShellExecute = $false
    $ProcessInfo.Arguments = [string]$ArgumentList
    $Process = New-Object System.Diagnostics.Process
    $Process.StartInfo = $ProcessInfo
    $Process.Start() | Out-Null
    if (!$Process.WaitForExit($Timeout)) {
        $Process.Kill()
        Write-Error ('Process timeout. Terminated. (Timeout:{0}s, Process:{1})' -f ($Timeout * 0.001), $FilePath)
    }
    $Process
}

Export-ModuleMember -Function *-TargetResource