. "$PSScriptRoot/Config.ps1"; . "$PSScriptRoot/../Types/OneShotTask.ps1"; . "$PSScriptRoot/../../Windows/Scripts/PowerManagement.ps1"; . "$PSScriptRoot/../../Windows/Scripts/Registry.ps1"; $null = New-Module { . "$PSScriptRoot/../Types/OneShotTask.ps1"; $oneShotTaskName = "PortValhalla OneShot"; $logName = "Application"; $oneShotTrigger = 1337; $taskOption = "OneShotTask"; # ToDo: Store "ProgramData/PortValhalla" path somewhere as const $errorPath = "$env:ProgramData/PortValhalla/error.txt"; $taskSetter = { param([Nullable[OneShotTask]] $Task) Set-SetupOption $taskOption ([string]$Task); }; function Start-Operation { param( [scriptblock] $Action ) $Global:ErrorActionPreference = 'Inquire'; $env:WSLENV = "CONFIG_MODULE/p"; if ($env:CONFIG_MODULE) { $env:CONFIG_MODULE = Resolve-Path $env:CONFIG_MODULE; } if (Test-Admin) { Disable-WindowsUpdateAutoRestart; } New-Alias -Force "sudo" gsudo; & $Action; } <# .SYNOPSIS Gets the current OneShot task. #> function Get-OneShotTask { [OneShotTask](Get-SetupOption $taskOption); } <# .SYNOPSIS Registers a task for listening to OneShot invocations. #> function Enable-OneShotListener { $tempTask = "PortValhalla Temp"; $action = New-ScheduledTaskAction -Execute "pwsh" -Argument ([string](Get-StartupArguments)); schtasks /Create /SC ONEVENT /EC $logName /MO "*[System[Provider[@Name='$logName'] and EventID=$($oneShotTrigger)]]" /TR cmd.exe /TN $tempTask; $trigger = (Get-ScheduledTask $tempTask).Triggers; $principal = New-ScheduledTaskPrincipal -UserId "SYSTEM" -RunLevel Highest; $task = New-ScheduledTask -Action $action -Principal $principal -Trigger $trigger; $null = Register-ScheduledTask -Force $oneShotTaskName -InputObject $task; $null = Unregister-ScheduledTask -Confirm:$false $tempTask; } <# .SYNOPSIS Removes the OneShot task. #> function Disable-OneShotListener { Unregister-ScheduledTask -Confirm:$false $oneShotTaskName; } <# .SYNOPSIS Invokes a one-shot task. .PARAMETER Task The task to run. #> function Invoke-OneShot { param( [OneShotTask] $Task ) $currentStage = Get-Stage; Set-Stage ([SetupStage]::OneShot); & $taskSetter $Task; & { $identifier = "EventLog$oneShotTrigger"; $log = [System.Diagnostics.EventLog]::new($logName); $log.EnableRaisingEvents = $true; $null = Register-ObjectEvent -InputObject $log -EventName EntryWritten -Action { $entry = $Event.SourceEventArgs.Entry; $trigger = $Event.MessageData.Trigger; $identifier = $Event.MessageData.Identifier; if ($entry.EventID -eq $trigger) { $null = New-Event -SourceIdentifier $identifier; } } ` -MessageData @{ Trigger = $oneShotTrigger; Identifier = $identifier; }; Write-EventLog -LogName $logName -Source $logName -EventId $oneShotTrigger -Message "Starting OneShot task ``$(Get-OneShotTask)``…"; for ($i = 0; $i -lt 2; $i++) { Remove-Event -EventIdentifier (Wait-Event -SourceIdentifier $identifier).EventIdentifier; } }; Set-Stage $currentStage; if (Test-Path $errorPath) { $errorMessage = Get-Content $errorPath; Remove-Item $errorPath; Write-Error $errorMessage; } } # ToDo: Store Run-OneShot and Receive-OneShot somewhere else in Windows folder <# .SYNOPSIS Executes the specified action and notifies the OneShot task executor. #> function Start-OneShot { param( [scriptblock] $Action ) try { Start-Operation @PSBoundParameters; } catch { Set-Content -Path $errorPath -Value $Error; Set-UserPermissions $errorPath; } finally { Set-Stage ([SetupStage]::Idle); Write-EventLog -LogName $logName -Source $logName -EventId $oneShotTrigger -Message "The OneShot task ``$(Get-OneShotTask)`` finished."; } } };