Compare commits

...

40 commits

Author SHA1 Message Date
Manuel Thalmann 0f71cb181e Add scripts for backing up and restoring LGHub 2024-08-28 05:05:55 +02:00
Manuel Thalmann 9eb81821b4 Allow users to restore a backup 2024-08-28 04:40:32 +02:00
Manuel Thalmann d2fdc0a427 Add scripts for backing up and restoring personal files 2024-08-28 04:40:00 +02:00
Manuel Thalmann fe76915df5 Fix non-functioning profile script 2024-08-28 04:39:15 +02:00
Manuel Thalmann 7708521a6e Ensure 7z is installed for backups 2024-08-28 04:38:56 +02:00
Manuel Thalmann c31e21b215 Streamline restoration of directories 2024-08-28 04:38:30 +02:00
Manuel Thalmann 9c32c634e7 Set a default path for backup artifacts 2024-08-28 00:38:20 +02:00
Manuel Thalmann 00d215e6fe Add capabilities to back up apps 2024-08-28 00:37:04 +02:00
Manuel Thalmann 75b208a7ac Allow specifying a backup action 2024-08-28 00:29:33 +02:00
Manuel Thalmann 3ea29e5014 Ignore unspecified backup archives 2024-08-28 00:22:38 +02:00
Manuel Thalmann 2b8d183f10 Ignore inexistent backup artifacts 2024-08-28 00:21:06 +02:00
Manuel Thalmann 74832e0e25 Make the install script action agnostic 2024-08-28 00:03:28 +02:00
Manuel Thalmann fa9b4c22b5 Rename the Windows installer script 2024-08-27 23:35:56 +02:00
Manuel Thalmann e1356440f2 Rename outdated script 2024-08-27 23:08:41 +02:00
Manuel Thalmann c645cfbad2 Silence errors concerning empty aliae configurations 2024-08-27 22:35:31 +02:00
Manuel Thalmann 5347dabd05 Make Operations script cross platform 2024-08-27 22:27:44 +02:00
Manuel Thalmann d9d07442c4 Handle OneShot tasks only on Windows 2024-08-27 21:32:49 +02:00
Manuel Thalmann 0653073e0c Add a script for managing backups 2024-08-27 21:05:51 +02:00
Manuel Thalmann fd7574406b Add tools for managing aliae 2024-08-27 18:58:33 +02:00
Manuel Thalmann 003fff6aaa Fix non-functioning aliae installation 2024-08-27 18:55:12 +02:00
Manuel Thalmann 320598c07a Create dedicated script for creating users 2024-08-27 17:04:17 +02:00
Manuel Thalmann bea63c6271 Create dedicated script for installing software 2024-08-27 16:41:08 +02:00
Manuel Thalmann a3262451f5 Prevent reading nix config multiple times 2024-08-27 14:35:04 +02:00
Manuel Thalmann cb7791e8ca Ensure only one user is enabled at once 2024-08-27 14:11:31 +02:00
Manuel Thalmann 4ff3e50fa5 Prevent unnecessary file creation 2024-08-27 14:06:56 +02:00
Manuel Thalmann 3e7cdff35e Execute OneShot tasks in any operation 2024-08-27 14:05:16 +02:00
Manuel Thalmann 1842caefb7 Use /mnt as mount directory 2024-08-27 04:30:12 +02:00
Manuel Thalmann 102ecaafb6 Force the use of the managed distribution 2024-08-27 04:26:25 +02:00
Manuel Thalmann 7bf86fb964 Initialize operation for all users 2024-08-27 04:24:29 +02:00
Manuel Thalmann c683ef9305 Handle initialization in operation code 2024-08-27 04:15:37 +02:00
Manuel Thalmann de6f77dd50 Execute script non-interactive during OneShot tasks 2024-08-27 03:50:08 +02:00
Manuel Thalmann 0d695bda04 Exit script after running OneShot task 2024-08-27 03:45:44 +02:00
Manuel Thalmann 8ec7f512a0 Modify user after first login 2024-08-27 03:27:54 +02:00
Manuel Thalmann 2a6fa9b406 Rearm Windows Activation before creating MSAcc 2024-08-27 03:25:19 +02:00
Manuel Thalmann a37b3a78be Register MSAcc logon script early 2024-08-27 03:24:37 +02:00
Manuel Thalmann 5348e66603 Allow rebooting without registering setup 2024-08-27 03:11:35 +02:00
Manuel Thalmann 993e4f1fb9 Prevent reboots during installation 2024-08-27 02:18:01 +02:00
Manuel Thalmann 744b115005 Fix non-functioning NoProfile argument 2024-08-27 02:09:04 +02:00
Manuel Thalmann 1e366410e3 Prevent unnecessary installation actions 2024-08-27 01:57:46 +02:00
Manuel Thalmann 7b18eeb25d Only install PowerShell module if necessary 2024-08-27 01:25:32 +02:00
25 changed files with 1441 additions and 903 deletions

View file

