From 1b0c7155146b29fc277e8571a19e8072167d689d Mon Sep 17 00:00:00 2001
From: Manuel Thalmann <m@nuth.ch>
Date: Tue, 27 Aug 2024 04:15:37 +0200
Subject: [PATCH] Handle initialization in operation code

---
 scripts/Common/Scripts/Operations.ps1 | 174 ++++-
 scripts/Windows/OS/Install.ps1        | 994 +++++++++++---------------
 2 files changed, 583 insertions(+), 585 deletions(-)

diff --git a/scripts/Common/Scripts/Operations.ps1 b/scripts/Common/Scripts/Operations.ps1
index ad264429..89a1b889 100644
--- a/scripts/Common/Scripts/Operations.ps1
+++ b/scripts/Common/Scripts/Operations.ps1
@@ -1,12 +1,16 @@
-. "$PSScriptRoot/Config.ps1";
+using namespace System.Management.Automation.Host;
+
 . "$PSScriptRoot/../Types/OneShotTask.ps1";
-. "$PSScriptRoot/../../Windows/Scripts/PowerManagement.ps1";
-. "$PSScriptRoot/../../Windows/Scripts/Registry.ps1";
-. "$PSScriptRoot/../../Windows/Scripts/Security.ps1";
-. "$PSScriptRoot/../../Windows/Scripts/WSL.ps1";
 
 $null = New-Module {
+    . "$PSScriptRoot/Config.ps1";
+    . "$PSScriptRoot/../Scripts/SoftwareManagement.ps1";
     . "$PSScriptRoot/../Types/OneShotTask.ps1";
+    . "$PSScriptRoot/../../Windows/Scripts/Hooks.ps1";
+    . "$PSScriptRoot/../../Windows/Scripts/PowerManagement.ps1";
+    . "$PSScriptRoot/../../Windows/Scripts/Registry.ps1";
+    . "$PSScriptRoot/../../Windows/Scripts/Security.ps1";
+    . "$PSScriptRoot/../../Windows/Scripts/WSL.ps1";
     $oneShotTaskName = "PortValhalla OneShot";
     $logName = "Application";
     $oneShotTrigger = 1337;
@@ -59,6 +63,166 @@ $null = New-Module {
                     Clear-OperationResources;
                 };
             }
