Compare commits

...

272 commits

Author SHA1 Message Date
Manuel Thalmann 91e5d860e7 Exclude unnecessary files from backup 2024-09-10 02:39:37 +02:00
Manuel Thalmann 4191d5e89d Add a word of warning after backup 2024-09-10 02:39:09 +02:00
Manuel Thalmann 513d873f0f Add a script for creating backups 2024-09-10 02:39:09 +02:00
Manuel Thalmann 61b898fdd5 Force profile selection for Windows installation actions 2024-09-10 02:39:09 +02:00
Manuel Thalmann 74273705ee Force line endings of Unix scripts 2024-09-10 02:39:09 +02:00
Manuel Thalmann 190248828d Start setup automatically 2024-09-10 02:39:09 +02:00
Manuel Thalmann c1b9674ff0 Show profile selection during setup 2024-09-10 02:39:09 +02:00
Manuel Thalmann 6962f6d323 Add a function for selecting the profile 2024-09-10 02:39:09 +02:00
Manuel Thalmann b8c8fb28f3 Use same installer script for all profiles 2024-09-10 02:39:09 +02:00
Manuel Thalmann d42320ce4a Fix non-functioning WSL installation 2024-09-10 02:39:09 +02:00
Manuel Thalmann 139cf706fc Make Oh-My-Posh theme location dynamic 2024-09-10 02:39:09 +02:00
Manuel Thalmann b74e9c632e Improve performance 2024-09-10 02:39:09 +02:00
Manuel Thalmann d1a0e38805 Update Selenium to the newest version 2024-09-10 02:39:09 +02:00
Manuel Thalmann 03c4f8012f Switch to named flakes 2024-09-10 02:39:09 +02:00
Manuel Thalmann 6e7bfed63e Store user related options properly 2024-09-10 02:39:09 +02:00
Manuel Thalmann e47e98b804 Refactor the directory structure 2024-09-10 02:39:09 +02:00
Manuel Thalmann eee70fdf2a Add code for cleaning up after installations 2024-09-10 02:39:09 +02:00
Manuel Thalmann ae0913e2ef Add functions for uninstalling packages 2024-09-10 02:39:09 +02:00
Manuel Thalmann d10dd9205c Improve assignments of groups 2024-09-10 02:39:09 +02:00
Manuel Thalmann ea3935e737 Remove unnecessary policy change 2024-09-10 02:39:09 +02:00
Manuel Thalmann 4e793a3a83 Migrate winiso script to fish 2024-09-10 02:39:09 +02:00
Manuel Thalmann d3cafda83a Ask for live scripts only once 2024-09-10 02:39:09 +02:00
Manuel Thalmann 6a852059fb Install Ubuntu automatically 2024-09-10 02:39:09 +02:00
Manuel Thalmann f410c33972 Add a backup script for reWASD 2024-09-10 02:39:09 +02:00
Manuel Thalmann 90f97848ce Add a backup script for Visual Studio 2024-09-10 02:39:09 +02:00
Manuel Thalmann 2397a1919d Allow backing up TrackMania Forever 2024-09-10 02:39:09 +02:00
Manuel Thalmann a8bc078525 Allow testing winget packages with specific scope 2024-09-10 02:39:09 +02:00
Manuel Thalmann 69a61e6002 Allow backing up RetroArch 2024-09-10 02:39:09 +02:00
Manuel Thalmann 0a83eb7e10 Add scripts for backing up PuTTY 2024-09-10 02:39:09 +02:00
Manuel Thalmann fb90448395 Add scripts for backing up osu! 2024-09-10 02:39:09 +02:00
Manuel Thalmann 7127bae277 Install osu!lazer per user 2024-09-10 02:39:09 +02:00
Manuel Thalmann 83101c8873 Add backup support for ManiaPlanet 2024-09-10 02:39:09 +02:00
Manuel Thalmann 9c6f6a85e5 Add scripts for backing up and restoring LGHub 2024-09-10 02:39:08 +02:00
Manuel Thalmann d33940c38c Allow users to restore a backup 2024-09-10 02:36:02 +02:00
Manuel Thalmann 6e6cef4392 Add scripts for backing up and restoring personal files 2024-09-10 02:36:02 +02:00
Manuel Thalmann 621e0842ed Fix non-functioning profile script 2024-09-10 02:36:02 +02:00
Manuel Thalmann 5dd9205437 Ensure 7z is installed for backups 2024-09-10 02:36:02 +02:00
Manuel Thalmann 1581ddc80c Streamline restoration of directories 2024-09-10 02:36:02 +02:00
Manuel Thalmann a107654d40 Set a default path for backup artifacts 2024-09-10 02:36:02 +02:00
Manuel Thalmann 372e75d655 Add capabilities to back up apps 2024-09-10 02:36:02 +02:00
Manuel Thalmann 678c56cf78 Allow specifying a backup action 2024-09-10 02:36:02 +02:00
Manuel Thalmann 66779b42cc Ignore unspecified backup archives 2024-09-10 02:36:02 +02:00
Manuel Thalmann 01791b293c Ignore inexistent backup artifacts 2024-09-10 02:36:02 +02:00
Manuel Thalmann 1e35fa150f Make the install script action agnostic 2024-09-10 02:36:02 +02:00
Manuel Thalmann 8c7d22a780 Rename the Windows installer script 2024-09-10 02:36:02 +02:00
Manuel Thalmann fa3e8cf821 Rename outdated script 2024-09-10 02:36:02 +02:00
Manuel Thalmann 253331ea7a Silence errors concerning empty aliae configurations 2024-09-10 02:36:02 +02:00
Manuel Thalmann afd1f38a81 Make Operations script cross platform 2024-09-10 02:36:02 +02:00
Manuel Thalmann 10a64e3424 Handle OneShot tasks only on Windows 2024-09-10 02:36:02 +02:00
Manuel Thalmann a381e0e892 Add a script for managing backups 2024-09-10 02:36:02 +02:00
Manuel Thalmann 1abc314a51 Add tools for managing aliae 2024-09-10 02:36:02 +02:00
Manuel Thalmann 597dcc9b83 Fix non-functioning aliae installation 2024-09-10 02:36:02 +02:00
Manuel Thalmann 36ae05b90d Create dedicated script for creating users 2024-09-10 02:36:02 +02:00
Manuel Thalmann 5991878f2d Create dedicated script for installing software 2024-09-10 02:36:02 +02:00
Manuel Thalmann 08b3f2d1e9 Prevent reading nix config multiple times 2024-09-10 02:36:02 +02:00
Manuel Thalmann b54ec95a7a Ensure only one user is enabled at once 2024-09-10 02:36:02 +02:00
Manuel Thalmann 6346644f76 Prevent unnecessary file creation 2024-09-10 02:36:02 +02:00
Manuel Thalmann 0a586e3323 Execute OneShot tasks in any operation 2024-09-10 02:36:02 +02:00
Manuel Thalmann ecaf4ff7b0 Use /mnt as mount directory 2024-09-10 02:36:02 +02:00
Manuel Thalmann e232b1ce9b Force the use of the managed distribution 2024-09-10 02:36:02 +02:00
Manuel Thalmann 1dcf168a9f Initialize operation for all users 2024-09-10 02:36:01 +02:00
Manuel Thalmann b1a15cfd66 Handle initialization in operation code 2024-08-27 04:15:37 +02:00
Manuel Thalmann 6a38a943c0 Execute script non-interactive during OneShot tasks 2024-08-27 03:50:08 +02:00
Manuel Thalmann 12f0b4aebe Exit script after running OneShot task 2024-08-27 03:45:44 +02:00
Manuel Thalmann 96818ef702 Modify user after first login 2024-08-27 03:27:54 +02:00
Manuel Thalmann a6a2b6331e Rearm Windows Activation before creating MSAcc 2024-08-27 03:25:19 +02:00
Manuel Thalmann 867553c479 Register MSAcc logon script early 2024-08-27 03:24:37 +02:00
Manuel Thalmann d8e31c4361 Allow rebooting without registering setup 2024-08-27 03:11:35 +02:00
Manuel Thalmann 5d89828dc4 Fix non-functioning NoProfile argument 2024-08-27 02:09:04 +02:00
Manuel Thalmann 9961690fea Prevent unnecessary installation actions 2024-08-27 01:57:46 +02:00
Manuel Thalmann 1ed75d314e Only install PowerShell module if necessary 2024-08-27 01:25:32 +02:00
Manuel Thalmann cb24c6bf17 Streamline PowerShell installation 2024-08-27 00:45:46 +02:00
Manuel Thalmann 8faaef98c9 Add further functionality to the WSL script 2024-08-27 00:38:46 +02:00
Manuel Thalmann 6f9437002a Create a separate script for WSL interaction 2024-08-26 23:33:46 +02:00
Manuel Thalmann 3b9c291689 Fix recursive configuration 2024-08-25 03:58:28 +02:00
Manuel Thalmann 171f34bd57 Fix malformed module 2024-08-24 18:35:43 +02:00
Manuel Thalmann fe63a74d88 Keep Windows fixes separate 2024-08-24 16:56:29 +02:00
Manuel Thalmann 42e9b3ddf1 Remove WSL after operation 2024-08-24 16:52:41 +02:00
Manuel Thalmann 8ddce6410a Make distribution name unique 2024-08-24 16:41:05 +02:00
Manuel Thalmann 846e3fee5a Streamline WSL distribution name 2024-08-24 16:27:34 +02:00
Manuel Thalmann 9a62c37880 Remove unused resources after user setup 2024-08-24 16:15:10 +02:00
Manuel Thalmann 85dd40fcbc Print update logs properly 2024-08-24 14:47:51 +02:00
Manuel Thalmann bf0c7abcc3 Allow overriding Windows settings 2024-08-24 14:20:22 +02:00
Manuel Thalmann d83b64608a Update incorrect path 2024-08-24 14:11:38 +02:00
Manuel Thalmann 1d4a62b7e2 Simplify osu!lazer installation 2024-08-24 14:10:02 +02:00
Manuel Thalmann 17e7699179 Determine name of setup user properly 2024-08-24 14:01:05 +02:00
Manuel Thalmann 41e79cdf07 Make OMP configuration platform independent 2024-08-24 13:27:48 +02:00
Manuel Thalmann a298518f37 Fix incorrect character in OMP theme 2024-08-24 13:27:35 +02:00
Manuel Thalmann d0fd6fcc61 Remove unnecessary code 2024-08-24 04:25:07 +02:00
Manuel Thalmann f1a3fd2f25 Remove unnecessary loop 2024-08-24 04:24:55 +02:00
Manuel Thalmann 2f82ae4544 Add missing module 2024-08-24 04:24:37 +02:00
Manuel Thalmann 2af45fbf89 Add nextcloud to the module list 2024-08-24 04:18:57 +02:00
Manuel Thalmann 0df3d90ca9 Add a function for creating shortcuts 2024-08-24 04:18:33 +02:00
Manuel Thalmann f721cd8910 Configure nextcloud syncs 2024-08-24 04:07:47 +02:00
Manuel Thalmann 4db4136aab Allow configuring nextcloud syncs 2024-08-24 04:07:35 +02:00
Manuel Thalmann 478e489911 Create separate option holding win users 2024-08-24 03:25:28 +02:00
Manuel Thalmann a93413d54f Rename Nextcloud installer 2024-08-24 01:50:07 +02:00
Manuel Thalmann 0cda6e7966 Add file system driver for dual boot 2024-08-24 01:41:09 +02:00
Manuel Thalmann 08e4d1e644 Prevent unnecessary config evaluation 2024-08-24 01:31:39 +02:00
Manuel Thalmann 40b88603c6 Fix non-functioning installer 2024-08-24 01:27:26 +02:00
Manuel Thalmann 6c9acc515d Install vscode extensions by default 2024-08-24 01:16:56 +02:00
Manuel Thalmann fcd05a87d2 Load theme file from WSL properly 2024-08-24 00:59:59 +02:00
Manuel Thalmann 588d410741 Update aliae configuration script 2024-08-24 00:42:57 +02:00
Manuel Thalmann 417db2d35b Strip duplicate variables and aliases 2024-08-24 00:08:58 +02:00
Manuel Thalmann b9f27baa9b Install posh theme automatically 2024-08-23 23:53:48 +02:00
Manuel Thalmann 682808480c Export missing function 2024-08-23 23:50:13 +02:00
Manuel Thalmann c97815f065 Install aliae by default 2024-08-23 23:46:23 +02:00
Manuel Thalmann 4b0d0afa4d Add scripts for changing aliae config 2024-08-23 23:44:51 +02:00
Manuel Thalmann 267eb3d7ec Fix compatibility with mixed new line characters 2024-08-23 23:44:23 +02:00
Manuel Thalmann 1ceb0cd8e4 Add a script for installing aliae 2024-08-23 22:38:28 +02:00
Manuel Thalmann 27064c97b5 Add desired posh theme 2024-08-23 19:43:06 +02:00
Manuel Thalmann 3aae307e2a Make option names more clear 2024-08-23 19:42:27 +02:00
Manuel Thalmann d957b98c33 Allow configuring oh-my-posh 2024-08-23 19:39:18 +02:00
Manuel Thalmann 70b3768ec2 Fetch config from proper section 2024-08-23 19:24:49 +02:00
Manuel Thalmann b2541dab68 Adjust configuration accordingly 2024-08-23 19:14:09 +02:00
Manuel Thalmann 020e592065 Refactor option descriptions 2024-08-23 19:02:06 +02:00
Manuel Thalmann 1264202a88 Clean up the Windows configuration 2024-08-23 18:59:49 +02:00
Manuel Thalmann e19429eb3a Clean up the users.nix file 2024-08-23 18:51:54 +02:00
Manuel Thalmann 971daed11f Create dedicated rclone module 2024-08-23 18:48:30 +02:00
Manuel Thalmann fc8113d2cc Move git module to separate directory 2024-08-23 18:42:16 +02:00
Manuel Thalmann cec1feaa2f Move git options to separate module 2024-08-23 18:40:24 +02:00
Manuel Thalmann 0e23435397 Fix inheritance of user config 2024-08-23 18:28:20 +02:00
Manuel Thalmann 66e5405e74 Allow OS specific settings 2024-08-23 18:11:48 +02:00
Manuel Thalmann 3f049600a4 Update archiso 2024-08-23 14:19:56 +02:00
Manuel Thalmann 9b06999370 Set user info during git setup 2024-08-23 02:01:16 +02:00
Manuel Thalmann cda5ce64c5 Make all config scripts platform independent 2024-08-23 01:57:53 +02:00
Manuel Thalmann 708f689113 Allow leaving aliases unspecified 2024-08-23 01:52:25 +02:00
Manuel Thalmann 9505d6891f Make scripts platform independent 2024-08-23 01:52:04 +02:00
Manuel Thalmann 6d74c1b6cc Add scripts for configuring git 2024-08-23 01:43:26 +02:00
Manuel Thalmann ce0473d106 Configure software implicitly 2024-08-23 01:41:32 +02:00
Manuel Thalmann eda3c967ae Skip profile creation for PinnedItem 2024-08-22 23:55:41 +02:00
Manuel Thalmann 2224796241 Allow skipping powershell module registration 2024-08-22 23:55:00 +02:00
Manuel Thalmann 44ae99f063 Add profiles to the flake 2024-08-22 23:37:53 +02:00
Manuel Thalmann f93b3697bc Remove user profile of OneShot user 2024-08-22 23:12:11 +02:00
Manuel Thalmann 63844c8cf5 Add missing OneShotTask declaration 2024-08-22 20:41:30 +02:00
Manuel Thalmann 980489a29d Fix infinite loop 2024-08-22 20:41:17 +02:00
Manuel Thalmann 91993ea2c7 Fix handling empty error messages 2024-08-22 20:12:18 +02:00
Manuel Thalmann 90fc39ef6d Add choco to the profile of the setup user 2024-08-22 13:46:55 +02:00
Manuel Thalmann 19bebca310 Fix incorrect typings 2024-08-22 11:11:12 +02:00
Manuel Thalmann dbd6e5d9d8 Fix permission issues when enabling Win hack 2024-08-22 11:11:00 +02:00
Manuel Thalmann b60c8ca60e Register setup script as admin 2024-08-22 11:10:39 +02:00
Manuel Thalmann 49b58727f2 Execute the entire installer using live scripts 2024-08-21 23:21:32 +02:00
Manuel Thalmann c0f63f7b52 Streamline the creation of users 2024-08-21 18:34:18 +02:00
Manuel Thalmann ef372f7feb Replace osk with cmd during debugging 2024-09-10 01:54:44 +02:00
Manuel Thalmann bdb4eaed80 Prevent pauses in OneShot tasks 2024-09-10 01:54:44 +02:00
Manuel Thalmann c9fbf55d52 Print commands in debug mode 2024-09-10 01:54:44 +02:00
Manuel Thalmann 1fa0a30755 Run OneShot tasks with dedicated user 2024-09-10 01:54:44 +02:00
Manuel Thalmann 43a9d867bb Add function for generating startup command 2024-09-10 01:54:44 +02:00
Manuel Thalmann bd9234e3bb Allow registering startup script for the default user 2024-09-10 01:54:44 +02:00
Manuel Thalmann b0dd02f3ce Prevent unnecessary errors during WSL execution 2024-09-10 01:54:44 +02:00
Manuel Thalmann 4157d698e3 Register WSL before running OneShot tasks 2024-09-10 01:54:43 +02:00
Manuel Thalmann 79d5b6d06c Overwrite broken module 2024-09-10 01:54:04 +02:00
Manuel Thalmann 394d06ae48 Prevent initialization of nested operations 2024-09-10 01:54:04 +02:00
Manuel Thalmann 75383437d8 Improve log messages of OneShot tasks 2024-09-10 01:54:04 +02:00
Manuel Thalmann 253fcbec6e Retry Linux path conversion for errors 2024-09-10 01:54:04 +02:00
Manuel Thalmann a23719f83b Fix typo 2024-09-10 01:54:04 +02:00
Manuel Thalmann 83cb3b33e4 Fix broken signature of Restart-Intermediate 2024-09-10 01:54:04 +02:00
Manuel Thalmann f3b83c78a0 Report unexpected path conversions 2024-09-10 01:54:04 +02:00
Manuel Thalmann 76a293d341 Load missing path 2024-09-10 01:54:04 +02:00
Manuel Thalmann 09cb18a0d5 Ensure error file can be read from 2024-09-10 01:54:04 +02:00
Manuel Thalmann 62d70c1375 Streamline OneShot task handler 2024-09-10 01:54:04 +02:00
Manuel Thalmann 1499099301 Simplify script registration 2024-09-10 01:54:04 +02:00
Manuel Thalmann 7902b864ed Fix broken regedit paths 2024-09-10 01:54:04 +02:00
Manuel Thalmann 34d9511736 Allow registering reboots for users 2024-09-10 01:54:04 +02:00
Manuel Thalmann b644ca406a Prevent users from being excluded 2024-09-10 01:54:04 +02:00
Manuel Thalmann fd9db7a4ff Force copying of Linux users to Windows 2024-09-10 01:54:04 +02:00
Manuel Thalmann a26b1fe78c Improve log messages of updates 2024-09-10 01:54:04 +02:00
Manuel Thalmann bdfc43b805 Remove unnecessary command 2024-09-10 01:54:04 +02:00
Manuel Thalmann c070bde72a Fix time for QEMU VMs 2024-09-10 01:54:04 +02:00
Manuel Thalmann 47e553ee6a Remove unnecessary desktop icons 2024-09-10 01:54:04 +02:00
Manuel Thalmann b3e8319348 Add a timeout for the reWASD downloader 2024-09-10 01:54:04 +02:00
Manuel Thalmann c32f40860c Allow setting a timeout for clicking download buttons 2024-09-10 01:54:04 +02:00
Manuel Thalmann c2e43c73df Emit errors concerning WSL commands 2024-09-10 01:54:04 +02:00
Manuel Thalmann ab95a43bdf Emit errors using Write-Error 2024-09-10 01:54:04 +02:00
Manuel Thalmann ccfe29799a Convert Argument to string explicitly 2024-09-10 01:54:04 +02:00
Manuel Thalmann ecf9e8e689 Ignore unfinished browser downloads 2024-09-10 01:54:04 +02:00
Manuel Thalmann 9ea809adfd Install powershell modules for all users 2024-09-10 01:54:04 +02:00
Manuel Thalmann bcbf53297b Fix typos 2024-09-10 01:54:04 +02:00
Manuel Thalmann 7ebf09b93f Install AutoHotkey as preparation 2024-09-10 01:54:04 +02:00
Manuel Thalmann 0e18b63853 Allow running live scripts in debug mode 2024-09-10 01:54:04 +02:00
Manuel Thalmann c6e7d2d3d5 Generate env variables using shorthand scripts 2024-09-10 01:54:04 +02:00
Manuel Thalmann 7838c7186e Allow running installation in debug mode 2024-09-10 01:54:04 +02:00
Manuel Thalmann d37f4da080 Redirect winiso exit code properly 2024-09-10 01:54:04 +02:00
Manuel Thalmann d611857375 Allow specifying winiso build type 2024-09-10 01:54:04 +02:00
Manuel Thalmann 4553548a3a Refactor winget check for rare issue 2024-09-10 01:54:04 +02:00
Manuel Thalmann 8f820297c7 Disable Windows Update reboot only as admin 2024-09-10 01:54:04 +02:00
Manuel Thalmann 11f80cda08 Add a function for queueing startup commands 2024-09-10 01:54:04 +02:00
Manuel Thalmann 2f2a3f53fb Hide output of DISM commands 2024-09-10 01:54:04 +02:00
Manuel Thalmann a5430d0298 Ensure website is loaded before download 2024-09-10 01:54:04 +02:00
Manuel Thalmann 1e3968fd0d Prevent Jellyfin from rebooting 2024-09-10 01:54:04 +02:00
Manuel Thalmann 3ca7554422 Improve handling of slow websites 2024-09-10 01:54:04 +02:00
Manuel Thalmann aa8513b15a Fix potential CRC errors 2024-09-10 01:54:04 +02:00
Manuel Thalmann 5f4548403c Ensure auto reboot is disabled properly 2024-09-10 01:54:04 +02:00
Manuel Thalmann 65f93af0b3 Disable auto reboot by default 2024-09-10 01:54:04 +02:00
Manuel Thalmann 70c9155bc0 Add methods for managing auto restart feature 2024-09-10 01:54:04 +02:00
Manuel Thalmann b09452a7bc Install Wave Link first 2024-09-10 01:54:04 +02:00
Manuel Thalmann 6c8882efd9 Throw an error when failing to load config 2024-09-10 01:54:04 +02:00
Manuel Thalmann 61be50fb63 Fix incorrect script path 2024-09-10 01:54:04 +02:00
Manuel Thalmann d6d416ce17 Allow leaving install action unspecified 2024-09-10 01:54:04 +02:00
Manuel Thalmann 29a744a154 Retrieve registry value properly 2024-09-10 01:54:04 +02:00
Manuel Thalmann 6274918f4b Add scripts for installing git 2024-09-10 01:54:04 +02:00
Manuel Thalmann cf1de70b3b Remove unnecessary code 2024-09-10 01:54:04 +02:00
Manuel Thalmann 61e38c2bec Add a function for removing the RunOnce key 2024-09-10 01:54:04 +02:00
Manuel Thalmann 7632e91793 Set user groups properly 2024-09-10 01:54:04 +02:00
Manuel Thalmann c481c54f41 Configure MS accounts properly 2024-09-10 01:54:04 +02:00
Manuel Thalmann 741b698a33 Queue next user after configuration finished 2024-09-10 01:54:02 +02:00
Manuel Thalmann 395945ec72 Disable UAC after logging in MS account 2024-09-10 01:53:07 +02:00
Manuel Thalmann f45081ff99 Enable OneShot listener for MS accounts 2024-09-10 01:53:07 +02:00
Manuel Thalmann 2e5fa8f5a0 Set timezone automatically 2024-09-10 01:53:07 +02:00
Manuel Thalmann f19e2eba1a Prevent variable overwrite 2024-09-10 01:53:07 +02:00
Manuel Thalmann ef56c3ab4b Register installer script after disabling UAG 2024-09-10 01:53:07 +02:00
Manuel Thalmann 09984cff8e Redirect user for configuration properly 2024-09-10 01:53:07 +02:00
Manuel Thalmann 869ca8870d Fix broken redirection of arguments 2024-09-10 01:53:07 +02:00
Manuel Thalmann 2063d276ec Determine installer action properly 2024-09-10 01:53:07 +02:00
Manuel Thalmann e8db7ea047 Redirect arguments to chocolatey properly 2024-09-10 01:53:07 +02:00
Manuel Thalmann 0cfa2f2fa0 Fix non-functioning OneShot script 2024-09-10 01:53:07 +02:00
Manuel Thalmann 97cbcc7dfb Fix oneshot task execution 2024-09-10 01:53:07 +02:00
Manuel Thalmann 00aae35c96 Allow removing the OneShot listener 2024-09-10 01:53:07 +02:00
Manuel Thalmann d95396b06b Remove duplicate code 2024-09-10 01:53:07 +02:00
Manuel Thalmann c46d241147 Fix typo 2024-09-10 01:53:07 +02:00
Manuel Thalmann 1696207b0a Fix copy paste error 2024-09-10 01:53:07 +02:00
Manuel Thalmann 52c5a6c6a3 Allow skipping the User parameter 2024-09-10 01:53:07 +02:00
Manuel Thalmann c347ff6377 Fix incorrect script path 2024-09-10 01:53:07 +02:00
Manuel Thalmann aa4c392569 Fix broken scripts 2024-09-10 01:53:07 +02:00
Manuel Thalmann 3a45dfca73 Remove unnecessary confirmation dialogue 2024-09-10 01:53:07 +02:00
Manuel Thalmann a9bd4f5eb4 Add a task for disabling UAC 2024-09-10 01:53:07 +02:00
Manuel Thalmann cfd1559782 Force creation of sudo alias 2024-09-10 01:53:07 +02:00
Manuel Thalmann 8dd65b0ad3 Allow execution of OneShot tasks 2024-09-10 01:53:07 +02:00
Manuel Thalmann 308e86efc8 Ensure CONFIG_MODULE is resolved 2024-09-10 01:53:07 +02:00
Manuel Thalmann add76b3986 Add dedicated functions for creating startup scripts 2024-09-10 01:53:07 +02:00
Manuel Thalmann 1a0e83735c Change login message 2024-09-10 01:53:07 +02:00
Manuel Thalmann 1d8c416fe1 Set up shared WSL 2024-09-10 01:53:07 +02:00
Manuel Thalmann 894eb30f23 Install updates only as admin 2024-09-10 01:53:07 +02:00
Manuel Thalmann a23b51f9f8 Disable boot message only as admin 2024-09-10 01:53:07 +02:00
Manuel Thalmann 54114ffbd2 Add a function for allowing user access 2024-09-10 01:53:07 +02:00
Manuel Thalmann f4eb58a3a1 Fix broken reboot registration 2024-09-10 01:53:07 +02:00
Manuel Thalmann a553bc9cb7 Ensure the script path is detected properly 2024-09-10 01:53:07 +02:00
Manuel Thalmann 9c603d173f Allow automatic script execution for MS accounts 2024-09-10 01:53:07 +02:00
Manuel Thalmann 9ed7773341 Reorder winget arguments 2024-09-10 01:53:07 +02:00
Manuel Thalmann 5b36f75abf Allow registering reboot for the default user 2024-09-10 01:53:07 +02:00
Manuel Thalmann 3decf57f5e Add a dedicated function for disabling boot message 2024-09-10 01:53:07 +02:00
Manuel Thalmann 9dff674894 Implement root install loop using a switch 2024-09-10 01:53:05 +02:00
Manuel Thalmann 8878a7d7fe Force computer reboots 2024-09-10 01:52:02 +02:00
Manuel Thalmann 7e31a0cac5 Add scripts for controlling UAC 2024-09-10 01:52:02 +02:00
Manuel Thalmann d2ddca8ab5 Set displayname of all users 2024-09-10 01:52:02 +02:00
Manuel Thalmann db31ae2419 Login to users for configuration 2024-09-10 01:52:00 +02:00
Manuel Thalmann 40d1ef5c78 Skip PWSH_PATH if undefined 2024-09-10 01:51:28 +02:00
Manuel Thalmann 1b4204cf3b Fix typo 2024-09-10 01:51:28 +02:00
Manuel Thalmann 460a30bf89 Add missing setup stage 2024-09-10 01:51:28 +02:00
Manuel Thalmann 2e92b9f6db Make Get-Users output explicit 2024-09-10 01:51:28 +02:00
Manuel Thalmann d6084b0ee8 Allow displaying a boot message 2024-09-10 01:51:28 +02:00
Manuel Thalmann 5209a9d5d8 Disable users by default 2024-09-10 01:51:28 +02:00
Manuel Thalmann f469bd6eb7 Add a stage for configuring users 2024-09-10 01:51:28 +02:00
Manuel Thalmann a43f09dce4 Detect installation properly 2024-09-10 01:51:28 +02:00
Manuel Thalmann 1baf93c48a Remove unnecessary icon 2024-09-10 01:51:28 +02:00
Manuel Thalmann 8034b77370 Add Predator Z301C to the hardware list 2024-09-10 01:51:28 +02:00
Manuel Thalmann c52ea65121 Add support for the sudo command 2024-09-10 01:51:28 +02:00
Manuel Thalmann 8473cf201f Fix renaming user 2024-09-10 01:51:28 +02:00
Manuel Thalmann 0e940efeeb Make specifying PWSH_PATH optional 2024-09-10 01:51:28 +02:00
Manuel Thalmann f3e1e4ee00 Show error properly 2024-09-10 01:51:28 +02:00
Manuel Thalmann b9dbb50f76 Fix typo 2024-09-10 01:51:28 +02:00
Manuel Thalmann 4068e95504 Remove code duplication 2024-09-10 01:51:28 +02:00
Manuel Thalmann 186d84704d Remove unnecessary console output 2024-09-10 01:51:28 +02:00
Manuel Thalmann 5c6b0c18fd Fix incorrect file paths 2024-09-10 01:51:28 +02:00
Manuel Thalmann 43e6cf47d1 Fix incorrect hardware name 2024-09-10 01:51:28 +02:00
Manuel Thalmann eea20772be Reorder installation steps 2024-09-10 01:51:28 +02:00
Manuel Thalmann 1fc9dafb89 Suppress unnecessary output 2024-09-10 01:51:28 +02:00
Manuel Thalmann 49770fa11b Refactor the wsl installation check 2024-09-10 01:51:28 +02:00
Manuel Thalmann 76496d0a7d Ensure WSL Ubuntu is installed 2024-09-10 01:51:28 +02:00
Manuel Thalmann 39f39238fe Make config script platform independent 2024-09-10 01:51:28 +02:00
Manuel Thalmann 2ab3b3b9cd Leave groups unspecified 2024-09-10 01:51:27 +02:00
Manuel Thalmann 300f629453 Add users during installation 2024-09-10 01:50:39 +02:00
130 changed files with 4587 additions and 1393 deletions