@ -1,7 +1,7 @@
#!/bin/pwsh
$null = New-Module {
. "$PSScriptRoot/../../../scripts/Common/Scripts/Context.ps1";
. "$PSScriptRoot/../../../scripts/Windows/OS/Manage.ps1";
. "$PSScriptRoot/../../../scripts/Windows/OS/Legacy.ps1";
Write-Host "Starting Backup of Windows";
$context = [Context]::new();

View file

@ -2,7 +2,7 @@
. "$PSScriptRoot/Drivers.ps1";
. "$PSScriptRoot/../../../scripts/Common/Scripts/Context.ps1";
. "$PSScriptRoot/../../../scripts/Windows/Collections/Personal.ps1"
. "$PSScriptRoot/../../../scripts/Windows/OS/Install.ps1";
. "$PSScriptRoot/../../../scripts/Windows/OS/Manage.ps1";
function Initialize-Configuration {
# Fix synchronization between Linux and Windows clock

View file

@ -1,6 +1,6 @@
#!/bin/pwsh
. "$PSScriptRoot/../../../scripts/Common/Scripts/Context.ps1";
. "$PSScriptRoot/../../../scripts/Windows/OS/Install.ps1";
. "$PSScriptRoot/../../../scripts/Windows/OS/Manage.ps1";
. "$PSScriptRoot/../../../scripts/Windows/Collections/Generic.ps1"
function Restore-Apps {

View file

@ -2,10 +2,13 @@ using namespace Microsoft.Win32;
using namespace System.Security.AccessControl;
using namespace System.Security.Principal;
enum SetupStage {
Idle
enum WindowsInstallerStage {
Initialize
OneShot
Run
Completed
}
enum SetupStage {
Configure
Install
CreateUser
@ -21,6 +24,7 @@ enum UserStage {
$null = New-Module {
[string] $configRoot = "HKLM:\Software\PortValhalla";
[string] $stageOption = "Stage";
[string] $setupStageOption = "SetupStage";
[string] $userOption = "SetupUser";
[string] $userStageOption = "UserStage";
[string] $accountOption = "MSAccount";
@ -275,11 +279,44 @@ $null = New-Module {
<#
.SYNOPSIS
Gets the name of the current setup stage.
Gets the name of the current stage of the Windows install script action.
#>
function Get-Stage {
$stage = Get-SetupOption $stageOption;
if ($null -ne $stage) {
$stage = [WindowsInstallerStage]$stage;
}
return $stage;
}
<#
.SYNOPSIS
Sets the name of the current stage of the Windows install script action.
.PARAMETER Name
The name of the stage to set.
#>
function Set-Stage {
param(
$Name
)
if (-not (($null -eq $Name) -or ($Name -is [string]))) {
$Name = ([WindowsInstallerStage]$Name).ToString();
}
$null = Set-SetupOption $stageOption $Name;
}
<#
.SYNOPSIS
Gets the name of the current setup stage.
#>
function Get-SetupStage {
$stage = Get-SetupOption $setupStageOption;
if ($null -ne $stage) {
$stage = [SetupStage]$stage;
}
@ -294,7 +331,7 @@ $null = New-Module {
.PARAMETER Name
The name to set the current stage to.
#>
function Set-Stage {
function Set-SetupStage {
param(
$Name
)
@ -303,7 +340,7 @@ $null = New-Module {
$Name = ([SetupStage]$Name).ToString();
}
$null = Set-SetupOption $stageOption $Name;
$null = Set-SetupOption $setupStageOption $Name;
}
<#
@ -390,7 +427,7 @@ $null = New-Module {
Gets a value indicating whether the setup has finished.
#>
function Get-IsFinished {
return [bool] (((Get-Stage) -eq ([SetupStage]::Idle)) -or (Get-SetupOption $finishedOption));
return [bool](Get-SetupOption $finishedOption);
}
<#

View file

@ -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;
@ -32,6 +36,11 @@ $null = New-Module {
$cleanup = { };
if ($IsWindows -and ($null -ne (Get-OneShotTask))) {
$taskPending = $true;
[switch] $NonInteractive = $true;
}
if (-not $Global:InOperation) {
if ($env:DEBUG) {
Set-PSDebug -Trace 1;
@ -59,9 +68,197 @@ $null = New-Module {
Clear-OperationResources;
};
}
& {
$initialized = $false;
while (-not $initialized) {
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;
if ((Get-FileHash $osk).Hash -ne (Get-FileHash $cmd).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-Command "7z")) {
Install-ChocoPackage 7zip.portable;
refreshenv;
continue;
}
if (-not (Test-Command "yq")) {
Install-ChocoPackage "yq";
refreshenv;
continue;
}
if (-not (Test-Wsl)) {
Install-Wsl;
Restart-Intermediate;
return;
}
if (-not (Test-WslDistribution)) {
if (-not (Test-Path (Get-WslDistributionDisk))) {
Install-WslDistribution;
}
Register-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;
}
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;
. "$PSScriptRoot/../../Windows/Software/PinnedItem/Manage.ps1";
}
Invoke-Hook "Install-PSModules" -Fallback {
$modules = @(
@("PSScriptAnalyzer")
) + (& {
if (-not $IsWindows) {
@()
} else {
@(
@("KnownFolders"),
@("PSWindowsUpdate"),
@("LocalAccounts", $true),
@("NuGet")
)
}
});
foreach ($module in $modules) {
$parameters = @{ };
if ($module -is [string]) {
$module = @($module);
}
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];
}
}
};
$initialized = $true;
}
}
}
if ($taskPending) {
Start-OneShot;
} else {
& $Action;
}
& $Action;
& $cleanup;
}
@ -70,7 +267,13 @@ $null = New-Module {
Gets the current OneShot task.
#>
function Get-OneShotTask {
[OneShotTask](Get-SetupOption $taskOption);
$task = Get-SetupOption $taskOption;
if ($task) {
return [OneShotTask]$task;
} else {
return $null;
}
}
<#
@ -123,8 +326,6 @@ $null = New-Module {
[OneShotTask] $Task
)
$currentStage = Get-Stage;
Set-Stage ([SetupStage]::OneShot);
& $taskSetter $Task;
& {
@ -153,8 +354,6 @@ $null = New-Module {
}
};
Set-Stage $currentStage;
if (Test-Path $errorPath) {
$errorMessage = Get-Content $errorPath;
Remove-Item $errorPath;
@ -172,19 +371,27 @@ $null = New-Module {
Executes the specified action and notifies the OneShot task executor.
#>
function Start-OneShot {
param(
[scriptblock] $Action
)
try {
Start-Operation -NonInteractive @PSBoundParameters;
Write-Host "Running OneShot task ``$(Get-OneShotTask)``";
Start-Operation {
switch (Get-OneShotTask) {
([OneShotTask]::InitializeMSAccount) {
Initialize-UserCreation;
}
([OneShotTask]::DisableUAC) {
Disable-UAC;
Register-Setup;
}
}
};
}
catch {
Set-Content -Path $errorPath -Value $Error;
Set-UserPermissions $errorPath;
}
finally {
Set-Stage ([SetupStage]::Idle);
& $taskSetter $null;
Write-EventLog -LogName $logName -Source $logName -EventId $oneShotTrigger -Message "The OneShot task ``$(Get-OneShotTask)`` finished.";
}
}
@ -194,6 +401,8 @@ $null = New-Module {
Clears resources allocated during the operation.
#>
function Clear-OperationResources {
Uninstall-WslDistribution;
if ($IsWindows) {
Uninstall-WslDistribution;
}
}
};

View file

@ -197,8 +197,10 @@ $null = New-Module {
function Start-SoftwareInstaller {
param(
[string] $Name,
[scriptblock] $Backup = $null,
[scriptblock] $Installer = $null,
[scriptblock] $Configurator = $null,
[scriptblock] $UserBackup = $null,
[scriptblock] $UserConfigurator = $null,
[Nullable[InstallerAction]] $Action,
[hashtable] $Arguments
@ -235,32 +237,53 @@ $null = New-Module {
installer = $installHandler;
arguments = $Arguments;
};
if ($action -eq ([InstallerAction]::Install)) {
if ($Installer) {
Write-Host "Installing $Name";
& $Installer @argumentList;
}
& $installHandler @argumentList -Action ([InstallerAction]::Configure);
switch ($Action) {
([InstallerAction]::Backup) {
if ($Backup) {
Write-Host "Backing up $Name";
& $Backup @argumentList;
}
}
([InstallerAction]::Install) {
if ($Installer) {
Write-Host "Installing $Name";
& $Installer @argumentList;
}
if ($UserConfigurator -and (-not (Test-SetupUser))) {
& $installHandler @argumentList -Action ([InstallerAction]::ConfigureUser);
& $installHandler @argumentList -Action ([InstallerAction]::Configure);
if ($UserConfigurator -and (-not (Test-SetupUser))) {
& $installHandler @argumentList -Action ([InstallerAction]::ConfigureUser);
}
}
# ToDo: Automatically configure after installation
} elseif ($Action -eq ([InstallerAction]::Configure)) {
if ($Configurator) {
Write-Host "Configuring $Name";
& $Configurator @argumentList;
([InstallerAction]::Configure) {
if ($Configurator) {
Write-Host "Configuring $Name";
& $Configurator @argumentList;
}
}
} elseif ($Action -eq ([InstallerAction]::ConfigureUser)) {
if ((-not $Arguments.ContainsKey($userArgument)) -or (-not $Arguments[$userArgument])) {
$Arguments.Add($userArgument, ($IsWindows ? $env:UserName : $env:USER));
}
if ($UserConfigurator) {
Write-Host "Configuring $Name for user ``$($Arguments[$userArgument])``";
& $UserConfigurator @argumentList;
default {
if ((-not $Arguments.ContainsKey($userArgument)) -or (-not $Arguments[$userArgument])) {
$Arguments.Add($userArgument, ($IsWindows ? $env:UserName : $env:USER));
}
$user = $Arguments[$userArgument];
switch ($_) {
([InstallerAction]::BackupUser) {
if ($UserBackup) {
Write-Host "Backing up ``$Name`` for user ``$user``";
& $UserBackup @argumentList;
}
}
([InstallerAction]::ConfigureUser) {
if ($UserConfigurator) {
Write-Host "Configuring $Name for user ``$user``";
& $UserConfigurator @argumentList;
}
}
}
}
}
};

View file

@ -103,3 +103,18 @@ function Test-PSPackage {
[bool] (Get-Package $Name -ErrorAction SilentlyContinue);
}
<#
.SYNOPSIS
Checks whether a module with the specified name is installed.
.PARAMETER Name
The name of the module to check.
#>
function Test-PSModule {
param(
[string] $Name
)
[bool](Get-Module -ListAvailable $Name -ErrorAction SilentlyContinue);
}

View file

@ -34,7 +34,14 @@ $null = New-Module {
)
$env:PENDING_MODULE_NAME = $Arguments.Name;
$installAction = { Install-Module -Scope AllUsers -Force $env:PENDING_MODULE_NAME @args };
$installAction = {
$module = $env:PENDING_MODULE_NAME;
if (-not (Get-Module -ListAvailable $module -ErrorAction SilentlyContinue)) {
Install-Module -Scope AllUsers -Force $module @args;
}
};
if (-not $Arguments.NativeOnly) {
& $installAction -AcceptLicense;
@ -48,19 +55,17 @@ $null = New-Module {
& $Installer -Action ([InstallerAction]::Configure) @PSBoundParameters;
};
configurator = {
configurator = ($NoProfile.IsPresent) ? { } : {
param(
[hashtable] $Arguments
)
if (-not $NoProfile) {
$name = $Arguments.Name;
$name = $Arguments.Name;
Add-PowerShellProfileStatement `
-DefaultUser `
-Category $name `
-Script "Import-Module `"$name`";";
}
Add-PowerShellProfileStatement `
-DefaultUser `
-Category $name `
-Script "Import-Module `"$name`";";
};
}
}

View file

@ -75,9 +75,11 @@ $null = New-Module {
Push-Location ~;
$profiles = $profiles |
ForEach-Object { [System.IO.Path]::GetRelativePath((Get-Location), $_) } |
ForEach-Object { "$HomeDir/$_" };
$profiles = @(
$profiles |
ForEach-Object { [System.IO.Path]::GetRelativePath((Get-Location), $_) } |
ForEach-Object { "$HomeDir/$_" }
);
Pop-Location;
}

View file

@ -34,14 +34,14 @@ Start-SoftwareInstaller @PSBoundParameters `
};
if (Test-Path $globalPath) {
& ([scriptblock]::Create((aliae init pwsh --config $globalPath)));
$null = & ([scriptblock]::Create((aliae init pwsh --config $globalPath))) *>&1;
}
if (Test-Path $userPath) {
& ([scriptblock]::Create((aliae init pwsh)));
$null = & ([scriptblock]::Create((aliae init pwsh))) *>&1;
}
& ([scriptblock]::Create((aliae completion powershell)));
aliae completion powershell | Out-String | Invoke-Expression;
}
) -join [System.Environment]::NewLine)
} `

View file

@ -1,5 +1,7 @@
enum InstallerAction {
Backup
Install
Configure
BackupUser
ConfigureUser
}

View file

@ -1,746 +0,0 @@
#!/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;
};
}
Install-Module -Scope AllUsers -AcceptLicense -Force $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;
Register-Setup -DefaultUser;
}
([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];
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) {
$msAccount = Get-UserConfig -UserName $name "microsoftAccount";
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-Computer;
return;
}
Clear-SetupRegistration;
Disable-OneShotListener;
}
Set-UserStage ([UserStage]::Configure);
}
}
(([UserStage]::Configure)) {
$adminGroup = @{
SID = [SecurityIdentifier]::new([WellKnownSidType]::BuiltinAdministratorsSid, $null);
};
Deploy-SoftwareAction -Action ([InstallerAction]::ConfigureUser);
Remove-LocalGroupMember -Member "$name" @adminGroup -ErrorAction SilentlyContinue;
foreach ($group in Get-UserConfig "groups") {
Add-LocalGroupMember -Member "$name" -Name "$group";
}
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;
}
}
}
}
}
}
}
}
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;
}
}
}
}
};

