#!/bin/pwsh using namespace System.Management.Automation.Host; using namespace System.Security.Principal; . "$PSScriptRoot/../../../scripts/Windows/Scripts/Prerequisites.ps1"; . "$PSScriptRoot/../../../scripts/Windows/Scripts/WSL.ps1"; . "$PSScriptRoot/../../Common/Scripts/Context.ps1"; . "$PSScriptRoot/../Scripts/Security.ps1"; . "$PSScriptRoot/../Software/Firefox/Install.ps1"; . "$PSScriptRoot/Manage.ps1"; . "$PSScriptRoot/User/Install.ps1"; $null = New-Module { . "$PSScriptRoot/../Scripts/Hooks.ps1"; . "$PSScriptRoot/../Scripts/PowerManagement.ps1"; . "$PSScriptRoot/../Scripts/Registry.ps1"; . "$PSScriptRoot/../Scripts/Security.ps1"; . "$PSScriptRoot/../Scripts/Update.ps1"; . "$PSScriptRoot/../Scripts/Users.ps1"; . "$PSScriptRoot/../../Common/Scripts/Config.ps1"; . "$PSScriptRoot/../../Common/Scripts/Operations.ps1"; . "$PSScriptRoot/../../Common/Scripts/Software.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; }; } <# .SYNOPSIS Starts the installation loop. #> function Start-InstallationLoop { while (-not (Get-IsFinished)) { 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; }; 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/../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/../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; } 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; } } }; break; } default { 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/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) { & "$softwarePath/vscode/Main.ps1" @arguments; Install-ChocoPackage ` gh ` github-desktop ` ida-free ` HxD ` docker-desktop ` imhex ` dotpeek ` ; Remove-DesktopIcon "IDA *"; Remove-DesktopIcon "GitHub*"; Remove-DesktopIcon "Docker*"; } & "$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); Restart-Intermediate; exit; } } } } Set-IsFinished $true; } } } } } } } } function Invoke-WindowsInstallation([Context] $context) { $Global:InformationPreference = "Continue"; $Global:ErrorActionPreference = "Inquire"; $context.UserNames ??= @("Manuel"); Start-OldWindowsInstallationScript $context; } function Start-OldWindowsInstallationScript([Context] $context) { . "$PSScriptRoot/Upgrade.ps1"; $finished = $false; Remove-Item Env:\POSH_THEME -ErrorAction SilentlyContinue; $configPath = "$PSScriptRoot/../Config"; $softwarePath = "$PSScriptRoot/../Software"; $initialConfigStage = "InitialConfiguration"; $prerequisitesStage = "InstallationPrerequisites"; $driverStage = "DriverInstallation"; $softwareStage = "MachineWideSoftwareInstallation"; $userStage = "CreatingUser"; $restorationStage = "Restoring"; while (-not $finished) { switch ($context.GetStage()) { { (-not $_) -or ($_ -eq $initialConfigStage) } { $context.SetStage($initialConfigStage); if ((Get-Command Initialize-Configuration -ErrorAction SilentlyContinue)) { Write-Information "Configuration initialization function was found. Running..."; Initialize-Configuration $context; } $null = Enable-WindowsOptionalFeature -Online -All -FeatureName "NetFx3"; . "$configPath/Windows/Install.ps1" $context; . "$configPath/Explorer/Install.ps1" $context; . "$configPath/OpenSSH/Install.ps1" $context; . "$configPath/chocolatey/Install.ps1"; $context.RemoveDesktopIcon("*Microsoft Edge*"); $context.SetStage($prerequisitesStage); break; } # Always install updates default { Write-Host "Starting Installation and Restoration of Windows"; Update-WindowsInstallation $context; } $prerequisitesStage { Write-Host "Installing prerequisites for installing software"; if (-not $(Get-Command winget)) { choco install -y winget; } Install-Module -AcceptLicense -Force "NuGet"; Import-Module NuGet; Install-Firefox $context; choco install -y selenium-gecko-driver; $null = Install-Package -Force Selenium.WebDriver -RequiredVersion 4.10.0 -SkipDependencies; winget install --accept-source-agreements --accept-package-agreements -e --id AutoHotkey.AutoHotkey; $context.SetStage($driverStage); break; } $driverStage { Write-Host "Installing drivers"; if ((Get-Command Install-PortValhallaDrivers -ErrorAction SilentlyContinue)) { Write-Information "Driver installation function was found. Starting installation"; Install-PortValhallaDrivers $context; } Write-Information "Finished installing drivers"; $context.SetStage($softwareStage); $context.Reboot(); exit; } $softwareStage { Write-Host "Setting up software with default app associations"; . "$softwarePath/WinSCP/Install.ps1" $context; . "$softwarePath/Thunderbird/Install.ps1" $context; Write-Host "Installing default settings for new users"; . "$softwarePath/aliae/Install.ps1" $context; . "$softwarePath/posh-git/Install.ps1"; . "$softwarePath/Terminal-Icons/Install.ps1"; . "$softwarePath/Oh My Posh/Install.ps1" $context; $context.SetStage($userStage); break; } $userStage { Install-PersonalUsers $context; $context.SetStage($restorationStage); break; } $restorationStage { Restore-WindowsInstallation $context; $finished = $true; break; } } } } };