+
+            Set-Stage ((Get-Stage) ?? ([SetupStage]::Initialize));
+
+            & {
+                while ((Get-Stage) -eq ([SetupStage]::Initialize)) {
+                    if ($IsWindows) {
+                        if (-not ((Test-Command "choco") -and (Test-Command "refreshenv"))) {
+                            Invoke-Hook "Install-Chocolatey" -Fallback {
+                                # Install chocolatey
+                                New-Item -Force $PROFILE;
+                                [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072;
+                                Invoke-Expression ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'));
+                                Import-Module $env:ChocolateyInstall/helpers/chocolateyProfile.psm1;
+                                refreshenv;
+                            };
+
+                            continue;
+                        }
+
+                        if (-not (Test-ChocoPackage "powershell-core")) {
+                            Invoke-Hook "Install-PowerShellCore" -Fallback {
+                                choco install -y powershell-core --install-arguments='"ADD_FILE_CONTEXT_MENU_RUNPOWERSHELL=1 ADD_EXPLORER_CONTEXT_MENU_OPENPOWERSHELL=1 REGISTER_MANIFEST=1 USER_MU=1 ENABLE_MU=1"';
+                            };
+
+                            Restart-Intermediate;
+                            return;
+                        }
+
+                        if ($env:PWSH_PATH -and (Test-Path $env:PWSH_PATH)) {
+                            attrib "-R" "$env:PWSH_PATH\*" /S /D;
+                            Remove-Item -Recurse -Force $env:PWSH_PATH;
+                            continue;
+                        }
+
+                        if ($env:DEBUG) {
+                            if (
+                                (Get-Item $env:INSTALLER_SCRIPT).IsReadOnly -and
+                                (Test-Qemu) -and
+                                ($Host.UI.PromptForChoice(
+                                    "Confirm",
+                                    "Do you wish to swap to live scripts?",
+                                    [ChoiceDescription[]]@(
+                                        [ChoiceDescription]::new("&No", "Use scripts stored in the virtual machine"),
+                                        [ChoiceDescription]::new("&Yes", "Use live scripts stored on the host")),
+                                    0) -eq 1)) {
+                                Install-ChocoPackage winfsp qemu-guest-agent;
+                                Get-Service VirtioFsSvc | Start-Service -PassThru | Set-Service -StartupType Automatic;
+
+                                while (-not (Test-Path Z:\)) {
+                                    Start-Sleep 0.1;
+                                }
+
+                                foreach ($name in @("CONFIG_MODULE", "INSTALLER_SCRIPT")) {
+                                    $variable = Get-Item "Env:\$name";
+
+                                    $path = Join-Path `
+                                        "Z:\Repositories\PortValhalla" `
+                                        ([System.IO.Path]::GetRelativePath("$PSScriptRoot/../../..", $variable.Value));
+
+                                    Set-Item "Env:\$name" $path;
+                                    Write-Host "The new value of ``$name`` is ``$path``";
+                                }
+
+                                Restart-Intermediate;
+                                exit;
+                            }
+                        }
+
+                        if (-not (Test-Command "gsudo")) {
+                            Install-ChocoPackage gsudo;
+                            refreshenv;
+                            continue;
+                        }
+
+                        if ($env:DEBUG) {
+                            & {
+                                $sys32 = "$env:WINDIR/System32";
+                                $osk = (Get-Item "$sys32/osk.exe").FullName;
+                                $cmd = (Get-Item "$sys32/cmd.exe").FullName;
+                                $tmpOsk = New-TemporaryFile;
+                                $tmpCmd = New-TemporaryFile;
+                                gsudo -d copy "$osk" "$tmpOsk";
+                                gsudo -d copy "$cmd" "$tmpCmd";
+
+                                if ((Get-FileHash $tmpOsk).Hash -ne (Get-FileHash $tmpCmd).Hash) {
+                                    Set-MpPreference -ExclusionPath $osk;
+                                    gsudo -d --ti move $osk "${osk}_";
+                                    gsudo -d -s copy $cmd $osk;
+                                    continue;
+                                }
+                            };
+                        }
+
+                        if (-not (Test-Winget)) {
+                            . "$PSScriptRoot/../../Windows/Software/winget/Manage.ps1";
+                            continue;
+                        }
+
+                        if (-not (Test-Command "git")) {
+                            Install-WingetPackage Git.Git;
+                            refreshenv;
+                            continue;
+                        }
+
+                        if (-not (Test-Wsl)) {
+                            Install-Wsl;
+                            Restart-Intermediate;
+                            return;
+                        }
+
+                        if (-not (Test-WslDistributions)) {
+                            Install-WslDistribution;
+                            continue;
+                        }
+
+                        if (-not (wsl --shell-type login type -t nix)) {
+                            wsl -- sh `<`(curl -L https://nixos.org/nix/install`) --daemon --yes;
+                            wsl --shutdown;
+                            continue;
+                        }
+
+                        Invoke-Hook "Install-PSModules" -Fallback {
+                            $modules = @(
+                                @("KnownFolders"),
+                                @("PSWindowsUpdate"),
+                                @("PSScriptAnalyzer"),
+                                @("LocalAccounts", $true),
+                                @("NuGet")
+                            );
+
+                            foreach ($module in $modules) {
+                                $parameters = @{ };
+
+                                if ($module[1]) {
+                                    $parameters = @{
+                                        allowPrerelease = $true;
+                                    };
+                                }
+
+                                if (-not (Test-PSModule $module[0])) {
+                                    Install-Module -Scope AllUsers -AcceptLicense -Force -AllowClobber $module[0] @parameters;
+                                    Import-Module $module[0];
+                                }
+                            }
+
+                            . "$PSScriptRoot/../../Windows/Software/PinnedItem/Manage.ps1";
+                        };
+
+                        if (-not (Test-PSPackage Selenium.WebDriver)) {
+                            Write-Host "Installing browser automation tools…";
+                            $null = Install-Package -Force Selenium.WebDriver -RequiredVersion 4.10.0 -SkipDependencies;
+                            continue;
+                        }
+
+                        Install-ChocoPackage selenium-gecko-driver firefox;
+                        Install-WingetPackage AutoHotkey.AutoHotkey;
+                        Set-Stage ([SetupStage]::Configure);
+                    }
+                }
+            }
         }
 
         & $Action;
diff --git a/scripts/Windows/OS/Install.ps1 b/scripts/Windows/OS/Install.ps1
index f1a6e0b2..26d243e2 100644
--- a/scripts/Windows/OS/Install.ps1
+++ b/scripts/Windows/OS/Install.ps1
@@ -1,5 +1,4 @@
 #!/bin/pwsh
-using namespace System.Management.Automation.Host;
 using namespace System.Security.Principal;
 
 . "$PSScriptRoot/../Scripts/Prerequisites.ps1";
@@ -42,615 +41,450 @@ $null = New-Module {
     #>
     function Start-InstallationLoop {
         while (-not (Get-IsFinished)) {
+            if (-not (Test-Wsl)) {
+                Register-WslDistribution;
+            }
+
             switch (Get-Stage) {
-                ($null) {
-                    Set-Stage ([SetupStage]::Initialize);
-                    break;
-                }
-                ([SetupStage]::Initialize) {
-                    if (-not ((Test-Command "choco") -and (Test-Command "refreshenv"))) {
-                        Invoke-Hook "Install-Chocolatey" -Fallback {
-                            # Install chocolatey
-                            New-Item -Force $PROFILE;
-                            [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072;
-                            Invoke-Expression ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'));
-                            Import-Module $env:ChocolateyInstall/helpers/chocolateyProfile.psm1;
-                            refreshenv;
-                        };
+                ([SetupStage]::OneShot) {
+                    Write-Host "Running OneShot task ``$(Get-OneShotTask)``";
 
-                        continue;
-                    }
-
-
-                    if (-not (Test-ChocoPackage "powershell-core")) {
-                        Invoke-Hook "Install-PowerShellCore" -Fallback {
-                            choco install -y powershell-core --install-arguments='"ADD_FILE_CONTEXT_MENU_RUNPOWERSHELL=1 ADD_EXPLORER_CONTEXT_MENU_OPENPOWERSHELL=1 REGISTER_MANIFEST=1 USER_MU=1 ENABLE_MU=1"';
-                        };
-
-                        Restart-Intermediate;
-                        return;
-                    }
-
-                    if ($env:PWSH_PATH -and (Test-Path $env:PWSH_PATH)) {
-                        attrib "-R" "$env:PWSH_PATH\*" /S /D;
-                        Remove-Item -Recurse -Force $env:PWSH_PATH;
-                        continue;
-                    }
-
-                    if ($env:DEBUG) {
-                        if (
-                            (Get-Item $env:INSTALLER_SCRIPT).IsReadOnly -and
-                            (Test-Qemu) -and
-                            ($Host.UI.PromptForChoice(
-                                    "Confirm",
-                                    "Do you wish to swap to live scripts?",
-                                    [ChoiceDescription[]]@(
-                                        [ChoiceDescription]::new("&No", "Use scripts stored in the virtual machine"),
-                                        [ChoiceDescription]::new("&Yes", "Use live scripts stored on the host")),
-                                    0) -eq 1)) {
-                            Install-ChocoPackage winfsp qemu-guest-agent;
-                            Get-Service VirtioFsSvc | Start-Service -PassThru | Set-Service -StartupType Automatic;
-
-                            while (-not (Test-Path Z:\)) {
-                                Start-Sleep 0.1;
+                    Start-OneShot {
+                        switch (Get-OneShotTask) {
+                            ([OneShotTask]::InitializeMSAccount) {
+                                Initialize-UserCreation;
                             }
-
-                            foreach ($name in @("CONFIG_MODULE", "INSTALLER_SCRIPT")) {
-                                $variable = Get-Item "Env:\$name";
-
-                                $path = Join-Path `
-                                    "Z:\Repositories\PortValhalla" `
-                                    ([System.IO.Path]::GetRelativePath("$PSScriptRoot/../../..", $variable.Value));
-
-                                Set-Item "Env:\$name" $path;
-                                Write-Host "The new value of ``$name`` is ``$path``";
-                            }
-
-                            Restart-Intermediate;
-                            exit;
-                        }
-                    }
-
-                    if (-not (Test-Command "gsudo")) {
-                        Install-ChocoPackage gsudo;
-                        refreshenv;
-                        continue;
-                    }
-
-                    if ($env:DEBUG) {
-                        & {
-                            $sys32 = "$env:WINDIR/System32";
-                            $osk = (Get-Item "$sys32/osk.exe").FullName;
-                            $cmd = (Get-Item "$sys32/cmd.exe").FullName;
-                            $tmpOsk = New-TemporaryFile;
-                            $tmpCmd = New-TemporaryFile;
-                            gsudo -d copy "$osk" "$tmpOsk";
-                            gsudo -d copy "$cmd" "$tmpCmd";
-
-                            if ((Get-FileHash $tmpOsk).Hash -ne (Get-FileHash $tmpCmd).Hash) {
-                                Set-MpPreference -ExclusionPath $osk;
-                                gsudo -d --ti move $osk "${osk}_";
-                                gsudo -d -s copy $cmd $osk;
-                                continue;
-                            }
-                        };
-                    }
-
-                    if (-not (Test-Winget)) {
-                        . "$PSScriptRoot/../Software/winget/Manage.ps1";
-                        continue;
-                    }
-
-                    if (-not (Test-Command "git")) {
-                        Install-WingetPackage Git.Git;
-                        refreshenv;
-                        continue;
-                    }
-
-                    if (-not (Test-Wsl)) {
-                        Install-Wsl;
-                        Restart-Intermediate;
-                        return;
-                    }
-
-                    if (-not (Test-WslDistributions)) {
-                        Install-WslDistribution;
-                        continue;
-                    }
-
-                    if (-not (wsl --shell-type login type -t nix)) {
-                        wsl -- sh `<`(curl -L https://nixos.org/nix/install`) --daemon --yes;
-                        wsl --shutdown;
-                        continue;
-                    }
-
-                    Invoke-Hook "Install-PSModules" -Fallback {
-                        $modules = @(
-                            @("KnownFolders"),
-                            @("PSWindowsUpdate"),
-                            @("PSScriptAnalyzer"),
-                            @("LocalAccounts", $true),
-                            @("NuGet")
-                        );
-
-                        foreach ($module in $modules) {
-                            $parameters = @{ };
-
-                            if ($module[1]) {
-                                $parameters = @{
-                                    allowPrerelease = $true;
-                                };
-                            }
-
-                            if (-not (Test-PSModule $module[0])) {
-                                Install-Module -Scope AllUsers -AcceptLicense -Force -AllowClobber $module[0] @parameters;
-                                Import-Module $module[0];
+                            ([OneShotTask]::DisableUAC) {
+                                Disable-UAC;
+                                Register-Setup;
                             }
                         }
-
-                        . "$PSScriptRoot/../Software/PinnedItem/Manage.ps1";
                     };
 
-                    if (-not (Test-PSPackage Selenium.WebDriver)) {
-                        Write-Host "Installing browser automation tools…";
-                        $null = Install-Package -Force Selenium.WebDriver -RequiredVersion 4.10.0 -SkipDependencies;
-                        continue;
-                    }
-
-                    Install-ChocoPackage selenium-gecko-driver firefox;
-
-                    Install-WingetPackage AutoHotkey.AutoHotkey;
-                    Set-Stage ([SetupStage]::Configure);
                     break;
                 }
                 default {
-                    if (-not (Test-Wsl)) {
-                        Register-WslDistribution;
+                    if (Test-Admin) {
+                        $null = Import-Module PSWindowsUpdate;
+
+                        Invoke-Hook "Invoke-WindowsUpdate" -Fallback {
+                            Update-WindowsInstallation;
+                        };
+
+                        if ((Get-WURebootStatus -Silent)) {
+                            Restart-Intermediate;
+                            return;
+                        }
+                    }
+
+                    <#
+                        .SYNOPSIS
+                        Deploys an action for each software.
+
+                        .PARAMETER Action
+                        The action to execute by default.
+                    #>
+                    function Deploy-SoftwareAction {
+                        param(
+                            [Nullable[InstallerAction]] $Action = $null
+                        )
+
+                        [bool] $install = $false;
+                        $arguments = [hashtable]@{ };
+
+                        if ($null -ne $Action) {
+                            $install = ($Action -eq ([InstallerAction]::Install));
+                            $null = $arguments.Add("action", $Action);
+                        } else {
+                            $install = $true;
+                        }
+
+                        # Drivers
+                        & {
+                            $driverPath = "$PSScriptRoot/../Drivers";
+                            $mbPath = "$driverPath/ROG Zenith Extreme Alpha";
+
+                            if ($install) {
+                                if (Get-Config "valhalla.hardware.elgatoWave") {
+                                    if (-not (Test-ChocoPackage wavelink)) {
+                                        Install-ChocoPackage wavelink -ArgumentList '--install-arguments="/norestart"';
+                                        Remove-DesktopIcon "*Wave Link*";
+                                        Restart-Intermediate;
+                                        exit;
+                                    }
+                                }
+                            }
+
+                            foreach ($component in (Get-Config "valhalla.hardware.components")) {
+                                switch ($component) {
+                                    ("ROG Zenith Extreme Alpha") {
+                                        & "$mbPath/MarvellEthernet/Manage.ps1" @arguments;
+                                        & "$mbPath/IntelWiFi/Manage.ps1" @arguments;
+                                        & "$mbPath/IntelBluetooth/Manage.ps1" @arguments;
+                                        & "$mbPath/AMDChipsetX399/Manage.ps1" @arguments;
+                                        & "$driverPath/AMDChipsetX399/Manage.ps1" @arguments;
+                                    }
+                                    ("Predator Z301C") {
+                                        & "$driverPath/Predator Z301C/Manage.ps1" @arguments;
+                                    }
+                                }
+                            }
+
+                            if ($install) {
+                                if (Get-Config "valhalla.hardware.amdCPU") {
+                                    Install-ChocoPackage amd-ryzen-master;
+                                    # ToDo: backup Ryzen energy saving plan
+                                }
+
+                                if (Get-Config "valhalla.hardware.nvidiaGPU") {
+                                    Install-ChocoPackage geforce-game-ready-driver;
+                                    Remove-DesktopIcon "*Geforce*";
+                                }
+
+                                if (Get-Config "valhalla.hardware.corsairDevice") {
+                                    Install-ChocoPackage icue;
+                                }
+                            }
+
+                            if (Get-Config "valhalla.hardware.eyeX") {
+                                & "$driverPath/Tobii EyeX/Manage.ps1" @arguments;
+                            }
+                        };
+
+                        & {
+                            # Windows Config
+                            $softwarePath = "$PSScriptRoot/../Software";
+                            $commonSoftware = "$PSScriptRoot/../../Common/Software";
+                            & "$softwarePath/Windows/Manage.ps1" @arguments;
+
+                            if (Get-Config "valhalla.hardware.logitechG") {
+                                & "$softwarePath/LGHub/Manage.ps1" @arguments;
+                            }
+
+                            if (Test-Collection "essential") {
+                                # Essentials
+                                & "$softwarePath/aliae/Main.ps1" @arguments;
+                                & "$softwarePath/git/Manage.ps1" @arguments;
+                                & "$softwarePath/OpenSSH/Manage.ps1" @arguments;
+                                & "$softwarePath/PowerShell/Manage.ps1" @arguments;
+                                & "$softwarePath/chocolatey/Manage.ps1" @arguments;
+                                & "$softwarePath/zoxide/Manage.ps1" @arguments;
+                                & "$commonSoftware/posh-git/Manage.ps1" @arguments;
+                                & "$commonSoftware/Terminal-Icons/Manage.ps1" @arguments;
+                                & "$softwarePath/Oh My Posh/Manage.ps1" @arguments;
+
+                                if (Get-Config "valhalla.windows.dualboot") {
+                                    & "$softwarePath/Ext4Fsd/Main.ps1" @arguments;
+                                }
+
+                                if ($install) {
+                                    Install-ChocoPackage `
+                                        procexp `
+                                        procmon `
+                                        ;
+
+                                    Install-WingetPackage `
+                                        KDE.KDEConnect `
+                                        ;
+                                }
+                            }
+
+                            if (Test-Collection "common") {
+                                # Common Software
+                                & "$softwarePath/WinSCP/Manage.ps1" @arguments;
+                                & "$softwarePath/Thunderbird/Manage.ps1" @arguments;
+                                & "$softwarePath/PuTTY/Manage.ps1" @arguments;
+
+                                if ($install) {
+                                    Install-ChocoPackage `
+                                        7zip `
+                                        chocolateygui `
+                                        DefaultProgramsEditor `
+                                        bitwarden `
+                                        keepass `
+                                        ;
+
+                                    Install-WingetPackage `
+                                        SomePythonThings.WingetUIStore `
+                                        ;
+
+                                    Remove-DesktopIcon "UniGetUI*";
+                                }
+                            }
+
+                            if (Test-Collection "desktopExperience") {
+                                if ($install) {
+                                    # Fonts
+                                    Install-ChocoPackage nerd-fonts-CascadiaCode;
+
+                                    # Internet Access
+                                    Install-WingetPackage Brave.Brave kamranahmedse.pennywise;
+                                    Remove-DesktopIcon "*Brave*";
+                                    Remove-TaskbarItem "*Brave*";
+                                    Remove-DesktopIcon "Pennywise*";
+
+                                    # Tools
+                                    Install-SetupPackage -Source "https://github.com/mRemoteNG/mRemoteNG/releases/download/2023.03.03-v1.77.3-nb/mRemoteNG-Installer-1.77.3.nb-1784.msi" -ArgumentList "/Quiet";
+                                    Remove-DesktopIcon "mRemoteNG*";
+
+                                    Install-ChocoPackage `
+                                        gimp `
+                                        gpu-z `
+                                        windirstat `
+                                        winmerge `
+                                        handbrake `
+                                        hwmonitor `
+                                        qbittorrent `
+                                        imgburn `
+                                        inkscape `
+                                        krita `
+                                        MetaX `
+                                        obs-studio `
+                                        ;
+
+                                    Remove-DesktopIcon "GIMP*";
+                                    Remove-DesktopIcon "GPU-Z*";
+                                    Remove-DesktopIcon "WinDirStat*";
+                                    Remove-DesktopIcon "*HWMonitor*";
+                                    Remove-DesktopIcon "ImgBurn*";
+                                    Remove-DesktopIcon "InkScape*";
+                                    Remove-DesktopIcon "Krita*";
+                                    Remove-DesktopIcon "MetaX*";
+                                    Remove-DesktopIcon "OBS Studio*";
+
+                                    Install-WingetPackage `
+                                        AntSoftware.AntRenamer `
+                                        AppWork.JDownloader;
+
+                                    Remove-DesktopIcon "JDownloader*";
+                                }
+
+                                # ToDo: Consider hiding behind own config?
+                                & "$softwarePath/Ubiquiti UniFi Controller/Manage.ps1" @arguments;
+
+                                # Internet Access
+                                & "$softwarePath/Firefox/Manage.ps1" @arguments;
+                                & "$softwarePath/MSEdgeRedirect/Manage.ps1" @arguments;
+
+                                if (Test-Collection "fileSync") {
+                                    & "$softwarePath/Nextcloud/Main.ps1" @arguments;
+                                }
+                            }
+
+                            if (Test-Collection "socialMedia") {
+                                if ($install) {
+                                    Install-ChocoPackage `
+                                        signal `
+                                        threema-desktop `
+                                        element-desktop `
+                                        teamspeak `
+                                        ;
+
+                                    Remove-DesktopIcon "*Element*";
+                                    Remove-DesktopIcon "*TeamSpeak*";
+
+                                    Install-WingetPackage Discord.Discord;
+                                    Remove-DesktopIcon "*Discord*";
+                                }
+                            }
+
+                            if (Test-Collection "media") {
+                                if ($install) {
+                                    Install-ChocoPackage `
+                                        k-litecodecpackmega `
+                                        vlc `
+                                        ;
+
+                                    Remove-DesktopIcon "VLC*";
+                                    Install-ChocoPackage jellyfin-media-player -ArgumentList "--install-args","/norestart";
+                                    Remove-DesktopIcon "Jellyfin Media Player*";
+                                    Install-WingetPackage Ytmdesktop.Ytmdesktop;
+                                    Remove-DesktopIcon "Youtube Music*";
+                                }
+                            }
+
+                            if (Test-Collection "coding") {
+                                if ($install) {
+                                    Install-ChocoPackage `
+                                        gh `
+                                        github-desktop `
+                                        ida-free `
+                                        HxD `
+                                        docker-desktop `
+                                        imhex `
+                                        dotpeek `
+                                        ;
+
+                                    Remove-DesktopIcon "IDA *";
+                                    Remove-DesktopIcon "GitHub*";
+                                    Remove-DesktopIcon "Docker*";
+                                }
+
+                                & "$softwarePath/vscode/Main.ps1" @arguments;
+                                & "$softwarePath/VisualStudio/Manage.ps1" @arguments;
+
+                                # Node.js
+                                & "$softwarePath/NVS/Manage.ps1" @arguments;
+                            }
+
+                            if (Test-Collection "gaming") {
+                                # Gaming
+                                if ($install) {
+                                    Install-ChocoPackage `
+                                        goggalaxy `
+                                        epicgameslauncher `
+                                        rayman-controlpanel `
+                                        ppsspp `
+                                        ;
+
+                                    Remove-DesktopIcon "*Epic Games*";
+                                    Remove-DesktopIcon "*PPSSPP *-Bit*";
+
+                                    Install-ChocoPackage `
+                                        steam `
+                                        ubisoft-connect `
+                                        -ArgumentList "--ignore-checksums" `
+                                        ;
+
+                                    Remove-DesktopIcon "*Steam*";
+                                    Remove-DesktopIcon "*Ubisoft Connect*";
+
+                                    Install-WingetPackage ElectronicArts.EADesktop;
+                                    Remove-DesktopIcon "EA.*";
+                                }
+
+                                & "$softwarePath/TrackMania Nations Forever/Manage.ps1" @arguments;
+                                & "$softwarePath/TrackMania United Forever/Manage.ps1" @arguments;
+                                & "$softwarePath/ManiaPlanet/Manage.ps1" @arguments;
+                                & "$softwarePath/osu!/Manage.ps1" @arguments;
+                                & "$softwarePath/osu!lazer/Manage.ps1" @arguments;
+                                & "$softwarePath/RetroArch/Manage.ps1" @arguments;
+                                & "$softwarePath/reWASD/Manage.ps1" @arguments;
+                            }
+                        };
                     }
 
                     switch ($_) {
-                        ([SetupStage]::OneShot) {
-                            Write-Host "Running OneShot task ``$(Get-OneShotTask)``";
-
-                            Start-OneShot {
-                                switch (Get-OneShotTask) {
-                                    ([OneShotTask]::InitializeMSAccount) {
-                                        Initialize-UserCreation;
-                                    }
-                                    ([OneShotTask]::DisableUAC) {
-                                        Disable-UAC;
-                                        Register-Setup;
-                                    }
+                        ([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";
                                 }
-                            };
 
-                            break;
+                                # 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-Stage ([SetupStage]::Install);
                         }
-                        default {
-                            if (Test-Admin) {
-                                $null = Import-Module PSWindowsUpdate;
+                        ([SetupStage]::Install) {
+                            Write-Host "Entering install phase";
+                            Deploy-SoftwareAction;
+                            Set-Stage ([SetupStage]::CreateUser);
+                        }
+                        ([SetupStage]::CreateUser) {
+                            $users = @(Get-Users);
+                            $i = Get-CurrentUser;
 
-                                Invoke-Hook "Invoke-WindowsUpdate" -Fallback {
-                                    Update-WindowsInstallation;
-                                };
+                            for (; $i -lt $users.Count; $i++) {
+                                $name = $users[$i];
+                                $msAccount = Get-UserConfig -UserName $name "microsoftAccount";
+                                Set-CurrentUser $i;
 
-                                if ((Get-WURebootStatus -Silent)) {
-                                    Restart-Intermediate;
-                                    return;
-                                }
-                            }
-
-                            <#
-                                .SYNOPSIS
-                                Deploys an action for each software.
-
-                                .PARAMETER Action
-                                The action to execute by default.
-                            #>
-                            function Deploy-SoftwareAction {
-                                param(
-                                    [Nullable[InstallerAction]] $Action = $null
-                                )
-
-                                [bool] $install = $false;
-                                $arguments = [hashtable]@{ };
-
-                                if ($null -ne $Action) {
-                                    $install = ($Action -eq ([InstallerAction]::Install));
-                                    $null = $arguments.Add("action", $Action);
-                                } else {
-                                    $install = $true;
+                                if (Test-Admin) {
+                                    Disable-BootMessage;
                                 }
 
-                                # Drivers
-                                & {
-                                    $driverPath = "$PSScriptRoot/../Drivers";
-                                    $mbPath = "$driverPath/ROG Zenith Extreme Alpha";
-
-                                    if ($install) {
-                                        if (Get-Config "valhalla.hardware.elgatoWave") {
-                                            if (-not (Test-ChocoPackage wavelink)) {
-                                                Install-ChocoPackage wavelink -ArgumentList '--install-arguments="/norestart"';
-                                                Remove-DesktopIcon "*Wave Link*";
-                                                Restart-Intermediate;
-                                                exit;
-                                            }
+                                while ((Get-UserStage) -ne ([UserStage]::Completed)) {
+                                    switch (Get-UserStage) {
+                                        ($null) {
+                                            Set-UserStage ([UserStage]::Create);
+                                            continue;
                                         }
-                                    }
+                                        ([UserStage]::Create) {
+                                            if ($env:UserName -ne $name) {
+                                                New-ValhallaUser $name;
 
-                                    foreach ($component in (Get-Config "valhalla.hardware.components")) {
-                                        switch ($component) {
-                                            ("ROG Zenith Extreme Alpha") {
-                                                & "$mbPath/MarvellEthernet/Manage.ps1" @arguments;
-                                                & "$mbPath/IntelWiFi/Manage.ps1" @arguments;
-                                                & "$mbPath/IntelBluetooth/Manage.ps1" @arguments;
-                                                & "$mbPath/AMDChipsetX399/Manage.ps1" @arguments;
-                                                & "$driverPath/AMDChipsetX399/Manage.ps1" @arguments;
-                                            }
-                                            ("Predator Z301C") {
-                                                & "$driverPath/Predator Z301C/Manage.ps1" @arguments;
-                                            }
-                                        }
-                                    }
-
-                                    if ($install) {
-                                        if (Get-Config "valhalla.hardware.amdCPU") {
-                                            Install-ChocoPackage amd-ryzen-master;
-                                            # ToDo: backup Ryzen energy saving plan
-                                        }
-
-                                        if (Get-Config "valhalla.hardware.nvidiaGPU") {
-                                            Install-ChocoPackage geforce-game-ready-driver;
-                                            Remove-DesktopIcon "*Geforce*";
-                                        }
-
-                                        if (Get-Config "valhalla.hardware.corsairDevice") {
-                                            Install-ChocoPackage icue;
-                                        }
-                                    }
-
-                                    if (Get-Config "valhalla.hardware.eyeX") {
-                                        & "$driverPath/Tobii EyeX/Manage.ps1" @arguments;
-                                    }
-                                };
-
-                                & {
-                                    # Windows Config
-                                    $softwarePath = "$PSScriptRoot/../Software";
-                                    $commonSoftware = "$PSScriptRoot/../../Common/Software";
-                                    & "$softwarePath/Windows/Manage.ps1" @arguments;
-
-                                    if (Get-Config "valhalla.hardware.logitechG") {
-                                        & "$softwarePath/LGHub/Manage.ps1" @arguments;
-                                    }
-
-                                    if (Test-Collection "essential") {
-                                        # Essentials
-                                        & "$softwarePath/aliae/Main.ps1" @arguments;
-                                        & "$softwarePath/git/Manage.ps1" @arguments;
-                                        & "$softwarePath/OpenSSH/Manage.ps1" @arguments;
-                                        & "$softwarePath/PowerShell/Manage.ps1" @arguments;
-                                        & "$softwarePath/chocolatey/Manage.ps1" @arguments;
-                                        & "$softwarePath/zoxide/Manage.ps1" @arguments;
-                                        & "$commonSoftware/posh-git/Manage.ps1" @arguments;
-                                        & "$commonSoftware/Terminal-Icons/Manage.ps1" @arguments;
-                                        & "$softwarePath/Oh My Posh/Manage.ps1" @arguments;
-
-                                        if (Get-Config "valhalla.windows.dualboot") {
-                                            & "$softwarePath/Ext4Fsd/Main.ps1" @arguments;
-                                        }
-
-                                        if ($install) {
-                                            Install-ChocoPackage `
-                                                procexp `
-                                                procmon `
-                                                ;
-
-                                            Install-WingetPackage `
-                                                KDE.KDEConnect `
-                                                ;
-                                        }
-                                    }
-
-                                    if (Test-Collection "common") {
-                                        # Common Software
-                                        & "$softwarePath/WinSCP/Manage.ps1" @arguments;
-                                        & "$softwarePath/Thunderbird/Manage.ps1" @arguments;
-                                        & "$softwarePath/PuTTY/Manage.ps1" @arguments;
-
-                                        if ($install) {
-                                            Install-ChocoPackage `
-                                                7zip `
-                                                chocolateygui `
-                                                DefaultProgramsEditor `
-                                                bitwarden `
-                                                keepass `
-                                                ;
-
-                                            Install-WingetPackage `
-                                                SomePythonThings.WingetUIStore `
-                                                ;
-
-                                            Remove-DesktopIcon "UniGetUI*";
-                                        }
-                                    }
-
-                                    if (Test-Collection "desktopExperience") {
-                                        if ($install) {
-                                            # Fonts
-                                            Install-ChocoPackage nerd-fonts-CascadiaCode;
-
-                                            # Internet Access
-                                            Install-WingetPackage Brave.Brave kamranahmedse.pennywise;
-                                            Remove-DesktopIcon "*Brave*";
-                                            Remove-TaskbarItem "*Brave*";
-                                            Remove-DesktopIcon "Pennywise*";
-
-                                            # Tools
-                                            Install-SetupPackage -Source "https://github.com/mRemoteNG/mRemoteNG/releases/download/2023.03.03-v1.77.3-nb/mRemoteNG-Installer-1.77.3.nb-1784.msi" -ArgumentList "/Quiet";
-                                            Remove-DesktopIcon "mRemoteNG*";
-
-                                            Install-ChocoPackage `
-                                                gimp `
-                                                gpu-z `
-                                                windirstat `
-                                                winmerge `
-                                                handbrake `
-                                                hwmonitor `
-                                                qbittorrent `
-                                                imgburn `
-                                                inkscape `
-                                                krita `
-                                                MetaX `
-                                                obs-studio `
-                                                ;
-
-                                            Remove-DesktopIcon "GIMP*";
-                                            Remove-DesktopIcon "GPU-Z*";
-                                            Remove-DesktopIcon "WinDirStat*";
-                                            Remove-DesktopIcon "*HWMonitor*";
-                                            Remove-DesktopIcon "ImgBurn*";
-                                            Remove-DesktopIcon "InkScape*";
-                                            Remove-DesktopIcon "Krita*";
-                                            Remove-DesktopIcon "MetaX*";
-                                            Remove-DesktopIcon "OBS Studio*";
-
-                                            Install-WingetPackage `
-                                                AntSoftware.AntRenamer `
-                                                AppWork.JDownloader;
-
-                                            Remove-DesktopIcon "JDownloader*";
-                                        }
-
-                                        # ToDo: Consider hiding behind own config?
-                                        & "$softwarePath/Ubiquiti UniFi Controller/Manage.ps1" @arguments;
-
-                                        # Internet Access
-                                        & "$softwarePath/Firefox/Manage.ps1" @arguments;
-                                        & "$softwarePath/MSEdgeRedirect/Manage.ps1" @arguments;
-
-                                        if (Test-Collection "fileSync") {
-                                            & "$softwarePath/Nextcloud/Main.ps1" @arguments;
-                                        }
-                                    }
-
-                                    if (Test-Collection "socialMedia") {
-                                        if ($install) {
-                                            Install-ChocoPackage `
-                                                signal `
-                                                threema-desktop `
-                                                element-desktop `
-                                                teamspeak `
-                                                ;
-
-                                            Remove-DesktopIcon "*Element*";
-                                            Remove-DesktopIcon "*TeamSpeak*";
-
-                                            Install-WingetPackage Discord.Discord;
-                                            Remove-DesktopIcon "*Discord*";
-                                        }
-                                    }
-
-                                    if (Test-Collection "media") {
-                                        if ($install) {
-                                            Install-ChocoPackage `
-                                                k-litecodecpackmega `
-                                                vlc `
-                                                ;
-
-                                            Remove-DesktopIcon "VLC*";
-                                            Install-ChocoPackage jellyfin-media-player -ArgumentList "--install-args","/norestart";
-                                            Remove-DesktopIcon "Jellyfin Media Player*";
-                                            Install-WingetPackage Ytmdesktop.Ytmdesktop;
-                                            Remove-DesktopIcon "Youtube Music*";
-                                        }
-                                    }
-
-                                    if (Test-Collection "coding") {
-                                        if ($install) {
-                                            Install-ChocoPackage `
-                                                gh `
-                                                github-desktop `
-                                                ida-free `
-                                                HxD `
-                                                docker-desktop `
-                                                imhex `
-                                                dotpeek `
-                                                ;
-
-                                            Remove-DesktopIcon "IDA *";
-                                            Remove-DesktopIcon "GitHub*";
-                                            Remove-DesktopIcon "Docker*";
-                                        }
-
-                                        & "$softwarePath/vscode/Main.ps1" @arguments;
-                                        & "$softwarePath/VisualStudio/Manage.ps1" @arguments;
-
-                                        # Node.js
-                                        & "$softwarePath/NVS/Manage.ps1" @arguments;
-                                    }
-
-                                    if (Test-Collection "gaming") {
-                                        # Gaming
-                                        if ($install) {
-                                            Install-ChocoPackage `
-                                                goggalaxy `
-                                                epicgameslauncher `
-                                                rayman-controlpanel `
-                                                ppsspp `
-                                                ;
-
-                                            Remove-DesktopIcon "*Epic Games*";
-                                            Remove-DesktopIcon "*PPSSPP *-Bit*";
-
-                                            Install-ChocoPackage `
-                                                steam `
-                                                ubisoft-connect `
-                                                -ArgumentList "--ignore-checksums" `
-                                                ;
-
-                                            Remove-DesktopIcon "*Steam*";
-                                            Remove-DesktopIcon "*Ubisoft Connect*";
-
-                                            Install-WingetPackage ElectronicArts.EADesktop;
-                                            Remove-DesktopIcon "EA.*";
-                                        }
-
-                                        & "$softwarePath/TrackMania Nations Forever/Manage.ps1" @arguments;
-                                        & "$softwarePath/TrackMania United Forever/Manage.ps1" @arguments;
-                                        & "$softwarePath/ManiaPlanet/Manage.ps1" @arguments;
-                                        & "$softwarePath/osu!/Manage.ps1" @arguments;
-                                        & "$softwarePath/osu!lazer/Manage.ps1" @arguments;
-                                        & "$softwarePath/RetroArch/Manage.ps1" @arguments;
-                                        & "$softwarePath/reWASD/Manage.ps1" @arguments;
-                                    }
-                                };
-                            }
-
-                            switch ($_) {
-                                ([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-Stage ([SetupStage]::Install);
-                                }
-                                ([SetupStage]::Install) {
-                                    Write-Host "Entering install phase";
-                                    Deploy-SoftwareAction;
-                                    Set-Stage ([SetupStage]::CreateUser);
-                                }
-                                ([SetupStage]::CreateUser) {
-                                    $users = @(Get-Users);
-                                    $i = Get-CurrentUser;
-
-                                    for (; $i -lt $users.Count; $i++) {
-                                        $name = $users[$i];
-                                        $msAccount = Get-UserConfig -UserName $name "microsoftAccount";
-                                        Set-CurrentUser $i;
-
-                                        if (Test-Admin) {
-                                            Disable-BootMessage;
-                                        }
-
-                                        while ((Get-UserStage) -ne ([UserStage]::Completed)) {
-                                            switch (Get-UserStage) {
-                                                ($null) {
-                                                    Set-UserStage ([UserStage]::Create);
-                                                    continue;
-                                                }
-                                                ([UserStage]::Create) {
-
-                                                    if ($env:UserName -ne $name) {
-                                                        New-ValhallaUser $name;
-
-                                                        if ($msAccount) {
-                                                            logoff;
-                                                        } else {
-                                                            Restart-Intermediate;
-                                                        }
-
-                                                        exit;
-                                                    } else {
-                                                        if ($msAccount) {
-                                                            if (-not (Test-Admin)) {
-                                                                Invoke-OneShot DisableUAC;
-                                                                Restart-Intermediate -NoRegister;
-                                                                return;
-                                                            }
-
-                                                            Clear-SetupRegistration;
-                                                            Disable-OneShotListener;
-                                                        }
-
-                                                        Set-UserStage ([UserStage]::Configure);
-                                                    }
-                                                }
-                                                (([UserStage]::Configure)) {
-                                                    $displayName = Get-UserConfig -UserName $name "displayName";
-
-                                                    $userArguments = @{
-                                                        name = $name;
-                                                    };
-
-                                                    if ($displayName) {
-                                                        $userArguments.fullName = $displayName;
-                                                    }
-
-                                                    $adminGroup = @{
-                                                        SID = [SecurityIdentifier]::new([WellKnownSidType]::BuiltinAdministratorsSid, $null);
-                                                    };
-
-                                                    Set-LocalUser @userArguments;
-                                                    Deploy-SoftwareAction -Action ([InstallerAction]::ConfigureUser);
-                                                    Remove-LocalGroupMember -Member $name @adminGroup -ErrorAction SilentlyContinue;
-
-                                                    foreach ($group in Get-UserConfig -UserName $name "groups") {
-                                                        Add-LocalGroupMember -Member $name -Name "$group";
-                                                    }
-
-                                                    if (-not $msAccount) {
-                                                        net user $name /logonpasswordchg:yes;
-                                                    }
-
-                                                    Set-UserStage ([UserStage]::Cleanup);
-                                                }
-                                                ([UserStage]::Cleanup) {
-                                                    $user = Get-SetupUser;
-                                                    Enable-LocalUser $user;
-                                                    Set-AutologinUser $user;
-                                                    Unregister-WslDistribution;
-                                                    Set-UserStage ([UserStage]::Completed);
+                                                if ($msAccount) {
+                                                    logoff;
+                                                } else {
                                                     Restart-Intermediate;
                                                     exit;
                                                 }
+
+                                                exit;
+                                            } else {
+                                                if ($msAccount) {
+                                                    if (-not (Test-Admin)) {
+                                                        Invoke-OneShot DisableUAC;
+                                                        Restart-Intermediate -NoRegister;
+                                                        return;
+                                                    }
+
+                                                    Clear-SetupRegistration;
+                                                    Disable-OneShotListener;
+                                                }
+
+                                                Set-UserStage ([UserStage]::Configure);
                                             }
                                         }
-                                    }
+                                        (([UserStage]::Configure)) {
+                                            $displayName = Get-UserConfig -UserName $name "displayName";
 
-                                    Set-IsFinished $true;
+                                            $userArguments = @{
+                                                name = $name;
+                                            };
+
+                                            if ($displayName) {
+                                                $userArguments.fullName = $displayName;
+                                            }
+
+                                            $adminGroup = @{
+                                                SID = [SecurityIdentifier]::new([WellKnownSidType]::BuiltinAdministratorsSid, $null);
+                                            };
+
+                                            Set-LocalUser @userArguments;
+                                            Deploy-SoftwareAction -Action ([InstallerAction]::ConfigureUser);
+                                            Remove-LocalGroupMember -Member $name @adminGroup -ErrorAction SilentlyContinue;
+
+                                            foreach ($group in Get-UserConfig -UserName $name "groups") {
+                                                Add-LocalGroupMember -Member $name -Name "$group";
+                                            }
+
+                                            if (-not $msAccount) {
+                                                net user $name /logonpasswordchg:yes;
+                                            }
+
+                                            Set-UserStage ([UserStage]::Cleanup);
+                                        }
+                                        ([UserStage]::Cleanup) {
+                                            $user = Get-SetupUser;
+                                            Enable-LocalUser $user;
+                                            Set-AutologinUser $user;
+                                            Unregister-WslDistribution;
+                                            Set-UserStage ([UserStage]::Completed);
+                                            Restart-Intermediate;
+                                        }
+                                    }
                                 }
                             }
+
+                            Set-IsFinished $true;
                         }
                     }
                 }