2
.gitattributes vendored Normal file
View file

@ -0,0 +1,2 @@
*.fish text eol=lf
*.sh text eol=lf

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,10 @@
packages = {
archiso = pkgs.archiso;
};
});
})) // {
valhalla = {
DerGeret = import ./profiles/machines/manuel/DerGeret/Arch/config.nix;
ManuSurface = import ./profiles/machines/manuel/ManuSurface/Arch/config.nix;
};
};
}

15
lib/eval-attribute.nix Normal file
View file

@ -0,0 +1,15 @@
let
inherit (nixpkgs) lib;
nixpkgs = import <nixpkgs> { config = {}; overlay = []; };
property = (builtins.getEnv "PROPERTY");
processor = if (builtins.stringLength property > 0)
then
(_: lib.attrsets.getAttrFromPath (lib.strings.splitString "." property) _)
else
(_: _);
in
_: processor (lib.evalModules {
modules = [
_
];
}).config

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,48 +1,14 @@
{ 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 (
{ ... }: {
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;
};
};
});
mkUserType = { options }: (
types.submodule (
{ ... }: {
userType = types.submodule (
{ ... } : {
options = {
displayName = mkOption {
type = types.nullOr types.str;
@ -61,16 +27,22 @@
description = "The additional groups of the user.";
default = [];
};
git = (import ./git/options.nix) { inherit lib; };
} // options;
}));
userType = mkUserType {
options = linuxOptions;
};
});
winUserType = mkUserType {
linuxUserType = types.submodule (
{ ... }: {
options = {
defaultShell = mkOption {
type = types.nullOr types.str;
description = "The default shell of the user.";
default = null;
};
};
});
winUserType = types.submodule (
{ ... }: {
options = {
microsoftAccount = mkOption {
type = types.bool;
@ -78,7 +50,7 @@
default = false;
};
};
};
});
in {
options = {
valhalla = {
@ -88,25 +60,31 @@
default = {};
};
windows.users = mkOption {
linux.users = mkOption {
type = types.attrsOf linuxUserType;
};
windows = mkOption {
type = types.submoduleWith {
modules = [
({ config, options, ... }: {
options = {
users = mkOption {
type = types.attrsOf winUserType;
description = "The users to create on the Windows machine.";
};
winUsers = mkOption {
type = options.users.type;
description = "Blablabla";
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 = [];
name: options: {
${capitalize name} = options;
}) config.users);
};
};
})
];
};
}) cfg.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, ... }: {
in {
options = {
setupUser = mkOption {
type = types.str;
description = "The name of the user for setting up Windows.";
default = capitalize setupUser;
};
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 = {};
};
valhalla.windows = {
setupUser.name = mkDefault (capitalize config.valhalla.setupUser.name);
dualboot.linuxPercentage = mkIf (!config.valhalla.windows.dualboot.enable) (mkDefault 0);
};
};
}

