Compare commits

...

189 commits

Author SHA1 Message Date
Manuel Thalmann 879c4bc5d4 Add code for cleaning up after installations 2024-09-03 22:15:15 +02:00
Manuel Thalmann 2025fa8afd Add functions for uninstalling packages 2024-09-03 22:14:21 +02:00
Manuel Thalmann c483d13e73 Improve assignments of groups 2024-09-03 20:32:01 +02:00
Manuel Thalmann cc657ca0d8 Remove unnecessary policy change 2024-09-03 16:31:12 +02:00
Manuel Thalmann 36332b92c5 Migrate winiso script to fish 2024-09-03 12:08:47 +02:00
Manuel Thalmann 11cc9b1c65 Ask for live scripts only once 2024-09-03 12:08:35 +02:00
Manuel Thalmann 07ce2f2de5 Install Ubuntu automatically 2024-09-03 12:08:14 +02:00
Manuel Thalmann e08e9559e1 Add a backup script for reWASD 2024-09-03 12:02:48 +02:00
Manuel Thalmann dde27d8fde Add a backup script for Visual Studio 2024-09-03 12:02:32 +02:00
Manuel Thalmann 74d6e80560 Allow backing up TrackMania Forever 2024-09-03 12:02:09 +02:00
Manuel Thalmann 14cdf638f5 Allow testing winget packages with specific scope 2024-09-03 01:16:42 +02:00
Manuel Thalmann abb07af518 Allow backing up RetroArch 2024-08-28 13:07:58 +02:00
Manuel Thalmann 4342645275 Add scripts for backing up PuTTY 2024-08-28 13:00:37 +02:00
Manuel Thalmann 54cbbaf548 Add scripts for backing up osu! 2024-08-28 12:47:07 +02:00
Manuel Thalmann fde93b0b9a Install osu!lazer per user 2024-08-28 12:37:20 +02:00
Manuel Thalmann 2d8e1e9572 Add backup support for ManiaPlanet 2024-08-28 05:18:52 +02:00
Manuel Thalmann 15d38ca5ed Add scripts for backing up and restoring LGHub 2024-08-28 05:05:55 +02:00
Manuel Thalmann f47d858806 Allow users to restore a backup 2024-08-28 04:40:32 +02:00
Manuel Thalmann f4cc0514dd Add scripts for backing up and restoring personal files 2024-08-28 04:40:00 +02:00
Manuel Thalmann eb0ca51bb5 Fix non-functioning profile script 2024-08-28 04:39:15 +02:00
Manuel Thalmann 000fb9237e Ensure 7z is installed for backups 2024-08-28 04:38:56 +02:00
Manuel Thalmann 0fecb0546c Streamline restoration of directories 2024-08-28 04:38:30 +02:00
Manuel Thalmann ab4d874aae Set a default path for backup artifacts 2024-08-28 00:38:20 +02:00
Manuel Thalmann 7b2eb20220 Add capabilities to back up apps 2024-08-28 00:37:04 +02:00
Manuel Thalmann 185b19f6fd Allow specifying a backup action 2024-08-28 00:29:33 +02:00
Manuel Thalmann 3c01f7802d Ignore unspecified backup archives 2024-08-28 00:22:38 +02:00
Manuel Thalmann 6096a088f3 Ignore inexistent backup artifacts 2024-08-28 00:21:06 +02:00
Manuel Thalmann 0b60d65696 Make the install script action agnostic 2024-08-28 00:03:28 +02:00
Manuel Thalmann d1de499daf Rename the Windows installer script 2024-08-27 23:35:56 +02:00
Manuel Thalmann 8fa4396b2a Rename outdated script 2024-08-27 23:08:41 +02:00
Manuel Thalmann ace3d59d39 Silence errors concerning empty aliae configurations 2024-08-27 22:35:31 +02:00
Manuel Thalmann 28b32263c0 Make Operations script cross platform 2024-08-27 22:27:44 +02:00
Manuel Thalmann 7c84dfdedd Handle OneShot tasks only on Windows 2024-08-27 21:32:49 +02:00
Manuel Thalmann 0e2a70903f Add a script for managing backups 2024-08-27 21:05:51 +02:00
Manuel Thalmann 044c20461c Add tools for managing aliae 2024-08-27 18:58:33 +02:00
Manuel Thalmann 4eb25a2d71 Fix non-functioning aliae installation 2024-08-27 18:55:12 +02:00
Manuel Thalmann 9ccf2806ec Create dedicated script for creating users 2024-08-27 17:04:17 +02:00
Manuel Thalmann e09d5b1613 Create dedicated script for installing software 2024-08-27 16:41:08 +02:00
Manuel Thalmann 909fd1a2e5 Prevent reading nix config multiple times 2024-08-27 14:35:04 +02:00
Manuel Thalmann 5741d30539 Ensure only one user is enabled at once 2024-08-27 14:11:31 +02:00
Manuel Thalmann 03d158a5ff Prevent unnecessary file creation 2024-08-27 14:06:56 +02:00
Manuel Thalmann 8ef5920789 Execute OneShot tasks in any operation 2024-08-27 14:05:16 +02:00
Manuel Thalmann 4f9957dad4 Use /mnt as mount directory 2024-08-27 04:30:12 +02:00
Manuel Thalmann c292a3c7fc Force the use of the managed distribution 2024-08-27 04:26:25 +02:00
Manuel Thalmann 6022adac79 Initialize operation for all users 2024-08-27 04:24:29 +02:00
Manuel Thalmann 9a37921063 Handle initialization in operation code 2024-08-27 04:15:37 +02:00
Manuel Thalmann e0b5abe72b Execute script non-interactive during OneShot tasks 2024-08-27 03:50:08 +02:00
Manuel Thalmann 0f67360232 Exit script after running OneShot task 2024-08-27 03:45:44 +02:00
Manuel Thalmann fd53dd903e Modify user after first login 2024-08-27 03:27:54 +02:00
Manuel Thalmann fb633298ba Rearm Windows Activation before creating MSAcc 2024-08-27 03:25:19 +02:00
Manuel Thalmann 2afaff1999 Register MSAcc logon script early 2024-08-27 03:24:37 +02:00
Manuel Thalmann 94f5657ea7 Allow rebooting without registering setup 2024-08-27 03:11:35 +02:00
Manuel Thalmann beb97a95f5 Fix non-functioning NoProfile argument 2024-08-27 02:09:04 +02:00
Manuel Thalmann f9a68c631c Prevent unnecessary installation actions 2024-08-27 01:57:46 +02:00
Manuel Thalmann 3a0f841160 Only install PowerShell module if necessary 2024-08-27 01:25:32 +02:00
Manuel Thalmann 6c615c4707 Streamline PowerShell installation 2024-08-27 00:45:46 +02:00
Manuel Thalmann 8b0048c7ee Add further functionality to the WSL script 2024-08-27 00:38:46 +02:00
Manuel Thalmann 273f3c9965 Create a separate script for WSL interaction 2024-08-26 23:33:46 +02:00
Manuel Thalmann 4f8c3b1c4d Fix recursive configuration 2024-08-25 03:58:28 +02:00
Manuel Thalmann 496620d367 Fix malformed module 2024-08-24 18:35:43 +02:00
Manuel Thalmann 1ac885964e Keep Windows fixes separate 2024-08-24 16:56:29 +02:00
Manuel Thalmann 493944f358 Remove WSL after operation 2024-08-24 16:52:41 +02:00
Manuel Thalmann 5daeb40d88 Make distribution name unique 2024-08-24 16:41:05 +02:00
Manuel Thalmann 2728c45ac5 Streamline WSL distribution name 2024-08-24 16:27:34 +02:00
Manuel Thalmann fa5b462312 Remove unused resources after user setup 2024-08-24 16:15:10 +02:00
Manuel Thalmann cfbe29eb0e Print update logs properly 2024-08-24 14:47:51 +02:00
Manuel Thalmann 64e6e62c29 Allow overriding Windows settings 2024-08-24 14:20:22 +02:00
Manuel Thalmann ff925b57d7 Update incorrect path 2024-08-24 14:11:38 +02:00
Manuel Thalmann dd11967f95 Simplify osu!lazer installation 2024-08-24 14:10:02 +02:00
Manuel Thalmann a4577812b3 Determine name of setup user properly 2024-08-24 14:01:05 +02:00
Manuel Thalmann 1da7ad2a44 Make OMP configuration platform independent 2024-08-24 13:27:48 +02:00
Manuel Thalmann a9f2abf033 Fix incorrect character in OMP theme 2024-08-24 13:27:35 +02:00
Manuel Thalmann 758502ae08 Remove unnecessary code 2024-08-24 04:25:07 +02:00
Manuel Thalmann e064c55087 Remove unnecessary loop 2024-08-24 04:24:55 +02:00
Manuel Thalmann 196e530627 Add missing module 2024-08-24 04:24:37 +02:00
Manuel Thalmann e89a34b304 Add nextcloud to the module list 2024-08-24 04:18:57 +02:00
Manuel Thalmann 576e52d604 Add a function for creating shortcuts 2024-08-24 04:18:33 +02:00
Manuel Thalmann 4900b6b081 Configure nextcloud syncs 2024-08-24 04:07:47 +02:00
Manuel Thalmann 21907e77f6 Allow configuring nextcloud syncs 2024-08-24 04:07:35 +02:00
Manuel Thalmann e63d263247 Create separate option holding win users 2024-08-24 03:25:28 +02:00
Manuel Thalmann d10c040e4e Rename Nextcloud installer 2024-08-24 01:50:07 +02:00
Manuel Thalmann 147f67e11c Add file system driver for dual boot 2024-08-24 01:41:09 +02:00
Manuel Thalmann a4819bf1c6 Prevent unnecessary config evaluation 2024-08-24 01:31:39 +02:00
Manuel Thalmann b495406999 Fix non-functioning installer 2024-08-24 01:27:26 +02:00
Manuel Thalmann 3dd2c7de8f Install vscode extensions by default 2024-08-24 01:16:56 +02:00
Manuel Thalmann bedde68d66 Load theme file from WSL properly 2024-08-24 00:59:59 +02:00
Manuel Thalmann 3b0baae206 Update aliae configuration script 2024-08-24 00:42:57 +02:00
Manuel Thalmann 60e47dc297 Strip duplicate variables and aliases 2024-08-24 00:08:58 +02:00
Manuel Thalmann ab4b6dc63c Install posh theme automatically 2024-08-23 23:53:48 +02:00
Manuel Thalmann 0ad9e94a1f Export missing function 2024-08-23 23:50:13 +02:00
Manuel Thalmann 896c6fb2fb Install aliae by default 2024-08-23 23:46:23 +02:00
Manuel Thalmann 87fc264f6b Add scripts for changing aliae config 2024-08-23 23:44:51 +02:00
Manuel Thalmann 1d5b147b21 Fix compatibility with mixed new line characters 2024-08-23 23:44:23 +02:00
Manuel Thalmann 0bdf6e33ed Add a script for installing aliae 2024-08-23 22:38:28 +02:00
Manuel Thalmann e24dbe89f9 Add desired posh theme 2024-08-23 19:43:06 +02:00
Manuel Thalmann 4c6f9d8dbf Make option names more clear 2024-08-23 19:42:27 +02:00
Manuel Thalmann 689e55b6d7 Allow configuring oh-my-posh 2024-08-23 19:39:18 +02:00
Manuel Thalmann e40d22676c Fetch config from proper section 2024-08-23 19:24:49 +02:00
Manuel Thalmann 8ccef0e870 Adjust configuration accordingly 2024-08-23 19:14:09 +02:00
Manuel Thalmann 361827218b Refactor option descriptions 2024-08-23 19:02:06 +02:00
Manuel Thalmann fedd304543 Clean up the Windows configuration 2024-08-23 18:59:49 +02:00
Manuel Thalmann fd1a6f2973 Clean up the users.nix file 2024-08-23 18:51:54 +02:00
Manuel Thalmann 4c9568f974 Create dedicated rclone module 2024-08-23 18:48:30 +02:00
Manuel Thalmann cf04b3d320 Move git module to separate directory 2024-08-23 18:42:16 +02:00
Manuel Thalmann 865fc519f0 Move git options to separate module 2024-08-23 18:40:24 +02:00
Manuel Thalmann 1445192c55 Fix inheritance of user config 2024-08-23 18:28:20 +02:00
Manuel Thalmann 4d7cc6f567 Allow OS specific settings 2024-08-23 18:11:48 +02:00
Manuel Thalmann 727a80b24c Update archiso 2024-08-23 14:19:56 +02:00
Manuel Thalmann c81f63b416 Set user info during git setup 2024-08-23 02:01:16 +02:00
Manuel Thalmann 3aa6967734 Make all config scripts platform independent 2024-08-23 01:57:53 +02:00
Manuel Thalmann fc2bf2276c Allow leaving aliases unspecified 2024-08-23 01:52:25 +02:00
Manuel Thalmann 720ec85bf0 Make scripts platform independent 2024-08-23 01:52:04 +02:00
Manuel Thalmann 47f6d45da6 Add scripts for configuring git 2024-08-23 01:43:26 +02:00
Manuel Thalmann 7d6c3d6a60 Configure software implicitly 2024-08-23 01:41:32 +02:00
Manuel Thalmann 6cade00931 Skip profile creation for PinnedItem 2024-08-22 23:55:41 +02:00
Manuel Thalmann b2f5dd6fc1 Allow skipping powershell module registration 2024-08-22 23:55:00 +02:00
Manuel Thalmann 3c4f794d0a Add profiles to the flake 2024-08-22 23:37:53 +02:00
Manuel Thalmann 9b5c9d1126 Remove user profile of OneShot user 2024-08-22 23:12:11 +02:00
Manuel Thalmann b303844e4a Add missing OneShotTask declaration 2024-08-22 20:41:30 +02:00
Manuel Thalmann 2afc7a0c69 Fix infinite loop 2024-08-22 20:41:17 +02:00
Manuel Thalmann 834aaa2d5b Fix incorrect variable name 2024-08-22 20:34:16 +02:00
Manuel Thalmann fe48bbe881 Fix handling empty error messages 2024-08-22 20:12:18 +02:00
Manuel Thalmann 110d55a302 Add choco to the profile of the setup user 2024-08-22 13:46:55 +02:00
Manuel Thalmann f063536b7d Fix incorrect typings 2024-08-22 11:11:12 +02:00
Manuel Thalmann 06c9f61030 Fix permission issues when enabling Win hack 2024-08-22 11:11:00 +02:00
Manuel Thalmann 317509167d Register setup script as admin 2024-08-22 11:10:39 +02:00
Manuel Thalmann 51655b2291 Execute the entire installer using live scripts 2024-08-21 23:21:32 +02:00
Manuel Thalmann 539780ba3c Streamline the creation of users 2024-08-21 18:34:18 +02:00
Manuel Thalmann 899eddf507 Replace osk with cmd during debugging 2024-08-21 18:33:41 +02:00
Manuel Thalmann d82c3ae1e9 Prevent pauses in OneShot tasks 2024-08-21 18:28:50 +02:00
Manuel Thalmann b441e9231a Print commands in debug mode 2024-08-21 18:28:08 +02:00
Manuel Thalmann 83165588f9 Run OneShot tasks with dedicated user 2024-08-21 18:27:47 +02:00
Manuel Thalmann d00d571194 Add function for generating startup command 2024-08-21 18:26:58 +02:00
Manuel Thalmann 977fe76248 Allow registering startup script for the default user 2024-08-21 18:20:11 +02:00
Manuel Thalmann 187f0d465a Prevent unnecessary errors during WSL execution 2024-08-21 14:08:26 +02:00
Manuel Thalmann 4c587f87b1 Register WSL before running OneShot tasks 2024-08-21 03:37:44 +02:00
Manuel Thalmann d871b48864 Overwrite broken module 2024-08-21 03:20:37 +02:00
Manuel Thalmann 7feae37eb9 Prevent initialization of nested operations 2024-08-21 03:18:31 +02:00
Manuel Thalmann d2dbe59071 Improve log messages of OneShot tasks 2024-08-21 02:02:30 +02:00
Manuel Thalmann d029018563 Retry Linux path conversion for errors 2024-08-20 00:20:33 +02:00
Manuel Thalmann 72d46420f4 Fix typo 2024-08-20 00:20:07 +02:00
Manuel Thalmann f5359efad7 Fix broken signature of Restart-Intermediate 2024-08-19 12:07:26 +02:00
Manuel Thalmann 8e3abf6087 Report unexpected path conversions 2024-08-19 02:50:41 +02:00
Manuel Thalmann 4f89c167cb Load missing path 2024-08-19 02:50:19 +02:00
Manuel Thalmann 4d56597f86 Ensure error file can be read from 2024-08-19 02:24:45 +02:00
Manuel Thalmann 4dccba5632 Streamline OneShot task handler 2024-08-19 02:24:30 +02:00
Manuel Thalmann fae955e126 Simplify script registration 2024-08-19 02:24:13 +02:00
Manuel Thalmann 59e61b6ea8 Fix broken regedit paths 2024-08-19 01:38:25 +02:00
Manuel Thalmann 8eecac02bf Allow registering reboots for users 2024-08-19 01:37:14 +02:00
Manuel Thalmann 345b3fb1df Prevent users from being excluded 2024-08-19 01:10:29 +02:00
Manuel Thalmann d8596f0a58 Force copying of Linux users to Windows 2024-08-19 00:54:13 +02:00
Manuel Thalmann df57160ef5 Improve log messages of updates 2024-08-18 12:20:21 +02:00
Manuel Thalmann 2f59726682 Remove unnecessary command 2024-08-18 10:24:15 +02:00
Manuel Thalmann 7dbf75e591 Fix time for QEMU VMs 2024-08-18 09:35:16 +02:00
Manuel Thalmann 0b2824cf9e Remove unnecessary desktop icons 2024-08-18 09:25:23 +02:00
Manuel Thalmann bd8224b3f4 Add a timeout for the reWASD downloader 2024-08-18 09:05:04 +02:00
Manuel Thalmann 5c0e462cc7 Allow setting a timeout for clicking download buttons 2024-08-18 09:04:42 +02:00
Manuel Thalmann 7015a69d16 Emit errors concerning WSL commands 2024-08-17 13:51:10 +02:00
Manuel Thalmann 0a23112e2c Emit errors using Write-Error 2024-08-17 13:49:21 +02:00
Manuel Thalmann d684d1ec42 Convert Argument to string explicitly 2024-08-16 23:03:19 +02:00
Manuel Thalmann 40b3472700 Ignore unfinished browser downloads 2024-08-16 17:57:22 +02:00
Manuel Thalmann 24ff14ca99 Install powershell modules for all users 2024-08-16 16:43:30 +02:00
Manuel Thalmann 60074b9ad0 Fix typos 2024-08-16 16:10:09 +02:00
Manuel Thalmann 73c0f0913e Install AutoHotkey as preparation 2024-08-16 15:22:09 +02:00
Manuel Thalmann ff8b949b35 Allow running live scripts in debug mode 2024-08-16 15:21:41 +02:00
Manuel Thalmann 6a73d54056 Generate env variables using shorthand scripts 2024-08-16 15:16:56 +02:00
Manuel Thalmann 0d8ea792fc Allow running installation in debug mode 2024-08-16 15:16:28 +02:00
Manuel Thalmann f3e70d2908 Redirect winiso exit code properly 2024-08-16 15:13:53 +02:00
Manuel Thalmann a3a3b5e9b4 Allow specifying winiso build type 2024-08-16 15:13:33 +02:00
Manuel Thalmann cb0af07f0c Refactor winget check for rare issue 2024-08-16 15:04:37 +02:00
Manuel Thalmann 36dd010efb Disable Windows Update reboot only as admin 2024-08-16 14:35:35 +02:00
Manuel Thalmann 1e198093cc Add a function for queueing startup commands 2024-08-15 18:34:48 +02:00
Manuel Thalmann d6a85c8cda Hide output of DISM commands 2024-08-15 13:57:15 +02:00
Manuel Thalmann fac547f4be Ensure website is loaded before download 2024-08-15 02:42:00 +02:00
Manuel Thalmann 1ff78c6769 Prevent Jellyfin from rebooting 2024-08-15 02:22:07 +02:00
Manuel Thalmann 18a0b3d577 Improve handling of slow websites 2024-08-14 18:47:29 +02:00
Manuel Thalmann 318a880b5f Fix potential CRC errors 2024-08-14 18:46:42 +02:00
Manuel Thalmann fcfc58ff7e Ensure auto reboot is disabled properly 2024-08-12 21:32:53 +02:00
Manuel Thalmann 580cbd2f2a Disable auto reboot by default 2024-08-12 01:27:50 +02:00
Manuel Thalmann a9090b9b9c Add methods for managing auto restart feature 2024-08-12 01:23:42 +02:00
Manuel Thalmann 908a847bbe Install Wave Link first 2024-08-11 18:27:16 +02:00
Manuel Thalmann df0a2847c4 Throw an error when failing to load config 2024-08-11 18:27:06 +02:00
Manuel Thalmann dfc70a2b0c Fix incorrect script path 2024-08-10 20:37:10 +02:00
Manuel Thalmann 6db6fd02ee Allow leaving install action unspecified 2024-08-10 19:27:56 +02:00
Manuel Thalmann b504ee0979 Retrieve registry value properly 2024-08-10 19:26:53 +02:00
Manuel Thalmann 234a0f17d5 Add scripts for installing git 2024-08-10 15:28:10 +02:00
Manuel Thalmann 77ed70468e Remove unnecessary code 2024-08-10 15:24:15 +02:00
Manuel Thalmann e0771278a5 Add a function for removing the RunOnce key 2024-08-10 15:24:04 +02:00
Manuel Thalmann 2fd325d580 Set user groups properly 2024-08-10 15:23:38 +02:00
87 changed files with 3730 additions and 1367 deletions

