using namespace System.Security.Principal

param (
    [switch] $Run,
    [switch] $Uninstall
)

$ErrorActionPreference = "Stop"

$UpdateActiveHours = {
    $key = "HKLM:\SOFTWARE\Microsoft\WindowsUpdate\UX\Settings"
    $hour = (get-date).hour
    if ($hour -ge 18 -or $hour -lt 6) {
        Set-ItemProperty $key ActiveHoursStart 18
        Set-ItemProperty $key ActiveHoursEnd 12
    } 
    else {
        Set-ItemProperty $key ActiveHoursStart 6
        Set-ItemProperty $key ActiveHoursEnd 0
    }
    Set-ItemProperty $key IsActiveHoursEnabled 1
}

function GetTask {
    return Get-ScheduledTask | Where-Object { $_.TaskName -eq $TaskName -and $_.TaskPath -eq $TaskPath }
}

function RunTask {
    $task = GetTask
    if ($task) {
        $task | Start-ScheduledTask
        Write-Output "$TaskPath$TaskName executed"
    }
    else {
        Write-Output "$TaskPath$TaskName not found"
    }
}

function InstallTask {
    $command = EncodeCommand $UpdateActiveHours
    $arguments = "-NoLogo -NonInteractive -WindowStyle Hidden"
    $options = @{
        Force = $true
        Action = New-ScheduledTaskAction `
            -Execute "powershell" `
            -Argument "$arguments -EncodedCommand $command"
        Principal = New-ScheduledTaskPrincipal `
            -UserId "LOCALSERVICE" `
            -LogonType ServiceAccount `
            -RunLevel Highest
        Settings = New-ScheduledTaskSettingsSet `
            -WakeToRun `
            -StartWhenAvailable `
            -DontStopOnIdleEnd `
            -AllowStartIfOnBatteries `
            -DontStopIfGoingOnBatteries
        Trigger = @(
            New-ScheduledTaskTrigger_AtWakeUp
            New-ScheduledTaskTrigger -AtStartup
            New-ScheduledTaskTrigger -Daily -At "06:00"
            New-ScheduledTaskTrigger -Daily -At "18:00"
        )
    }
    Register-ScheduledTask $TaskName $TaskPath @options | Out-Null
    Write-Output "$TaskPath$TaskName installed"
    RunTask
}

function UninstallTask {
    $task = GetTask
    if ($task) {
        $task | Unregister-ScheduledTask -Confirm:$false
        $pathName = $TaskPath.Replace("\", "")
        $scheduleObject = New-Object -ComObject Schedule.Service
        $scheduleObject.Connect()
        $rootFolder = $scheduleObject.GetFolder("\")
        $rootFolder.DeleteFolder("$pathName", $null)
        Write-Output "$TaskPath$TaskName uninstalled"
    }
    else {
        Write-Output "$TaskPath$TaskName not found"
    }
}

function New-ScheduledTaskTrigger_AtWakeUp {
    $name = "MSFT_TaskEventTrigger"
    $namespace = "Root/Microsoft/Windows/TaskScheduler:MSFT_TaskEventTrigger"
    $class = Get-CimClass -ClassName $name -Namespace $namespace
    $trigger = New-CimInstance -CimClass $class -ClientOnly
    $trigger.Enabled = $true
    $trigger.Subscription = "<QueryList><Query Id=""0"" Path=""System""><Select Path=""System"">*[System[Provider[@Name='Microsoft-Windows-Power-Troubleshooter'] and EventID=1]]</Select></Query></QueryList>"
    return $trigger
}

function EncodeCommand {
    param ([string] $command)
    $bytes = [System.Text.Encoding]::Unicode.GetBytes($command)
    $encodedCommand = [Convert]::ToBase64String($bytes)
    return $encodedCommand
}

if (-not ([WindowsPrincipal][WindowsIdentity]::GetCurrent()).IsInRole([WindowsBuiltInRole]::Administrator)) {
    Write-Output "Run as administrator"
    exit
}

$TaskName = "Update"
$TaskPath = "\Win10ActiveHours\"

if ($Run.IsPresent) {
    RunTask
}
elseif ($Uninstall.IsPresent) {
    UninstallTask
}
else {
    InstallTask
}

exit