View file

@ -1,19 +0,0 @@
#!/bin/bash -e
function install() {
function installDrivers() {
. "../../../scripts/Arch/Config/SecureBoot/install.sh";
. "../../../scripts/Arch/Software/nvidia-dkms/install.sh";
. "../../../scripts/Arch/Software/xone/install.sh";
. "../../../scripts/Arch/Software/bt-dualboot/install.sh";
}
function initializeConfig() {
. "../../../scripts/Unix/Devices/Logitech G903/install.sh";
}
pushd "$dir" > /dev/null;
. "../../../scripts/Arch/OS/install.sh";
popd > /dev/null;
}
install;

View file

@ -1,6 +0,0 @@
#!/bin/pwsh
$env:WIN_COMPUTER_NAME = "DerGeret";
$env:SETUP_SCRIPT_NAME = "$PSScriptRoot/Restore.ps1";
$env:CONFIG_MODULE = "$PSScriptRoot/../config.nix";
. "$PSScriptRoot/../../../scripts/Windows/OS/Setup.ps1";

View file

@ -1,13 +0,0 @@
#!/bin/pwsh
. "$PSScriptRoot/../../../scripts/Common/Scripts/Context.ps1";
. "$PSScriptRoot/../../../scripts/Windows/OS/Install.ps1";
. "$PSScriptRoot/../../../scripts/Windows/Collections/Generic.ps1"
function Restore-Apps {
param([Context] $context)
Restore-GenericApps $context;
}
[Context]$context = [Context]::new();
Invoke-WindowsInstallation $context;
Restart-Computer -Force;

View file

@ -1,6 +0,0 @@
#!/bin/pwsh
$env:WIN_COMPUTER_NAME ??= "win11";
$env:SETUP_SCRIPT_NAME ??= "$PSScriptRoot/Install.ps1";
$env:CONFIG_MODULE ??= "$PSScriptRoot/../config.nix";
. "$PSScriptRoot/../../../scripts/Windows/OS/Setup.ps1";

