#!/bin/pwsh using namespace System.Security.Principal; . "$PSScriptRoot/../Scripts/Security.ps1"; . "$PSScriptRoot/../Scripts/WSL.ps1"; $null = New-Module { . "$PSScriptRoot/../Scripts/Constants.ps1"; . "$PSScriptRoot/../Scripts/Deployment.ps1"; . "$PSScriptRoot/../Scripts/Hooks.ps1"; . "$PSScriptRoot/../Scripts/PowerManagement.ps1"; . "$PSScriptRoot/../Scripts/Registry.ps1"; . "$PSScriptRoot/../Scripts/Security.ps1"; . "$PSScriptRoot/../Scripts/SoftwareManagement.ps1"; . "$PSScriptRoot/../Scripts/System.ps1"; . "$PSScriptRoot/../Scripts/Update.ps1"; . "$PSScriptRoot/../Scripts/Users.ps1"; . "$PSScriptRoot/../Types/WindowsInstallerAction.ps1"; . "$PSScriptRoot/../../Common/Scripts/Config.ps1"; . "$PSScriptRoot/../../Common/Scripts/Operations.ps1"; . "$PSScriptRoot/../../Common/Scripts/Scripting.ps1"; . "$PSScriptRoot/../../Common/Scripts/SoftwareManagement.ps1"; . "$PSScriptRoot/../../Common/Types/InstallerAction.ps1"; <# .SYNOPSIS Finishes the installation of a running Windows machine. #> function Start-WindowsInstallation { Start-Operation -NoImplicitCleanup { Start-InstallationLoop ([WindowsInstallerAction]::Install); }; } <# .SYNOPSIS Creates a backup of the current Windows machine. #> function Start-WindowsBackup { Start-Operation -NoImplicitCleanup { Start-InstallationLoop ([WindowsInstallerAction]::Backup); }; } <# .SYNOPSIS Starts the installation loop. #> function Start-InstallationLoop { param( [WindowsInstallerAction] $Action ) while ((Get-Stage) -ne ([WindowsInstallerStage]::Completed)) { switch (Get-Stage) { ($null) { Set-Stage ([WindowsInstallerStage]::Initialize); break; } ([WindowsInstallerStage]::Initialize) { $env:BACKUP_ARCHIVE = pwsh -Command Write-Host ( Read-Host ( & { switch ($Action) { ([WindowsInstallerAction]::Backup) { "Please select the path you wish to store your backup at" } ([WindowsInstallerAction]::Install) { "Please select an archive you wish to restore from, if you wish to restore from a backup" } } })); Set-Stage ([WindowsInstallerStage]::Run); break; } ([WindowsInstallerStage]::Run) { switch ($Action) { ([WindowsInstallerAction]::Install) { while (-not (Get-IsFinished)) { if (Test-Admin) { $null = Import-Module PSWindowsUpdate; Invoke-Hook "Invoke-WindowsUpdate" -Fallback { Update-WindowsInstallation; }; if ((Get-WURebootStatus -Silent)) { Restart-Intermediate; return; } } switch (Get-SetupStage) { ($null) { Set-SetupStage ([SetupStage]::Initialize); break; } ([SetupStage]::Initialize) { Set-SetupStage ([SetupStage]::Configure); } ([SetupStage]::Configure) { if (Get-Config "valhalla.windows.dualboot.enable") { if (-not (Test-Qemu)) { # Fix synchronization between Linux and Windows clocks. Set-ItemProperty "HKLM:\SYSTEM\CurrentControlSet\Control\TimeZoneInformation" -Name "RealTimeIsUniversal" -Value 1 -Type "DWord"; } # Force time resynchronization $timeZoneOption = "Start"; $timeZoneKey = "HKLM:\SYSTEM\CurrentControlSet\Services\tzautoupdate"; $service = Get-Service W32Time; $autoUpdate = (Get-Item $timeZoneKey).GetValue($timeZoneOption); $stopped = ($service.Status -eq "Stopped"); $setUpdate = { param([int] $Value) Set-ItemProperty $timeZoneKey -Name $timeZoneOption $Value }; & $setUpdate 3; Start-Service $service; w32tm /resync /force; & $setUpdate $autoUpdate; if ($stopped) { Stop-Service $service; } } Set-SetupStage ([SetupStage]::Install); } ([SetupStage]::Install) { Write-Host "Entering install phase"; Deploy-SoftwareAction; Set-SetupStage ([SetupStage]::CreateUser); Restart-Intermediate; return; } ([SetupStage]::CreateUser) { Install-ValhallaUsers; Set-IsFinished $true; } } } } ([WindowsInstallerAction]::Backup) { $finished = $false; $setupUser = Get-SetupUser; $adminGroup = @{ SID = [SecurityIdentifier]::new([WellKnownSidType]::BuiltinAdministratorsSid, $null); }; while (-not $finished) { switch (Get-BackupStage) { $null { Set-BackupStage ([BackupStage]::Initialize); } ([BackupStage]::Initialize) { $null = New-LocalUser $setupUser -NoPassword; Set-LocalUser $setupUser -PasswordNeverExpires $true; Set-LocalUser $setupUser -PasswordNeverExpires $false; Add-LocalGroupMember -Member $setupUser @adminGroup; Set-AutologinUser $setupUser; Disable-UAC; Set-BackupStage ([BackupStage]::Backup); Restart-Intermediate; return; } ([BackupStage]::Backup) { Deploy-SoftwareAction ([InstallerAction]::Backup); Set-BackupStage ([BackupStage]::BackupUsers); } ([BackupStage]::BackupUsers) { $users = @(Get-Users); $i = Get-CurrentUser; Disable-LocalUser $setupUser; for (; $i -lt $users.Count; $i++) { Set-CurrentUser $i; $user = $users[$i]; if ($env:UserName -ne $user) { Set-BootMessage "Please Log In" "Please log in with the user ``$user``"; Add-LocalGroupMember -Member "$user" @adminGroup -ErrorAction SilentlyContinue; Disable-Autologin; Restart-Intermediate; return; } else { Deploy-SoftwareAction -Action ([InstallerAction]::BackupUser); Remove-LocalGroupMember -Member "$user" @adminGroup; foreach ($group in Get-UserConfig -UserName "$user" "groups") { Add-LocalGroupMember -Member "$user" $group; } } } Disable-BootMessage; Write-Host "Never forget to store the backup somewhere safe!"; Write-Host "I mean… what kind of a dumbass would ever forget to do so, right?"; Read-Host "Press enter once you're done"; $finished = $true; } } } } } Set-Stage ([WindowsInstallerStage]::Cleanup); break; } ([WindowsInstallerStage]::Cleanup) { $taskName = "PortValhalla Cleaner"; $setupUser = Get-SetupUser; Clear-OperationResources; Remove-Item -Recurse -Force "C:\ProgramData\PortValhalla"; Get-SetupConfigKey | Remove-Item -Recurse -Force; Disable-Autologin; Disable-LocalUser $setupUser; $script = { param( $TaskName, $UserName, $ProjectRoot, $ArtifactRoot ) $user = Get-LocalUser $UserName; [string] $sid = $user.SID; Remove-LocalUser $user; Get-CimInstance Win32_UserProfile | Where-Object { $_.SID -eq $sid } | Remove-CimInstance; Unregister-ScheduledTask -Confirm:$false $TaskName; Remove-Item -Recurse -Force "$ArtifactRoot"; if ($ProjectRoot) { Remove-Item -Recurse -Force "$ProjectRoot"; } }; $trigger = New-ScheduledTaskTrigger -AtStartup; $task = New-ScheduledTaskAction -Execute "pwsh" ` -Argument (@( "-Command & { $script }", (ConvertTo-Injection $taskName), (ConvertTo-Injection $setupUser), (ConvertTo-Injection "$env:VALHALLA_ROOT"), (ConvertTo-Injection (Get-ArtifactRoot)) ) -join " "); $null = Register-ScheduledTask -Force $taskName -Action $task -Trigger $trigger -RunLevel Highest -User "SYSTEM"; Set-Stage ([WindowsInstallerStage]::Completed); Enable-UAC; Restart-Intermediate -NoRegister; break; } } } } };