View file

@ -0,0 +1,63 @@
#!/bin/pwsh
. "$PSScriptRoot/../Scripts/PersonalFiles.ps1";
. "$PSScriptRoot/../Software/Firefox/Install.ps1";
. "$PSScriptRoot/../Software/Nextcloud/Install.ps1";
. "$PSScriptRoot/../Collections/Personal.ps1";
. "$PSScriptRoot/../../Common/Scripts/Context.ps1";
function Backup-WindowsInstallation([Context] $context) {
Write-Information "Backing up Windows";
$Global:InformationPreference = "Continue";
$Global:ErrorActionPreference = "Inquire";
. "$PSScriptRoot/../../../scripts/Windows/Scripts/Prerequisites.ps1";
$backupRoot = $context.BackupRoot();
Backup-PersonalFiles $context;
Backup-PersonalApps $context;
$context.Backup($backupRoot, "$backupRoot.7z", @("-sdel"), $false);
$context.Cleanup();
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?";
}
function Restore-WindowsInstallation([Context] $context) {
Write-Host "Restoring Windows";
choco feature enable -n useEnhancedExitCodes;
function Read-Path()
{
$backupPath = Read-Host -Prompt "Please enter the path to the archive to load the backup from.";
if ($backupPath -and (-not (Test-Path -PathType Leaf $backupPath)))
{
Write-Host "No file could be found at the specified path.";
return Read-Path;
}
else
{
return $backupPath;
}
}
Install-Firefox $context;
Restore-Nextcloud $context;
Write-Information "Determining Backup Archive Path";
$backupPath = Read-Path;
$context.BackupName ??= "PortValhalla";
$context.RootDir = $context.GetTempDirectory();
if ($backupPath)
{
$context.Restore($backupPath, $context.BackupRoot());
}
Copy-UserInternationalSettingsToSystem -WelcomeScreen $True -NewUser $False;
Restore-PersonalFiles $context;
if ((Get-Command Restore-Apps -ErrorAction SilentlyContinue)) {
Restore-Apps $context;
}
Remove-Item -Recurse $context.RootDir;
$context.Cleanup();
}