View file

@ -1,4 +0,0 @@
#!/bin/pwsh
$env:SETUP_SCRIPT_NAME ??= "$PSScriptRoot/Install.ps1";
. "$PSScriptRoot/../../Generic/Windows/Setup.ps1";

View file

@ -1,5 +0,0 @@
#!/bin/env fish
begin
set -l dir (status dirname)
source "$dir/../../../scripts/Arch/OS/install.fish"
end

View file

@ -1,26 +0,0 @@
#!/bin/bash -e
function install() {
function installDrivers() {
. "../../../scripts/Arch/Config/SecureBoot/install.sh";
. "../../../scripts/Arch/Drivers/SurfaceBook2/install.sh";
}
function installSoftware() {
. "../../../scripts/Arch/Collections/school.sh";
}
function initializeConfig() {
. "../../../scripts/Common/Config/Steam/hidpi.sh";
. "../../../scripts/Unix/Devices/Surface Book 2/install.sh";
. "../../../scripts/Unix/Devices/Logitech G903/install.sh";
# Because, as it looks, Surface Books are fucking stupid.
. "../../../scripts/Common/Config/GRUB/verbose.sh";
}
pushd "${BASH_SOURCE%/*}" > /dev/null;
. "../../../scripts/Arch/OS/install.sh";
popd > /dev/null;
}
install;

View file

@ -1,16 +0,0 @@
#!/bin/bash
pushd "${BASH_SOURCE%/*}" > /dev/null;
# Set Hostname
sudo hostnamectl set-hostname ManuSurface;
source "../../../scripts/PopOS/Scripts/preinstall.sh";
source "../../../scripts/PopOS/OS/install.sh";
source "../../../scripts/Debian/Drivers/SurfaceBook2/Setup/install.sh";
source "../../../scripts/PopOS/Software/Collections/school.sh";
INSTALL_FONTS=1 NEXTCLOUD_DIR="${NEXTCLOUD_DIR}" source "../../../scripts/Common/Config/UserProfile/install.sh";
# Install equalizer
source "../../../scripts/Common/Config/EasyEffects/SurfaceBook2/install.sh";
source "../../../scripts/PopOS/Scripts/postinstall.sh";
popd > /dev/null;

View file

@ -1,12 +0,0 @@
#!/bin/bash
pushd "${BASH_SOURCE%/*}" > /dev/null;
# Set Hostname
sudo hostnamectl set-hostname ManuPopOSLive;
source "../../scripts/PopOS/Scripts/prepare.sh";
source "../../scripts/PopOS/OS/install.sh";
source "../../scripts/PopOS/Software/Collections/personal.sh";
INSTALL_FONTS=1 NEXTCLOUD_DIR="${NEXTCLOUD_DIR}" source "../../scripts/Common/Config/UserProfile/personal.sh";
source "../../scripts/PopOS/Scripts/postinstall.sh";
popd > /dev/null;

View file

@ -0,0 +1,19 @@
#!/bin/bash -e
function install() {
function installDrivers() {
. "../../../../../scripts/Arch/Config/SecureBoot/install.sh";
. "../../../../../scripts/Arch/Software/nvidia-dkms/install.sh";
. "../../../../../scripts/Arch/Software/xone/install.sh";
. "../../../../../scripts/Arch/Software/bt-dualboot/install.sh";
}
function initializeConfig() {
. "../../../../../scripts/Unix/Devices/Logitech G903/install.sh";
}
pushd "$dir" > /dev/null;
. "../../../../../scripts/Arch/OS/install.sh";
popd > /dev/null;
}
install;

View file

@ -6,8 +6,8 @@ begin
echo "$dir/install.fish"
end
CONFIG_MODULE="$dir/config.nix" \
CONFIG_NAME="DerGeret" \
ARCH_HOSTNAME="der-geret" \
USER_DISPLAYNAME="Manuel Thalmann" \
source "$(status dirname)/../../../scripts/Arch/OS/setup.fish"
source "$(status dirname)/../../../../../scripts/Arch/OS/setup.fish"
end

View file

@ -4,6 +4,6 @@ pushd "${BASH_SOURCE%/*}" > /dev/null;
CONFIG_MODULE="./config.nix" \
ARCH_HOSTNAME="der-geret" \
USER_DISPLAYNAME="Manuel Thalmann" \
. "../../../scripts/Arch/OS/setup.sh";
. "../../../../../scripts/Arch/OS/setup.sh";
popd > /dev/null;

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/Common/Scripts/Context.ps1";
. "$PSScriptRoot/../../../../../scripts/Windows/OS/Legacy.ps1";
Write-Host "Starting Backup of Windows";
$context = [Context]::new();

View file

@ -1,12 +1,12 @@
#!/bin/pwsh
. "$PSScriptRoot/../../../scripts/Common/Scripts/Context.ps1";
. "$PSScriptRoot/../../../../../scripts/Common/Scripts/Context.ps1";
function Install-PortValhallaDrivers {
param(
[Context] $context
)
$winPath = "$PSScriptRoot/../../../scripts/Windows";
$winPath = "$PSScriptRoot/../../../../../scripts/Windows";
$driverPath = "$winPath/Drivers";
$mbDriverPath = "$driverPath/ROG Zenith Extreme Alpha";
$context.RegisterReboot();
@ -38,7 +38,7 @@ function Install-PersonalDrivers {
[Context] $context
)
$softwarePath = "$PSScriptRoot/../../../scripts/Windows/Software";
$softwarePath = "$PSScriptRoot/../../../../../scripts/Windows/Software";
. "$softwarePath/TobiiGhost/Install.ps1" $context;
. "$softwarePath/TobiiGameHub/Install.ps1" $context;
}

View file

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

View file

@ -0,0 +1,5 @@
#!/bin/pwsh
$env:WIN_COMPUTER_NAME = "DerGeret";
$env:CONFIG_NAME = $env:WIN_COMPUTER_NAME;
. "$PSScriptRoot/../../../../../scripts/Windows/OS/Setup.ps1";

View file

