esPreSso.psm1

#Region '.\Public\Get-KeepAwake.ps1' -1

function Get-KeepAwake {
    <#
    .SYNOPSIS
    Checks the registered scheduled tasks for the esPreSso job that runs Start-KeepAwake
    .DESCRIPTION
    Checks the registered scheduled tasks for the esPreSso job that runs Start-KeepAwake and return an object representing its settings
    .EXAMPLE
    PS> Get-KeepAwake
 
    TaskPath TaskName State
    -------- -------- -----
    \Microsoft\Windows\PowerShell\ScheduledJobs\ esPreSso Ready
 
    #>

    [CmdletBinding()]
    param ()

    $TaskName = "esPreSso"
    $TaskPath = "\Microsoft\Windows\PowerShell\ScheduledJobs\"
    try {
        Get-ScheduledTask -TaskName $TaskName -TaskPath $TaskPath -ErrorAction Stop
    } catch {
        Write-Verbose "esPreSso scheduled task not found"
    }
}
#EndRegion '.\Public\Get-KeepAwake.ps1' 26
#Region '.\Public\Register-KeepAwake.ps1' -1

function Register-KeepAwake {
    <#
    .SYNOPSIS
    registers a scheduled job to run Start-KeepAwake at user login
    .DESCRIPTION
    registers a scheduled job to run Start-KeepAwake at user login. Allows control over the Start-KeepAwake settings as well as some scheduled job settings.
    .EXAMPLE
    PS> Register-KeepAwake
 
    when ran in an administrative PowerShell session this will create a scheduled task that runs at logon and starts Start-KeepAwake with the -PowerControl parameter
    #>

    [CmdletBinding()]
    param ()

    # check if we're running as admin and quit if not

    $IsAdmin = ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator)
    if ($IsAdmin) {
        # get the currently logged in user in case the PowerShell session was elevated via a different username than the one logged in to the computer
        $UserName = (Get-CimInstance -Class Win32_ComputerSystem).Username
        $ActionArgs = 'powershell.exe -NoLogo -NonInteractive -NoProfile -WindowStyle Hidden -Command "& {Start-KeepAwake -PowerControl}"'
        $TaskSettings = @{
                    Action = $(New-ScheduledTaskAction -Execute "Conhost.exe" -Argument $ActionArgs)
                    Principal = $(New-ScheduledTaskPrincipal -UserId $Username -LogonType Interactive)
                    TaskName = "esPreSso"
                    TaskPath = "\Microsoft\Windows\PowerShell\ScheduledJobs\"
                    Trigger = $(New-ScheduledTaskTrigger -AtLogOn -User $UserName)
                }
        $ExistingTask = Get-KeepAwake
        if ($ExistingTask) {
            Remove-KeepAwake
        }
        Register-ScheduledTask @TaskSettings
    } else {
        Write-Warning "Registering a scheduled task requires elevation. Please re-run PowerShell with 'run as administrator' and try again."
    }
}
#EndRegion '.\Public\Register-KeepAwake.ps1' 38
#Region '.\Public\Remove-KeepAwake.ps1' -1

function Remove-KeepAwake {
    <#
    .SYNOPSIS
    Removes the esPreSso scheduled task from Task Scheduler
    .DESCRIPTION
    Unregisters the scheduled task created by Register-KeepAwake. There is no output.
    .EXAMPLE
    PS> Remove-KeepAwake
 
    if there is an existing scheduled task for esPreSso this will cleanly remove it from Task Scheduler.
    #>

    [CmdletBinding()]
    param ()

    $ScheduledTask = Get-KeepAwake
    if ($ScheduledTask) {
        $IsAdmin = ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator)
        if ($IsAdmin) {
            Write-Verbose "Removing scheduled task named $($ScheduledTask.TaskName) in $($ScheduledTask.TaskPath)"
            Unregister-ScheduledTask -InputObject $ScheduledTask -Confirm:$false
        } else {
            Write-Warning "Removing a scheduled task requires elevation. Please re-run PowerShell and 'run as administrator' and try again."
        }
    } else {
        Write-Warning "No scheduled task for esPreSso found"
    }
}
#EndRegion '.\Public\Remove-KeepAwake.ps1' 28
#Region '.\Public\Start-KeepAwake.ps1' -1