View file

@ -1,63 +1,244 @@
#!/bin/pwsh
. "$PSScriptRoot/../Scripts/PersonalFiles.ps1";
. "$PSScriptRoot/../Software/Firefox/Install.ps1";
. "$PSScriptRoot/../Software/Nextcloud/Install.ps1";
. "$PSScriptRoot/../Collections/Personal.ps1";
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/Legacy.ps1";
. "$PSScriptRoot/User/Install.ps1";
function Backup-WindowsInstallation([Context] $context) {
Write-Information "Backing up Windows";
$Global:InformationPreference = "Continue";
$Global:ErrorActionPreference = "Inquire";
. "$PSScriptRoot/../../../scripts/Windows/Scripts/Prerequisites.ps1";
$backupRoot = $context.BackupRoot();
Backup-PersonalFiles $context;
Backup-PersonalApps $context;
$context.Backup($backupRoot, "$backupRoot.7z", @("-sdel"), $false);
$context.Cleanup();
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?";
}
$null = New-Module {
. "$PSScriptRoot/../Scripts/Deployment.ps1";
. "$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/../Types/WindowsInstallerAction.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";
function Restore-WindowsInstallation([Context] $context) {
Write-Host "Restoring Windows";
choco feature enable -n useEnhancedExitCodes;
<#
.SYNOPSIS
Finishes the installation of a running Windows machine.
#>
function Start-WindowsInstallation {
Start-Operation -NoImplicitCleanup {
Start-InstallationLoop ([WindowsInstallerAction]::Install);
};
}
<#
.SYNOPSIS
Starts the installation loop.
#>
function Start-InstallationLoop {
param(
[WindowsInstallerAction] $Action
)
function Read-Path()
{
$backupPath = Read-Host -Prompt "Please enter the path to the archive to load the backup from.";
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 the backup archive you wish to restore from"
}
}
}));
if ($backupPath -and (-not (Test-Path -PathType Leaf $backupPath)))
{
Write-Host "No file could be found at the specified path.";
return Read-Path;
}
else
{
return $backupPath;
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]::Configure);
break;
}
([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);
}
([SetupStage]::CreateUser) {
Install-ValhallaUsers;
Set-IsFinished $true;
}
}
}
}
}
Set-Stage ([WindowsInstallerStage]::Completed);
break;
}
}
}
}
Install-Firefox $context;
Restore-Nextcloud $context;
Write-Information "Determining Backup Archive Path";
$backupPath = Read-Path;
$context.BackupName ??= "PortValhalla";
$context.RootDir = $context.GetTempDirectory();
if ($backupPath)
{
$context.Restore($backupPath, $context.BackupRoot());
function Invoke-WindowsInstallation([Context] $context) {
$Global:InformationPreference = "Continue";
$Global:ErrorActionPreference = "Inquire";
$context.UserNames ??= @("Manuel");
Start-OldWindowsInstallationScript $context;
}
Copy-UserInternationalSettingsToSystem -WelcomeScreen $True -NewUser $False;
Restore-PersonalFiles $context;
if ((Get-Command Restore-Apps -ErrorAction SilentlyContinue)) {
Restore-Apps $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;
}
}
}
}
Remove-Item -Recurse $context.RootDir;
$context.Cleanup();
}
};

