PortValhalla/scripts/Common/Scripts/Config.ps1

608 lines
15 KiB
PowerShell

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
Install
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 (-not $IsWindows -or (Test-Command "wsl")) {
return Invoke-ConfigScript "getProfiles";
} else {
return Get-ChildItem "$PSScriptRoot/../../../.config" | ForEach-Object { Split-Path -LeafBase $_ };
}
};
$choice = $Host.UI.PromptForChoice(
"Select Profile",
(& {
if ($IsWindows) {
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?";
}
}
} else {
"Please select a profile:";
}
}),
(& {
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.
.PARAMETER Path
The path to convert.
#>
function ConvertTo-LinuxPath {
param(
[string] $Path
)
& {
$ErrorActionPreference = 'Continue';
$completed = $false;
while (-not $completed) {
$job = Start-Job {
$env:Value = Resolve-Path $Using:Path;
$env:WSLENV = "Value/p";
$result = wsl -- bash -c 'echo "$Value"';
wsl -e printf "%q" "$result";
};
$result = Receive-Job -Wait $job;
if ((Split-Path -Leaf $Path) -ne (Split-Path -Leaf $result)) {
Write-Error "The result of the path conversion of ``$Path`` was unexpected: ``$result``";
continue;
}
if ($job.State -ne ([System.Management.Automation.JobState]::Completed)) {
Write-Error "An error occurred while converting ``$Path`` to a Linux path.`nOutput: ``$result``";
continue;
}
$completed = $true;
}
$result;
};
}
<#
.SYNOPSIS
Gets the registry key containing options related to the setup.
#>
function Get-SetupConfigKey {
if (-not (Test-Path $configRoot)) {
$key = New-Item $configRoot;
$acl = Get-Acl $configRoot;
$acl.AddAccessRule(
[RegistryAccessRule]::new(
[SecurityIdentifier]::new([WellKnownSidType]::BuiltinUsersSid, $null),
[RegistryRights]::FullControl,
[InheritanceFlags]::ObjectInherit -bor [InheritanceFlags]::ContainerInherit,
[PropagationFlags]::None,
[AccessControlType]::Allow));
Set-Acl $configRoot $acl;
} else {
$key = Get-Item $configRoot;
}
return $key;
}
<#
.SYNOPSIS
Runs a script based on the `config.fish` script.
.PARAMETER Script
The script to run.
#>
function Invoke-ConfigScript {
param(
[string] $Script
)
$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
}
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;
}
}
<#
.SYNOPSIS
Gets a configuration option.
.PARAMETER Name
The name of the configuration value to get.
.PARAMETER ArgumentList
The arguments to send to the configuration script.
#>
function Get-Config {
param(
[string] $Name,
[Parameter(ValueFromRemainingArguments)]
[string[]] $ArgumentList
)
Invoke-ConfigScript "getConfig $Name --json $ArgumentList";
}
<#
.SYNOPSIS
Gets the name of the config root.
#>
function Get-OSConfigRoot {
return "valhalla.$($IsWindows ? "windows" : "linux")";
}
<#
.SYNOPSIS
Gets the configuration value for the current operating system.
.PARAMETER Name
The name of the configuration value to get.
.PARAMETER ArgumentList
The arguments to send to the configuration script.
#>
function Get-OSConfig {
param(
[string] $Name,
[Parameter(ValueFromRemainingArguments)]
[string[]] $ArgumentList
)
return Get-Config -Name "$(Get-OSConfigRoot).$Name" @PSBoundParameters;
}
<#
.SYNOPSIS
Gets the name of the user root.
#>
function Get-UserConfigRoot {
return "$(Get-OSConfigRoot).$($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-UserConfigRoot).$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";
}
<#
.SYNOPSIS
Gets the names of the users to create.
#>
function Get-Users {
[OutputType([string[]])]
param()
Get-Attributes "$(Get-UserConfigRoot)";
}
<#
.SYNOPSIS
Gets the name of the setup user.
#>
function Get-SetupUser {
[OutputType([string])]
param()
Get-OSConfig "setupUser.name";
}
<#
.SYNOPSIS
Gets the value of an option related to the setup.
.PARAMETER Name
The name of the option value to get.
#>
function Get-SetupOption {
param(
[string] $Name
)
$key = Get-SetupConfigKey;
if ($key.GetValueNames().Contains($Name)) {
return $key.GetValue($Name);
} else {
return $null;
}
}
<#
.SYNOPSIS
Sets the value of an option related to the setup.
.PARAMETER Name
The name of the option to set.
.PARAMETER Value
The value to set the option to.
#>
function Set-SetupOption {
param(
[string] $Name,
$Value
)
$key = (Get-SetupConfigKey).PSPath;
if ($null -eq $Value) {
Remove-ItemProperty $key -Name $Name;
} else {
$null = Set-ItemProperty $key -Name $Name -Value $Value;
}
}
<#
.SYNOPSIS
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;
}
return $stage;
}
<#
.SYNOPSIS
Sets the current stage.
.PARAMETER Name
The name to set the current stage to.
#>
function Set-SetupStage {
param(
$Name
)
if (-not (($null -eq $Name) -or ($Name -is [string]))) {
$Name = ([SetupStage]$Name).ToString();
}
$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;
}
<#
.SYNOPSIS
Gets a value indicating whether the setup has finished.
#>
function Get-IsFinished {
return [bool](Get-SetupOption $finishedOption);
}
<#
.SYNOPSIS
Sets a value indicating whether the setup has finished.
#>
function Set-IsFinished {
param(
$Value
)
Set-SetupOption $finishedOption $true;
}
<#
.SYNOPSIS
Checks whether the running system is a QEMU virtual machine.
#>
function Test-Qemu {
((Get-WmiObject win32_computersystem).Manufacturer) -eq "QEMU";
}
<#
.SYNOPSIS
Checks whether the current user is the setup user.
#>
function Test-SetupUser {
($IsWindows ? $env:UserName : $env:USER) -eq (Get-SetupUser);
}
<#
.SYNOPSIS
Checks whether the active session is executed with admin rights.
#>
function Test-Admin {
net session 2> $null | Out-Null;
return $?;
}
}