View file

@ -23,7 +23,7 @@ automated_script() {
sleep 1
done
printf '%s: downloading %s\n' "$0" "${script}"
curl "${script}" --location --retry-connrefused --retry 10 -s -o /tmp/startup_script
curl "${script}" --location --retry-connrefused --retry 10 --fail -s -o /tmp/startup_script
rt=$?
else
cp "${script}" /tmp/startup_script

View file

@ -1,8 +1,8 @@
diff --git a/airootfs/root/.zlogin b/airootfs/root/.zlogin
index bf6bc8f..76e5893 100755
index bf6bc8f..a0dae7b 100755
--- a/airootfs/root/.zlogin
+++ b/airootfs/root/.zlogin
@@ -4,3 +4,18 @@ if grep -Fqa 'accessibility=' /proc/cmdline &> /dev/null; then
@@ -4,3 +4,19 @@ if grep -Fqa 'accessibility=' /proc/cmdline &> /dev/null; then
fi
~/.automated_script.sh
@ -16,13 +16,14 @@ index bf6bc8f..76e5893 100755
+
+git diff -p -R --no-ext-diff --no-color --diff-filter=M \
+ | grep -E "^(diff|(old|new) mode)" --color=never \
+ | sed "/^diff/{ x; d; }; x; /./{ p; z; }; x;" \
+ | git apply
+
+popd > /dev/null
+
+loadkeys de_CH-latin1
diff --git a/packages.x86_64 b/packages.x86_64
index 9e876e7..b89ab30 100755
index 9e876e7..c5db92a 100755
--- a/packages.x86_64
+++ b/packages.x86_64
@@ -30,8 +30,10 @@ ethtool
@ -36,7 +37,15 @@ index 9e876e7..b89ab30 100755
gnu-netcat
gpart
gpm
@@ -75,6 +77,7 @@ nbd
@@ -45,6 +47,7 @@ irssi
iw
iwd
jfsutils
+jq
kitty-terminfo
ldns
less
@@ -75,6 +78,7 @@ nbd
ndisc6
nfs-utils
nilfs-utils

View file

@ -6,7 +6,7 @@
flake-utils.url = "github:numtide/flake-utils?ref=b1d9ab70662946ef0850d488da1c9019f3a9752a";
};
outputs = { self, flake-utils, nixpkgs }: flake-utils.lib.eachDefaultSystem (
outputs = { self, flake-utils, nixpkgs }: (flake-utils.lib.eachDefaultSystem (
system:
let
pkgs = import nixpkgs {
@ -32,5 +32,11 @@
packages = {
archiso = pkgs.archiso;
};
});
})) // {
valhalla = {
"DerGeret Windows" = import ./profiles/DerGeret/config.nix;
"der-geret Arch Linux" = import ./profiles/DerGeret/Arch/config.nix;
"manu-surface Arch Linux" = import ./profiles/ManuSurface/Arch/config.nix;
};
};
}

View file

@ -1,7 +0,0 @@
{ lib, ... }: {
options = {
valhalla = {
git = (import ./git/options.nix) { inherit lib; };
};
};
}

View file

@ -1,33 +0,0 @@
{ lib, ... }:
let
inherit (lib)
mkOption
types
;
in {
defaultBranch = mkOption {
type = types.nullOr types.str;
description = "The name of the default branch in git.";
default = null;
};
flow = {
mainBranch = mkOption {
type = types.nullOr types.str;
description = "The name of the stable branch in git flow.";
default = null;
};
devBranch = mkOption {
type = types.nullOr types.str;
description = "The name of the development branch in git flow.";
default = null;
};
};
aliases = mkOption {
type = types.attrsOf types.str;
description = "Git command aliases to install.";
default = {};
};
}

52
lib/modules/os.nix Normal file
View file

@ -0,0 +1,52 @@
{ lib, ... }:
let
inherit (lib)
mkOption
types
;
in {
options = {
valhalla = mkOption {
type = types.submodule (
{ extendModules, ... }:
let
osVariant = extendModules {
modules = [
({ config, ... }: {
options = {
config = mkOption {
type = types.attrs;
description = "The configuration of the Operating System.";
default = builtins.removeAttrs config ["_module" "config" "linux" "windows"];
visible = false;
};
};
})
];
};
linuxVariant = osVariant.extendModules { };
windowsVariant = osVariant.extendModules { };
in {
options = {
linux = mkOption {
inherit (linuxVariant) type;
description = "The options for setting up Linux.";
default = {};
visible = "shallow";
};
windows = mkOption {
inherit (windowsVariant) type;
description = "The options for setting up Windows.";
default = {};
visible = "shallow";
};
};
});
description = "Configuration for PortValhalla.";
default = {};
};
};
}

View file

@ -0,0 +1,59 @@
{ lib, ... }:
let
inherit (lib)
mkOption
types
;
gitType = types.submodule (
{ ... }: {
options = {
defaultBranch = mkOption {
type = types.nullOr types.str;
description = "The name of the default branch in newly created repositories.";
default = null;
};
flow = {
mainBranch = mkOption {
type = types.nullOr types.str;
description = "The name of the stable branch in git flow.";
default = null;
};
devBranch = mkOption {
type = types.nullOr types.str;
description = "The name of the development branch in git flow.";
default = null;
};
};
aliases = mkOption {
type = types.attrsOf types.str;
description = "The git command aliases to install.";
default = {};
};
};
});
gitOption = mkOption {
type = gitType;
description = "The git related options.";
default = {};
};
in {
options = {
valhalla = {
git = gitOption;
users = mkOption {
type = types.attrsOf (types.submodule (
{ ... }: {
options = {
git = gitOption;
};
}));
};
};
};
}

View file

@ -0,0 +1,44 @@
{ lib, ... }:
let
inherit (lib)
mkEnableOption
mkOption
types
;
syncType = types.submodule (
{ ... }: {
options = {
remotePath = mkOption {
type = types.str;
description = "The path to the folder on the cloud to sync.";
};
localPath = mkOption {
type = types.str;
description = "The path to sync the cloud content to.";
};
virtualFiles = (mkEnableOption "virtual file support") // {
default = true;
};
};
});
in {
options = {
valhalla.windows.users = mkOption {
type = types.attrsOf (types.submodule (
{ ... }: {
options = {
nextcloud = {
folderSyncs = mkOption {
type = types.listOf syncType;
description = "The folders to synchronize.";
default = [];
};
};
};
}));
};
};
}

View file

@ -0,0 +1,60 @@
{ lib, ... }:
let
inherit (lib)
mkOption
types
;
themeType = types.submodule (
{ config, ... }: {
options = {
source = mkOption {
type = types.nullOr types.path;
description = "The path to the oh-my-posh theme to use.";
default = null;
};
name = mkOption {
type = types.nullOr types.str;
description = "The name of the theme.";
default = if (config.source != null)
then
lib.strings.removeSuffix ".omp" (lib.strings.removeSuffix ".json" (builtins.baseNameOf config.source))
else
null;
};
};
});
ompType = types.submodule (
{ config, ... }: {
options = {
theme = mkOption {
type = types.either types.str themeType;
description = "The default theme.";
default = {};
};
additionalThemes = mkOption {
type = types.listOf themeType;
description = "A set of additional themes to install.";
default = [];
};
};
});
in {
options = {
valhalla.users = mkOption {
type = types.attrsOf (types.submodule (
{ ... }: {
options = {
oh-my-posh = mkOption {
type = ompType;
description = "The Oh My Posh configuration to apply.";
default = {};
};
};
}));
};
};
}

View file

@ -0,0 +1,40 @@
{ lib, ... }:
let
inherit (lib)
mkOption
types
;
syncType = types.submodule (
{ ... }: {
options = {
dirName = mkOption {
type = types.str;
description = "The name of the directory to sync the remote files to.";
};
cacheDuration = mkOption {
type = types.nullOr types.str;
description = "The amount of time to keep cached files.";
default = null;
};
};
});
in {
options = {
valhalla.linux.users = mkOption {
type = types.attrsOf (types.submodule (
{ ... }: {
options = {
rclone = {
configurations = mkOption {
type = types.attrsOf syncType;
description = "The configurations of the rclone mounts.";
default = {};
};
};
};
}));
};
};
}

View file