View file

@ -0,0 +1,293 @@
. "$PSScriptRoot/../../Common/Scripts/Software.ps1";
. "$PSScriptRoot/../../Common/Scripts/SoftwareManagement.ps1";
. "$PSScriptRoot/../../Common/Types/InstallerAction.ps1";
<#
.SYNOPSIS
Deploys an action for each software selected for installation.
.PARAMETER
The action to execute.
#>
function Deploy-SoftwareAction {
param(
[System.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;
}
};
& {
$softwarePath = "$PSScriptRoot/../Software";
$commonSoftware = "$PSScriptRoot/../../Common/Software";
# Windows Config
& "$softwarePath/Windows/Manage.ps1" @arguments;
if (Get-Config "valhalla.hardware.logitechG") {
& "$softwarePath/LGHub/Manage.ps1" @arguments;
}
# Essentials
if (Test-Collection "essential") {
& "$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-Icon/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 `
;
}
}
# Common Software
if (Test-Collection "common") {
& "$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 "*HWMonior*";
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*";
# When installing Jellyfin Media Player after iCUE, Jellyfin will try to reboot automatically
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;
}
# Gaming
if (Test-Collection "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;
}
};
}

View file

@ -53,6 +53,7 @@ $null = New-Module {
function Get-StartupCommand {
($env:PWSH_PATH ? "`$env:PWSH_PATH = $(ConvertTo-Injection $env:PWSH_PATH);" : "") +
($env:DEBUG ? "`$env:DEBUG = $([int]$env:DEBUG);" : "") +
($env:BACKUP_ARCHIVE ? "`$env:BACKUP_ARCHIVE = $(ConvertTo-Injection (Resolve-Path $env:BACKUP_ARCHIVE));" : "") +
"`$env:INSTALLER_SCRIPT = $(ConvertTo-Injection (Resolve-Path $env:INSTALLER_SCRIPT));" +
"`$env:CONFIG_MODULE = $(ConvertTo-Injection (Resolve-Path $env:CONFIG_MODULE));" +
"& `$env:INSTALLER_SCRIPT;";
@ -166,18 +167,22 @@ $null = New-Module {
#>
function Restart-Intermediate {
param(
[Parameter(ParameterSetName="Default")]
[Parameter(ParameterSetName="None")]
[switch] $NoRegister,
[Parameter(ParameterSetName="Default", Mandatory)]
[switch] $DefaultUser,
[Parameter(ParameterSetName="Current", Mandatory)]
[switch] $CurrentUser
)
if ($DefaultUser.IsPresent) {
Register-Setup -DefaultUser;
} elseif ($CurrentUser.IsPresent) {
Register-Setup -User;
} else {
Register-Setup;
if (-not $NoRegister.IsPresent) {
if ($DefaultUser.IsPresent) {
Register-Setup -DefaultUser;
} elseif ($CurrentUser.IsPresent) {
Register-Setup -User;
} else {
Register-Setup;
}
}
Restart-Computer -Force;

View file

@ -0,0 +1,171 @@
using namespace System.Collections.Generic;
. "$PSScriptRoot/../../Common/Scripts/System.ps1";
$null = New-Module {
$pathResolver = {
param(
[string] $User,
[string] $Path
)
[string] $result = $null;
if ($User) {
$result = "Users/$User";
} else {
$result = "System";
}
if (-not $Path) {
$Path = "Files";
}
$result = Join-Path $result $Path;
return $result;
};
<#
.SYNOPSIS
Gets the name of the variable holding the path to the backup archive of the current machine.
#>
function Get-ArchiveVariableName {
return "BACKUP_ARCHIVE";
}
<#
.SYNOPSIS
Gets the path to the backup archive of the current machine.
#>
function Get-ValhallaBackupArchive {
(Get-Item "Env:\$(Get-ArchiveVariableName)").Value;
}
<#
.SYNOPSIS
Sets the path to the backup archive of the current machine.
.PARAMETER Path
The path to set.
#>
function Set-ValhallaBackupArchive {
param(
[string] $Path
)
Set-Item "Env:\$(Get-ArchiveVariableName)" $Path;
}
<#
.SYNOPSIS
Adds files to the backup archive.
.PARAMETER User
The user to add the files to.
.PARAMETER Source
The file or directory to add to the backup archive.
.PARAMETER Path
The path to the location to store the file or directory at.
.PARAMETER ArgumentList
The arguments to pass to the `7z` command.
#>
function Add-BackupArtifacts {
param(
[string] $User,
[string] $Source,
[string] $Path,
[string[]] $Include,
[string[]] $Exclude
)
if ($env:BACKUP_ARCHIVE) {
[List[string]] $argumentList = @();
$dir = New-TemporaryDirectory;
$targetPath = & $pathResolver @PSBoundParameters;
$fullPath = Join-Path $dir $targetPath;
$null = New-Item -ItemType Directory -Force (Split-Path -Parent $fullPath);
if (Test-Path -PathType Container $Source) {
$null = New-Item -ItemType Junction $fullPath -Target $Source;
} elseif (Test-Path -PathType Leaf $Source) {
$null = New-Item -ItemType Directory -Force $fullPath;
Copy-Item $Source $fullPath;
}
$options = @(
@("i", $Include),
@("x", $Exclude)
);
foreach ($option in $options) {
$indicator = $option[0];
$list = $option[1];
foreach ($pattern in $list) {
$argumentList.Add("-$indicator!`"$(Join-Path $targetPath $pattern)`"");
}
}
Start-Process `
-NoNewWindow `
-Wait `
-WorkingDirectory $dir `
-FilePath 7z `
-ArgumentList (
@(
"a",
(Get-ValhallaBackupArchive),
"-xr!desktop.ini",
"-xr!thumbs.db",
"-xr!Thumbs.db"
) + $argumentList);
Remove-Item -Recurse -Force $dir;
}
}
<#
.SYNOPSIS
Extracts the specified backup artifacts to the specified target path.
.PARAMETER User
The user to restore the files for.
.PARAMETER Path
The path to restore the files from.
.PARAMETER Target
The path to restore the files to.
.PARAMETER ArgumentList
The arguments to pass to `7z`.
#>
function Expand-BackupArtifacts {
param(
[string] $User,
[string] $Path,
[string] $Target,
[Parameter(ValueFromRemainingArguments)]
[string[]] $ArgumentList
)
if ($env:BACKUP_ARCHIVE) {
$dir = New-TemporaryDirectory;
$sourcePath = & $pathResolver @PSBoundParameters;
$filePath = Join-Path $dir $sourcePath;
7z x "-o$dir" (Get-ValhallaBackupArchive) $sourcePath @ArgumentList;
if (Test-Path $filePath) {
if (Test-Path -PathType Container $filePath) {
$filePath = "$filePath/*";
}
Copy-Item -Recurse $filePath $Target -Force;
}
Remove-Item -Recurse -Force $dir;
}
}
};

View file

@ -2,20 +2,122 @@ using namespace System.Management.Automation.Host;
using namespace System.Security.Principal;
$null = New-Module {
. "$PSScriptRoot/../Scripts/Deployment.ps1";
. "$PSScriptRoot/../../Common/Scripts/Config.ps1";
. "$PSScriptRoot/../../Common/Scripts/Operations.ps1";
$loggedInUserOption = "LoggedInUser";
<#
.SYNOPSIS
Installs all pending users to the system.
#>
function Install-ValhallaUsers {
$users = @(Get-Users);
$i = Get-CurrentUser;
for (; $i -lt $users.Count; $i++) {
Set-CurrentUser $i;
if (Test-Admin) {
Disable-BootMessage;
}
while ((Get-UserStage) -ne ([UserStage]::Completed)) {
switch (Get-UserStage) {
($null) {
Set-UserStage ([UserStage]::Create);
break;
}
([UserStage]::Create) {
$msAccount = Get-UserConfig -UserName $name "microsoftAccount";
if ($env:UserName -ne $name) {
$userInfo = @{
name = $name;
msAccount = $msAccount;
};
New-ValhallaUser @userInfo;
if ($msAccount) {
logoff;
} else {
Restart-Intermediate;
}
exit;
} else {
if ($msAccount) {
if (-not (Test-Admin)) {
Invoke-OneShot DisableUAC;
Restart-Intermediate -NoRegister;
exit;
}
Clear-SetupRegistration;
Disable-OneShotListener;
}
Set-UserStage ([UserStage]::Configure);
}
}
([UserStage]::Configure) {
$displayName = Get-UserConfig -UserName $name "displayName";
$userInfo = @{
name = $name;
};
if ($displayName) {
$userInfo.fullName = $displayName;
}
$adminGroup = @{
SID = [SecurityIdentifier]::new([WellKnownSidType]::BuiltinAdministratorsSid, $null);
};
Set-LocalUser @userInfo;
Deploy-SoftwareAction -Action ConfigureUser;
Remove-LocalGroupMember -Member "$name" @adminGroup -ErrorAction SilentlyContinue;
foreach ($group in Get-UserConfig "groups") {
Add-LocalGroupMember -Member "$name" -Name "$group";
}
Set-UserStage ([UserStage]::Cleanup);
}
([UserStage]::Cleanup) {
$user = Get-SetupUser;
Disable-LocalUser $name;
Enable-LocalUser $user;
Set-AutologinUser $user;
Unregister-WslDistribution;
Set-UserStage ([UserStage]::Completed);
Restart-Intermediate;
}
}
}
}
foreach ($user in $users) {
Enable-LocalUser $user;
}
}
<#
.SYNOPSIS
Creates a new user for the PortValhalla setup.
.PARAMETER Name
The name of the user to create.
.PARAMETER MSAccount
A value indicating whether the user should be created as a Microsoft Account.
#>
function New-ValhallaUser {
param(
[string] $Name
[string] $Name,
[switch] $MSAccount
)
function Add-MicrosoftAccount {
@ -83,13 +185,18 @@ $null = New-Module {
Set-MSAccountName ([string]$newUser);
}
$msAccount = Get-UserConfig -UserName $Name "microsoftAccount";
if ($msAccount) {
if ($MSAccount) {
if (Test-Admin) {
Write-Host "Preparing environment for creating MS Account";
Register-Setup -DefaultUser;
Enable-OneShotListener;
Enable-UAC;
# Reset Windows activation status
# Otherwise the login won't work - Windows is fricking frustrating.
slmgr /upk;
slmgr /cpky;
slmgr /rearm;
Restart-Intermediate -CurrentUser;
exit;
}
@ -97,7 +204,7 @@ $null = New-Module {
Write-Host "Creating personal user ``$Name``";
if ($msAccount) {
if ($MSAccount) {
Add-MicrosoftAccount $Name;
Set-SetupOption $loggedInUserOption $env:UserName;
Invoke-OneShot ([OneShotTask]::InitializeMSAccount);
@ -114,7 +221,6 @@ $null = New-Module {
function Initialize-UserCreation {
$name = (@(Get-Users))[(Get-CurrentUser)];
$msAccount = Get-UserConfig -UserName $name "microsoftAccount";
$displayName = Get-UserConfig -UserName $Name "displayName";
Write-Host "Initializing user ``$name``";
@ -122,10 +228,6 @@ $null = New-Module {
name = $name;
};
if ($displayName) {
$userArguments.fullName = $displayName;
}
$adminGroup = @{
SID = [SecurityIdentifier]::new([WellKnownSidType]::BuiltinAdministratorsSid, $null);
};

View file

@ -40,6 +40,14 @@ function Test-WslDistributions {
& { $null = wsl -l; $?; };
}
<#
.SYNOPSIS
Checks whether the managed distribution is installed.
#>
function Test-WslDistribution {
& { $null = wsl -d (Get-WslDistributionName) -e true; $?; };
}
<#
.SYNOPSIS
Installs `wsl` on the system.
@ -55,6 +63,12 @@ function Install-Wsl {
function Install-WslDistribution {
$dir = Get-WslDistributionPath;
$root = Split-Path -Parent $dir;
$registryPath = "HKCU:/Software/Microsoft/Windows/CurrentVersion/Lxss";
$key = Get-Item $registryPath;
if ($key) {
$key = $key | Rename-Item -NewName "$(Split-Path -Leaf $key)_" -PassThru;
}
if (-not (Test-Path $root)) {
$null = New-Item -ItemType Directory $root;
@ -64,6 +78,11 @@ function Install-WslDistribution {
Set-UserPermissions $dir;
& "$dir\ubuntu.exe" install --root;
wsl --shutdown;
Remove-Item -Recurse -Force $registryPath;
if ($key) {
Move-Item $key.PSPath $registryPath;
}
}
<#

View file

@ -3,13 +3,81 @@ param(
[hashtable] $Arguments
)
. "$PSScriptRoot/../../Scripts/Restoration.ps1";
. "$PSScriptRoot/../../../Common/Scripts/Software.ps1";
. "$PSScriptRoot/../../Scripts/AppAssociations.ps1";
$null = New-Module {
param ($Parameters)
$configPath = "$env:LocalAppData/LGHUB";
Export-ModuleMember -Function @();
<#
.SYNOPSIS
Stops the running Logitech G Hub instance.
#>
function Stop-LGHub {
[OutputType([string])]
param()
$hubName = "lghub_system_tray.exe";
$lghubPath = $(Get-Process | Where-Object { $_.Path -and ((Split-Path -Leaf $_.Path) -eq $hubName) })[0].Path;
$mainProcesses = Get-Process | Where-Object {
$_.Path -and
(@("lghub.exe", "lghub_agent.exe", $hubName) -contains (Split-Path -Leaf $_.Path)) -and
(($_.Parent.ProcessName -eq "explorer") -or ($null -eq $_.Parent))
};
$null = $mainProcesses | ForEach-Object { $_.Kill($true) };
return $lghubPath;
}
<#
.SYNOPSIS
Edits the Logitech G Hub configuration.
#>
function Edit-LGHubConfig {
param(
[scriptblock] $Action
)
Write-Host "Stopping Logitech G Hub";
$path = Stop-LGHub;
& $Action;
if ($path) {
Write-Host "Restarting Logitech G Hub";
Start-Process $path;
}
}
Start-SoftwareInstaller @Parameters `
-Installer {
Install-ChocoPackage lghub;
Remove-DesktopIcon "*G HUB*";
} `
-UserBackup {
param(
[hashtable] $Arguments
)
Edit-LGHubConfig {
Add-BackupArtifacts -User $Arguments.Name -Source $configPath -Path "LGHub" `
-Include @("settings.db", "icon_cache")
};
} `
-UserConfigurator {
param(
[hashtable] $Arguments
)
Edit-LGHubConfig {
Expand-BackupArtifacts -User $Arguments.Name -Path "LGHub" -Target $configPath;
};
};
} $PSBoundParameters;
Start-SoftwareInstaller @PSBoundParameters `
-Installer {
Install-ChocoPackage lghub;
Remove-DesktopIcon "*G HUB*";
};
# ToDo: Add restoration

View file

@ -21,12 +21,15 @@ Start-SoftwareInstaller @parameters -Installer {
[hashtable] $Arguments
)
$feature = "NetFx3";
if ((Get-WindowsOptionalFeature -Online -FeatureName $feature).State -ne "Enabled") {
Write-Host "Enabling ``$feature`` feature…";
choco install --source windowsFeatures -y $feature;
}
$module = $Arguments.Name;
& $Arguments.Installer @PSBoundParameters;
if (-not (& { powershell -Command "Import-Module $module"; $?; })) {
$feature = "NetFx3";
if ((Get-WindowsOptionalFeature -Online -NoRestart -FeatureName $feature).State -ne "Enabled") {
Write-Host "Enabling ``$feature`` feature…";
choco install --source windowsFeatures -y $feature;
}
}
}

View file

@ -0,0 +1,37 @@
Pictures/Feedback
Documents/BeamNG.drive
Documents/Default.rdp
Documents/den4b/ReNamer
Documents/Dolphin Emulator
Documents/eFisc
Documents/IISExpress
Documents/KINGDOM HEARTS HD 1.5+2.5 ReMIX
Documents/ManiaPlanet
Documents/MetaX
Documents/MuseScore3
Documents/My Web Sites
Documents/OneNote-Notizbücher
Documents/PCSX2
Documents/PowerShell
Documents/PPSSPP
Documents/PS Vita
Documents/PSV Packages
Documents/PSV Updates
Documents/Repositories
Documents/Rise of the Tomb Raider
Documents/S2
Documents/SEGA
Documents/SEGA Mega Drive Classics
Documents/SQL Server Management Studio
Documents/Square Enix
Documents/TI-Nspire CX
Documents/TmForever
Documents/TrackMania
Documents/UltraVNC
Documents/Visual Studio 2017
Documents/Visual Studio 2019
Documents/Visual Studio 2022
Documents/Viwizard M4V Converter
Documents/WindowsPowerShell
Documents/Zoom
Music/iTunes

View file

@ -5,13 +5,41 @@ param(
[hashtable] $Arguments
)
. "$PSScriptRoot/../../Scripts/Registry.ps1";
. "$PSScriptRoot/../../../Common/Scripts/Config.ps1";
. "$PSScriptRoot/../../../Common/Scripts/System.ps1";
. "$PSScriptRoot/../../../Common/Scripts/Software.ps1";
. "$PSScriptRoot/../../../Common/Types/InstallerAction.ps1";
Start-SoftwareInstaller @PSBoundParameters `
$null = New-Module {
param($Parameters)
. "$PSScriptRoot/../../Scripts/Registry.ps1";
. "$PSScriptRoot/../../Scripts/Restoration.ps1";
. "$PSScriptRoot/../../../Common/Scripts/Config.ps1";
. "$PSScriptRoot/../../../Common/Scripts/System.ps1";
$userFolders = @(
"Pictures",
"Documents",
"Downloads",
"Music",
"Videos"
);
$userExclusions = @(
"Documents/Eigene*",
"Documents/My Games",
"Documents/My Music",
"Documents/My Pictures",
"Documents/My Videos"
);
[string[]] $homeExclusions = Get-Content "$PSScriptRoot/Home.exclude.txt";
Start-SoftwareInstaller @Parameters `
-Backup {
Add-BackupArtifacts -Source "$env:PUBLIC" -Path "Public" `
-Include ($userFolders) `
-Exclude ($userExclusions + @("Documents/Hyper-V", "Documents/reWASD"));
} `
-Configurator {
$dir = New-TemporaryDirectory;
Push-Location $dir;
@ -54,7 +82,7 @@ Start-SoftwareInstaller @PSBoundParameters `
)
$path = "$($Key.PSPath)\Software\Microsoft\Lighting";
$null = New-Item $path;
$null = New-Item $path -ErrorAction SilentlyContinue;
Set-ItemProperty $path -Name "AmbientLightingEnabled" -Value 0 -Type "DWord";
};
}
@ -136,4 +164,20 @@ Start-SoftwareInstaller @PSBoundParameters `
Pop-Location;
Remove-Item -Recurse $dir;
Expand-BackupArtifacts -Path "Public" -Target $env:PUBLIC;
} `
-UserBackup {
param(
[hashtable] $Arguments
)
Add-BackupArtifacts -User $Arguments.Name -Source $HOME -Path "Home" -Include ($userFolders) -Exclude ($userExclusions + $homeExclusions);
} `
-UserConfigurator {
param(
[hashtable] $Arguments
)
Expand-BackupArtifacts -User $Arguments.Name -Path "Home" -Target $HOME;
};
} $PSBoundParameters;

View file

@ -0,0 +1,4 @@
enum WindowsInstallerAction {
Backup
Install
}

View file

@ -16,6 +16,7 @@ begin
argparse --name (status filename) -x "iso,usb" "iso" "usb" "debug" -- $argv
or exit 1
set -l mountDir "/mnt"
set -l setupLabel "winiso-valhalla"
set -l projectPath "PortValhalla"
set -l systemDrivePath "sources/\$OEM\$/\$1"
@ -23,9 +24,9 @@ begin
set -l localProjectPath "$systemDrivePath/$projectPath"
set -l cacheDir ~/.cache/winiso-valhalla
set -l winpe "$cacheDir/winpe.iso"
set -l winPath "/media/win"
set -l winpePath "/media/winpe"
set -l valhallaPath "/media/winiso-valhalla"
set -l winPath "$mountDir/win"
set -l winpePath "$mountDir/winpe"
set -l valhallaPath "$mountDir/winiso-valhalla"
set -l winpeOverlay (mktemp -d)
set -l winOverlay (mktemp -d)
set -l upperDir (mktemp -d)
@ -228,8 +229,8 @@ begin
-output "$isoFile" \
"$valhallaPath"
else
set -l bootPath "/media/boot"
set -l dataPath "/media/data"
set -l bootPath "$mountDir/boot"
set -l dataPath "$mountDir/data"
set -a mountPaths \
"$bootPath" \