@ -1,6 +1,6 @@
{ ... }: {
imports = [
../Generic/config.nix
../defaults.nix
];
config = {
@ -11,8 +11,9 @@
linuxPercentage = 70; # better safe than sorry
};
users.Manuel = {
users.manuel = {
microsoftAccount = true;
groups = ["Administrators"];
};
};
@ -32,6 +33,7 @@
hardware = {
components = [
"ROG Zenith Extreme Alpha"
"Predator Z301C"
];
eyeX = true;

View file

@ -3,11 +3,11 @@ function install() {
local dir="$(realpath "${BASH_SOURCE%/*}")";
function installDrivers() {
. "$dir/../../../scripts/Arch/Config/SecureBoot/install.sh";
. "$dir/../../../../../scripts/Arch/Config/SecureBoot/install.sh";
}
. "../../../scripts/Arch/OS/install.sh";
. "../../../../../scripts/Arch/OS/install.sh";
}
install;

View file

@ -4,6 +4,6 @@ pushd "${BASH_SOURCE%/*}" > /dev/null;
ARCH_MOUNT_ROOT="/mnt" \
ARCH_HOSTNAME="archlinux" \
USER_DISPLAYNAME="Manuel Thalmann" \
. "../../../scripts/Arch/OS/setup.sh";
. "../../../../../scripts/Arch/OS/setup.sh";
popd > /dev/null;

View file

@ -0,0 +1,13 @@
#!/bin/pwsh
. "$PSScriptRoot/../../../../../scripts/Common/Scripts/Context.ps1";
. "$PSScriptRoot/../../../../../scripts/Windows/OS/Manage.ps1";
. "$PSScriptRoot/../../../../../scripts/Windows/Collections/Generic.ps1"
function Restore-Apps {
param([Context] $context)
Restore-GenericApps $context;
}
[Context]$context = [Context]::new();
Invoke-WindowsInstallation $context;
Restart-Computer -Force;

View file

@ -0,0 +1,5 @@
#!/bin/pwsh
$env:WIN_COMPUTER_NAME ??= "win11";
$env:CONFIG_MODULE ??= "$PSScriptRoot/../config.nix";
. "$PSScriptRoot/../../../../../scripts/Windows/OS/Setup.ps1";

View file

@ -1,9 +1,9 @@
{ lib, config, ... }:
let
fs = import ../../lib/modules/partition/fs.nix;
fs = import ../../../../lib/modules/partition/fs.nix;
in {
imports = [
../../lib/modules/valhalla.nix
../defaults.nix
];
config = {
@ -35,31 +35,6 @@
};
};
users = {
manuel = {
displayName = "Manuel Thalmann";
mailAddress = "m@nuth.ch";
groups = [
"wheel"
"nix-users"
];
defaultShell = "fish";
rclone = {
configurations = {
nextcloud = {
dirName = "Nextcloud";
};
proton = {
dirName = "Proton";
};
};
};
};
};
timeZone = "Europe/Zurich";
keyMap = "de_CH-latin1";
keyboardLayout = "ch";

View file

@ -14,4 +14,4 @@ function Install-PortValhallaDrivers {
choco install -y spice-agent;
}
. "$PSScriptRoot/../../Generic/Windows/Install.ps1";
. "$PSScriptRoot/../../../../Generic/Windows/Install.ps1";

View file

@ -0,0 +1,2 @@
#!/bin/pwsh
. "$PSScriptRoot/../../../../Generic/Windows/Setup.ps1";

View file

@ -0,0 +1,5 @@
#!/bin/env fish
begin
set -l dir (status dirname)
source "$dir/../../../../../scripts/Arch/OS/install.fish"
end

View file

@ -0,0 +1,26 @@
#!/bin/bash -e
function install() {
function installDrivers() {
. "../../../../../scripts/Arch/Config/SecureBoot/install.sh";
. "../../../../../scripts/Arch/Drivers/SurfaceBook2/install.sh";
}
function installSoftware() {
. "../../../../../scripts/Arch/Collections/school.sh";
}
function initializeConfig() {
. "../../../../../scripts/Common/Config/Steam/hidpi.sh";
. "../../../../../scripts/Unix/Devices/Surface Book 2/install.sh";
. "../../../../../scripts/Unix/Devices/Logitech G903/install.sh";
# Because, as it looks, Surface Books are fucking stupid.
. "../../../../../scripts/Common/Config/GRUB/verbose.sh";
}
pushd "${BASH_SOURCE%/*}" > /dev/null;
. "../../../../../scripts/Arch/OS/install.sh";
popd > /dev/null;
}
install;

View file

@ -3,7 +3,7 @@ begin
set -l dir (status dirname)
function installDrivers -V dir -S
source "$dir/../../../scripts/Common/Scripts/config.fish"
source "$dir/../../../../../scripts/Common/Scripts/config.fish"
pacstrap -K (getConfig valhalla.partition.rootDir) linux-firmware-marvell;
end
@ -11,8 +11,8 @@ begin
echo "$dir/install.fish"
end
CONFIG_MODULE="$(status dirname)/config.nix" \
CONFIG_NAME="ManuSurface" \
ARCH_HOSTNAME="manu-surface" \
USER_DISPLAYNAME="Manuel Thalmann" \
source "$(status dirname)/../../../scripts/Arch/OS/setup.fish";
source "$(status dirname)/../../../../../scripts/Arch/OS/setup.fish";
end

View file

@ -0,0 +1,16 @@
#!/bin/bash
pushd "${BASH_SOURCE%/*}" > /dev/null;
# Set Hostname
sudo hostnamectl set-hostname ManuSurface;
source "../../../../../scripts/PopOS/Scripts/preinstall.sh";
source "../../../../../scripts/PopOS/OS/install.sh";
source "../../../../../scripts/Debian/Drivers/SurfaceBook2/Setup/install.sh";
source "../../../../../scripts/PopOS/Software/Collections/school.sh";
INSTALL_FONTS=1 NEXTCLOUD_DIR="${NEXTCLOUD_DIR}" source "../../../../../scripts/Common/Config/UserProfile/install.sh";
# Install equalizer
source "../../../../../scripts/Common/Config/EasyEffects/SurfaceBook2/install.sh";
source "../../../../../scripts/PopOS/Scripts/postinstall.sh";
popd > /dev/null;

View file

@ -0,0 +1,12 @@
#!/bin/bash
pushd "${BASH_SOURCE%/*}" > /dev/null;
# Set Hostname
sudo hostnamectl set-hostname ManuPopOSLive;
source "../../../../scripts/PopOS/Scripts/prepare.sh";
source "../../../../scripts/PopOS/OS/install.sh";
source "../../../../scripts/PopOS/Software/Collections/personal.sh";
INSTALL_FONTS=1 NEXTCLOUD_DIR="${NEXTCLOUD_DIR}" source "../../../../scripts/Common/Config/UserProfile/personal.sh";
source "../../../../scripts/PopOS/Scripts/postinstall.sh";
popd > /dev/null;

View file

@ -0,0 +1,6 @@
{ ... }: {
imports = [
../../users/manuel/config.nix
../../../lib/modules/valhalla.nix
];
}

View file

@ -0,0 +1,66 @@
{ ... }: {
imports = [
../../../lib/modules/valhalla.nix
];
config = {
valhalla = {
users.manuel = {
displayName = "Manuel Thalmann";
mailAddress = "m@nuth.ch";
oh-my-posh = {
theme = {
source = ./manuel.omp.json;
};
};
};
linux.users.manuel = {
defaultShell = "fish";
groups = [
"wheel"
"nix-users"
];
rclone = {
configurations = {
nextcloud = {
dirName = "Nextcloud";
};
proton = {
dirName = "Proton";
};
};
};
};
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";
}
];
};
};
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

@ -24,7 +24,7 @@ if [ (id -u) -eq 0 ]
echo "$name ALL=(ALL:ALL) NOPASSWD: ALL"
end > "$sudoConfig"
and sudo --preserve-env="CONFIG_MODULE" --user "$name" "$INSTALLER_SCRIPT"
and sudo --preserve-env="CONFIG_NAME" --user "$name" "$INSTALLER_SCRIPT"
rm "$sudoConfig"
userdel -r "$name"
else

View file

@ -39,7 +39,7 @@ function runSetup
function wrapScript -S
printf %s\n \
"cd $PROJECT_CLONE_ROOT" \
"export CONFIG_MODULE=$(string escape (getCloneFile "$CONFIG_MODULE"))" \
"export CONFIG_NAME=$(string escape (getCloneFile "$CONFIG_NAME"))" \
"$argv"
end

View file

@ -15,18 +15,10 @@ $null = New-Module {
)
if (-not ("OpenQA.Selenium.Firefox.FirefoxDriver" -as [type])) {
$zipFile = [System.IO.Compression.ZipFile]::OpenRead((Get-Package Selenium.WebDriver).Source);
$webDriver = ($zipFile.Entries | Where-Object { $_.FullName -like "lib/net6.0/WebDriver.dll" })[0];
$stream = [System.IO.MemoryStream]::new();
$reader = [System.IO.StreamReader]($webDriver).Open();
$reader.BaseStream.CopyTo($stream);
[byte[]]$bytes = $stream.ToArray();
$reader.Close();
$reader.Dispose();
$stream.Close();
$stream.Dispose();
$zipFile.Dispose();
$null = [System.Reflection.Assembly]::Load($bytes);
$packageRoot = Split-Path -Parent (Get-Package Selenium.WebDriver).Source;
$file = Join-Path $packageRoot "lib/netstandard2.0/WebDriver.dll";
$env:SE_MANAGER_PATH = Join-Path $packageRoot "manager" ($IsWindows ? "windows" : "linux") "selenium-manager$($IsWindows ? ".exe" : '')";
$null = [System.Reflection.Assembly]::LoadFile($file);
}
& $Action;
@ -68,8 +60,9 @@ $null = New-Module {
$downloadChecker = {
$files = Get-ChildItem $dir;
if ((@($files)).Count -gt 0) {
foreach ($file in $files) {
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);
@ -80,7 +73,6 @@ $null = New-Module {
catch {
return $true;
}
}
return $false;
} else {
@ -90,6 +82,12 @@ $null = New-Module {
$browser = [OpenQA.Selenium.Firefox.FirefoxDriver]::new($options);
$browser.Navigate().GoToUrl($URL);
while (-not ($browser.ExecuteScript("return document.readyState;") -eq "complete")) {
Start-Sleep 0.1;
}
try {
$null = & $downloadAction -Browser $browser;
while (& $downloadChecker) {
@ -103,6 +101,10 @@ $null = New-Module {
Remove-Item -Recurse $dir;
$result;
}
catch {
Write-Error $Error;
}
}
}
<#
@ -117,12 +119,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 +136,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

@ -1,7 +1,15 @@
using namespace Microsoft.Win32;
using namespace System.Management.Automation.Host;
using namespace System.Security.AccessControl;
using namespace System.Security.Principal;
enum WindowsInstallerStage {
Initialize
Run
Cleanup
Completed
}
enum SetupStage {
Initialize
Configure
@ -9,12 +17,78 @@ enum SetupStage {
CreateUser
}
enum BackupStage {
Initialize
Backup
BackupUsers
}
enum UserStage {
Create
Configure
Cleanup
Completed
}
$null = New-Module {
[string] $configRoot = "HKLM:\Software\PortValhalla";
[string] $stageOption = "Stage";
[string] $setupStageOption = "SetupStage";
[string] $backupStageOption = "BackupStage";
[string] $userOption = "SetupUser";
[string] $userStageOption = "UserStage";
[string] $accountOption = "MSAccount";
[string] $finishedOption = "Finished";
[RegistryKey] $key = $null;
<#
.SYNOPSIS
Prompts the user to select a profile to act on.
#>
function Show-ProfileNamePrompt {
. "$PSScriptRoot/../../Windows/Types/WindowsInstallerAction.ps1";
$profiles = & {
. "$PSScriptRoot/SoftwareManagement.ps1";
if (Test-Command "wsl") {
return Invoke-ConfigScript "getProfiles";
} else {
return Get-ChildItem "$PSScriptRoot/../../../.config" | ForEach-Object { Split-Path -LeafBase $_ };
}
};
$choice = $Host.UI.PromptForChoice(
"Select Profile",
(& {
switch (Get-Stage) {
([WindowsInstallerAction]::Backup) {
"Which profile do you wish to back up?";
}
([WindowsInstallerAction]::Install) {
"Which profile do you wish to install?";
}
$null {
"Which profile do you wish to set up?";
}
}
}),
(& {
for ($i = 0; $i -lt $profiles.Count; $i++) {
[ChoiceDescription]"&$i - $($profiles[$i])";
}
[ChoiceDescription]"&Abort";
}),
$profiles.Count);
if ($choice -eq $profiles.Count) {
exit;
} else {
$env:CONFIG_NAME = $profiles[$choice];
}
}
<#
.SYNOPSIS
Converts the specified path to linux and escapes it for the use in a script.
@ -27,6 +101,11 @@ $null = New-Module {
[string] $Path
)
& {
$ErrorActionPreference = 'Continue';
$completed = $false;
while (-not $completed) {
$job = Start-Job {
$env:Value = Resolve-Path $Using:Path;
$env:WSLENV = "Value/p";
@ -34,7 +113,24 @@ $null = New-Module {
wsl -e printf "%q" "$result";
};
Receive-Job -Wait $job;
$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;
};
}
<#
@ -76,11 +172,49 @@ $null = New-Module {
$scriptPath = "$PSScriptRoot/../../Common/Scripts/config.fish";
if ($env:CONFIG_NAME -or ($Script -eq "getProfiles")) {
$output = & {
if (-not $IsWindows) {
$escapedPath = (fish -c 'string escape $argv' "$scriptPath");
fish -c ". $escapedPath; $Script";
} else {
$cleanup = { };
$projectRoot = "$PSScriptRoot/../../..";
$archisoDir = "$projectRoot/archiso";
function fish {
wsl --shell-type login -- nix --extra-experimental-features "nix-command flakes" run nixpkgs`#fish -- $args
}
fish -c ". $(ConvertTo-LinuxPath $scriptPath); $Script" | ConvertFrom-Json;
if (Test-Path -PathType Container "$archisoDir") {
$git = {
git -C "$projectRoot" -c safe.directory="$("$(Resolve-Path $projectRoot)".Replace("\", "/"))" @args;
};
& $git rm -r --cached "$archisoDir" *> $null;
$cleanup = { & $git restore --staged "$archisoDir" };
}
$output = fish -c ". $(ConvertTo-LinuxPath $scriptPath); $Script";
if (-not $?) {
Write-Error "The configuration could not be retrieved!";
} else {
$output;
}
& $cleanup *> $null;
}
}
if (-not ($output -and ($output | Test-Json))) {
Write-Error "The value ``$output`` is not valid JSON.";
} else {
$output | ConvertFrom-Json;
}
} else {
$null;
}
}
<#
@ -100,6 +234,46 @@ $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.
.PARAMETER UserName
The name of the user to get the configuration for.
.PARAMETER Name
The name of the configuration to get.
#>
function Get-UserConfig {
param(
[string] $UserName = ($IsWindows ? $env:UserName : $env:USER),
[Parameter(Mandatory, Position = 0)]
[string] $Name
)
if ((Get-Users) -contains $UserName) {
Get-Config "$(Get-UserRootName).$UserName.$Name";
} else {
return $null;
}
}
<#
.SYNOPSIS
Gets the attributes of a configuration object.
@ -120,7 +294,19 @@ $null = New-Module {
Gets the names of the users to create.
#>
function Get-Users {
Get-Attributes "valhalla.windows.users";
[OutputType([string[]])]
param()
Get-Attributes "$(Get-UserRootName)";
}
<#
.SYNOPSIS
Gets the name of the setup user.
#>
function Get-SetupUser {
[OutputType([string])]
param()
Get-Config "$(Get-ConfigRootName).setupUser.name";
}
<#
@ -166,11 +352,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;
}
@ -185,7 +404,7 @@ $null = New-Module {
.PARAMETER Name
The name to set the current stage to.
#>
function Set-Stage {
function Set-SetupStage {
param(
$Name
)
@ -194,7 +413,119 @@ $null = New-Module {
$Name = ([SetupStage]$Name).ToString();
}
$null = Set-SetupOption $stageOption $Name;
$null = Set-SetupOption $setupStageOption $Name;
}
<#
.SYNOPSIS
Gets the name of the current stage of the backup.
#>
function Get-BackupStage {
$stage = Get-SetupOption $backupStageOption;
if ($null -ne $stage) {
$stage = [BackupStage]$stage;
}
return $stage;
}
<#
.SYNOPSIS
Sets the current stage of the backup.
.PARAMETER Name
The name to set the current stage to.
#>
function Set-BackupStage {
param(
$Name
)
if (-not (($null -eq $Name) -or ($Name -is [string]))) {
$Name = ([BackupStage]$Name).ToString();
}
$null = Set-SetupOption $backupStageOption $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;
}
<#
@ -202,7 +533,7 @@ $null = New-Module {
Gets a value indicating whether the setup has finished.
#>
function Get-IsFinished {
return [bool] (Get-SetupOption $finishedOption);
return [bool](Get-SetupOption $finishedOption);
}
<#
@ -219,17 +550,10 @@ $null = New-Module {
<#
.SYNOPSIS
Checks whether the specified software collection is enabled.
.PARAMETER Name
The name of the collection to check.
Checks whether the running system is a QEMU virtual machine.
#>
function Test-Collection {
param(
[string] $Name
)
Get-Config "valhalla.software.$Name";
function Test-Qemu {
((Get-WmiObject win32_computersystem).Manufacturer) -eq "QEMU";
}
<#
@ -237,7 +561,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,14 +1,429 @@
function Start-Operation {
using namespace System.Management.Automation.Host;
. "$PSScriptRoot/../Types/OneShotTask.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;
$taskOption = "OneShotTask";
# 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]);
}
}
return $modules;
}
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_NAME";
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 @("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.24.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];
}
}
};
if (-not $env:CONFIG_NAME) {
Show-ProfileNamePrompt;
}
$initialized = $true;
}
}
}
if ($taskPending) {
Start-OneShot;
} else {
& $Action;
}
}
& $cleanup;
}
<#
.SYNOPSIS
Gets the current OneShot task.
#>
function Get-OneShotTask {
$task = Get-SetupOption $taskOption;
if ($task) {
return [OneShotTask]$task;
} else {
return $null;
}
}
<#
.SYNOPSIS
Registers a task for listening to OneShot invocations.
#>
function Enable-OneShotListener {
$tempTask = "PortValhalla Temp";
$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;
$null = Register-ScheduledTask -Force $oneShotTaskName -Action $action -Trigger $trigger -RunLevel Highest -User $user -Password $password;
$null = Unregister-ScheduledTask -Confirm:$false $tempTask;
}
<#
.SYNOPSIS
Removes the OneShot task.
#>
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;
}
<#
.SYNOPSIS
Invokes a one-shot task.
.PARAMETER Task
The task to run.
#>
function Invoke-OneShot {
param(
[OneShotTask] $Task
)
& $taskSetter $Task;
& {
$identifier = "EventLog$oneShotTrigger";
$log = [System.Diagnostics.EventLog]::new($logName);
$log.EnableRaisingEvents = $true;
$null = Register-ObjectEvent -InputObject $log -EventName EntryWritten -Action {
$entry = $Event.SourceEventArgs.Entry;
$trigger = $Event.MessageData.Trigger;
$identifier = $Event.MessageData.Identifier;
if ($entry.EventID -eq $trigger) {
$null = New-Event -SourceIdentifier $identifier;
}
} `
-MessageData @{
Trigger = $oneShotTrigger;
Identifier = $identifier;
};
Write-EventLog -LogName $logName -Source $logName -EventId $oneShotTrigger -Message "Starting OneShot task ``$(Get-OneShotTask)``";
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;
if ($errorMessage) {
Write-Error $errorMessage;
}
}
}
# ToDo: Store Run-OneShot and Receive-OneShot somewhere else in Windows folder
<#
.SYNOPSIS
Executes the specified action and notifies the OneShot task executor.
#>
function Start-OneShot {
try {
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 {
& $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)) {
Remove-Module -Force $module[0] -ErrorAction SilentlyContinue;
Uninstall-Module -Force -Name $module[0] -ErrorAction SilentlyContinue;
}
}
};

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,70 @@ $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);
[string[]] $arguments = $ArgumentList + (& {
if ($Action -eq 'install') {
@("--accept-package-agreements")
};
});
foreach ($name in $Names) {
if ($Force.IsPresent -or (& $Guard $name $PSBoundParameters)) {
winget $Action `
--accept-source-agreements `
--source winget `
@arguments `
--exact --id $name ;
} else {
Write-Host "Package ``$name`` is already installed"
}
}
};
<#
.SYNOPSIS
Installs the specified packages using chocolatey.
@ -26,24 +90,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,20 +142,40 @@ $null = New-Module {
[string[]] $AdditionalNames = @()
)
[System.Collections.ArrayList] $Names = @();
$null = $Names.Add($Name);
$Names.AddRange($AdditionalNames);
foreach ($name in $Names) {
if ($Force.IsPresent -or -not (Test-WingetPackage $name)) {
winget install `
--accept-source-agreements --accept-package-agreements `
--source winget `
--exact --id $name $ArgumentList;
& $wingetRunner @PSBoundParameters `
-Guard {
param($Name, $Parameters)
if (Test-WingetPackage @Parameters) {
Write-Host "Package ``$Name`` is already installed"
$false;
} else {
Write-Host "Package ``$name`` is already installed"
$true;
}
};
}
<#
.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 not installed"
$false;
}
};
}
<#
@ -196,15 +295,17 @@ $null = New-Module {
function Start-SoftwareInstaller {
param(
[string] $Name,
[scriptblock] $Installer = { },
[scriptblock] $Configurator = { },
[scriptblock] $UserConfigurator = { },
[scriptblock] $Backup = $null,
[scriptblock] $Installer = $null,
[scriptblock] $Configurator = $null,
[scriptblock] $UserBackup = $null,
[scriptblock] $UserConfigurator = $null,
[Nullable[InstallerAction]] $Action,
[hashtable] $Arguments
)
[InstallerAction] $Action = & {
if ($Action.HasValue) {
if ($null -ne $Action) {
$Action;
} else {
[InstallerAction]::Install;
@ -235,26 +336,54 @@ $null = New-Module {
arguments = $Arguments;
};
if ($action -eq ([InstallerAction]::Install)) {
switch ($Action) {
([InstallerAction]::Backup) {
if ($Backup) {
Write-Host "Backing up $Name";
& $Backup @argumentList;
}
}
([InstallerAction]::Install) {
if ($Installer) {
Write-Host "Installing $Name";
& $Installer @argumentList;
# ToDo: Automatically configure after installation
} elseif ($Action -eq ([InstallerAction]::Configure)) {
}
& $installHandler @argumentList -Action ([InstallerAction]::Configure);
if ($UserConfigurator -and (-not (Test-SetupUser))) {
& $installHandler @argumentList -Action ([InstallerAction]::ConfigureUser);
}
}
([InstallerAction]::Configure) {
if ($Configurator) {
Write-Host "Configuring $Name";
& $Configurator @argumentList;
if (-not (Test-SetupUser)) {
$argumentList.Add("action", [InstallerAction]::ConfigureUser);
& $installHandler @argumentList;
}
} elseif ($Action -eq ([InstallerAction]::ConfigureUser)) {
if ((-not $Arguments.ContainsKey($userArgument)) -or ($null -eq $Arguments[$userArgument])) {
$argumentList.Add($userArgument, ($env:UserName));
}
default {
if ((-not $Arguments.ContainsKey($userArgument)) -or (-not $Arguments[$userArgument])) {
$Arguments.Add($userArgument, ($IsWindows ? $env:UserName : $env:USER));
}
Write-Host "Configuring $Name for user ``$($Arguments[$userArgument])``";
$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;
}
}
}
}
}
};
& $installHandler -Action $Action -Arguments $Arguments;

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),
(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

@ -1,11 +1,16 @@
#!/bin/env fish
function isConfigured -S
set -q "$CONFIG_MODULE"
set -q "$CONFIG_NAME"
end
function getProfiles -S
source "$(status dirname)/eval-flake.fish";
evalFlake "" "" --apply "builtins.attrNames" --json
end
function getConfig -S -a property
source "$(status dirname)/eval-module.fish"
evalModule "$CONFIG_MODULE" "$property" $argv[2..]
source "$(status dirname)/eval-flake.fish"
evalFlake "$CONFIG_NAME" "$property" $argv[2..]
end
function getAttributes -S -a property

View file

@ -0,0 +1,27 @@
#!/bin/env fish
function evalFlake --argument-names config property
set -l argv $argv[3..]
argparse --ignore-unknown "apply=" "json" -- $argv
if [ -z "$_flag_json" ]
set -a argv --raw
else
set -a argv --json
end
if [ -z "$_flag_apply" ]
set _flag_apply "_: _"
end
if [ -n "$config" ]
set config ".$config"
set _flag_apply "_: ($_flag_apply) ((import $(status dirname)/../../../lib/eval-attribute.nix) _)"
end
ROOT="$(realpath (status dirname))/../../.." \
PROPERTY="$property" \
nix eval --impure --extra-experimental-features "nix-command flakes" \
--apply "$_flag_apply" \
"$(status dirname)/../../..#valhalla$config" \
$argv
end

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, "%AppData%/$([System.IO.Path]::GetRelativePath($env:AppData, $path))", "User");
} else {
. "$PSScriptRoot/../aliae/Manage.ps1";
Add-EnvironmentVariable -User $Arguments.Name $varName ($path).Replace("~", "{{ .Home }}");
}
}
};

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 |
$profiles = @(
$profiles |
ForEach-Object { [System.IO.Path]::GetRelativePath((Get-Location), $_) } |
ForEach-Object { "$HomeDir/$_" };
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,113 @@
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");
}
$config = Get-Config "$root.git";
<#
.SYNOPSIS
Sets a configuration option in git.
#>
function Set-GitConfig {
sudo @sudoArgs git config @configArgs $args;
}
if ((-not $IsWindows) -or $User) {
$branch = $config.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 = $config."$key".mainBranch;
$devBranch = $config."$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 = $config.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

@ -26,7 +26,7 @@ begin
"Terminal=false" (
printf "%s " \
"Exec=env" \
"CONFIG_MODULE=$(echo "$CONFIG_MODULE" | string escape)" \
"CONFIG_NAME=$(echo "$CONFIG_NAME" | string escape)" \
"konsole -e fish $(realpath (status filename) | string escape) userConfig"
)
end | sudo -u "$name" tee "$entryPoint" > /dev/null
@ -36,7 +36,7 @@ begin
rm "$entryPoint"
rm ~"$name"/.config/plasma-welcomerc
else if [ -n "$name" ] && [ "$name" != "$USER" ]
sudo -Eu "$name" CONFIG_MODULE="$CONFIG_MODULE" fish "$(status filename)" userConfig
sudo -Eu "$name" CONFIG_NAME="$CONFIG_NAME" fish "$(status filename)" userConfig
else
systemctl --user enable rclone.service
echo "Please complete the setup of your rclone configurations!"

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

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

View file

@ -4,7 +4,7 @@ param(
)
. "$PSScriptRoot/../../../Common/Scripts/Software.ps1";
. "$PSScriptRoot/../../Scripts/System.ps1";
. "$PSScriptRoot/../../../Common/Scripts/System.ps1";
Start-SoftwareInstaller @PSBoundParameters `
-Installer {

View file

@ -3,7 +3,9 @@ param(
[hashtable] $Arguments
)
$null = New-Module {
& {
param($parameters);
. "$PSScriptRoot/../../../Common/Scripts/Software.ps1";
$softwarePath = "$PSScriptRoot/../../Software";
@ -12,17 +14,17 @@ $null = New-Module {
"$softwarePath/TobiiGameHub/Manage.ps1"
);
Start-SoftwareInstaller @PSBoundParameters `
Start-SoftwareInstaller @parameters `
-Installer {
Install-SetupPackage -Source "https://files.update.tech.tobii.com/Tobii_Eye_Tracking_Core_v2.16.8.214_x86.exe";
foreach ($script in $appScripts) {
. $script @PSBoundParameters;
. $script @parameters;
}
} `
-UserConfigurator {
foreach ($script in $appScripts) {
. $script @PSBoundParameters;
. $script @parameters;
}
};
};
} $PSBoundParameters;

View file

@ -0,0 +1,4 @@
#!/bin/pwsh
. "$PSScriptRoot/Manage.ps1";
$env:INSTALLER_SCRIPT = "$PSCommandPath";
Start-WindowsBackup;

View file

@ -1,526 +1,3 @@
#!/bin/pwsh
. "$PSScriptRoot/../../../scripts/Windows/Scripts/Prerequisites.ps1";
. "$PSScriptRoot/../../Common/Scripts/Context.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/Update.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 {
while (-not (Get-IsFinished)) {
if ($null -eq (Get-Stage)) {
Set-Stage ([SetupStage]::Initialize);
} elseif ((Get-Stage) -eq ([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 "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 (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 (& { wsl --status; $?; })) {
wsl --install --no-launch;
Restart-Intermediate;
return;
}
if (-not (wsl --shell-type login type -t nix)) {
ubuntu install --root;
wsl -- sh `<`(curl -L https://nixos.org/nix/install`) --daemon --yes;
wsl --shutdown;
continue;
}
Invoke-Hook "Install-PSModules" -Fallback {
Install-Module -AcceptLicense -Force PSWindowsUpdate;
Install-Module -AcceptLicense -Force PSScriptAnalyzer;
. "$PSScriptRoot/../Software/PinnedItem/Manage.ps1";
};
if (-not (Test-PSPackage Selenium.WebDriver)) {
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;
Set-Stage ([SetupStage]::Configure);
} else {
$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
)
[bool] $install = $null;
$arguments = [hashtable]@{ };
if ($Action) {
$install = $true;
$null = $arguments.Add("action", $Action);
} else {
$install = ($Action -eq ([InstallerAction]::Install));
}
# Drivers
$null = New-Module {
$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.corsairLighting") {
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;
}
};
$null = New-Module {
# 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/RetorArch/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
$service = Get-Service W32Time;
$stopped = ($service.Status -eq "Stopped");
Start-Service $service;
w32tm /resync /force;
if ($stopped) {
Stop-Service $service;
}
}
Set-Stage ([SetupStage]::Install);
}
([SetupStage]::Install) {
Write-Host "Entering install phase";
Deploy-SoftwareAction;
Set-Stage ([SetupStage]::CreateUser);
}
([SetupStage]::CreateUser) {
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;
}
}
}
}
};
Start-WindowsInstallation;

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,350 @@
#!/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";
using namespace System.Security.Principal;
function Backup-WindowsInstallation([Context] $context) {
Write-Information "Backing up Windows";
. "$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";
$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";
<#
.SYNOPSIS
Finishes the installation of a running Windows machine.
#>
function Start-WindowsInstallation {
Start-Operation -NoImplicitCleanup {
Start-InstallationLoop ([WindowsInstallerAction]::Install);
};
}
<#
.SYNOPSIS
Creates a backup of the current Windows machine.
#>
function Start-WindowsBackup {
Start-Operation -NoImplicitCleanup {
Start-InstallationLoop ([WindowsInstallerAction]::Backup);
};
}
<#
.SYNOPSIS
Starts the installation loop.
#>
function Start-InstallationLoop {
param(
[WindowsInstallerAction] $Action
)
while ((Get-Stage) -ne ([WindowsInstallerStage]::Completed)) {
switch (Get-Stage) {
($null) {
Set-Stage ([WindowsInstallerStage]::Initialize);
break;
}
([WindowsInstallerStage]::Initialize) {
$env:BACKUP_ARCHIVE = pwsh -Command Write-Host (
Read-Host (
& {
switch ($Action) {
([WindowsInstallerAction]::Backup) {
"Please select the path you wish to store your backup at"
}
([WindowsInstallerAction]::Install) {
"Please select an archive you wish to restore from, if you wish to restore from a backup"
}
}
}));
Set-Stage ([WindowsInstallerStage]::Run);
break;
}
([WindowsInstallerStage]::Run) {
switch ($Action) {
([WindowsInstallerAction]::Install) {
while (-not (Get-IsFinished)) {
if (Test-Admin) {
$null = Import-Module PSWindowsUpdate;
Invoke-Hook "Invoke-WindowsUpdate" -Fallback {
Update-WindowsInstallation;
};
if ((Get-WURebootStatus -Silent)) {
Restart-Intermediate;
return;
}
}
switch (Get-SetupStage) {
($null) {
Set-SetupStage ([SetupStage]::Initialize);
break;
}
([SetupStage]::Initialize) {
Set-SetupStage ([SetupStage]::Configure);
}
([SetupStage]::Configure) {
if (Get-Config "valhalla.windows.dualboot.enable") {
if (-not (Test-Qemu)) {
# Fix synchronization between Linux and Windows clocks.
Set-ItemProperty "HKLM:\SYSTEM\CurrentControlSet\Control\TimeZoneInformation" -Name "RealTimeIsUniversal" -Value 1 -Type "DWord";
}
# Force time resynchronization
$timeZoneOption = "Start";
$timeZoneKey = "HKLM:\SYSTEM\CurrentControlSet\Services\tzautoupdate";
$service = Get-Service W32Time;
$autoUpdate = (Get-Item $timeZoneKey).GetValue($timeZoneOption);
$stopped = ($service.Status -eq "Stopped");
$setUpdate = { param([int] $Value) Set-ItemProperty $timeZoneKey -Name $timeZoneOption $Value };
& $setUpdate 3;
Start-Service $service;
w32tm /resync /force;
& $setUpdate $autoUpdate;
if ($stopped) {
Stop-Service $service;
}
}
Set-SetupStage ([SetupStage]::Install);
}
([SetupStage]::Install) {
Write-Host "Entering install phase";
Deploy-SoftwareAction;
Set-SetupStage ([SetupStage]::CreateUser);
}
([SetupStage]::CreateUser) {
Install-ValhallaUsers;
Set-IsFinished $true;
}
}
}
}
([WindowsInstallerAction]::Backup) {
$finished = $false;
$setupUser = Get-SetupUser;
$adminGroup = @{
SID = [SecurityIdentifier]::new([WellKnownSidType]::BuiltinAdministratorsSid, $null);
};
while (-not $finished) {
switch (Get-BackupStage) {
$null {
Set-BackupStage ([BackupStage]::Initialize);
}
([BackupStage]::Initialize) {
$null = New-LocalUser $setupUser -NoPassword;
Set-LocalUser $setupUser -PasswordNeverExpires $true;
Set-LocalUser $setupUser -PasswordNeverExpires $false;
Add-LocalGroupMember -Member $setupUser @adminGroup;
Set-AutologinUser $setupUser;
Disable-UAC;
Set-BackupStage ([BackupStage]::Backup);
Restart-Intermediate;
return;
}
([BackupStage]::Backup) {
Deploy-SoftwareAction ([InstallerAction]::Backup);
Set-BackupStage ([BackupStage]::BackupUsers);
}
([BackupStage]::BackupUsers) {
$users = @(Get-Users);
$i = Get-CurrentUser;
Disable-LocalUser $setupUser;
for (; $i -lt $users.Count; $i++) {
Set-CurrentUser $i;
$user = $users[$i];
if ($env:UserName -ne $user) {
Set-BootMessage "Please Log In" "Please log in with the user ``$user``";
Add-LocalGroupMember -Member "$user" @adminGroup -ErrorAction SilentlyContinue;
Disable-Autologin;
Restart-Intermediate;
return;
} else {
Deploy-SoftwareAction -Action ([InstallerAction]::BackupUser);
Remove-LocalGroupMember -Member "$user" @adminGroup;
foreach ($group in Get-UserConfig -UserName "$user" "groups") {
Add-LocalGroupMember -Member "$user" $group;
}
}
}
Disable-BootMessage;
Write-Host "Never forget to store the backup somewhere safe!";
Write-Host "I mean… what kind of a dumbass would ever forget to do so, right?";
Read-Host "Press enter once you're done";
$finished = $true;
}
}
}
}
}
Set-Stage ([WindowsInstallerStage]::Cleanup);
break;
}
([WindowsInstallerStage]::Cleanup) {
$taskName = "PortValhalla Cleaner";
$setupUser = Get-SetupUser;
Clear-OperationResources;
Remove-Item -Recurse -Force "C:\ProgramData\PortValhalla";
Get-SetupConfigKey | Remove-Item -Recurse -Force;
Disable-Autologin;
Disable-LocalUser $setupUser;
$script = {
param(
$TaskName,
$UserName
)
$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);
Enable-UAC;
Restart-Intermediate -NoRegister;
break;
}
}
}
}
function Invoke-WindowsInstallation([Context] $context) {
$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;
$context.UserNames ??= @("Manuel");
Start-OldWindowsInstallationScript $context;
}
else
{
return $backupPath;
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;
Restore-Nextcloud $context;
choco install -y selenium-gecko-driver;
$null = Install-Package -Force Selenium.WebDriver -RequiredVersion 4.10.0 -SkipDependencies;
Write-Information "Determining Backup Archive Path";
$backupPath = Read-Path;
$context.BackupName ??= "PortValhalla";
$context.RootDir = $context.GetTempDirectory();
winget install --accept-source-agreements --accept-package-agreements -e --id AutoHotkey.AutoHotkey;
if ($backupPath)
{
$context.Restore($backupPath, $context.BackupRoot());
$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;
}
Copy-UserInternationalSettingsToSystem -WelcomeScreen $True -NewUser $False;
Restore-PersonalFiles $context;
if ((Get-Command Restore-Apps -ErrorAction SilentlyContinue)) {
Restore-Apps $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;
Remove-Item -Recurse $context.RootDir;
$context.Cleanup();
}
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

@ -2,16 +2,18 @@
. "$PSScriptRoot/../../Common/Scripts/Scripting.ps1";
function Start-Setup {
param($ConfigurationName)
. "$PSScriptRoot/../../Common/Scripts/Config.ps1";
. "$PSScriptRoot/../../Common/Scripts/Scripting.ps1";
$Global:InformationPreference = "Continue";
$Global:ErrorActionPreference = "Inquire";
$env:CONFIG_NAME ??= $ConfigurationName;
$null = $env:WIN_COMPUTER_NAME;
$null = $env:SETUP_SCRIPT_NAME;
$null = $env:CONFIG_MODULE;
$env:WSLENV = "CONFIG_MODULE/p";
$valhallaConfig = ConvertFrom-Json (Get-Content "$env:CONFIG_MODULE.json");
$null = $env:SETUP_SCRIPT_NAME ??= "$PSScriptRoot/Install.ps1";
$env:WSLENV = "CONFIG_NAME";
Show-ProfileNamePrompt;
$valhallaConfig = ConvertFrom-Json (Get-Content "$PSScriptRoot/../../../.config/$env:CONFIG_NAME.json");
[xml]$unattendedConfig = [xml]::new();
$unattendedConfig.PreserveWhitespace = $true;
@ -186,6 +188,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 +226,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_NAME = $(ConvertTo-Injection $env:CONFIG_NAME);" +
"& (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;
@ -254,4 +266,4 @@ function Start-Setup {
& "$SETUP_DRIVE\setup.exe" /Unattend:$unattendedConfigFile;
}
Start-Setup
Start-Setup @args;

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

@ -61,7 +61,6 @@ $null = New-Module {
[System.Xml.XmlNode] $association = $null;
$document = Get-DefaultAppAssociations;
$candidates = $document.SelectNodes((& $getSelector $Identifier));
Write-Host "Number of potential associations: $($candidates.Count)"
if ($candidates.Count -eq 1) {
$association = $candidates[0];
@ -105,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,296 @@
. "$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;
}
$hardware = Get-Config "valhalla.hardware";
$collections = Get-Config "valhalla.windows.software";
# Drivers
& {
$driverPath = "$PSScriptRoot/../Drivers";
$mbPath = "$driverPath/ROG Zenith Extreme Alpha";
if ($install) {
if ($hardware.elgatoWave) {
if (-not (Test-ChocoPackage wavelink)) {
Install-ChocoPackage wavelink -ArgumentList '--install-arguments="/norestart"';
Remove-DesktopIcon "*Wave Link*";
Restart-Intermediate;
exit;
}
}
}
foreach ($component in $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 ($hardware.amdCPU) {
Install-ChocoPackage amd-ryzen-master;
# ToDo: backup Ryzen energy saving plan
}
if ($hardware.nvidiaGPU) {
Install-ChocoPackage geforce-game-ready-driver;
Remove-DesktopIcon "*Geforce*";
}
if ($hardware.corsairDevice) {
Install-ChocoPackage icue;
}
}
if ($hardware.eyeX) {
& "$driverPath/Tobii EyeX/Manage.ps1" @arguments;
}
};
& {
$softwarePath = "$PSScriptRoot/../Software";
$commonSoftware = "$PSScriptRoot/../../Common/Software";
# Windows Config
& "$softwarePath/Windows/Manage.ps1" @arguments;
if ($hardware.logitechG) {
& "$softwarePath/LGHub/Manage.ps1" @arguments;
}
# Essentials
if ($collections.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 ($collections.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 ($collections.desktopExperience) {
if ($install) {
# Fonts
Install-ChocoPackage nerd-fonts-CascadiaCode;
# Internet Access
Install-WingetPackage Brave.Brave kamranahmedse.pennywise;
Remove-DesktopIcon "*Brave*";
Remove-TaskbarItem "*Brave*";
Remove-DesktopIcon "Pennywise*";
# Tools
Install-SetupPackage -Source "https://github.com/mRemoteNG/mRemoteNG/releases/download/2023.03.03-v1.77.3-nb/mRemoteNG-Installer-1.77.3.nb-1784.msi" -ArgumentList "/Quiet";
Remove-DesktopIcon "mRemoteNG*";
Install-ChocoPackage `
gimp `
gpu-z `
windirstat `
winmerge `
handbrake `
hwmonitor `
qbittorrent `
imgburn `
inkscape `
krita `
MetaX `
obs-studio `
;
Remove-DesktopIcon "GIMP*";
Remove-DesktopIcon "GPU-Z*";
Remove-DesktopIcon "WinDirStat*";
Remove-DesktopIcon "*HWMonitor*";
Remove-DesktopIcon "ImgBurn*";
Remove-DesktopIcon "InkScape*";
Remove-DesktopIcon "Krita*";
Remove-DesktopIcon "MetaX*";
Remove-DesktopIcon "OBS Studio*";
Install-WingetPackage `
AntSoftware.AntRenamer `
AppWork.JDownloader `
;
Remove-DesktopIcon "JDownloader*";
}
# ToDo: Consider hiding behind own config?
& "$softwarePath/Ubiquiti UniFi Controller/Manage.ps1" @arguments;
# Internet Access
& "$softwarePath/Firefox/Manage.ps1" @arguments;
& "$softwarePath/MSEdgeRedirect/Manage.ps1" @arguments;
if ($collections.fileSync) {
& "$softwarePath/Nextcloud/Main.ps1" @arguments;
}
}
if ($collections.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 ($collections.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 ($collections.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 ($collections.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

@ -1,17 +1,62 @@
using namespace Microsoft.Win32;
$null = New-Module {
. "$PSScriptRoot/../Scripts/Registry.ps1";
. "$PSScriptRoot/../../Common/Scripts/Config.ps1";
. "$PSScriptRoot/../../Common/Scripts/Scripting.ps1";
[RegistryKey] $key = $null;
$runOncePath = "HKLM:\Software\Microsoft\Windows\CurrentVersion\RunOnce";
$runOncePath = "Software\Microsoft\Windows\CurrentVersion\RunOnce";
$systemRunOncePath = "HKLM:\$runOncePath";
$logonPath = "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon"
$runOnceName = "PortValhalla";
$autologinOption = "AutoAdminLogon";
$domainOption = "DefaultDomainName";
$userOption = "DefaultUserName";
$passwordOption = "DefaultPassword";
<#
.SYNOPSIS
Gets the reghistry key containing the `RunOnce` commands.
#>
function Get-RunOnceKey {
Get-Item $runOncePath;
param(
[RegistryKey] $UserKey
)
[string] $path = $null;
if ($UserKey) {
$path = Join-Path ($UserKey.PSPath) $runOncePath;
} else {
$path = $systemRunOncePath;
}
if (-not (Test-Path $path)) {
New-Item $path;
} else {
Get-Item $path;
}
}
<#
.SYNOPSIS
Generates a script for executing the installer.
#>
function Get-StartupScript {
"pwsh -Command " + (Get-StartupCommand);
}
<#
.SYNOPSIS
Generates a command for running the installer using `pwsh`.
#>
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 ([System.IO.Path]::GetFullPath($env:BACKUP_ARCHIVE)));" : "") +
"`$env:INSTALLER_SCRIPT = $(ConvertTo-Injection (Resolve-Path $env:INSTALLER_SCRIPT));" +
"`$env:CONFIG_NAME = $(ConvertTo-Injection $env:CONFIG_NAME);" +
"& `$env:INSTALLER_SCRIPT;";
}
<#
@ -23,28 +68,123 @@ $null = New-Module {
#>
function Register-Setup {
param(
[Parameter(ParameterSetName="System")]
[switch] $System,
[Parameter(ParameterSetName="DefaultUser", Mandatory)]
[switch] $DefaultUser,
[Parameter(ParameterSetName="User", Mandatory)]
[switch] $User,
[Parameter(ParameterSetName="User")]
[Parameter(ParameterSetName="SpecificUser", Mandatory)]
[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:\";
}
$key = Get-RunOnceKey $UserKey;
} else {
$key = Get-RunOnceKey;
}
Set-ItemProperty -Path $key.PSPath -Name $runOnceName -Type "ExpandString" -Value (
"pwsh -Command " +
"`$env:PWSH_PATH = $(ConvertTo-Injection $env:PWSH_PATH);" +
"`$env:INSTALLER_SCRIPT = $(ConvertTo-Injection $env:INSTALLER_SCRIPT);" +
"`$env:CONFIG_MODULE = $(ConvertTo-Injection $env:CONFIG_MODULE);" +
"& `$env:INSTALLER_SCRIPT;"
);
Set-ItemProperty -Path $key.PSPath -Name $runOnceName -Type "ExpandString" -Value (Get-StartupScript);
$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.
.PARAMETER Name
The name of the user to login automatically.
#>
function Set-AutologinUser {
param(
[string] $Name
)
Set-ItemProperty $logonPath -Name $autologinOption "1";
if (-not $Name) {
$Name = Get-SetupUser;
}
$options = @{
$domainOption = "";
$userOption = $Name;
$passwordOption = "";
};
foreach ($key in $options.Keys) {
Set-ItemProperty $logonPath -Name $key -Value $options[$key];
}
}
<#
.SYNOPSIS
Disables the automatic login.
#>
function Disable-Autologin {
Set-ItemProperty $logonPath -Name $autologinOption "0";
foreach ($key in @($domainOption, $userOption, $passwordOption)) {
Remove-ItemProperty $logonPath -Name $key -ErrorAction SilentlyContinue;
}
}
<#
.SYNOPSIS
Reboots the machine intermediately and restarts the setup after the next login.
#>
function Restart-Intermediate {
param(
[Parameter(ParameterSetName="None")]
[switch] $NoRegister,
[Parameter(ParameterSetName="Default", Mandatory)]
[switch] $DefaultUser,
[Parameter(ParameterSetName="Current", Mandatory)]
[switch] $CurrentUser
)
if (-not $NoRegister.IsPresent) {
if ($DefaultUser.IsPresent) {
Register-Setup -DefaultUser;
} elseif ($CurrentUser.IsPresent) {
Register-Setup -User;
} else {
Register-Setup;
Restart-Computer;
}
}
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
@ -16,4 +18,49 @@ $null = New-Module {
[System.GC]::Collect();
& reg unload $regRootPath;
}
<#
.SYNOPSIS
Sets a message to show on the login screen.
.PARAMETER Caption
The title of the message.
.PARAMETER Message
The text of the message.
#>
function Set-BootMessage {
param(
[string] $Caption,
[string] $Message
)
$options = @{
legalnoticecaption = $Caption;
legalnoticetext = $Message;
};
foreach ($key in $options.Keys) {
Set-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System" `
-Name $key `
-Type "String" `
-Value ($options[$key]);
}
}
<#
.SYNOPSIS
Disables the boot message.
#>
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

@ -0,0 +1,70 @@
using namespace System.Security.AccessControl;
using namespace System.Security.Principal;
$null = New-Module {
$uacOption = "EnableLUA";
$systemPolicyPath = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System";
$uacSetter = {
param(
[bool] $Value
)
Set-ItemProperty -Path $systemPolicyPath -Name $uacOption -Value ([int]$Value);
}
<#
.SYNOPSIS
Determines whether UAC is enabled.
#>
function Get-UACStatus {
[bool](Get-ItemProperty -Path $systemPolicyPath -Name $uacOption);
}
<#
.SYNOPSIS
Enables UAC.
#>
function Enable-UAC {
& $uacSetter $true;
}
<#
.SYNOPSIS
Disables UAC.
#>
function Disable-UAC {
& $uacSetter $false;
}
<#
.SYNOPSIS
Sets read/write permissions for users at the specified path.
.PARAMETER Path
The path to allow access to users.
#>
function Set-UserPermissions {
param(
[string] $Path
)
$acl = Get-Acl $Path;
$acl.AddAccessRule(
[FileSystemAccessRule]::new(
[SecurityIdentifier]::new([WellKnownSidType]::BuiltinUsersSid, $null),
[FileSystemRights]::FullControl,
(& {
if (Test-Path -PathType Container $Path) {
[InheritanceFlags]::ObjectInherit -bor [InheritanceFlags]::ContainerInherit
} else {
0
}
}),
[PropagationFlags]::InheritOnly,
[AccessControlType]::Allow));
Set-Acl $Path $acl;
}
};

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

@ -0,0 +1,267 @@
using namespace System.Management.Automation.Host;
using namespace System.Security.Principal;
$null = New-Module {
. "$PSScriptRoot/../Scripts/Deployment.ps1";
. "$PSScriptRoot/../../Common/Scripts/Config.ps1";
. "$PSScriptRoot/../../Common/Scripts/Operations.ps1";
$loggedInUserOption = "LoggedInUser";
<#
.SYNOPSIS
Installs all pending users to the system.
#>
function Install-ValhallaUsers {
$users = @(Get-Users);
$i = Get-CurrentUser;
for (; $i -lt $users.Count; $i++) {
Set-CurrentUser $i;
$name = $users[$i];
$msAccount = Get-UserConfig -UserName $name "microsoftAccount";
if (Test-Admin) {
Disable-BootMessage;
}
while ((Get-UserStage) -ne ([UserStage]::Completed)) {
switch (Get-UserStage) {
($null) {
Set-UserStage ([UserStage]::Create);
break;
}
([UserStage]::Create) {
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";
}
if (-not $msAccount) {
net user $name /logonpasswordchg:yes;
}
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(
[string] $Name
)
$newUser = & {
while ($true) {
$currentUsers = Get-LocalUser | ForEach-Object { $_.Name };
Write-Host (
@(
"So… Windows is too dumb to create users which are bound to a Microsoft Account.",
"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)";
$null = Read-Host "Hit enter once you're done";
$newUsers = @(Get-LocalUser | Where-Object { -not ($currentUsers -contains $_.Name) });
if ($newUsers.Count) {
if ($newUsers.Count -eq 1) {
$newUser = $newUsers[0];
Write-Host "Found new user ``$newUser``";
if (
$Host.UI.PromptForChoice(
"Confirm",
"Is ``$newUser`` your user?",
[ChoiceDescription[]]@(
[ChoiceDescription]::new("&No", "``$newUser`` is not your user"),
[ChoiceDescription]::new("&Yes", "``$newUser`` is your user")),
0) -eq 1) {
return $newUser;
}
} else {
$result = $Host.UI.PromptForChoice(
"Select your User",
"Which one is your user?",
[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);
if ($result -gt 0) {
return $newUsers[$result - 1];
}
}
} else {
Write-Host "";
Write-Host "Unable to determine the new user";
Write-Host "Retrying…";
}
}
};
Set-MSAccountName ([string]$newUser);
}
if ($MSAccount) {
if (Test-Admin) {
Write-Host "Preparing environment for creating MS Account";
Register-Setup -DefaultUser;
Enable-OneShotListener;
Enable-UAC;
# Reset Windows activation status
# Otherwise the login won't work - Windows is fricking frustrating.
slmgr /upk;
slmgr /cpky;
slmgr /rearm;
Restart-Intermediate -CurrentUser;
exit;
}
}
Write-Host "Creating personal user ``$Name``";
if ($MSAccount) {
Add-MicrosoftAccount $Name;
Set-SetupOption $loggedInUserOption $env:UserName;
Invoke-OneShot ([OneShotTask]::InitializeMSAccount);
} else {
New-LocalUser -NoPassword $Name;
Set-LocalUser $Name -PasswordNeverExpires $true;
Set-LocalUser $Name -PasswordNeverExpires $false;
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,126 @@
. "$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;
# Microsoft broke WSL - Quelle surprise!
# ToDo: Remove this workaround once it's unbroken
. "$PSScriptRoot/../../Common/Scripts/Software.ps1";
Install-SetupPackage "https://github.com/microsoft/WSL/releases/download/2.3.17/wsl.2.3.17.0.x64.msi" -ArgumentList "/Quiet";
}
<#
.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 (-not (Get-AppxPackage $ubuntuPattern)) {
Install-Wsl;
}
wsl --shutdown;
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 `
<#
.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 = $candidates[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

Some files were not shown because too many files have changed in this diff Show more