function Start-KeepAwake {
    <#
    .SYNOPSIS
    This function attempts to keep the computer awake by sending a key-press every 60 seconds (by default)
    .DESCRIPTION
    Using the WScript namespace to send keys this function will send a key combination of shift+F15 every 60 seconds by default to keep the computer awake and preven the screensaver
    from activating.
    .PARAMETER Minutes
    Number of minutes to run the keep awake
    .PARAMETER Hours
    Number of hours to run the keep awake
    .PARAMETER Until
    A date time representing when to stop running the keep awake. Accepts common datetime formats
    .PARAMETER Interval
    The interval for how often a key press is sent. Default is 60 seconds and this should be fine for most scenarios.
    .PARAMETER PowerControl
    Switch parameter that tells Start-KeepAwake to register a request via SetThreadExecutionState to keep the display awake and prevent sleep.
    Cancelled with Ctrl+C or other terminating signal.
    .EXAMPLE
    PS> Start-KeepAwake
 
    When ran with no parameters the function will attempt to keep the computer awake indefinitely until cancelled.
    .EXAMPLE
    PS> Start-KeepAwake -Until "3:00pm"
 
    will send a keypress of shift+F15 every minute until 3:00 pm the same day
    .EXAMPLE
    PS> Start-KeepAwake -PowerControl
 
    Will also attempt to keep the computer awake indefinitely but won't send any key presses.
    .NOTES
    Credit to marioraulperez for his class definition: https://github.com/marioraulperez/keep-windows-awake
    #>

    [CmdletBinding(DefaultParameterSetName = 'Manual')]
    [Alias("nosleep","ka")]
    Param(
        [Parameter(Position=1, ParameterSetName='Manual')]
        [Alias("m")]
        [Int32]$Minutes,
        [Parameter(Position=0, ParameterSetName='Manual')]
        [Alias("h")]
        [Int32]$Hours,
        [Parameter(ParameterSetName='Until')]
        [Alias("u")]
        [DateTime]$Until,
        [Parameter(ParameterSetName='Manual')]
        [Parameter(ParameterSetName='Until')]
        [ValidateRange(1,86400)]
        [Int32]$Interval = 60,
        [Parameter(ParameterSetName='PowerPlan')]
        [Switch]$PowerControl
    )

    if ($PowerControl) {
            try {
                $Definition = @"
using System;
using System.Runtime.InteropServices;
 
public class PowerCtrl {
    [DllImport("kernel32.dll", SetLastError = true)]
    public static extern uint SetThreadExecutionState(uint esFlags);
 
    public static void PreventSleep() {
        // ES_CONTINUOUS | ES_SYSTEM_REQUIRED | ES_DISPLAY_REQUIRED
        SetThreadExecutionState(0x80000002 | 0x00000001 | 0x00000002);
    }
 
    public static void AllowSleep() {
        // ES_CONTINUOUS
        SetThreadExecutionState(0x80000000);
    }
}
"@

                Add-Type -Language CSharp -TypeDefinition $Definition
                Write-Verbose "Preventing sleep via PowerCtrl"
                $BackgroundJob = Start-Job -Name "esPreSso" -ScriptBlock {
                    Add-Type -Language CSharp -TypeDefinition $args[0]
                    [PowerCtrl]::PreventSleep()
                    while ($true) {
                        Start-Sleep -Seconds 60
                    }
                } -ArgumentList $Definition
                Wait-Job -Job $BackgroundJob
            } catch {
                Write-Error $_
            } finally {
                Write-Verbose "Removing PowerCtrl"
                Stop-Job -Job $BackgroundJob
                Remove-Job -Job $BackgroundJob
                [PowerCtrl]::AllowSleep()
            }

    } else {
        $TSParams = @{}
        switch ($PSBoundParameters.Keys) {
            'Minutes' {
                $TSParams.Add('Minutes', $Minutes)
                Write-Verbose "Adding $Minutes minutes of duration"
            }
            'Hours' {
                $TSParams.Add('Hours', $Hours)
                Write-Verbose "Adding $Hours hours of duration"
            }
            'Until' {
                Write-Verbose "Stopping time provided of: $($Until.ToShortTimeString())"
                $UntilDuration = ($Until - (Get-Date)).TotalMinutes
                If ($UntilDuration -lt 1) {
                    $UntilDuration = 1
                }
                Write-Verbose "Adding $UntilDuration minutes of duration"
                $TSParams.Add('Minutes', $UntilDuration)
            }
        }
        if (-not $TSParams.Count) {
            Write-Verbose "Defaulting to indefinite runtime"
            $Duration = $true
        } else {
            $Duration = (New-TimeSpan @TSParams).TotalMinutes
            Write-Verbose "Total duration is $Duration minutes"
        }

        $WShell = New-Object -ComObject WScript.Shell
        Write-Verbose "Keeping computer awake by sending 'Shift + F15' every $Interval seconds"
        while ($RunTime -le $Duration) {
            if ($Duration.GetType().Name -ne "Boolean") {
                Write-Verbose $('{0:n2} minutes remaining' -f ($Duration - $Runtime))
                $Runtime += $($Interval/60)
            }
            $WShell.SendKeys('+{F15}')
            Start-Sleep -seconds $Interval
        }
    }
}
#EndRegion '.\Public\Start-KeepAwake.ps1' 135