Compare commits
12 commits
493847e727
...
39abd90b34
Author | SHA1 | Date | |
---|---|---|---|
Manuel Thalmann | 39abd90b34 | ||
Manuel Thalmann | 540481e966 | ||
Manuel Thalmann | a25e743047 | ||
Manuel Thalmann | f9562472fe | ||
Manuel Thalmann | 1532fbbc9e | ||
Manuel Thalmann | 8f6195c958 | ||
Manuel Thalmann | 0ed1f9e218 | ||
Manuel Thalmann | eecea60f1c | ||
Manuel Thalmann | 32be282910 | ||
Manuel Thalmann | 3daf4ee8e7 | ||
Manuel Thalmann | c7fd9676ce | ||
Manuel Thalmann | dbef105780 |
|
@ -1,10 +1,29 @@
|
|||
{ lib, ... }:
|
||||
{ config, 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 = {
|
||||
|
@ -21,44 +40,45 @@
|
|||
};
|
||||
});
|
||||
|
||||
userType = types.submodule (
|
||||
{ ... }: {
|
||||
options = {
|
||||
displayName = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
description = "The human-readable name of the user.";
|
||||
default = null;
|
||||
};
|
||||
|
||||
mailAddress = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
description = "The mail address of the user.";
|
||||
default = null;
|
||||
};
|
||||
|
||||
groups = mkOption {
|
||||
type = types.listOf types.str;
|
||||
description = "The additional groups of the user.";
|
||||
default = [];
|
||||
};
|
||||
|
||||
defaultShell = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
description = "The default shell of the user.";
|
||||
default = null;
|
||||
};
|
||||
|
||||
git = (import ./git/options.nix) { inherit lib; };
|
||||
|
||||
rclone = {
|
||||
configurations = mkOption {
|
||||
type = types.attrsOf syncType;
|
||||
description = "The configurations of the rclone mounts.";
|
||||
default = {};
|
||||
mkUserType = { options }: (
|
||||
types.submodule (
|
||||
{ ... }: {
|
||||
options = {
|
||||
displayName = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
description = "The human-readable name of the user.";
|
||||
default = null;
|
||||
};
|
||||
};
|
||||
|
||||
mailAddress = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
description = "The mail address of the user.";
|
||||
default = null;
|
||||
};
|
||||
|
||||
groups = mkOption {
|
||||
type = types.listOf types.str;
|
||||
description = "The additional groups of the user.";
|
||||
default = [];
|
||||
};
|
||||
|
||||
git = (import ./git/options.nix) { inherit lib; };
|
||||
} // options;
|
||||
}));
|
||||
|
||||
userType = mkUserType {
|
||||
options = linuxOptions;
|
||||
};
|
||||
|
||||
winUserType = mkUserType {
|
||||
options = {
|
||||
microsoftAccount = mkOption {
|
||||
type = types.bool;
|
||||
description = "A value indicating whether this user is a Microsoft Account.";
|
||||
default = false;
|
||||
};
|
||||
});
|
||||
};
|
||||
};
|
||||
in {
|
||||
options = {
|
||||
valhalla = {
|
||||
|
@ -67,6 +87,27 @@
|
|||
description = "The users to create on the machine.";
|
||||
default = {};
|
||||
};
|
||||
|
||||
windows.users = mkOption {
|
||||
type = types.attrsOf winUserType;
|
||||
description = "The users to create on the Windows machine.";
|
||||
default = (lib.attrsets.concatMapAttrs (
|
||||
name: options:
|
||||
if builtins.elem name (builtins.attrNames linuxOptions)
|
||||
then {}
|
||||
else {
|
||||
${capitalize name} = (lib.attrsets.concatMapAttrs (
|
||||
name: value:
|
||||
if builtins.elem name (builtins.attrNames linuxOptions)
|
||||
then {}
|
||||
else {
|
||||
${name} = value;
|
||||
}
|
||||
) options) // {
|
||||
groups = [];
|
||||
};
|
||||
}) cfg.users);
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{ lib, config, options, ... }:
|
||||
{ lib, config, ... }:
|
||||
let
|
||||
inherit (lib)
|
||||
mkOption
|
||||
|
@ -7,16 +7,8 @@
|
|||
types
|
||||
;
|
||||
|
||||
users = config.valhalla.users;
|
||||
setupUser = config.valhalla.setupUser.name;
|
||||
|
||||
capitalize = text:
|
||||
let
|
||||
chars = lib.strings.stringToCharacters text;
|
||||
in lib.strings.concatStrings (
|
||||
[(lib.strings.toUpper (builtins.elemAt chars 0))] ++
|
||||
(lib.lists.drop 1 chars)
|
||||
);
|
||||
capitalize = (import ../text.nix { inherit lib; }).capitalize;
|
||||
|
||||
winType = types.submodule (
|
||||
{ config, ... }: {
|
||||
|
@ -27,15 +19,6 @@
|
|||
default = capitalize setupUser;
|
||||
};
|
||||
|
||||
users = mkOption {
|
||||
type = options.valhalla.users.type;
|
||||
description = "The users to add.";
|
||||
default = lib.attrsets.concatMapAttrs (
|
||||
name: options: {
|
||||
${capitalize name} = options;
|
||||
}) users;
|
||||
};
|
||||
|
||||
dualboot = {
|
||||
enable = mkEnableOption "dual boot";
|
||||
|
||||
|
|
9
lib/text.nix
Normal file
9
lib/text.nix
Normal file
|
@ -0,0 +1,9 @@
|
|||
{ lib, ... }: {
|
||||
capitalize = text:
|
||||
let
|
||||
chars = lib.strings.stringToCharacters text;
|
||||
in lib.strings.concatStrings (
|
||||
[(lib.strings.toUpper (builtins.elemAt chars 0))] ++
|
||||
(lib.lists.drop 1 chars)
|
||||
);
|
||||
}
|
|
@ -10,6 +10,10 @@
|
|||
enable = true;
|
||||
linuxPercentage = 30;
|
||||
};
|
||||
|
||||
users.Manuel = {
|
||||
microsoftAccount = true;
|
||||
};
|
||||
};
|
||||
|
||||
partition.os.partitions = {
|
||||
|
|
|
@ -76,11 +76,16 @@ $null = New-Module {
|
|||
|
||||
$scriptPath = "$PSScriptRoot/../../Common/Scripts/config.fish";
|
||||
|
||||
function fish {
|
||||
wsl --shell-type login -- nix --extra-experimental-features "nix-command flakes" run nixpkgs`#fish -- $args
|
||||
}
|
||||
if (-not $IsWindows) {
|
||||
$escapedPath = (fish -c 'string escape $argv' "$scriptPath");
|
||||
fish -c ". $escapedPath; $Script";
|
||||
} else {
|
||||
function fish {
|
||||
wsl --shell-type login -- nix --extra-experimental-features "nix-command flakes" run nixpkgs`#fish -- $args
|
||||
}
|
||||
|
||||
fish -c ". $(ConvertTo-LinuxPath $scriptPath); $Script" | ConvertFrom-Json;
|
||||
fish -c ". $(ConvertTo-LinuxPath $scriptPath); $Script" | ConvertFrom-Json;
|
||||
}
|
||||
}
|
||||
|
||||
<#
|
||||
|
@ -92,10 +97,51 @@ $null = New-Module {
|
|||
#>
|
||||
function Get-Config {
|
||||
param(
|
||||
[string] $Name,
|
||||
[Parameter(ValueFromRemainingArguments)]
|
||||
[string[]] $ArgumentList
|
||||
)
|
||||
|
||||
Invoke-ConfigScript "getConfig $Name --json $ArgumentList";
|
||||
}
|
||||
|
||||
<#
|
||||
.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 = $env:UserName,
|
||||
[Parameter(Mandatory, Position = 0)]
|
||||
[string] $Name
|
||||
)
|
||||
|
||||
Invoke-ConfigScript "getConfig $Name --json";
|
||||
if ((Get-Users) -contains $UserName) {
|
||||
Get-Config "valhalla.windows.users.$UserName.$Name";
|
||||
} else {
|
||||
return $null;
|
||||
}
|
||||
}
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Gets the attributes of a configuration object.
|
||||
|
||||
.PARAMETER Name
|
||||
The name of the configuration to get the attributes of.
|
||||
#>
|
||||
function Get-Attributes {
|
||||
param(
|
||||
[string] $Name
|
||||
)
|
||||
|
||||
Invoke-ConfigScript "getAttributes $Name";
|
||||
}
|
||||
|
||||
<#
|
||||
|
@ -103,7 +149,7 @@ $null = New-Module {
|
|||
Gets the names of the users to create.
|
||||
#>
|
||||
function Get-Users {
|
||||
Invoke-ConfigScript "getUsers";
|
||||
Get-Attributes "valhalla.windows.users";
|
||||
}
|
||||
|
||||
<#
|
||||
|
|
|
@ -196,9 +196,9 @@ $null = New-Module {
|
|||
function Start-SoftwareInstaller {
|
||||
param(
|
||||
[string] $Name,
|
||||
[scriptblock] $Installer = { },
|
||||
[scriptblock] $Configurator = { },
|
||||
[scriptblock] $UserConfigurator = { },
|
||||
[scriptblock] $Installer = $null,
|
||||
[scriptblock] $Configurator = $null,
|
||||
[scriptblock] $UserConfigurator = $null,
|
||||
[Nullable[InstallerAction]] $Action,
|
||||
[hashtable] $Arguments
|
||||
)
|
||||
|
@ -236,12 +236,16 @@ $null = New-Module {
|
|||
};
|
||||
|
||||
if ($action -eq ([InstallerAction]::Install)) {
|
||||
Write-Host "Installing $Name…";
|
||||
& $Installer @argumentList;
|
||||
if ($Installer) {
|
||||
Write-Host "Installing $Name…";
|
||||
& $Installer @argumentList;
|
||||
}
|
||||
# ToDo: Automatically configure after installation
|
||||
} elseif ($Action -eq ([InstallerAction]::Configure)) {
|
||||
Write-Host "Configuring $Name…";
|
||||
& $Configurator @argumentList;
|
||||
if ($Configurator) {
|
||||
Write-Host "Configuring $Name…";
|
||||
& $Configurator @argumentList;
|
||||
}
|
||||
|
||||
if (-not (Test-SetupUser)) {
|
||||
$argumentList.Add("action", [InstallerAction]::ConfigureUser);
|
||||
|
@ -252,8 +256,10 @@ $null = New-Module {
|
|||
$argumentList.Add($userArgument, ($env:UserName));
|
||||
}
|
||||
|
||||
Write-Host "Configuring $Name for user ``$($Arguments[$userArgument])``…";
|
||||
& $UserConfigurator @argumentList;
|
||||
if ($UserConfigurator) {
|
||||
Write-Host "Configuring $Name for user ``$($Arguments[$userArgument])``…";
|
||||
& $UserConfigurator @argumentList;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -8,8 +8,12 @@ function getConfig -S -a property
|
|||
evalModule "$CONFIG_MODULE" "$property" $argv[2..]
|
||||
end
|
||||
|
||||
function getAttributes -S -a property
|
||||
getConfig "$property" --apply "builtins.attrNames" --json
|
||||
end
|
||||
|
||||
function getUsers -S
|
||||
getConfig valhalla.users --apply "builtins.attrNames" --json
|
||||
getAttributes "valhalla.users"
|
||||
end
|
||||
|
||||
function isSet -S -a property
|
||||
|
|
|
@ -9,6 +9,7 @@ $null = New-Module {
|
|||
. "$PSScriptRoot/../Scripts/Hooks.ps1";
|
||||
. "$PSScriptRoot/../Scripts/PowerManagement.ps1";
|
||||
. "$PSScriptRoot/../Scripts/Update.ps1";
|
||||
. "$PSScriptRoot/../Scripts/Users.ps1";
|
||||
. "$PSScriptRoot/../../Common/Scripts/Config.ps1";
|
||||
. "$PSScriptRoot/../../Common/Scripts/Operations.ps1";
|
||||
. "$PSScriptRoot/../../Common/Scripts/Software.ps1";
|
||||
|
@ -72,26 +73,25 @@ $null = New-Module {
|
|||
continue;
|
||||
}
|
||||
|
||||
if (-not (& { wsl --status; $?; })) {
|
||||
if (-not (& { $null = wsl --status; $?; })) {
|
||||
wsl --install --no-launch;
|
||||
Restart-Intermediate;
|
||||
return;
|
||||
}
|
||||
|
||||
if (-not (wsl --shell-type login type -t nix)) {
|
||||
|
||||
if (-not (& { $null = wsl -l; $?; })) {
|
||||
ubuntu install --root;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (-not (wsl --shell-type login type -t nix)) {
|
||||
wsl -- sh `<`(curl -L https://nixos.org/nix/install`) --daemon --yes;
|
||||
wsl --shutdown;
|
||||
continue;
|
||||
}
|
||||
|
||||
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)) {
|
||||
Write-Host "Installing browser automation tools…";
|
||||
Install-Module -AcceptLicense -Force NuGet;
|
||||
Import-Module NuGet;
|
||||
$null = Install-Package -Force Selenium.WebDriver -RequiredVersion 4.10.0 -SkipDependencies;
|
||||
|
@ -99,6 +99,13 @@ $null = New-Module {
|
|||
}
|
||||
|
||||
Install-ChocoPackage selenium-gecko-driver firefox;
|
||||
|
||||
Invoke-Hook "Install-PSModules" -Fallback {
|
||||
Install-Module -AcceptLicense -Force PSWindowsUpdate;
|
||||
Install-Module -AcceptLicense -Force PSScriptAnalyzer;
|
||||
. "$PSScriptRoot/../Software/PinnedItem/Manage.ps1";
|
||||
};
|
||||
|
||||
Set-Stage ([SetupStage]::Configure);
|
||||
} else {
|
||||
$null = Import-Module PSWindowsUpdate;
|
||||
|
@ -411,6 +418,7 @@ $null = New-Module {
|
|||
Set-Stage ([SetupStage]::CreateUser);
|
||||
}
|
||||
([SetupStage]::CreateUser) {
|
||||
Start-ValhallaUserSetup;
|
||||
Set-IsFinished $true;
|
||||
}
|
||||
}
|
||||
|
|
132
scripts/Windows/Scripts/Users.ps1
Normal file
132
scripts/Windows/Scripts/Users.ps1
Normal file
|
@ -0,0 +1,132 @@
|
|||
using namespace System.Management.Automation.Host;
|
||||
|
||||
$null = New-Module {
|
||||
. "$PSScriptRoot/../../Common/Scripts/Config.ps1";
|
||||
[string] $userOption = "SetupUser";
|
||||
[string] $userStageOption = "UserStage";
|
||||
|
||||
enum UserStage {
|
||||
Create
|
||||
ReEnableFeatures
|
||||
}
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Gets the current stage of the user creation.
|
||||
#>
|
||||
function Get-UserStage {
|
||||
Get-SetupOption -Name $userStageOption;
|
||||
}
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Sets the current user creation stage.
|
||||
|
||||
.PARAMETER Value
|
||||
The value to set the stage to.
|
||||
#>
|
||||
function Set-UserStage {
|
||||
param(
|
||||
[UserStage] $Value
|
||||
)
|
||||
|
||||
Set-SetupOption -Name $userStageOption -Value $Value;
|
||||
}
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Creates the configured users.
|
||||
#>
|
||||
function Start-ValhallaUserSetup {
|
||||
[int] $current = Get-SetupOption $userOption;
|
||||
[string[]] $users = Get-Users;
|
||||
|
||||
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)…";
|
||||
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];
|
||||
}
|
||||
}
|
||||
|
||||
Write-Host "Unable to determine the new user";
|
||||
Write-Host "Retrying…";
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Write-Host "Renaming the new user to ``$Name``…";
|
||||
Rename-LocalUser $newUser $Name;
|
||||
}
|
||||
|
||||
for ($i = $current ?? 0; $i -lt $users.Count; $i++) {
|
||||
Set-SetupOption $userOption $i;
|
||||
$name = $users[$i];
|
||||
Write-Host "Creating personal user ``$name``…";
|
||||
|
||||
if (Get-UserConfig -UserName $name "microsoftAccount") {
|
||||
Add-MicrosoftAccount $name;
|
||||
} else {
|
||||
$displayName = Get-UserConfig -UserName $name "displayName";
|
||||
|
||||
$userArguments = @{
|
||||
name = $name;
|
||||
};
|
||||
|
||||
if ($displayName) {
|
||||
$userArguments.fullName = $displayName;
|
||||
}
|
||||
|
||||
New-LocalUser -NoPassword @userArguments;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
Loading…
Reference in a new issue