@ -1,84 +1,56 @@
{ config, lib, ... }:
{ lib, ... }:
let
inherit (lib)
mkOption
types
;
cfg = config.valhalla;
capitalize = (import ../text.nix { inherit lib; }).capitalize;
linuxOptions = {
defaultShell = mkOption {
type = types.nullOr types.str;
description = "The default shell of the user.";
default = null;
};
rclone = {
configurations = mkOption {
type = types.attrsOf syncType;
description = "The configurations of the rclone mounts.";
default = {};
};
};
};
syncType = types.submodule (
{ ... }: {
userType = types.submodule (
{ ... } : {
options = {
dirName = mkOption {
type = types.str;
description = "The name of the directory to sync the remote files to.";
displayName = mkOption {
type = types.nullOr types.str;
description = "The human-readable name of the user.";
default = null;
};
cacheDuration = mkOption {
mailAddress = mkOption {
type = types.nullOr types.str;
description = "The amount of time to keep cached files.";
description = "The mail address of the user.";
default = null;
};
groups = mkOption {
type = types.listOf types.str;
description = "The additional groups of the user.";
default = [];
};
};
});
linuxUserType = types.submodule (
{ ... }: {
options = {
defaultShell = mkOption {
type = types.nullOr types.str;
description = "The default shell of the user.";
default = null;
};
};
});
mkUserType = { options }: (
types.submodule (
{ ... }: {
options = {
displayName = mkOption {
type = types.nullOr types.str;
description = "The human-readable name of the user.";
default = null;
};
mailAddress = mkOption {
type = types.nullOr types.str;
description = "The mail address of the user.";
default = null;
};
groups = mkOption {
type = types.listOf types.str;
description = "The additional groups of the user.";
default = [];
};
git = (import ./git/options.nix) { inherit lib; };
} // options;
}));
userType = mkUserType {
options = linuxOptions;
};
winUserType = mkUserType {
options = {
microsoftAccount = mkOption {
type = types.bool;
description = "A value indicating whether this user is a Microsoft Account.";
default = false;
winUserType = types.submodule (
{ ... }: {
options = {
microsoftAccount = mkOption {
type = types.bool;
description = "A value indicating whether this user is a Microsoft Account.";
default = false;
};
};
};
};
});
in {
options = {
valhalla = {
@ -88,25 +60,31 @@
default = {};
};
windows.users = mkOption {
type = types.attrsOf winUserType;
description = "The users to create on the Windows machine.";
default = (lib.attrsets.concatMapAttrs (
name: options:
if builtins.elem name (builtins.attrNames linuxOptions)
then {}
else {
${capitalize name} = (lib.attrsets.concatMapAttrs (
name: value:
if builtins.elem name (builtins.attrNames linuxOptions)
then {}
else {
${name} = value;
}
) options) // {
groups = [];
linux.users = mkOption {
type = types.attrsOf linuxUserType;
};
windows = mkOption {
type = types.submoduleWith {
modules = [
({ config, options, ... }: {
options = {
users = mkOption {
type = types.attrsOf winUserType;
};
}) cfg.users);
winUsers = mkOption {
type = options.users.type;
description = "Blablabla";
default = (lib.attrsets.concatMapAttrs (
name: options: {
${capitalize name} = options;
}) config.users);
};
};
})
];
};
};
};
};

View file

@ -6,9 +6,13 @@
;
in {
imports = [
./git.nix
./packages/git.nix
./packages/nextcloud.nix
./packages/oh-my-posh.nix
./packages/rclone.nix
./hardware.nix
./i18n.nix
./os.nix
./partition.nix
./software.nix
./users.nix

View file

@ -1,24 +1,18 @@
{ lib, config, ... }:
let
inherit (lib)
mkOption
mkDefault
mkEnableOption
mkIf
mkOption
types
;
setupUser = config.valhalla.setupUser.name;
capitalize = (import ../text.nix { inherit lib; }).capitalize;
winType = types.submodule (
{ config, ... }: {
options = {
setupUser = mkOption {
type = types.str;
description = "The name of the user for setting up Windows.";
default = capitalize setupUser;
};
in {
options = {
valhalla = {
windows = {
dualboot = {
enable = mkEnableOption "dual boot";
@ -41,19 +35,13 @@
dynamicLighting = mkEnableOption "dynamic lighting";
adware = mkEnableOption "adware"; # Fuck you for displaying ads on an OS I fricking paid for!
};
};
};
config = {
dualboot.linuxPercentage = mkIf (!config.dualboot.enable) 0;
};
});
in {
options = {
valhalla = {
windows = mkOption {
type = winType;
description = "The options for setting up Windows.";
default = {};
};
config = {
valhalla.windows = {
setupUser.name = mkDefault (capitalize config.valhalla.setupUser.name);
dualboot.linuxPercentage = mkIf (!config.valhalla.windows.dualboot.enable) (mkDefault 0);
};
};
}

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

@ -11,8 +11,9 @@
linuxPercentage = 30;
};
users.Manuel = {
users.manuel = {
microsoftAccount = true;
groups = ["Administrators"];
};
};

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

@ -3,6 +3,7 @@
fs = import ../../lib/modules/partition/fs.nix;
in {
imports = [
../manuel/config.nix
../../lib/modules/valhalla.nix
];
@ -39,14 +40,17 @@
manuel = {
displayName = "Manuel Thalmann";
mailAddress = "m@nuth.ch";
};
};
linux.users.manuel = {
defaultShell = "fish";
groups = [
"wheel"
"nix-users"
];
defaultShell = "fish";
rclone = {
configurations = {
nextcloud = {
@ -57,6 +61,25 @@
};
};
};
};
windows.users.manuel = {
nextcloud = {
folderSyncs =
let
localPath = "C:/tools/RetroArch-Win64";
remotePath = "/Saved Games/RetroArch";
in [
{
remotePath = "${remotePath}/Saves";
localPath = "${localPath}/saves";
virtualFiles = false;
}
{
remotePath = "${remotePath}/System";
localPath = "${localPath}/system";
}
];
};
};

View file

@ -0,0 +1,23 @@
{ ... }: {
imports = [
../../lib/modules/valhalla.nix
];
config = {
valhalla = {
users.manuel = {
oh-my-posh = {
theme = {
source = ./manuel.omp.json;
};
};
};
partition = {
os = {
partitions = { };
};
};
};
};
}

View file

@ -0,0 +1,173 @@
{
"$schema": "https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json",
"version": 2,
"blocks": [
{
"type": "prompt",
"alignment": "left",
"segments": [
{
"type": "os",
"style": "diamond",
"leading_diamond": "\ue0b6",
"trailing_diamond": "\ue0b4",
"background_templates": [
"{{ if eq .OS \"ubuntu\" }}#EA531A{{ end }}",
"{{ if eq .OS \"debian\" }}#D80150{{ end }}",
"{{ if eq .OS \"arch\" }}#1793D1{{ end }}"
],
"foreground": "p:white",
"template": "{{ if ne .OS \"windows\" }}{{ .Icon }} {{ end }}"
},
{
"type": "session",
"style": "diamond",
"leading_diamond": "\ue0b6",
"trailing_diamond": "\ue0b0",
"background": "p:yellow",
"foreground": "p:black",
"properties": {
"display_host": false
},
"template": " {{ if .SSHSession }}\ueb39 {{ end }}{{ .UserName }} "
},
{
"type": "path",
"style": "powerline",
"powerline_symbol": "\ue0b0",
"background": "p:orange",
"foreground": "p:black",
"properties": {
"home_icon": "~",
"style": "folder"
},
"template": " \udb80\ude4b {{ path .Path .Location }} "
},
{
"type": "dotnet",
"style": "powerline",
"powerline_symbol": "\ue0b0",
"foreground": "p:black",
"background": "#00ffff",
"template": " \udb81\ude10 {{ .Full }} "
},
{
"type": "java",
"style": "powerline",
"powerline_symbol": "\ue0b0",
"background": "#4063d8",
"template": " \udb82\udf37 {{ .Full }} "
},
{
"type": "python",
"style": "powerline",
"powerline_symbol": "\ue0b0",
"background": "#906cff",
"template": " \udb80\udf20 {{ .Full }} "
},
{
"type": "git",
"style": "powerline",
"powerline_symbol": "\ue0b0",
"trailing_diamond": "\ue0b4",
"background": "p:green",
"background_templates": [
"{{ if or (.Working.Changed) (.Staging.Changed) }}p:yellow{{ end }}",
"{{ if and (gt .Ahead 0) (gt .Behind 0) }}p:red{{ end }}",
"{{ if gt .Ahead 0 }}#49416D{{ end }}",
"{{ if gt .Behind 0 }}#7A306C{{ end }}"
],
"foreground": "p:black",
"foreground_templates": [
"{{ if or (.Working.Changed) (.Staging.Changed) }}p:black{{ end }}",
"{{ if and (gt .Ahead 0) (gt .Behind 0) }}p:white{{ end }}",
"{{ if gt .Ahead 0 }}p:white{{ end }}"
],
"properties": {
"branch_max_length": 25,
"fetch_stash_count": true,
"fetch_status": true,
"fetch_upstream_icon": true,
"upstream_icons": {
"codeberg.org": "\uf330 ",
"git.nuth.ch": "\uf335",
"git.jonascosta.ch": "\uf339 ",
"git.romhackersworld.eu": "\uf339 ",
"aur.archlinux.org": "\uf303 "
}
},
"templates": [
"{{ if .UpstreamURL }} {{ url .UpstreamIcon .UpstreamURL }}{{ end }}",
" {{ .HEAD }} ",
"{{ if .BranchStatus }}{{ .BranchStatus }} {{ end }}",
"{{ if .Working.Changed }} \uf044 {{ .Working.String }} {{ end }}",
"{{ if and (.Working.Changed) (or (.Staging.Changed) (gt .StashCount 0)) }} | {{ end }}",
"{{ if .Staging.Changed }} \uf046 {{ .Staging.String }} {{ end }}",
"{{ if and (.Staging.Changed) (gt .StashCount 0) }} | {{ end }}",
"{{ if gt .StashCount 0 }} \udb80\udd93 {{ .StashCount }}{{ end }} "
]
},
{
"type": "node",
"style": "powerline",
"powerline_symbol": "\ue0b0",
"background": "#6ca35e",
"foreground": "p:white",
"properties": {
"fetch_version": true
},
"template": " \udb80\udf99 {{ if .PackageManagerIcon }}{{ .PackageManagerIcon }} {{ end }}{{ .Full }} "
},
{
"type": "root",
"style": "powerline",
"powerline_symbol": "\ue0b0",
"background": "p:yellow",
"foreground": "p:white",
"properties": {
"root_icon": "\uf0e7"
}
},
{
"type": "executiontime",
"style": "plain",
"background": "#83769c",
"foreground": "p:white",
"properties": {
"always_enabled": true
},
"template": "<transparent>\ue0b0</> \udb81\udead {{ .FormattedMs }}\u2800"
},
{
"type": "text",
"style": "diamond",
"background": "p:blue",
"trailing_diamond": "\ue0b4",
"background_templates": [
"{{ if gt .Code 0 }}p:red{{ end }}"
],
"foreground": "p:white",
"properties": {
"always_enabled": true
},
"template": "<parentBackground>\ue0b0</> {{ if gt .Code 0 }}\uf00d{{ else }}\uf00c{{ end }} "
}
]
}
],
"transient_prompt": {
"background": "transparent",
"foreground": "p:black",
"template": "<p:yellow,transparent>\ue0b6</><,p:yellow> {{ .Folder }} </><p:yellow,transparent>\ue0b0</> "
},
"final_space": true,
"palette": {
"black": "#262B44",
"blue": "#4B95E9",
"green": "#59C9A5",
"orange": "#F07623",
"red": "#D81E5B",
"white": "#E0DEF4",
"yellow": "#F3AE35"
}
}

View file

@ -68,19 +68,19 @@ $null = New-Module {
$downloadChecker = {
$files = Get-ChildItem $dir;
if ((@($files)).Count -gt 0) {
foreach ($file in $files) {
try {
$stream = [System.IO.File]::Open($file.FullName, [System.IO.FileMode]::Open, [System.IO.FileAccess]::ReadWrite, [System.IO.FileShare]::None);
if ($stream) {
$stream.Close();
}
}
catch {
return $true;
if ((@($files)).Count -eq 1) {
$file = $files[0];
try {
$stream = [System.IO.File]::Open($file.FullName, [System.IO.FileMode]::Open, [System.IO.FileAccess]::ReadWrite, [System.IO.FileShare]::None);
if ($stream) {
$stream.Close();
}
}
catch {
return $true;
}
return $false;
} else {
@ -90,18 +90,28 @@ $null = New-Module {
$browser = [OpenQA.Selenium.Firefox.FirefoxDriver]::new($options);
$browser.Navigate().GoToUrl($URL);
$null = & $downloadAction -Browser $browser;
while (& $downloadChecker) {
Write-Host "Waiting for the download to finish…";
Start-Sleep 1;
while (-not ($browser.ExecuteScript("return document.readyState;") -eq "complete")) {
Start-Sleep 0.1;
}
try {
$null = & $downloadAction -Browser $browser;
while (& $downloadChecker) {
Write-Host "Waiting for the download to finish…";
Start-Sleep 1;
}
$file = Get-ChildItem $dir;
$result = Move-Item $file $OutDir -PassThru;
$browser.Quit();
Remove-Item -Recurse $dir;
$result;
}
catch {
Write-Error $Error;
}
$file = Get-ChildItem $dir;
$result = Move-Item $file $OutDir -PassThru;
$browser.Quit();
Remove-Item -Recurse $dir;
$result;
}
}
@ -117,12 +127,16 @@ $null = New-Module {
.PARAMETER OutDir
The directory to download the file to.
.PARAMETER Timeout
The number of seconds to wait before clicking the download button.
#>
function Start-BrowserDownload {
param(
[string] $URL,
[string] $ButtonSelector,
[string] $OutDir = $null
[string] $OutDir = $null,
[double] $Timeout = 0
)
Start-CustomBrowserDownload @PSBoundParameters -Action {
@ -130,7 +144,28 @@ $null = New-Module {
[OpenQA.Selenium.Firefox.FirefoxDriver] $Browser
)
$Browser.FindElement([OpenQA.Selenium.By]::CssSelector($ButtonSelector)).Click();
$selector = [OpenQA.Selenium.By]::CssSelector($ButtonSelector);
[OpenQA.Selenium.IWebElement] $element = $null;
for ($i = 0; $i -lt 5; $i++) {
$element = $Browser.FindElement($selector);
if ($element) {
break;
} else {
Start-Sleep 1;
}
}
if ($Timeout -gt 0) {
Start-Sleep $Timeout;
}
if ($element) {
$Browser.FindElement($selector).Click();
} else {
Write-Error "Unable to find download button!";
}
};
}
};

View file

@ -2,19 +2,33 @@ using namespace Microsoft.Win32;
using namespace System.Security.AccessControl;
using namespace System.Security.Principal;
enum SetupStage {
Idle
enum WindowsInstallerStage {
Initialize
OneShot
Run
Cleanup
Completed
}
enum SetupStage {
Configure
Install
CreateUser
ConfigureUser
}
enum UserStage {
Create
Configure
Cleanup
Completed
}
$null = New-Module {
[string] $configRoot = "HKLM:\Software\PortValhalla";
[string] $stageOption = "Stage";
[string] $setupStageOption = "SetupStage";
[string] $userOption = "SetupUser";
[string] $userStageOption = "UserStage";
[string] $accountOption = "MSAccount";
[string] $finishedOption = "Finished";
[RegistryKey] $key = $null;
@ -30,14 +44,36 @@ $null = New-Module {
[string] $Path
)
$job = Start-Job {
$env:Value = Resolve-Path $Using:Path;
$env:WSLENV = "Value/p";
$result = wsl -- bash -c 'echo "$Value"';
wsl -e printf "%q" "$result";
};
& {
$ErrorActionPreference = 'Continue';
$completed = $false;
Receive-Job -Wait $job;
while (-not $completed) {
$job = Start-Job {
$env:Value = Resolve-Path $Using:Path;
$env:WSLENV = "Value/p";
$result = wsl -- bash -c 'echo "$Value"';
wsl -e printf "%q" "$result";
};
$result = Receive-Job -Wait $job;
if ((Split-Path -Leaf $Path) -ne (Split-Path -Leaf $result)) {
Write-Error "The result of the path conversion of ``$Path`` was unexpected: ``$result``";
continue;
}
if ($job.State -ne ([System.Management.Automation.JobState]::Completed)) {
Write-Error "An error occurred while converting ``$Path`` to a Linux path.`nOutput: ``$result``";
continue;
}
$completed = $true;
}
$result;
};
}
<#
@ -79,15 +115,33 @@ $null = New-Module {
$scriptPath = "$PSScriptRoot/../../Common/Scripts/config.fish";
if (-not $IsWindows) {
$escapedPath = (fish -c 'string escape $argv' "$scriptPath");
fish -c ". $escapedPath; $Script";
} else {
function fish {
wsl --shell-type login -- nix --extra-experimental-features "nix-command flakes" run nixpkgs`#fish -- $args
if ($env:CONFIG_MODULE) {
$output = & {
if (-not $IsWindows) {
$escapedPath = (fish -c 'string escape $argv' "$scriptPath");
fish -c ". $escapedPath; $Script";
} else {
function fish {
wsl --shell-type login -- nix --extra-experimental-features "nix-command flakes" run nixpkgs`#fish -- $args
}
$output = fish -c ". $(ConvertTo-LinuxPath $scriptPath); $Script";
if (-not $?) {
Write-Error "The configuration could not be retrieved!";
} else {
$output;
}
}
}
fish -c ". $(ConvertTo-LinuxPath $scriptPath); $Script" | ConvertFrom-Json;
if (-not ($output -and ($output | Test-Json))) {
Write-Error "The value ``$output`` is not valid JSON.";
} else {
$output | ConvertFrom-Json;
}
} else {
$null;
}
}
@ -108,6 +162,22 @@ $null = New-Module {
Invoke-ConfigScript "getConfig $Name --json $ArgumentList";
}
<#
.SYNOPSIS
Gets the name of the config root.
#>
function Get-ConfigRootName {
return "valhalla.$($IsWindows ? "windows" : "linux")";
}
<#
.SYNOPSIS
Gets the name of the user root.
#>
function Get-UserRootName {
return "$(Get-ConfigRootName).$($IsWindows ? "winUsers" : "users")";
};
<#
.SYNOPSIS
Gets a user configuration.
@ -120,13 +190,13 @@ $null = New-Module {
#>
function Get-UserConfig {
param(
[string] $UserName = $env:UserName,
[string] $UserName = ($IsWindows ? $env:UserName : $env:USER),
[Parameter(Mandatory, Position = 0)]
[string] $Name
)
if ((Get-Users) -contains $UserName) {
Get-Config "valhalla.windows.users.$UserName.$Name";
Get-Config "$(Get-UserRootName).$UserName.$Name";
} else {
return $null;
}
@ -154,7 +224,7 @@ $null = New-Module {
function Get-Users {
[OutputType([string[]])]
param()
Get-Attributes "valhalla.windows.users";
Get-Attributes "$(Get-UserRootName)";
}
<#
@ -164,7 +234,7 @@ $null = New-Module {
function Get-SetupUser {
[OutputType([string])]
param()
Get-Config "valhalla.windows.setupUser";
Get-Config "$(Get-ConfigRootName).setupUser.name";
}
<#
@ -210,11 +280,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;
}
@ -229,7 +332,7 @@ $null = New-Module {
.PARAMETER Name
The name to set the current stage to.
#>
function Set-Stage {
function Set-SetupStage {
param(
$Name
)
@ -238,7 +341,86 @@ $null = New-Module {
$Name = ([SetupStage]$Name).ToString();
}
$null = Set-SetupOption $stageOption $Name;
$null = Set-SetupOption $setupStageOption $Name;
}
<#
.SYNOPSIS
Gets the current user to set up.
#>
function Get-CurrentUser {
return (Get-SetupOption $userOption) ?? 0;
}
<#
.SYNOPSIS
Sets the index of the current user to set up.
.PARAMETER Value
The index of the user to set up.
#>
function Set-CurrentUser {
param(
[int] $Value
)
Set-SetupOption $userOption $value;
}
<#
.SYNOPSIS
Gets the name of the current stage of the user setup.
#>
function Get-UserStage {
$stage = Get-SetupOption $userStageOption;
if ($null -ne $stage) {
$stage = [UserStage]$stage;
}
return $stage;
}
<#
.SYNOPSIS
Sets the current stage of the user setup.
.PARAMETER Name
The name of the stage to set.
#>
function Set-UserStage {
param(
$Name
)
if (-not (($null -eq $Name) -or ($Name -is [string]))) {
$Name = ([UserStage]$Name).ToString();
}
$null = Set-SetupOption $userStageOption $Name;
}
<#
.SYNOPSIS
Gets the name of the microsoft account to create.
#>
function Get-MSAccountName {
return Get-SetupOption $accountOption;
}
<#
.SYNOPSIS
Sets the name of the microsoft account to create.
.PARAMETER Name
The name of the microsoft account to create.
#>
function Set-MSAccountName {
param(
[string] $Name
)
Set-SetupOption $accountOption $Name;
}
<#
@ -246,7 +428,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);
}
<#
@ -273,7 +455,15 @@ $null = New-Module {
[string] $Name
)
Get-Config "valhalla.software.$Name";
Get-Config "$(Get-ConfigRootName).software.$Name";
}
<#
.SYNOPSIS
Checks whether the running system is a QEMU virtual machine.
#>
function Test-Qemu {
((Get-WmiObject win32_computersystem).Manufacturer) -eq "QEMU";
}
<#
@ -281,7 +471,7 @@ $null = New-Module {
Checks whether the current user is the setup user.
#>
function Test-SetupUser {
$env:UserName -eq (Get-Config "valhalla.windows.setupUser");
($IsWindows ? $env:UserName : $env:USER) -eq (Get-SetupUser);
}
<#

View file

@ -1,9 +1,16 @@
. "$PSScriptRoot/Config.ps1";
using namespace System.Management.Automation.Host;
. "$PSScriptRoot/../Types/OneShotTask.ps1";
. "$PSScriptRoot/../../Windows/Scripts/PowerManagement.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;
@ -11,25 +18,262 @@ $null = New-Module {
# ToDo: Store "ProgramData/PortValhalla" path somewhere as const
$errorPath = "$env:ProgramData/PortValhalla/error.txt";
$getUserName = {
"$(Get-SetupUser)OneShot";
};
$taskSetter = {
param([Nullable[OneShotTask]] $Task)
Set-SetupOption $taskOption ([string]$Task);
};
<#
.SYNOPSIS
Gets the PowerShell modules required for operating.
#>
function Get-RequiredModules {
$modules = @(
@("PSScriptAnalyzer")
) + (& {
if (-not $IsWindows) {
@()
} else {
@(
@("KnownFolders"),
@("PSWindowsUpdate"),
@("LocalAccounts", $true),
@("NuGet")
)
}
});
for ($i = 0; $i -lt $modules.Count; $i++) {
if ($modules[$i] -is [string]) {
$modules[$i] = @($modules[$i]);
}
}
}
function Start-Operation {
param(
[switch] $NonInteractive,
[switch] $NoImplicitCleanup,
[scriptblock] $Action
)
$Global:ErrorActionPreference = 'Inquire';
$env:WSLENV = "CONFIG_MODULE/p";
$cleanup = { };
$taskPending = $false;
if ($env:CONFIG_MODULE) {
$env:CONFIG_MODULE = Resolve-Path $env:CONFIG_MODULE;
if (-not $Global:InOperation) {
if ($env:DEBUG) {
Set-PSDebug -Trace 1;
}
if ($IsWindows -and ($null -ne (Get-OneShotTask))) {
$taskPending = $true;
[switch] $NonInteractive = $true;
}
$Global:InOperation = $true;
$Global:ErrorActionPreference = $NonInteractive.IsPresent ? 'Continue' : 'Inquire';
if ($IsWindows) {
$env:WSLENV = "CONFIG_MODULE/p";
if ($env:CONFIG_MODULE) {
$env:CONFIG_MODULE = Resolve-Path $env:CONFIG_MODULE;
}
New-Alias -Force "sudo" gsudo;
}
if (-not $NoImplicitCleanup.IsPresent) {
$cleanup = {
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) {
$liveScriptOption = "LiveScripts";
if (($null -eq (Get-SetupOption $liveScriptOption)) -and (Test-Qemu)) {
$result = $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);
Set-SetupOption $liveScriptOption $result;
if ($result -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 {
foreach ($module in (Get-RequiredModules)) {
$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;
}
}
}
New-Alias -Force "sudo" gsudo;
& $Action;
if ($taskPending) {
Start-OneShot;
} else {
& $Action;
}
& $cleanup;
}
<#
@ -37,7 +281,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;
}
}
<#
@ -46,12 +296,23 @@ $null = New-Module {
#>
function Enable-OneShotListener {
$tempTask = "PortValhalla Temp";
$action = New-ScheduledTaskAction -Execute "pwsh" -Argument (Get-StartupArguments);
$user = & $getUserName;
$password = [string]([guid]::NewGuid());
$adminGroup = @{
SID = [SecurityIdentifier]::new([WellKnownSidType]::BuiltinAdministratorsSid, $null);
};
$null = New-LocalUser -Name $user -Password (ConvertTo-SecureString -AsPlainText $password);
Add-LocalGroupMember -Member $user @adminGroup;
$path = "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\SpecialAccounts\UserList";
$null = New-Item -Force -ErrorAction SilentlyContinue $path;
Set-ItemProperty $path -Name $user -Value 0;
$action = New-ScheduledTaskAction -Execute "pwsh" -Argument "-Command & { $([string](Get-StartupCommand)) } 2>&1 | Tee-Object -FilePath `$env:ProgramData/PortValhalla/OneShotTask.log";
schtasks /Create /SC ONEVENT /EC $logName /MO "*[System[Provider[@Name='$logName'] and EventID=$($oneShotTrigger)]]" /TR cmd.exe /TN $tempTask;
$trigger = (Get-ScheduledTask $tempTask).Triggers;
$principal = New-ScheduledTaskPrincipal -UserId "SYSTEM" -RunLevel Highest;
$task = New-ScheduledTask -Action $action -Principal $principal -Trigger $trigger;
$null = Register-ScheduledTask -Force $oneShotTaskName -InputObject $task;
$null = Register-ScheduledTask -Force $oneShotTaskName -Action $action -Trigger $trigger -RunLevel Highest -User $user -Password $password;
$null = Unregister-ScheduledTask -Confirm:$false $tempTask;
}
@ -61,6 +322,10 @@ $null = New-Module {
#>
function Disable-OneShotListener {
Unregister-ScheduledTask -Confirm:$false $oneShotTaskName;
$user = Get-LocalUser (& $getUserName);
[string] $sid = $user.SID;
Remove-LocalUser $user;
Get-CimInstance Win32_UserProfile | Where-Object { $_.SID -eq $sid } | Remove-CimInstance;
}
<#
@ -75,8 +340,6 @@ $null = New-Module {
[OneShotTask] $Task
)
$currentStage = Get-Stage;
Set-Stage ([SetupStage]::OneShot);
& $taskSetter $Task;
& {
@ -99,16 +362,19 @@ $null = New-Module {
};
Write-EventLog -LogName $logName -Source $logName -EventId $oneShotTrigger -Message "Starting OneShot task ``$(Get-OneShotTask)``";
Remove-Event -EventIdentifier (Wait-Event -SourceIdentifier $identifier).EventIdentifier;
$null = Wait-Event -SourceIdentifier $identifier;
};
Set-Stage $currentStage;
for ($i = 0; $i -lt 2; $i++) {
Remove-Event -EventIdentifier (Wait-Event -SourceIdentifier $identifier).EventIdentifier;
}
};
if (Test-Path $errorPath) {
$errorMessage = Get-Content $errorPath;
Remove-Item $errorPath;
throw $errorMessage;
if ($errorMessage) {
Write-Error $errorMessage;
}
}
}
@ -119,19 +385,43 @@ $null = New-Module {
Executes the specified action and notifies the OneShot task executor.
#>
function Start-OneShot {
param(
[scriptblock] $Action
)
try {
Start-Operation @PSBoundParameters;
Write-Host "Running OneShot task ``$(Get-OneShotTask)``";
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.";
}
}
<#
.SYNOPSIS
Clears resources allocated during the operation.
#>
function Clear-OperationResources {
if ($IsWindows) {
Uninstall-WslDistribution;
$null = Uninstall-Package Selenium.WebDriver -ErrorAction Continue;
Uninstall-ChocoPackage 7zip.portable gsudo selenium-gecko-driver yq;
Uninstall-WingetPackage AutoHotkey.AutoHotkey;
}
foreach ($module in (Get-RequiredModules)) {
Uninstall-Module -Force -Name $module[0];
}
}
};

View file

@ -51,6 +51,7 @@ function Write-PSScript {
Import-Module PSScriptAnalyzer;
$dirName = Split-Path -Parent $FileName;
$Script = ($Script -split "\r?\n") -join [System.Environment]::NewLine;
$content = Invoke-Formatter -ScriptDefinition $Script;
$exists = Test-Path -PathType Leaf $FileName;

View file

@ -9,6 +9,64 @@ $null = New-Module {
. "$PSScriptRoot/../Types/InstallerAction.ps1";
$userArgument = "name";
$chocoRunner = {
param(
[string] $Action = 'install',
[string[]] $ArgumentList,
[scriptblock] $Guard = { $true },
[Parameter(Position = 0)]
[string] $Name,
[Parameter(ValueFromRemainingArguments = $true)]
[string[]] $AdditionalNames = @()
)
[System.Collections.ArrayList] $Names = @();
$null = $Names.Add($Name);
$Names.AddRange($AdditionalNames);
if (-not ($Force.IsPresent)) {
for ($i = $Names.Count - 1; $i -ge 0; $i--) {
$name = $Names[$i];
if (-not (& $Guard $name)) {
$Names.RemoveAt($i);
}
}
}
if ($Names.Count -ge 1) {
choco $Action -y @ArgumentList @Names;
}
};
$wingetRunner = {
param(
[string] $Action = 'install',
[string[]] $ArgumentList,
[scriptblock] $Guard = { $true },
[Parameter(Position = 0)]
[string] $Name,
[Parameter(ValueFromRemainingArguments = $true)]
[string[]] $AdditionalNames = @()
)
[System.Collections.ArrayList] $Names = @();
$null = $Names.Add($Name);
$Names.AddRange($AdditionalNames);
foreach ($name in $Names) {
if ($Force.IsPresent -or (& $Guard $name $PSBoundParameters)) {
winget $Action `
--accept-source-agreements `
--source winget `
$ArgumentList `
--exact --id $name ;
} else {
Write-Host "Package ``$name`` is already installed"
}
}
};
<#
.SYNOPSIS
Installs the specified packages using chocolatey.
@ -26,24 +84,39 @@ $null = New-Module {
[string[]] $AdditionalNames = @()
)
[System.Collections.ArrayList] $Names = @();
$null = $Names.Add($Name);
$Names.AddRange($AdditionalNames);
if (-not ($Force.IsPresent)) {
for ($i = $Names.Count - 1; $i -ge 0; $i--) {
$name = $Names[$i];
if (Test-ChocoPackage $name) {
Write-Host "Package ``$name`` is already installed"
$Names.RemoveAt($i);
}
& $chocoRunner @PSBoundParameters -Guard {
param($Name)
if (Test-ChocoPackage $Name) {
Write-Host "Package ``$Name`` is already installed"
$false;
} else {
$true;
}
}
};
}
if ($Names.Count -ge 1) {
choco install -y @ArgumentList @Names;
}
<#
.SYNOPSIS
Uninstalls the specified packages using chocolatey.
#>
function Uninstall-ChocoPackage {
param(
[string[]] $ArgumentList,
[Parameter(Position=0)]
[string] $Name,
[Parameter(ValueFromRemainingArguments = $true)]
[string[]] $AdditionalNames = @()
)
& $chocoRunner @PSBoundParameters -Action 'uninstall' -Guard {
param($Name)
if (Test-ChocoPackage $Name) {
$true;
} else {
Write-Host "Package ``$Name`` is not installed";
$false;
}
};
}
<#
@ -63,21 +136,41 @@ $null = New-Module {
[string[]] $AdditionalNames = @()
)
[System.Collections.ArrayList] $Names = @();
$null = $Names.Add($Name);
$Names.AddRange($AdditionalNames);
& $wingetRunner @PSBoundParameters `
-ArgumentList @($PSBoundParameters.ArgumentList + @("--accept-package-agreements")) `
-Guard {
param($Name, $Parameters)
if (Test-WingetPackage @Parameters) {
Write-Host "Package ``$Name`` is already installed"
$false;
} else {
$true;
}
};
}
foreach ($name in $Names) {
if ($Force.IsPresent -or -not (Test-WingetPackage $name)) {
winget install `
--accept-source-agreements --accept-package-agreements `
--source winget `
$ArgumentList `
--exact --id $name ;
<#
.SYNOPSIS
Uninstalls the specified packages using `winget`.
#>
function Uninstall-WingetPackage {
param(
[string[]] $ArgumentList,
[Parameter(Position=0)]
[string] $Name,
[Parameter(ValueFromRemainingArguments = $true)]
[string[]] $AdditionalNames = @()
)
& $wingetRunner @PSBoundParameters -Action 'uninstall' -Guard {
param($Name, $Parameters)
if (Test-WingetPackage @Parameters) {
$true;
} else {
Write-Host "Package ``$name`` is already installed"
Write-Host "Package ``$Name`` is not installed"
$false;
}
}
};
}
<#
@ -197,8 +290,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,31 +330,53 @@ $null = New-Module {
installer = $installHandler;
arguments = $Arguments;
};
if ($action -eq ([InstallerAction]::Install)) {
if ($Installer) {
Write-Host "Installing $Name";
& $Installer @argumentList;
}
# ToDo: Automatically configure after installation
} elseif ($Action -eq ([InstallerAction]::Configure)) {
if ($Configurator) {
Write-Host "Configuring $Name";
& $Configurator @argumentList;
}
if (-not (Test-SetupUser)) {
$argumentList.Add("action", [InstallerAction]::ConfigureUser);
& $installHandler @argumentList;
switch ($Action) {
([InstallerAction]::Backup) {
if ($Backup) {
Write-Host "Backing up $Name";
& $Backup @argumentList;
}
}
} elseif ($Action -eq ([InstallerAction]::ConfigureUser)) {
if ((-not $Arguments.ContainsKey($userArgument)) -or (-not $Arguments[$userArgument])) {
$Arguments.Add($userArgument, ($env:UserName));
([InstallerAction]::Install) {
if ($Installer) {
Write-Host "Installing $Name";
& $Installer @argumentList;
}
& $installHandler @argumentList -Action ([InstallerAction]::Configure);
if ($UserConfigurator -and (-not (Test-SetupUser))) {
& $installHandler @argumentList -Action ([InstallerAction]::ConfigureUser);
}
}
if ($UserConfigurator) {
Write-Host "Configuring $Name for user ``$($Arguments[$userArgument])``";
& $UserConfigurator @argumentList;
([InstallerAction]::Configure) {
if ($Configurator) {
Write-Host "Configuring $Name";
& $Configurator @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

@ -53,10 +53,11 @@ function Test-ChocoPackage {
function Test-WingetPackage {
[OutputType([bool])]
param(
[string] $ID
[string] $Name,
[string[]] $ArgumentList
)
& { $null = winget list --accept-source-agreements -e --id $ID; $?; };
& { $null = winget list --accept-source-agreements -e --id $Name @ArgumentList; $?; };
}
<#
@ -79,10 +80,14 @@ function Test-Command {
Checks whether `winget` is working properly.
#>
function Test-Winget {
(Test-Command winget) -and -not (
[System.Linq.Enumerable]::Any(
[string[]](winget source update winget),
[System.Func[string,bool]]{ param($line) $line -eq "Cancelled"; }));
(Test-Command winget) -and (
& {
$output = winget source update winget;
$? -and -not ([System.Linq.Enumerable]::Any(
[string[]]($output),
[System.Func[string,bool]]{ param($line) $line -eq "Cancelled"; }));
});
}
<#
@ -99,3 +104,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

@ -30,6 +30,27 @@ function Remove-DesktopIcon {
}
}
<#
.SYNOPSIS
Adds a new shortcut to the start menu.
.PARAMETER Name
The name of the icon to create.
.PARAMETER Target
The file to link to.
#>
function Add-StartMenuIcon {
param(
[string] $Name,
[string] $Target
)
Import-Module KnownFolders;
Import-Module "$env:ChocolateyInstall/helpers/chocolateyInstaller.psm1";
Install-ChocolateyShortcut -ShortcutFilePath "$((Get-KnownFolder "Common Programs").Path)/$Name.lnk" -TargetPath ((Get-Item $Target).FullName);
}
<#
.SYNOPSIS
Removes icons from the task bar.

View file

@ -3,18 +3,12 @@ param (
[hashtable] $Arguments
)
. "$PSScriptRoot/../aliae/Manage.ps1";
. "$PSScriptRoot/../PowerShell/Profile.ps1";
. "$PSScriptRoot/../../Scripts/Software.ps1";
. "$PSScriptRoot/../../Types/InstallerAction.ps1";
Start-SoftwareInstaller @PSBoundParameters `
-Installer {
param(
[scriptblock] $Installer
)
& $Installer -Action ([InstallerAction]::Configure);
} `
-Configurator {
Add-PowerShellProfileStatement `
-System `
@ -25,4 +19,39 @@ Start-SoftwareInstaller @PSBoundParameters `
(Get-ScriptInitializer "oh-my-posh init pwsh"),
(Get-ScriptInitializer "oh-my-posh completion powershell")
) -join [System.Environment]::NewLine)
} `
-UserConfigurator {
param(
[hashtable] $Arguments
)
$theme = Get-UserConfig "oh-my-posh.theme";
if ($theme) {
$varName = "POSH_THEME";
if ($theme -isnot [string]) {
$root = "$($IsWindows ? $env:AppData : "~/.config")/oh-my-posh";
$path = Join-Path $root "$($theme.name).omp.json";
$null = New-Item -Force -ItemType Directory $root;
Set-Content $path (
& {
if ($IsWindows) {
wsl cat $theme.source
} else {
cat $theme.source
}
});
$theme = [string] $path;
}
if ($IsWindows) {
[System.Environment]::SetEnvironmentVariable($varName, $path, "User");
} else {
. "$PSScriptRoot/../aliae/Manage.ps1";
Add-EnvironmentVariable -User $Arguments.Name $varName $path;
}
}
};

View file

@ -8,13 +8,6 @@ param (
. "$PSScriptRoot/../../Types/InstallerAction.ps1";
Start-SoftwareInstaller @PSBoundParameters `
-Installer {
param(
[scriptblock] $Installer
)
& $Installer -Action ([InstallerAction]::Configure);
} `
-Configurator {
[string] $globalDir = $null;
$indicator = "# Profile Files";

View file

@ -8,11 +8,18 @@ $null = New-Module {
.PARAMETER Name
The name of the module to install.
.PARAMETER NativeOnly
A value indicating whether the module is installed in Windows PowerShell only.
.PARAMETER NoProfile
A value indicating whether the module is not added to the profile script of users.
#>
function Get-ModuleInstallerComponents {
param(
[string] $Name,
[switch] $NativeOnly
[switch] $NativeOnly,
[switch] $NoProfile
)
@{
@ -27,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;
@ -41,7 +55,7 @@ $null = New-Module {
& $Installer -Action ([InstallerAction]::Configure) @PSBoundParameters;
};
configurator = {
configurator = ($NoProfile.IsPresent) ? { } : {
param(
[hashtable] $Arguments
)

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

@ -0,0 +1,15 @@
<#
.SYNOPSIS
Gets a powershell expression which points to the global `aliae` configuration.
#>
function Get-GlobalConfigExpression {
return "`"$($IsWindows ? "`$env:ProgramData" : "/etc")/aliae/aliae.yml`"";
}
<#
.SYNOPSIS
Gets the path to the global `aliae` configuration.
#>
function Get-GlobalConfigPath {
return & ([scriptblock]::Create((Get-GlobalConfigExpression)));
}

View file

@ -0,0 +1,50 @@
param(
$Action,
[hashtable] $Arguments
)
. "$PSScriptRoot/Constants.ps1";
. "$PSScriptRoot/../PowerShell/Profile.ps1";
. "$PSScriptRoot/../../Scripts/Software.ps1";
Start-SoftwareInstaller @PSBoundParameters `
-Configurator {
. "$PSScriptRoot/Constants.ps1";
$pathExpression = Get-GlobalConfigExpression;
$path = Get-GlobalConfigPath;
$null = New-Item -Force -ItemType Directory (Split-Path -Parent $path);
Copy-Item -Force "$PSScriptRoot/aliae.yml" $path;
Add-PowerShellProfileStatement `
-System `
-Category "aliae" `
-Script (
@(
{
#aliae
},
"`$globalPath = $pathExpression",
{
$userPath = & {
if ($env:ALIAE_CONFIG) {
$env:ALIAE_CONFIG;
} else {
"~/.aliae.yaml";
}
};
if (Test-Path $globalPath) {
$null = & ([scriptblock]::Create((aliae init pwsh --config $globalPath))) *>&1;
}
if (Test-Path $userPath) {
$null = & ([scriptblock]::Create((aliae init pwsh))) *>&1;
}
aliae completion powershell | Out-String | Invoke-Expression;
}
) -join [System.Environment]::NewLine)
} `
-UserConfigurator {
Copy-Item -Force "$PSScriptRoot/aliae.yml" ~/.aliae.yml;
};

View file

@ -0,0 +1,98 @@
$null = New-Module {
. "$PSScriptRoot/Constants.ps1";
<#
.SYNOPSIS
Adds an alias to an existing `aliae` configuration.
.PARAMETER Name
The name of the alias to add.
.PARAMETER Value
The script the alias should point to.
.PARAMETER User
The user to add the alias to.
#>
function Add-Alias {
param(
[string] $Name,
[string] $Value,
[string] $User
)
Edit-Config `
-Variables @{
Name = "$Name";
Value = "$Value";
} `
".alias |= [((. // [])[] | select(.name != env.Name))] + [{ name: env.Name, value: env.Value }]" `
-User $User;
}
<#
.SYNOPSIS
Adds an environment variable to an existing `aliae` configuration.
.PARAMETER Name
The name of the variable to add.
.PARAMETER Value
The value of the variable.
#>
function Add-EnvironmentVariable {
param(
[string] $Name,
[string] $Value,
[string] $User
)
Edit-Config `
-Variables @{
Name = "$Name";
Value = "$Value";
} `
".env |= [((. // [])[] | select(.name != env.Name))] + [{ name: env.Name, value: env.Value }]" `
-User $User;
}
<#
.SYNOPSIS
Edits the underlying `aliae` configuration.
.PARAMETER Script
The yq script to run over the configuration.
.PARAMETER User
The user to edit the configuration for.
#>
function Edit-Config {
param(
[string] $Script,
[hashtable] $Variables,
[string] $User
)
if ($User) {
$path = "$($IsWindows ? "~" : "$(sudo -u $User bash -c "realpath ~")")/.aliae.yaml";
} else {
$path = Get-GlobalConfigPath;
}
Start-Job {
$file = New-TemporaryFile;
$variables = $using:Variables;
foreach ($key in $variables.Keys) {
Set-Item "Env:\$key" $variables[$key];
}
sudo -u $using:User cp $using:path $file;
yq -yi $using:Script $file;
sudo -u $using:User cp $file $using:path;
Remove-Item $file;
} | Receive-Job -Wait;
}
Export-ModuleMember -Function Add-Alias,Add-EnvironmentVariable;
};

View file

@ -1,22 +1,4 @@
alias:
- name: totsch
value: git
env:
- name: POSH_THEME
value: '{{ if eq .OS "windows" }}{{ .Home }}/Nextcloud/.omp{{ else }}/usr/local/share/oh-my-posh/themes{{ end }}/manuel.omp.json'
alias: []
env: []
path: []
script:
- value: |
# Profile Files
$profileRoot = Split-Path -Parent $PROFILE;
$profilePaths = @(
"$profileRoot/conf.d/*.ps1",
"{{ if eq .OS "windows" }}$env:ProgramData{{ else }}/etc{{ end }}/powershell/conf.d/*.ps1"
);
foreach ($profilePath in $profilePaths) {
if (Test-Path $profilePath) {
Get-Item $profilePath | ForEach-Object { . $_; };
}
}
if: match .Shell "pwsh"
script: []

View file

@ -10,28 +10,35 @@ begin
function configureSW -V dir
source "$dir/../bash/profile.fish"
source "$dir/../fish/profile.fish"
set -l file /etc/aliae/aliae.yml
echo "export ALIAE_CONFIG=$(string escape "$file")" | sudo tee /etc/profile.d/aliae.sh > /dev/null
set -l file (pwsh -CommandWithArgs '. $args[0]; Get-GlobalConfigPath' "$dir/Constants.ps1");
sudo install -Dm644 "$dir/aliae.yml" "$file"
begin
printf %s\n \
"# aliae" \
'eval "$(aliae init bash)"' \
"if [ -f $(string escape $file) ]" \
'then' \
" eval \"\$(aliae init bash --config $(string escape $file))\"" \
'fi' \
'' \
'if [ -n "$ALIAE_CONFIG" ] && [ -f "$ALIAE_CONFIG" ] || [ -f ~/.aliae.yaml ]' \
'then' \
' eval "$(aliae init bash)"' \
'fi' \
'' \
'eval "$(aliae completion bash)"'
end | installBashProfile "aliae" "aliae"
begin
printf %s\n "" \
"# aliae" \
'eval "$(aliae init bash)"' \
'eval "$(aliae completion bash)"'
end | sudo tee /etc/skel/.bashrc > /dev/null
if type -q fish
begin
printf %s\n \
"aliae init fish | source" \
"if [ -f $(string escape $file) ]" \
" eval \"\$(aliae init bash --config $(string escape $file))\"" \
'end' \
'' \
'if [ -n "$ALIAE_CONFIG" ] && [ -f "$ALIAE_CONFIG" ] || [ -f ~/.aliae.yaml ]' \
' aliae init fish | source' \
'end' \
'' \
"aliae completion fish | source"
end | installFishProfile "aliae" "aliae"
end

View file

@ -0,0 +1,126 @@
param (
$Action,
[hashtable] $Arguments
)
. "$PSScriptRoot/../../Scripts/Software.ps1";
. "$PSScriptRoot/../../Scripts/System.ps1";
. "$PSScriptRoot/../../Types/InstallerAction.ps1";
$null = New-Module {
param(
[hashtable] $Parameters
)
$configure = {
param(
[string] $User
)
$root = "valhalla";
if ($User) {
$root = "$root$($IsWindows ? ".windows" : '').users.$User";
$sudoArgs = @("-u", $User);
$configArgs = @("--global");
} else {
$sudoArgs = @();
$configArgs = @("--system");
}
<#
.SYNOPSIS
Gets the specified git configuration.
.PARAMETER Name
THe name of the configuration to get.
#>
function Get-GitConfig {
param(
[string] $Name
)
Get-Config "$root.git.$Name";
}
<#
.SYNOPSIS
Sets a configuration option in git.
#>
function Set-GitConfig {
sudo @sudoArgs git config @configArgs $args;
}
if ((-not $IsWindows) -or $User) {
$branch = Get-GitConfig "defaultBranch";
if ($branch) {
Set-GitConfig "init.defaultBranch" $branch;
}
}
if ($User) {
$displayName = Get-UserConfig "displayName";
$mailAddress = Get-UserConfig "mailAddress";
if ($displayName) {
Set-GitConfig "user.name" $displayName;
}
if ($mailAddress) {
Set-GitConfig "user.email" $mailAddress;
}
}
# Git Flow
. {
$dir = New-TemporaryDirectory;
$key = "flow";
$mainBranch = Get-GitConfig "$key.mainBranch";
$devBranch = Get-GitConfig "$key.devBranch";
& {
git -C "$dir" init;
git -C "$dir" config user.name "PortValhalla";
git -C "$dir" config user.email "no-reply@valhal.la";
git -C "$dir" commit --allow-empty -m "Initial commit";
git -C "$dir" branch master;
git -C "$dir" branch dev;
git -C "$dir" flow init --defaults;
} | Out-Null;
if ($mainBranch) {
git -C "$dir" branch $mainBranch | Out-Null;;
sudo @sudoArgs git -C "$dir" flow config set @configArgs master $mainBranch;
}
if ($devBranch) {
git -C "$dir" branch $devBranch | Out-Null;
sudo @sudoArgs git -C "$dir" flow config set @configArgs develop $devBranch;
}
Remove-Item -Recurse -Force $dir;
};
# Aliases
[PSCustomObject] $aliases = Get-GitConfig "aliases";
if ($aliases) {
foreach ($alias in ($aliases | Get-Member -MemberType Properties)) {
Set-GitConfig "alias.$($alias.Name)" $aliases.$($alias.Name);
}
}
};
Start-SoftwareInstaller @Parameters `
-Configurator {
& $configure @PSBoundParameters;
} `
-UserConfigurator {
param(
[hashtable] $Arguments
)
& $configure -User $Arguments.Name;
};
} $PSBoundParameters;

View file

@ -0,0 +1,26 @@
param(
$Action,
[hashtable] $Arguments
)
. "$PSScriptRoot/../../../Common/Scripts/Software.ps1";
. "$PSScriptRoot/../../../Common/Scripts/SoftwareManagement.ps1";
Start-SoftwareInstaller @PSBoundParameters `
-UserConfigurator {
param(
$Arguments
)
$bins = @("codium", "codium-insiders", "code", "code-insiders");
$extensions = @("zokugun.sync-settings", "zokugun.vsix-manager");
$user = $Arguments.Name;
foreach ($bin in $bins) {
if (Test-Command "$bin") {
foreach ($extension in $extensions) {
sudo -u "$user" "$bin" --install-extension "$extension";
}
}
}
};

View file

@ -2,19 +2,9 @@
begin
set -l dir (status dirname)
source "$dir/../../Scripts/software.fish"
source "$dir/../../../Common/Software/aliae/main.fish"
function userConfig -a name
set -l bins codium codium-insiders code code-insiders
set -l extensions zokugun.{sync-settings,vsix-manager}
for bin in $bins
if type -q "$bin"
for extension in $extensions
sudo -u "$name" "$bin" --install-extension "$extension"
end
end
end
function userConfig -V dir -a name
pwsh "$dir/Main.ps1" ConfigureUser;
end
runInstaller $argv

View file

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

View file

@ -1,3 +1,4 @@
enum OneShotTask {
InitializeMSAccount
DisableUAC
}

View file

@ -1,664 +0,0 @@
#!/bin/pwsh
using namespace System.Security.Principal;
. "$PSScriptRoot/../../../scripts/Windows/Scripts/Prerequisites.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 {
Start-InstallationLoop;
};
}
<#
.SYNOPSIS
Starts the installation loop.
#>
function Start-InstallationLoop {
$wslLocation = "$env:ProgramData\PortValhalla\Ubuntu";
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
[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-Command "gsudo")) {
Install-ChocoPackage gsudo;
refreshenv;
continue;
}
if (-not (Test-Command "git")) {
Install-ChocoPackage git;
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 (-not (Test-Winget)) {
. "$PSScriptRoot/../Software/winget/Manage.ps1";
continue;
}
if (-not (& { $null = wsl --status; $?; })) {
wsl --install --no-launch;
Restart-Intermediate;
return;
}
if (-not (& { $null = wsl -l; $?; })) {
$wslRoot = Split-Path -Parent $wslLocation;
if (-not (Test-Path $wslRoot)) {
$null = New-Item -ItemType Directory $wslRoot;
}
Copy-Item -Recurse -Force (Get-AppxPackage "*Ubuntu*").InstallLocation $wslLocation;
Set-UserPermissions $wslLocation;
& "$wslLocation\ubuntu.exe" install --root;
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…";
Install-Module -AcceptLicense -Force NuGet;
Import-Module NuGet;
$null = Install-Package -Force Selenium.WebDriver -RequiredVersion 4.10.0 -SkipDependencies;
continue;
}
Install-ChocoPackage selenium-gecko-driver firefox;
Invoke-Hook "Install-PSModules" -Fallback {
Install-Module -AcceptLicense -Force PSWindowsUpdate;
Install-Module -AcceptLicense -Force PSScriptAnalyzer;
. "$PSScriptRoot/../Software/PinnedItem/Manage.ps1";
};
Set-Stage ([SetupStage]::Configure);
break;
}
([SetupStage]::OneShot) {
Write-Host "Running a OneShot task";
Start-OneShot {
Write-Host "task is-a running!";
switch (Get-OneShotTask) {
([OneShotTask]::DisableUAC) {
Disable-UAC;
Register-Setup;
}
}
};
break;
}
default {
if (-not (& { $null = wsl -l; $? })) {
wsl --import-in-place "PortValhalla" "$wslLocation/ext4.vhdx";
wsl --set-default "PortValhalla";
}
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(
[InstallerAction] $Action = $null
)
[bool] $install = $null;
$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";
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.elgatoWave") {
if (-not (Test-ChocoPackage wavelink)) {
Install-ChocoPackage wavelink -ArgumentList '--install-arguments="/norestart"';
Remove-DesktopIcon "*Wave Link*";
Restart-Intermediate;
exit;
}
}
}
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/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;
& "$commonSoftware/Oh My Posh/Manage.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 `
;
}
}
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 "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/Manage.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 `
jellyfin-media-player `
vlc `
;
Remove-DesktopIcon "VLC*";
Install-WingetPackage Ytmdesktop.Ytmdesktop;
Remove-DesktopIcon "Youtube Music*";
}
}
if (Test-Collection "coding") {
if ($install) {
Install-ChocoPackage vscode -ArgumentList "--params","/NoDesktopIcon";
Install-ChocoPackage vscodium -ArgumentList "--params","/NoDesktopIcon /AssociateWithFiles";
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 `
steam `
rayman-controlpanel `
ppsspp `
;
Remove-DesktopIcon "*Epic Games*";
Remove-DesktopIcon "*Steam*";
Remove-DesktopIcon "*PPSSPP *-Bit*";
Install-ChocoPackage ubisoft-connect -ArgumentList "--ignore-checksums";
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 (Get-Stage) {
([SetupStage]::Configure) {
if (Get-Config "valhalla.windows.dualboot.enable") {
# 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-ItemProperty $timeZoneKey -Name $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) {
Start-ValhallaUserSetup;
Set-Stage ([SetupStage]::ConfigureUser);
}
([SetupStage]::ConfigureUser) {
$userOption = "CurrentUser";
function Get-CurrentUser {
(Get-SetupOption $userOption) ?? 0;
}
function Set-CurrentUser {
param([int] $Value)
Set-SetupOption $userOption $Value;
}
[string[]] $users = Get-Users;
$currentUser = Get-CurrentUser;
if (Test-Admin) {
Disable-BootMessage;
}
if ($currentUser -lt $users.Count) {
$user = Get-LocalUser $users[$currentUser];
$msAccount = Get-UserConfig -UserName "$user" -Name "microsoftAccount";
$adminGroup = @{
SID = [SecurityIdentifier]::new([WellKnownSidType]::BuiltinAdministratorsSid, $null);
};
Add-LocalGroupMember `
@adminGroup `
$user `
-ErrorAction SilentlyContinue;
if ($env:UserName -ne "$user") {
Disable-LocalUser $env:UserName;
Enable-LocalUser $user;
if ($msAccount) {
Enable-UAC;
Disable-Autologin;
Enable-OneShotListener;
Set-BootMessage -Caption "Please Log In" -Message "Please log in using your new Microsoft Account ``$user``.";
} else {
Set-AutologinUser "$user";
}
Restart-Intermediate -DefaultUser;
return;
} else {
$configure = {
Deploy-SoftwareAction -Action ([InstallerAction]::ConfigureUser);
Remove-LocalGroupMember -Member "$user" @adminGroup -ErrorAction SilentlyContinue;
}
if ($msAccount) {
if (-not (Test-Admin)) {
Invoke-OneShot DisableUAC;
Restart-Computer;
return;
} else {
& $configure;
Clear-SetupRegistration;
Disable-OneShotListener;
}
} else {
& $configure;
}
}
Set-CurrentUser ($currentUser + 1);
continue;
}
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,276 @@
#!/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/Scripting.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 an archive you wish to restore from, if you wish to restore from a backup"
}
}
}));
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);
Restart-Intermediate;
return;
}
([SetupStage]::CreateUser) {
Install-ValhallaUsers;
Set-IsFinished $true;
}
}
}
}
}
Set-Stage ([WindowsInstallerStage]::Cleanup);
break;
}
([WindowsInstallerStage]::Cleanup) {
$taskName = "PortValhalla Cleaner";
$setupUser = Get-SetupUser;
Clear-OperationResources;
Remove-Item -Recurse -Force "C:\ProgramData\PortValhalla";
Get-SetupConfigKey | Remove-Item -Recurse -Force;
Disable-Autologin;
Disable-LocalUser $setupUser;
$script = {
param(
$TaskName,
$UserName
)
$user = Get-LocalUser $UserName;
[string] $sid = $user.SID;
Remove-LocalUser $user;
Get-CimInstance Win32_UserProfile | Where-Object { $_.SID -eq $sid } | Remove-CimInstance;
Unregister-ScheduledTask -Confirm:$false $TaskName;
};
$trigger = New-ScheduledTaskTrigger -AtStartup;
$task = New-ScheduledTaskAction -Execute "pwsh" -Argument "-Command & { $script } $(ConvertTo-Injection $taskName) $(ConvertTo-Injection $setupUser)";
$null = Register-ScheduledTask -Force $taskName -Action $task -Trigger $trigger -RunLevel Highest -User "SYSTEM";
Set-Stage ([WindowsInstallerStage]::Completed);
Restart-Intermediate -NoRegister;
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

@ -186,6 +186,20 @@ function Start-Setup {
Move-PartitionRange -Disk $Disk -1 -1 ($To + 1)
}
function Add-StartupCommand {
param(
[string] $Script,
[string] $Description
)
$installationCommand = $oobeSettings.SelectSingleNode("./ua:FirstLogonCommands/ua:SynchronousCommand[last()]", $namespace);
$newCommand = $installationCommand.ParentNode.AppendChild($installationCommand.CloneNode($true));
$newCommand.SelectSingleNode("./ua:CommandLine", $namespace).InnerText = $Script;
$orderElement = $newCommand.SelectSingleNode("./ua:Order", $namespace);
$orderElement.InnerText = ([int]($orderElement.InnerText) + 1);
$newCommand.SelectSingleNode("./ua:Description", $namespace).InnerText = $Description;
}
# Collect necessary variables
$winpePass = Get-PassSettings "windowsPE";
$setupConfig = Get-Component $winpePass "Microsoft-Windows-Setup";
@ -210,22 +224,18 @@ function Start-Setup {
foreach ($xpath in @("./ua:AutoLogon/ua:Username",
"./ua:UserAccounts/ua:LocalAccounts/ua:LocalAccount/ua:Name",
"./ua:UserAccounts/ua:LocalAccounts/ua:LocalAccount/ua:DisplayName")) {
$oobeSettings.SelectSingleNode($xpath, $namespace).InnerText = $valhallaConfig.setupUser;
$oobeSettings.SelectSingleNode($xpath, $namespace).InnerText = $valhallaConfig.setupUser.name;
}
$installationCommand = $oobeSettings.SelectSingleNode("./ua:FirstLogonCommands/ua:SynchronousCommand[last()]", $namespace);
$newCommand = $installationCommand.ParentNode.AppendChild($installationCommand.CloneNode($true));
$newCommand.SelectSingleNode("./ua:CommandLine", $namespace).InnerText = `
"powershell -Command " + `
"`$env:PWSH_PATH = $(Get-PathInjection $env:PWSH_PATH);" + `
"`$env:INSTALLER_SCRIPT = $(Get-ScriptPathInjection $env:SETUP_SCRIPT_NAME);" + `
"`$env:CONFIG_MODULE = $(Get-ScriptPathInjection $env:CONFIG_MODULE);" + `
"& (Join-Path `$env:PWSH_PATH pwsh) `$env:INSTALLER_SCRIPT;";
$orderElement = $newCommand.SelectSingleNode("./ua:Order", $namespace);
$orderElement.InnerText = ([int]($orderElement.InnerText) + 1);
$newCommand.SelectSingleNode("./ua:Description", $namespace).InnerText = "Install PowerShell Core and git and run setup script";
Add-StartupCommand `
-Script (
"powershell -Command " +
($env:DEBUG ? "`$env:DEBUG = $([int]$env:DEBUG);" : "") +
"`$env:PWSH_PATH = $(Get-PathInjection $env:PWSH_PATH);" +
"`$env:INSTALLER_SCRIPT = $(Get-ScriptPathInjection $env:SETUP_SCRIPT_NAME);" +
"`$env:CONFIG_MODULE = $(Get-ScriptPathInjection $env:CONFIG_MODULE);" +
"& (Join-Path `$env:PWSH_PATH pwsh) `$env:INSTALLER_SCRIPT;") `
-Description "Install PowerShell Core and git and run setup script";
if ($valhallaConfig.dualboot.enable) {
$diskSize = [long](ConvertFrom-Csv (wmic diskdrive where "Index=$(Get-InstallDisk)" get Size | ForEach-Object { "$_".Trim(); })).Size;

View file

@ -206,12 +206,6 @@
</SynchronousCommand> -->
<SynchronousCommand wcm:action="add">
<Order>1</Order>
<RequiresUserInput>true</RequiresUserInput>
<CommandLine>cmd /C wmic useraccount where name="Admin" set PasswordExpires=false</CommandLine>
<Description>Password Never Expires</Description>
</SynchronousCommand>
<SynchronousCommand wcm:action="add">
<Order>2</Order>
<RequiresUserInput>false</RequiresUserInput>
<CommandLine>powershell -Command "Set-ExecutionPolicy -Force Bypass"</CommandLine>
<Description>Allow PowerShell scripts from anywhere.</Description>

View file

@ -104,7 +104,7 @@ $null = New-Module {
$writer = [XmlWriter]::Create($configFile.FullName, $writerSettings);
$document.Save($writer);
$writer.Dispose();
DISM /Online "/Import-DefaultAppAssociations:$($configFile.FullName)";
$null = DISM /Online "/Import-DefaultAppAssociations:$($configFile.FullName)";
Remove-Item $configFile;
}
}

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-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 `
;
}
}
# 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

@ -26,7 +26,7 @@ $null = New-Module {
[string] $path = $null;
if ($UserKey) {
$path = "$($UserKey.PSPath)\$runOncePath";
$path = Join-Path ($UserKey.PSPath) $runOncePath;
} else {
$path = $systemRunOncePath;
}
@ -43,22 +43,17 @@ $null = New-Module {
Generates a script for executing the installer.
#>
function Get-StartupScript {
"pwsh " + (Get-StartupArguments);
"pwsh -Command " + (Get-StartupCommand);
}
<#
.SYNOPSIS
Generates arguments for running the installer using `pwsh`.
Generates a command for running the installer using `pwsh`.
#>
function Get-StartupArguments {
"-Command " +
(& {
if ($env:PWSH_PATH) {
"`$env:PWSH_PATH = $(ConvertTo-Injection $env:PWSH_PATH);"
} else {
""
}
}) +
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;";
@ -75,6 +70,8 @@ $null = New-Module {
param(
[Parameter(ParameterSetName="System")]
[switch] $System,
[Parameter(ParameterSetName="DefaultUser", Mandatory)]
[switch] $DefaultUser,
[Parameter(ParameterSetName="User", Mandatory)]
[switch] $User,
[Parameter(ParameterSetName="User")]
@ -82,6 +79,18 @@ $null = New-Module {
[RegistryKey] $UserKey
)
if ($DefaultUser.IsPresent) {
Edit-DefaultUserKey {
param(
[RegistryKey] $Key
)
Register-Setup -UserKey $Key;
}
return;
}
if ($User.IsPresent -or $UserKey) {
if (-not $UserKey) {
$UserKey = Get-Item "HKCU:\";
@ -96,6 +105,21 @@ $null = New-Module {
$key.Handle.Close();
}
<#
.SYNOPSIS
Clears leftovers from past registrations.
#>
function Clear-SetupRegistration {
Edit-DefaultUserKey {
param(
[RegistryKey] $Key
)
$runOnceKey = Get-RunOnceKey $Key;
Remove-Item $runOnceKey.PSPath;
}
}
<#
.SYNOPSIS
Sets the user to login automatically on boot.
@ -143,21 +167,22 @@ $null = New-Module {
#>
function Restart-Intermediate {
param(
[switch] $DefaultUser
[Parameter(ParameterSetName="None")]
[switch] $NoRegister,
[Parameter(ParameterSetName="Default", Mandatory)]
[switch] $DefaultUser,
[Parameter(ParameterSetName="Current", Mandatory)]
[switch] $CurrentUser
)
$register = { param($UserKey) Register-Setup @PSBoundParameters; };
if ($DefaultUser) {
Edit-DefaultUserKey {
param(
[RegistryKey] $Key
)
& $register $Key;
if (-not $NoRegister.IsPresent) {
if ($DefaultUser.IsPresent) {
Register-Setup -DefaultUser;
} elseif ($CurrentUser.IsPresent) {
Register-Setup -User;
} else {
Register-Setup;
}
} else {
& $register;
}
Restart-Computer -Force;

View file

@ -1,6 +1,8 @@
using namespace Microsoft.Win32;
$null = New-Module {
$wuPolicyPath = "HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate";
function Edit-DefaultUserKey {
param(
[scriptblock] $Action
@ -53,4 +55,12 @@ $null = New-Module {
function Disable-BootMessage {
Set-BootMessage;
}
<#
.SYNOPSIS
Resets the automatic reboot state.
#>
function Reset-WindowsUpdateAutoRestart {
Remove-Item -Recurse "$wuPolicyPath";
}
}

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) {
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) {
$null = New-Item -ItemType Directory $Target -Force;
$filePath = "$filePath/*";
}
Copy-Item -Recurse $filePath $Target -Force;
}
Remove-Item -Recurse -Force $dir;
}
}
};

View file

@ -55,7 +55,13 @@ $null = New-Module {
[FileSystemAccessRule]::new(
[SecurityIdentifier]::new([WellKnownSidType]::BuiltinUsersSid, $null),
[FileSystemRights]::FullControl,
[InheritanceFlags]::ObjectInherit -bor [InheritanceFlags]::ContainerInherit,
(& {
if (Test-Path -PathType Container $Path) {
[InheritanceFlags]::ObjectInherit -bor [InheritanceFlags]::ContainerInherit
} else {
0
}
}),
[PropagationFlags]::InheritOnly,
[AccessControlType]::Allow));

View file

@ -7,12 +7,14 @@ function Update-WindowsInstallation {
Runs the Windows update loop.
#>
function Start-UpdateLoop {
Write-Host "Preparing for Windows Update";
$null = Import-Module PSWindowsUpdate;
$hasUpdates = $false;
Write-Host "Searching for updates…";
while (((Get-WindowsUpdate -IgnoreReboot).Count -gt 0)) {
Write-Host "There are updates available.";
Write-Host "Installing updates";
$hasUpdates = $true;
try {
$null = Install-WindowsUpdate -AcceptAll -IgnoreReboot -ErrorAction "SilentlyContinue";
@ -20,14 +22,18 @@ function Update-WindowsInstallation {
catch { }
if ((Get-WURebootStatus -Silent)) {
Write-Information "A Reboot is Required!";
Write-Information "Windows will reboot now and the installation will be continued automatically.";
Write-Host "A Reboot is Required!";
Write-Host "Windows will reboot now and the installation will be continued automatically.";
return;
} else {
Write-Information "Updating Windows finished successfully!";
Write-Host "Updating Windows finished successfully!";
return;
}
}
if (-not $hasUpdates) {
Write-Host "There are no updates available.";
}
}
Start-UpdateLoop;

View file

@ -1,16 +1,125 @@
using namespace System.Management.Automation.Host;
using namespace System.Security.Principal;
$null = New-Module {
. "$PSScriptRoot/../Scripts/Deployment.ps1";
. "$PSScriptRoot/../../Common/Scripts/Config.ps1";
[string] $userOption = "SetupUser";
. "$PSScriptRoot/../../Common/Scripts/Operations.ps1";
$loggedInUserOption = "LoggedInUser";
<#
.SYNOPSIS
Creates the configured users.
Installs all pending users to the system.
#>
function Start-ValhallaUserSetup {
[int] $current = Get-SetupOption $userOption;
[string[]] $users = Get-Users;
function Install-ValhallaUsers {
$users = @(Get-Users);
$i = Get-CurrentUser;
for (; $i -lt $users.Count; $i++) {
Set-CurrentUser $i;
$name = $users[$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 -UserName "$name" "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,
[switch] $MSAccount
)
function Add-MicrosoftAccount {
param(
@ -27,7 +136,7 @@ $null = New-Module {
"Thus, you have to do it by yourself.",
"So sorry…") -join "`n");
Write-Host "Create a user for ``$Name`` manually (because Windows is too stupid)";
Write-Host "Create a user for ``$Name`` manually (because Windows is too stupid)";
$null = Read-Host "Hit enter once you're done";
$newUsers = @(Get-LocalUser | Where-Object { -not ($currentUsers -contains $_.Name) });
@ -55,10 +164,9 @@ $null = New-Module {
[ChoiceDescription[]](
& {
[ChoiceDescription]::new("&None", "None of these users is yours");
for ($i = 0; $i -lt $newUsers.Count; $i++) {
$name = "$($newUsers[$i])";
[ChoiceDescription]::new("&$($i + 1) - ``$name``", "Your user is ``$name``");
}
}), 0);
@ -75,31 +183,80 @@ $null = New-Module {
}
};
Write-Host "Renaming the new user to ``$Name``";
Rename-LocalUser $newUser $Name;
Set-MSAccountName ([string]$newUser);
}
for ($i = $current ?? 0; $i -lt $users.Count; $i++) {
Set-SetupOption $userOption $i;
$name = $users[$i];
Write-Host "Creating personal user ``$name``";
$displayName = Get-UserConfig -UserName $name "displayName";
if ($MSAccount) {
if (Test-Admin) {
Write-Host "Preparing environment for creating MS Account";
Register-Setup -DefaultUser;
Enable-OneShotListener;
Enable-UAC;
$userArguments = @{
name = $name;
};
if ($displayName) {
$userArguments.fullName = $displayName;
# Reset Windows activation status
# Otherwise the login won't work - Windows is fricking frustrating.
slmgr /upk;
slmgr /cpky;
slmgr /rearm;
Restart-Intermediate -CurrentUser;
exit;
}
}
if (Get-UserConfig -UserName $name "microsoftAccount") {
Add-MicrosoftAccount $name;
} else {
New-LocalUser -Disabled -NoPassword @userArguments;
}
Write-Host "Creating personal user ``$Name``";
Set-LocalUser @userArguments;
if ($MSAccount) {
Add-MicrosoftAccount $Name;
Set-SetupOption $loggedInUserOption $env:UserName;
Invoke-OneShot ([OneShotTask]::InitializeMSAccount);
} else {
New-LocalUser -NoPassword @userArguments;
Initialize-UserCreation;
}
}
<#
.SYNOPSIS
Prepares the first login for initializing the current user under configuration.
#>
function Initialize-UserCreation {
$name = (@(Get-Users))[(Get-CurrentUser)];
$msAccount = Get-UserConfig -UserName $name "microsoftAccount";
Write-Host "Initializing user ``$name``";
$userArguments = @{
name = $name;
};
$adminGroup = @{
SID = [SecurityIdentifier]::new([WellKnownSidType]::BuiltinAdministratorsSid, $null);
};
if ($msAccount) {
$accountName = Get-MSAccountName;
Write-Host "Renaming ``$accountName`` to ``$name``"
Rename-LocalUser $accountName $name;
}
Set-LocalUser @userArguments;
if ($msAccount) {
Disable-LocalUser (Get-SetupOption $loggedInUserOption);
} else {
Disable-LocalUser $env:UserName;
}
Add-LocalGroupMember `
@adminGroup `
$name `
-ErrorAction SilentlyContinue;
if ($msAccount) {
Disable-Autologin;
Set-BootMessage -Caption "Please Log In" -Message "Please log in using your new Microsoft Account ``$name``.";
} else {
Set-AutologinUser "$name";
}
}
};

View file

@ -0,0 +1,120 @@
. "$PSScriptRoot/../Scripts/Security.ps1";
<#
.SYNOPSIS
Gets the name of the WSL distribution used for managing the configuration.
#>
function Get-WslDistributionName {
return "ValhallaUbuntu";
}
<#
.SYNOPSIS
Gets the path to the directory containing the WSL distribution.
#>
function Get-WslDistributionPath {
return "$env:ProgramData/PortValhalla/$(Get-WslDistributionName)";
}
<#
.SYNOPSIS
Gets the path to the virtual hard disk of the WSL distribution.
#>
function Get-WslDistributionDisk {
return "$(Get-WslDistributionPath)/ext4.vhdx";
}
<#
.SYNOPSIS
Checks whether `wsl` is installed properly.
#>
function Test-Wsl {
& { $null = wsl --status; $?; };
}
<#
.SYNOPSIS
Checks whether any WSL distributions are installed for the current user.
#>
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.
#>
function Install-Wsl {
wsl --install --no-launch;
}
<#
.SYNOPSIS
Installs a Ubuntu distribution to a shared directory.
#>
function Install-WslDistribution {
$dir = Get-WslDistributionPath;
$root = Split-Path -Parent $dir;
$ubuntuPattern = "*Ubuntu*";
$registryPath = "HKCU:/Software/Microsoft/Windows/CurrentVersion/Lxss";
$key = Get-Item $registryPath;
if (Get-AppxPackage $ubuntuPattern) {
Install-Wsl;
}
if ($key) {
$key = $key | Rename-Item -NewName "$(Split-Path -Leaf $key)_" -PassThru;
}
if (-not (Test-Path $root)) {
$null = New-Item -ItemType Directory $root;
}
Copy-Item -Recurse -Force (Get-AppxPackage $ubuntuPattern).InstallLocation $dir;
Set-UserPermissions $dir;
& "$dir\ubuntu.exe" install --root;
wsl --shutdown;
Remove-Item -Recurse -Force $registryPath;
if ($key) {
Move-Item $key.PSPath $registryPath;
}
}
<#
.SYNOPSIS
Uninstalls the managed WSL distribution.
#>
function Uninstall-WslDistribution {
wsl --unregister (Get-WslDistributionName);
}
<#
.SYNOPSIS
Registers the managed WSL distribution.
#>
function Register-WslDistribution {
wsl --import-in-place (Get-WslDistributionName) (Get-WslDistributionDisk);
wsl --set-default (Get-WslDistributionName);
}
<#
.SYNOPSIS
Unregisters the managed WSL distribution.
#>
function Unregister-WslDistribution {
$wslDisk = Get-WslDistributionDisk;
wsl --shutdown;
$tempDisk = Rename-Item -Force $wslDisk "ext4_.vhdx" -PassThru;
Uninstall-WslDistribution;
Move-Item $tempDisk $wslDisk;
}

View file

@ -0,0 +1,12 @@
param (
$Action,
[hashtable] $Arguments
)
. "$PSScriptRoot/../../../Common/Scripts/Software.ps1";
. "$PSScriptRoot/../../../Common/Types/InstallerAction.ps1";
Start-SoftwareInstaller @PSBoundParameters `
-Installer {
Install-SetupPackage "https://github.com/bobranten/Ext4Fsd/releases/download/v0.71/Ext2Fsd-0.71-setup.exe";
};

View file

@ -13,7 +13,6 @@ Start-SoftwareInstaller @PSBoundParameters `
)
Install-ChocoPackage firefox;
& $Installer -Action ([InstallerAction]::Configure)
} `
-Configurator {
Write-Host "Making Firefox the default browser…";

View file

@ -3,13 +3,83 @@ param(
[hashtable] $Arguments
)
. "$PSScriptRoot/../../../Common/Scripts/Software.ps1";
. "$PSScriptRoot/../../Scripts/AppAssociations.ps1";
& {
param ($Parameters)
. "$PSScriptRoot/../../../Common/Scripts/Software.ps1";
. "$PSScriptRoot/../../Scripts/Restoration.ps1";
$configPath = "$env:LocalAppData/LGHUB";
Start-SoftwareInstaller @PSBoundParameters `
-Installer {
Install-ChocoPackage lghub;
Remove-DesktopIcon "*G HUB*";
};
<#
.SYNOPSIS
Stops the running Logitech G Hub instance.
#>
function Stop-LGHub {
[OutputType([string])]
param()
$hubName = "lghub_system_tray.exe";
$candidates = Get-Process | Where-Object { $_.Path -and ((Split-Path -Leaf $_.Path) -eq $hubName) };
if ($candidates.Count -gt 0) {
$lghubPath = $()[0].Path;
} else {
$lghubPath = $null;
}
$mainProcesses = Get-Process | Where-Object {
$_.Path -and
(@("lghub.exe", "lghub_agent.exe", "lghub_updater.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;
# ToDo: Add restoration

View file

@ -12,7 +12,6 @@ Start-SoftwareInstaller @PSBoundParameters `
)
Install-ChocoPackage MSEdgeRedirect;
& $Installer -Action ([InstallerAction]::Configure);
} `
-Configurator {
$configPath = "HKLM:\SOFTWARE\Robert Maehl Software\MSEdgeRedirect";

View file

@ -3,13 +3,44 @@ param(
[hashtable] $Arguments
)
. "$PSScriptRoot/../../../Common/Scripts/Software.ps1";
. "$PSScriptRoot/../../../Common/Scripts/System.ps1";
& {
param($Parameters)
. "$PSScriptRoot/../../Scripts/Restoration.ps1";
. "$PSScriptRoot/../../../Common/Scripts/Software.ps1";
. "$PSScriptRoot/../../../Common/Scripts/System.ps1";
$path = "$HOME/Documents/ManiaPlanet";
Start-SoftwareInstaller @PSBoundParameters `
-Installer {
Install-WingetPackage Nadeo.ManiaPlanet;
Remove-DesktopIcon "ManiaPlanet*";
};
Start-SoftwareInstaller @Parameters `
-Installer {
Install-WingetPackage Nadeo.ManiaPlanet;
Remove-DesktopIcon "ManiaPlanet*";
} `
-UserBackup {
param(
[hashtable] $Arguments
)
Add-BackupArtifacts -User $Arguments.Name -Source $path -Path "ManiaPlanet" `
-Include @(
"Actions",
"Blocks",
"Items",
"Maps",
"Media",
"Modules",
"Packs",
"Replays",
"Scripts",
"Skins"
);
} `
-UserConfigurator {
param(
[hashtable] $Arguments
)
Expand-BackupArtifacts -User $Arguments.Name -Path "ManiaPlanet" -Target $path;
};
} $PSBoundParameters;
# ToDo: Add restoration

View file

@ -22,7 +22,6 @@ Start-SoftwareInstaller @PSBoundParameters `
refreshenv;
Set-UserPermissions $env:NVS_HOME;
& $Installer -Action ([InstallerAction]::Configure);
} `
-Configurator {
nvs add latest;

View file

@ -0,0 +1,125 @@
param(
$Action,
[hashtable] $Arguments
)
. "$PSScriptRoot/../../Scripts/PowerManagement.ps1";
. "$PSScriptRoot/../../../Common/Scripts/Software.ps1";
& {
param($Parameters)
<#
.SYNOPSIS
Gets the path to the Nextcloud configuration file.
#>
function Get-ConfigFile {
return "$env:APPDATA/Nextcloud/nextcloud.cfg";
}
<#
.SYNOPSIS
Adds a new nextcloud sync to the current user.
#>
function Add-NextcloudSync {
param(
[string] $RemotePath,
[string] $LocalPath,
[switch] $VirtualFiles
)
Write-Host "Adding a Nextcloud sync";
Write-Host "$RemotePath <=> $LocalPath";
$configName = "Folders";
$virtualName = "WithPlaceholders";
$LocalPath = $LocalPath.Replace("\", "/");
$RemotePath = $RemotePath.Replace("\", "/");
$oldContent = Get-Content (Get-ConfigFile);
$additionalSettings = @();
$pattern = "^\d+\\$configName(?:$virtualName)?\\(\d+)";
$folderID = (
$oldContent | `
Where-Object { $_ -match "$pattern" } | `
ForEach-Object { $_ -replace "$pattern.*$","`$1" } | `
Sort-Object -Unique | `
Measure-Object -Maximum).Maximum + 1;
if ($VirtualFiles.IsPresent) {
$configName += $virtualName;
$additionalSettings = @("0\$configName\$folderID\virtualFilesMode=wincfapi");
}
$newSettings = (
@(
"0\$configName\$folderID\localPath=$LocalPath",
"0\$configName\$folderID\targetPath=$RemotePath"
) + $additionalSettings
) -join "`n";
& {
$accountSectionEntered = $false;
$accountSectionLeft = $false;
for ($i = 0; $i -lt $oldContent.Count; $i++) {
$line = $oldContent[$i];
if ($line -eq "[Accounts]") {
$accountSectionEntered = $true;
}
if ($line -eq "" -and $accountSectionEntered) {
$accountSectionLeft = $true;
$newSettings;
}
$line;
if (
(-not $accountSectionLeft) -and
($i -eq ($oldContent.Count - 1))) {
$newSettings;
}
}
} | Set-Content (Get-ConfigFile);
}
Start-SoftwareInstaller @Parameters `
-Installer {
Install-ChocoPackage nextcloud-client -ArgumentList "-y","--params='/KeepUpdateCheck'";
} `
-UserConfigurator {
param($Arguments)
$user = $Arguments.Name;
& {
$syncs = Get-UserConfig -UserName $user "nextcloud.folderSyncs";
$configExists = { (Test-Path (Get-ConfigFile) ) };
if ($syncs.Count -gt 0) {
if (-not (& $configExists)) {
while (-not (& $configExists)) {
Read-Host "Please log in to the Nextcloud app and hit enter to continue";
if (-not (& $configExists)) {
Write-Error -ErrorAction Continue "The login seems to have failed. Please try again.";
}
}
}
Write-Host "Stopping Nextcloud process";
$nextcloudProcess = Get-Process nextcloud;
$nextcloudPath = [string]$nextcloudProcess[0].Path;
$nextcloudProcess | Stop-Process -Force;
foreach ($sync in $syncs) {
Add-NextcloudSync -LocalPath $sync.localPath -RemotePath $sync.remotePath -VirtualFiles:$sync.virtualFiles;
}
Write-Host "Restarting Nextcloud";
Start-Process $nextcloudPath;
}
};
};
} $PSBoundParameters;

View file

@ -1,32 +0,0 @@
param(
$Action,
[hashtable] $Arguments
)
. "$PSScriptRoot/../../../Common/Scripts/Software.ps1";
Start-SoftwareInstaller @PSBoundParameters `
-Installer {
Install-ChocoPackage nextcloud-client -ArgumentList "-y","--params='/KeepUpdateCheck'";
} `
-UserConfigurator {
if (-not (Test-Path $context.GetNextcloudConfigFile())) {
Write-Information "Setting up Nextcloud configuration";
Write-Information "Ensuring all Let's Encrypt certificates are cached";
$null = Invoke-WebRequest https://valid-isrgrootx1.letsencrypt.org/;
while (-not (Test-Path $context.GetNextcloudConfigFile())) {
Write-Host "Nextcloud has been installed!";
Read-Host "Please log in in the Nextcloud app and hit enter to continue";
if (-not (Test-Path $context.GetNextcloudConfigFile())) {
Write-Error "The login seems to have failed. Please try again.";
}
}
$context.Reboot();
exit;
}
};

View file

@ -6,16 +6,18 @@ param (
. "$PSScriptRoot/../../../Common/Scripts/Software.ps1";
. "$PSScriptRoot/../../../Common/Types/InstallerAction.ps1";
Start-SoftwareInstaller @PSBoundParameters `
-Installer {
param(
[scriptblock] $Installer
)
& {
param($Parameters)
$base = "$PSScriptRoot/../../../Common/Software/Oh My Posh/Manage.ps1";
Install-WingetPackage JanDeDobbeleer.OhMyPosh -ArgumentList "--scope","machine";
& $Installer -Action ([InstallerAction]::Configure);
} `
-Configurator {
. "$PSScriptRoot/../../../Common/Software/Oh My Posh/Manage.ps1" `
-Action ([InstallerAction]::Configure);
};
Start-SoftwareInstaller @Parameters `
-Installer {
Install-WingetPackage JanDeDobbeleer.OhMyPosh -ArgumentList "--scope","machine";
} `
-Configurator {
. $base -Action ([InstallerAction]::Configure);
} `
-UserConfigurator {
. $base -Action ([InstallerAction]::ConfigureUser);
};
} $PSBoundParameters;

View file

@ -8,13 +8,6 @@ param(
. "$PSScriptRoot/../../../Common/Scripts/Software.ps1";
Start-SoftwareInstaller @PSBoundParameters `
-Installer {
param(
[scriptblock] $Installer
)
& $Installer -Action ([InstallerAction]::Configure)
} `
-Configurator {
Set-Service ssh-agent -StartupType AutomaticDelayedStart;
};

View file

@ -6,7 +6,7 @@ param (
. "$PSScriptRoot/../../../Common/Software/PowerShell/Module.ps1";
. "$PSScriptRoot/../../../Common/Scripts/Software.ps1";
$parameters = Get-ModuleInstallerComponents "PinnedItem" -NativeOnly;
$parameters = Get-ModuleInstallerComponents "PinnedItem" -NativeOnly -NoProfile;
foreach ($key in $PSBoundParameters.Keys) {
$parameters.Add($key, $PSBoundParameters.TryGetValue($key));
@ -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 -NoProfile -Command "Import-Module $module; exit ([bool]`$Error)" 2> $null; $?; })) {
$feature = "NetFx3";
if ((Get-WindowsOptionalFeature -Online -FeatureName $feature).State -ne "Enabled") {
Write-Host "Enabling ``$feature`` feature…";
choco install --source windowsFeatures -y $feature;
}
}
}

View file

@ -7,13 +7,6 @@ param (
. "$PSScriptRoot/../../../Common/Types/InstallerAction.ps1";
Start-SoftwareInstaller @PSBoundParameters `
-Installer {
param(
[scriptblock] $Installer
)
& $Installer -Action ([InstallerAction]::Configure);
} `
-Configurator {
. "$PSScriptRoot/../../../Common/Software/PowerShell/Manage.ps1" `
-Action ([InstallerAction]::Configure);

View file

@ -6,10 +6,28 @@ param(
)
. "$PSScriptRoot/../../Scripts/AppAssociations.ps1";
. "$PSScriptRoot/../../Scripts/Restoration.ps1";
. "$PSScriptRoot/../../../Common/Scripts/Software.ps1";
. "$PSScriptRoot/../../../Common/Scripts/System.ps1";
Start-SoftwareInstaller @PSBoundParameters `
-Installer {
Install-ChocoPackage putty;
} `
-UserBackup {
param([hashtable] $Arguments)
$dir = New-TemporaryDirectory;
$fileName = Join-Path "$dir" PuTTY.reg;
& reg export "HKCU\Software\SimonTatham\PuTTY" $fileName /y;
Add-BackupArtifacts -User $Arguments.Name -Source $fileName -Path "PuTTY/PuTTY.reg";
Remove-Item -Recurse -Force $dir;
} `
-UserConfigurator {
param([hashtable] $Arguments)
$dir = New-TemporaryDirectory;
$fileName = Join-Path "$dir" PuTTY.reg;
Expand-BackupArtifacts -User $Arguments.Name -Path "PuTTY/PuTTY.reg" -Target $fileName;
& reg import $fileName;
Remove-Item -Recurse -Force $dir;
};
# ToDo: Add restoration

View file

@ -3,13 +3,34 @@ param(
[hashtable] $Arguments
)
. "$PSScriptRoot/../../../Common/Scripts/Software.ps1";
Start-SoftwareInstaller @PSBoundParameters `
-Installer {
Install-ChocoPackage retroarch;
# ToDo: Add start menu shortcut
# ToDo: Add function for this purpose
};
$null = New-Module {
param($Parameters)
. "$PSScriptRoot/../../Scripts/Restoration.ps1";
. "$PSScriptRoot/../../../Common/Scripts/Software.ps1";
. "$PSScriptRoot/../../../Common/Scripts/System.ps1";
$path = "C:/tools/RetroArch-Win64";
# ToDo: Add restoration
Start-SoftwareInstaller @Parameters `
-Backup {
Add-BackupArtifacts -Path "RetroArch" -Source $path `
-Include @(
"config",
"cores",
"downloads",
"playlists",
"recordings",
"screenshots",
"content_history.lpl",
"content_*_history.lpl",
"retroarch.cfg"
);
} `
-Installer {
Install-ChocoPackage retroarch;
} `
-Configurator {
Add-StartMenuIcon "RetroArch" "C:\tools\RetroArch-Win64\retroarch.exe";
Expand-BackupArtifacts -Path "RetroArch" -Target $path;
};
} $PSBoundParameters;

View file

@ -15,7 +15,6 @@ Start-SoftwareInstaller @PSBoundParameters `
)
Install-ChocoPackage thunderbird -ArgumentList "--params",'"/NoTaskbarShortcut /NoDesktopShortcut"'
& $Installer -Action ([InstallerAction]::Configure)
} `
-Configurator {
Write-Host "Making Thunderbird the default mail program…";

View file

@ -3,19 +3,42 @@ param(
[hashtable] $Arguments
)
. "$PSScriptRoot/../../../Common/Scripts/Software.ps1";
Start-SoftwareInstaller @PSBoundParameters `
-Installer {
foreach ($feature in @("DirectPlay", "NetFx3")) {
if ((Get-WindowsOptionalFeature -Online -FeatureName $feature).State -ne "Enabled") {
Write-Information "Enabling the ``$feature`` feature…";
choco install --source windowsFeatures -y $feature;
& {
param($Parameters)
. "$PSScriptRoot/../../Scripts/Restoration.ps1";
. "$PSScriptRoot/../../../Common/Scripts/Software.ps1";
$path = "$HOME/Documents/TmForever";
Start-SoftwareInstaller @Parameters `
-Installer {
foreach ($feature in @("DirectPlay", "NetFx3")) {
if ((Get-WindowsOptionalFeature -Online -FeatureName $feature).State -ne "Enabled") {
Write-Information "Enabling the ``$feature`` feature…";
choco install --source windowsFeatures -y $feature;
}
}
Install-WingetPackage Nadeo.TrackManiaNationsForever;
Remove-DesktopIcon "*TmNationsForever*";
}
};
# ToDo: Add restoration
} `
-UserBackup {
param([hashtable] $Arguments)
$name = $Arguments.Name;
Add-BackupArtifacts -User $name -Source $path -Path "TmNationsForever" `
-Include @(
"ChallengeMusics",
"MediaTracker",
"MenuMusics",
"Painter",
"Scores",
"Skins",
"Tracks"
);
} `
-UserConfigurator {
param([hashtable] $Arguments)
$name = $Arguments.Name;
Expand-BackupArtifacts -User $name -Path "TmNationsForever" -Target $path;
};
} $PSBoundParameters;

View file

@ -3,10 +3,15 @@ param(
[hashtable] $Arguments
)
. "$PSScriptRoot/../../../Common/Scripts/Software.ps1";
. "$PSScriptRoot/../../../Common/Scripts/System.ps1";
Start-SoftwareInstaller @PSBoundParameters `
& {
param($Parameters)
. "$PSScriptRoot/../../Scripts/Restoration.ps1";
. "$PSScriptRoot/../../../Common/Scripts/Software.ps1";
. "$PSScriptRoot/../../../Common/Scripts/System.ps1";
$path = "$HOME/Documents/TrackMania";
Start-SoftwareInstaller @Parameters `
-Installer {
$file = "TmUnitedForever.exe";
$dir = New-TemporaryDirectory;
@ -28,6 +33,21 @@ Start-SoftwareInstaller @PSBoundParameters `
$null = Pop-Location;
Remove-Item -Recurse $dir;
} `
-UserBackup {
param([hashtable] $Arguments)
Add-BackupArtifacts -User $Arguments.Name -Source $path -Path "TmUnitedForever" `
-Include @(
"ChallengeMusics",
"MediaTracker",
"MenuMusics",
"Scores",
"Skins",
"Tracks"
);
} `
-UserConfigurator {
param([hashtable] $Arguments)
Expand-BackupArtifacts -User $Arguments.Name -Path "TmUnitedForever" -Target $path;
};
# ToDo: Add restoration
} $PSBoundParameters;

View file

@ -6,6 +6,8 @@ param(
& {
param($parameters)
. "$PSScriptRoot/../../Scripts/Restoration.ps1";
. "$PSScriptRoot/../../../Common/Scripts/SoftwareManagement.ps1";
. "$PSScriptRoot/../../../Common/Scripts/BrowserAutomation.ps1";
. "$PSScriptRoot/../../../Common/Scripts/Software.ps1";
. "$PSScriptRoot/../../../Common/Scripts/System.ps1";
@ -16,19 +18,65 @@ param(
[System.Tuple]::Create("visualstudio2022enterprise", "VisualStudio.17.Release", "Microsoft.VisualStudio.Product.Enterprise"),
[System.Tuple]::Create("visualstudio2022community", "VisualStudio.17.Release", "Microsoft.VisualStudio.Product.Community")
);
<#
.SYNOPSIS
Gets the path to the Visual Studio Installer.
#>
function Get-InstallerPath {
return "$((Get-KnownFolder ProgramFilesX86).Path)/Microsoft Visual Studio/Installer/vs_installer.exe";
}
<#
.SYNOPSIS
Gets the path to the configuration file in the backup archive.
.PARAMETER PackageName
The name of the package to get the configuration for.
#>
function Get-ConfigPath {
param(
[string] $PackageName
)
return Join-Path "Visual Studio" "$PackageName.vsconfig";
}
Start-SoftwareInstaller @parameters `
-Backup {
foreach ($version in $versions) {
if (Test-ChocoPackage $version[0]) {
Write-Host "Backing up ``$($version[0])";
$configFile = New-TemporaryFile;
Start-Process -FilePath (Get-InstallerPath) -Wait `
-ArgumentList @(
"export",
"--channelId", $version[1],
"--productId", $version[2],
"--config", $configFile,
"--quiet"
);
Add-BackupArtifacts -Source $configFile -Path (Get-ConfigPath $version[0]);
Remove-Item $configFile;
}
}
} `
-Installer {
foreach ($version in $versions) {
$packageName = $version[0];
Write-Host "Installing ``$packageName``";
Install-ChocoPackage $packageName;
$file = New-TemporaryFile;
Remove-Item $file;
Expand-BackupArtifacts -Path (Get-ConfigPath $packageName) -Target $file;
if (Test-Path $file) {
Write-Host "Restoring ``$packageName``";
Install-ChocoPackage $packageName -ArgumentList "--params","--config `"$file`"";
}
}
Remove-DesktopIcon "CocosCreator*";
Remove-DesktopIcon "Unity Hub*";
};
# ToDo: Add restoration
# Only restore version if it has been backed up
} $PSBoundParameters;

View file

@ -11,12 +11,7 @@ param(
Start-SoftwareInstaller @PSBoundParameters `
-Installer {
param(
[scriptblock] $Installer
)
Install-ChocoPackage winscp;
& $Installer -Action ([InstallerAction]::Configure)
} `
-Configurator {
Remove-DesktopIcon "WinSCP*";

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,19 +5,40 @@ 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 `
-Installer {
param(
[scriptblock] $Installer
)
$null = New-Module {
param($Parameters)
& $Installer -Action ([InstallerAction]::Configure)
. "$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;
@ -61,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";
};
}
@ -143,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,23 @@
param (
$Action,
[hashtable] $Arguments
)
. "$PSScriptRoot/../../../Common/Scripts/Software.ps1";
. "$PSScriptRoot/../../../Common/Types/InstallerAction.ps1";
& {
param($Parameters)
$base = "$PSScriptRoot/../../../Common/Software/aliae/Manage.ps1";
Start-SoftwareInstaller @Parameters `
-Installer {
Install-WingetPackage JanDeDobbeleer.Aliae;
} `
-Configurator {
. $base -Action ([InstallerAction]::Configure);
} `
-UserConfigurator {
. $base -Action ([InstallerAction]::ConfigureUser);
};
} $PSBoundParameters;

View file

@ -8,13 +8,6 @@ param(
. "$PSScriptRoot/../../../Common/Scripts/Software.ps1";
Start-SoftwareInstaller @PSBoundParameters `
-Installer {
param(
[scriptblock] $Installer
)
& $Installer -Action ([InstallerAction]::Configure)
} `
-Configurator {
[string] $backup = $null;
$nativeProfile = powershell -c '$PROFILE';

View file

@ -0,0 +1,39 @@
param (
$Action,
[hashtable] $Arguments
)
. "$PSScriptRoot/../../../Common/Types/InstallerAction.ps1";
. "$PSScriptRoot/../../../Common/Scripts/Software.ps1";
. "$PSScriptRoot/../../../Common/Scripts/Config.ps1";
& {
param(
[hashtable] $Parameters
)
. "$PSScriptRoot/../../../Common/Types/InstallerAction.ps1";
$base = "$PSScriptRoot/../../../Common/Software/git/Manage.ps1";
Start-SoftwareInstaller @Parameters `
-Installer {
$params = "/WindowsTerminalProfile";
$defaultBranch = Get-Config "valhalla.git.defaultBranch";
if ($defaultBranch) {
$params += " /DefaultBranchName:`"$defaultBranch`"";
}
Install-ChocoPackage git -ArgumentList "--params",$params;
} `
-Configurator {
& $base ([InstallerAction]::Configure);
} `
-UserConfigurator {
param(
$Arguments
)
& $base ([InstallerAction]::ConfigureUser) @PSBoundParameterrs;
};
} $PSBoundParameters;

View file

@ -5,10 +5,45 @@ param(
. "$PSScriptRoot/../../../Common/Scripts/Software.ps1";
Start-SoftwareInstaller @PSBoundParameters `
-Installer {
Install-ChocoPackage osu;
Remove-DesktopIcon "*osu*";
};
$null = New-Module {
param($Parameters)
. "$PSScriptRoot/../../Scripts/Restoration.ps1";
Export-ModuleMember -Function @();
# ToDo: Add restoration
<#
.SYNOPSIS
Gets the path to the installation directory of osu!.
#>
function Get-InstallPath {
return "$((Get-KnownFolder -SpecialFolder ProgramFilesX86).Path)/osu!";
}
Start-SoftwareInstaller @Parameters `
-Installer {
Install-ChocoPackage osu;
Remove-DesktopIcon "*osu*";
} `
-Backup {
Add-BackupArtifacts -Source (Get-InstallPath) -Path "osu!" `
-Include @(
"Screenshots",
"Skins",
"Songs",
"osu!.cfg",
"scores.db"
);
} `
-Configurator {
Expand-BackupArtifacts -Path "osu!" -Target (Get-InstallPath);
} `
-UserBackup {
param([hashtable] $Arguments)
$name = $Arguments.Name;
Add-BackupArtifacts -Source "$(Get-InstallPath)/osu!.$name.cfg" -User $name -Path "osu!/osu!.cfg";
} `
-UserConfigurator {
param([hashtable] $Arguments)
$name = $Arguments.Name;
Expand-BackupArtifacts -User $name -Path "osu!/osu!.cfg" -Target "$(Get-InstallPath)/osu!.$name.cfg";
};
} $PSBoundParameters;

View file

@ -3,29 +3,30 @@ param(
[hashtable] $Arguments
)
. "$PSScriptRoot/../../../Common/Scripts/Software.ps1";
. "$PSScriptRoot/../../../Common/Scripts/System.ps1";
& {
param($Parameters)
. "$PSScriptRoot/../../Scripts/Restoration.ps1";
. "$PSScriptRoot/../../../Common/Scripts/Software.ps1";
. "$PSScriptRoot/../../../Common/Scripts/System.ps1";
$path = "$env:AppData/osu";
Start-SoftwareInstaller @PSBoundParameters `
-Installer {
$file = "osu!lazer.exe";
$processName = "osu!";
$dir = New-TemporaryDirectory;
Push-Location $dir;
Invoke-WebRequest "https://github.com/ppy/osu/releases/latest/download/install.exe" -OutFile $file;
Start-Process -FilePath $file;
while (-not (Get-Process -ErrorAction SilentlyContinue $processName)) {
Start-Sleep 1;
}
Start-Sleep 10;
Get-Process $processName | Stop-Process -Force;
Pop-Location;
Remove-Item -Recurse $dir;
Remove-DesktopIcon "*osu*";
};
# ToDo: Add restoration
Start-SoftwareInstaller @Parameters `
-UserBackup {
param([hashtable] $Arguments)
Add-BackupArtifacts -User $Arguments.Name -Source $path -Path "osu!lazer" `
-Include @(
"files",
"rulesets",
"screenshots",
"framework.ini",
"game.ini",
"input.json"
);
} `
-UserConfigurator {
param([hashtable] $Arguments)
Install-WingetPackage "ppy.osu" -ArgumentList "--scope","user";
Remove-DesktopIcon "*osu*";
Expand-BackupArtifacts -User $Arguments.Name -Path "osu!lazer" -Target $path;
};
} $PSBoundParameters;

View file

@ -3,20 +3,42 @@ param(
[hashtable] $Arguments
)
. "$PSScriptRoot/../../../Common/Scripts/BrowserAutomation.ps1";
. "$PSScriptRoot/../../../Common/Scripts/Software.ps1";
. "$PSScriptRoot/../../../Common/Scripts/System.ps1";
& {
param($Parameters)
. "$PSScriptRoot/../../Scripts/Restoration.ps1";
. "$PSScriptRoot/../../../Common/Scripts/BrowserAutomation.ps1";
. "$PSScriptRoot/../../../Common/Scripts/Software.ps1";
. "$PSScriptRoot/../../../Common/Scripts/System.ps1";
Start-SoftwareInstaller @PSBoundParameters `
-Installer {
Write-Host "Downloading reWASD…";
$dir = New-TemporaryDirectory;
$file = Start-BrowserDownload -URL "https://rewasd.com/" -ButtonSelector 'a.btn-default[href="#"]' -OutDir $dir;
$path = "$env:Public/Documents/reWASD";
Write-Host "Installing reWASD…";
Start-Process -Wait -FilePath $($file.FullName) -ArgumentList "/S";
Remove-Item -Recurse $dir;
Remove-DesktopIcon "*reWASD*";
};
Start-SoftwareInstaller @Parameters `
-Backup {
Add-BackupArtifacts -Path "reWASD" -Source $path `
-Exclude @(
"Logs",
"Presets",
"Profiles/Destop",
"Profiles/Duality",
"Profiles/Fortnite",
"Profiles/PS4 Remote*",
"Profiles/Switch console",
"Profiles/Switch to Xbox 360",
"Profiles/Valorant",
"Profiles/xCloud"
);
} `
-Installer {
Write-Host "Downloading reWASD…";
$dir = New-TemporaryDirectory;
$file = Start-BrowserDownload -URL "https://rewasd.com/" -ButtonSelector 'a.btn-default[href="#"]' -OutDir $dir -Timeout 1;
# ToDo: Add restoration
Write-Host "Installing reWASD…";
Start-Process -Wait -FilePath $($file.FullName) -ArgumentList "/S";
Remove-Item -Recurse $dir;
Remove-DesktopIcon "*reWASD*";
} `
-Configurator {
Expand-BackupArtifacts -Path "reWASD" -Target $path;
};
} $PSBoundParameters;

View file

@ -0,0 +1,28 @@
param(
$Action,
[hashtable] $Arguments
)
& {
param (
[hashtable] $Parameters
)
. "$PSScriptRoot/../../../Common/Scripts/Software.ps1";
. "$PSScriptRoot/../../../Common/Types/InstallerAction.ps1";
$base = "$PSScriptRoot/../../../Common/Software/vscode/Main.ps1";
Start-SoftwareInstaller @Parameters `
-Installer {
Install-ChocoPackage vscode -ArgumentList "--params","/NoDesktopIcon";
Install-ChocoPackage vscodium -ArgumentList "--params","/NoDesktopIcon /AssociateWithFiles";
refreshenv;
} `
-UserConfigurator {
param(
$Arguments
)
& $base ([InstallerAction]::ConfigureUser) @PSBoundParameters;
};
} $PSBoundParameters;

View file

@ -14,7 +14,6 @@ Start-SoftwareInstaller @PSBoundParameters `
Install-ChocoPackage zoxide;
Install-WingetPackage junegunn.fzf;
& $Installer -Action ([InstallerAction]::Configure);
} `
-Configurator {
Add-PowerShellProfileStatement `

View file

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

View file

@ -1,11 +1,19 @@
#!/bin/env fish
begin
set -l varName WIN11_IMAGE_PATH
set -l $varName
set -l dir (status dirname)
source "$dir/lib/choose-disk.fish"
set $varName (bash -c ". $(string escape $dir)/.env; echo \$$varName" 2> /dev/null)
set -q WIN11_IMAGE_PATH
[ ! -z "$$varName" ]
or begin
echo "Please specify the Windows 11 ISO in the `WIN11_IMAGE_PATH` variable."
if [ ! -f "$dir/.env" ]
cp $dir/.env.template $dir/.env
end
echo "Please epecify the path to the Windows 11 ISO image in your .env file located at:"
realpath --relative-to (pwd) (realpath $dir/.env)
exit 1
end
@ -13,6 +21,10 @@ begin
sed "s/\//\\\\/g"
end
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"
@ -20,9 +32,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)
@ -131,6 +143,13 @@ begin
"$git[5]\\bin"
) \
"set SETUP_LABEL=$setupLabel" \
(
begin
if [ -n "$_flag_debug" ]
echo "set DEBUG=1"
end
end
) \
"set PWSH_PATH=$(echo "$pwshPath" | mkWinPath)" \
"set LOCAL_PROJECT_PATH=$(echo "$localProjectPath" | mkWinPath)" \
"set REMOTE_PROJECT_PATH=$(echo "$projectPath" | mkWinPath)" \
@ -147,7 +166,7 @@ begin
end
mkdir -p "$(dirname "$winpe")"
sudo mount --mkdir "$WIN11_IMAGE_PATH" "$winPath"
sudo mount --mkdir $$varName "$winPath"
mkwinpeimg --iso --arch amd64 --overlay "$winpeOverlay" --windows-dir "$winPath" "$winpe"
sudo mount --mkdir "$winpe" "$winpePath"
@ -192,7 +211,7 @@ begin
find "$projectPath/profiles" -type f -name "*.nix" | while read -l file
set -l CONFIG_MODULE "$file"
getConfig "valhalla.windows" --json > "$file.json"
getConfig "valhalla.windows.config" --json > "$file.json"
end
end
@ -218,8 +237,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" \

View file

@ -1,25 +0,0 @@
#!/bin/bash
WIN_DISK="${WIN_DISK}";
workingDir="$(pwd)";
pushd "${BASH_SOURCE%/*}" > /dev/null;
. "./.env" > /dev/null 2>&1;
if [ ! -z "$WIN11_IMAGE_PATH" ]
then
WIN11_IMAGE_PATH="$(bash -c "realpath $WIN11_IMAGE_PATH")";
fi;
if [ ! -f "$WIN11_IMAGE_PATH" ]
then
if [ ! -f "./.env" ]
then
cp .env.template .env;
fi;
echo "Please specify the path to the Windows 11 ISO image in your .env file located at:";
realpath --relative-to "$workingDir" "$(realpath .env)";
else
WIN11_IMAGE_PATH="$WIN11_IMAGE_PATH" fish ./deploy.fish;
fi;
popd > /dev/null;