2023-07-12 20:37:31 +00:00
|
|
|
#!/bin/pwsh
|
2024-08-07 19:05:32 +00:00
|
|
|
. "$PSScriptRoot/../../Common/Scripts/Scripting.ps1";
|
2024-07-31 12:55:00 +00:00
|
|
|
|
2024-07-28 18:52:07 +00:00
|
|
|
function Start-Setup {
|
2024-09-08 15:09:01 +00:00
|
|
|
param($ConfigurationName)
|
2024-09-08 15:48:02 +00:00
|
|
|
. "$PSScriptRoot/../../Common/Scripts/Config.ps1";
|
2024-08-07 19:05:32 +00:00
|
|
|
. "$PSScriptRoot/../../Common/Scripts/Scripting.ps1";
|
2024-07-28 18:52:07 +00:00
|
|
|
$Global:InformationPreference = "Continue";
|
|
|
|
$Global:ErrorActionPreference = "Inquire";
|
2024-09-08 15:09:01 +00:00
|
|
|
$env:CONFIG_NAME ??= $ConfigurationName;
|
2024-09-08 15:47:28 +00:00
|
|
|
$null = $env:SETUP_SCRIPT_NAME ??= "$PSScriptRoot/Install.ps1";
|
2024-09-08 15:09:01 +00:00
|
|
|
$env:WSLENV = "CONFIG_NAME";
|
2024-07-28 18:52:07 +00:00
|
|
|
|
2024-09-08 15:48:02 +00:00
|
|
|
Show-ProfileNamePrompt;
|
2024-09-08 15:09:01 +00:00
|
|
|
$valhallaConfig = ConvertFrom-Json (Get-Content "$PSScriptRoot/../../../.config/$env:CONFIG_NAME.json");
|
2024-07-28 18:52:07 +00:00
|
|
|
[xml]$unattendedConfig = [xml]::new();
|
|
|
|
$unattendedConfig.PreserveWhitespace = $true;
|
|
|
|
|
|
|
|
$readerSettings = [System.Xml.XmlReaderSettings]::new();
|
|
|
|
$readerSettings.IgnoreComments = $true;
|
|
|
|
$reader = [System.Xml.XmlReader]::Create("$PSScriptRoot/../Resources/Autounattend.template.xml", $readerSettings);
|
|
|
|
|
|
|
|
$unattendedConfig.Load($reader);
|
|
|
|
$namespace = New-Object -TypeName "Xml.XmlNamespaceManager" -ArgumentList $unattendedConfig.NameTable;
|
|
|
|
$namespace.AddNamespace("ua", $unattendedConfig.DocumentElement.NamespaceURI);
|
|
|
|
|
2024-07-28 23:44:12 +00:00
|
|
|
function Get-InstallDisk {
|
|
|
|
[int]$installTarget.Disk.InnerText;
|
|
|
|
}
|
|
|
|
|
2024-07-28 18:52:07 +00:00
|
|
|
function Get-PassSettings {
|
|
|
|
[OutputType([xml])]
|
|
|
|
param(
|
|
|
|
[string] $passName
|
|
|
|
)
|
|
|
|
|
|
|
|
return $unattendedConfig.SelectSingleNode("/ua:unattend/ua:settings[@pass='$passName']", $namespace);
|
|
|
|
}
|
|
|
|
|
2024-07-28 23:44:12 +00:00
|
|
|
function Get-Component {
|
|
|
|
[OutputType([xml])]
|
|
|
|
param(
|
|
|
|
[System.Xml.XmlNode] $pass,
|
|
|
|
[string] $componentName = $null
|
|
|
|
);
|
|
|
|
|
|
|
|
$Local:selector = "./ua:component";
|
|
|
|
|
|
|
|
if ($null -ne $componentName) {
|
|
|
|
$Local:selector += "[@name='$componentName']";
|
|
|
|
}
|
|
|
|
|
|
|
|
return $pass.SelectSingleNode($Local:selector, $namespace);
|
|
|
|
}
|
|
|
|
|
2024-07-28 18:52:07 +00:00
|
|
|
function Get-RemoteScriptPath($path) {
|
|
|
|
$relativePath = [System.IO.Path]::GetRelativePath("$PSScriptRoot/../../..", $path);
|
|
|
|
Join-Path $env:REMOTE_PROJECT_PATH $relativePath;
|
|
|
|
}
|
|
|
|
|
2024-07-31 12:47:42 +00:00
|
|
|
function Get-PathInjection($path) {
|
2024-10-06 19:25:34 +00:00
|
|
|
"(Join-Path `$env:SystemDrive $(ConvertTo-Injection $path))";
|
2024-07-31 12:47:42 +00:00
|
|
|
}
|
|
|
|
|
2024-07-28 18:52:07 +00:00
|
|
|
function Get-ScriptPathInjection($path) {
|
2024-10-06 19:25:34 +00:00
|
|
|
Get-PathInjection (Get-RemoteScriptPath $path);
|
2024-07-28 18:52:07 +00:00
|
|
|
}
|
|
|
|
|
2024-07-28 23:44:12 +00:00
|
|
|
function Get-DiskConfig {
|
|
|
|
param(
|
|
|
|
[int] $Disk
|
|
|
|
)
|
|
|
|
|
|
|
|
$node = $disks | Where-Object { $_.SelectSingleNode("./ua:DiskID", $namespace).InnerText -eq $Disk };
|
|
|
|
$creations = $node.SelectSingleNode("./ua:CreatePartitions", $namespace);
|
|
|
|
$modifications = $node.SelectSingleNode("./ua:ModifyPartitions", $namespace);
|
|
|
|
|
|
|
|
@{
|
2024-10-06 19:25:34 +00:00
|
|
|
PartitionCreationContainer = $creations;
|
|
|
|
PartitionCreations = $creations.SelectNodes("./ua:CreatePartition", $namespace);
|
2024-07-28 23:44:12 +00:00
|
|
|
PartitionModificationContainer = $modifications;
|
2024-10-06 19:25:34 +00:00
|
|
|
PartitionModifications = $modifications.SelectNodes("./ua:ModifyPartition", $namespace);
|
2024-07-28 23:44:12 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
function Move-PartitionRange {
|
|
|
|
param (
|
|
|
|
[int] $Disk = (Get-InstallDisk),
|
2024-10-06 19:25:34 +00:00
|
|
|
[Parameter(Position = 0)]
|
2024-07-28 23:44:12 +00:00
|
|
|
[int] $From = 0,
|
2024-10-06 19:25:34 +00:00
|
|
|
[Parameter(Position = 1)]
|
2024-07-28 23:44:12 +00:00
|
|
|
[System.Nullable[int]] $To = $null,
|
2024-10-06 19:25:34 +00:00
|
|
|
[Parameter(Position = 2)]
|
2024-07-28 23:44:12 +00:00
|
|
|
[int] $By = 1
|
|
|
|
)
|
|
|
|
|
|
|
|
$diskInfo = Get-DiskConfig $Disk;
|
|
|
|
|
|
|
|
if ((Get-InstallDisk) -eq $Disk) {
|
|
|
|
$partition = [int]$installTarget.Partition.InnerText;
|
|
|
|
|
|
|
|
if (($partition -ge $From) -and (($null -eq $To) -or ($partition -le $To))) {
|
|
|
|
$installTarget.Partition.InnerText = "$($partition + $By)";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-10-06 19:25:34 +00:00
|
|
|
foreach ($config in @(
|
|
|
|
@($diskInfo.PartitionCreations, @("Order")),
|
|
|
|
@($diskInfo.PartitionModifications, @("Order", "PartitionID")))) {
|
2024-07-28 23:44:12 +00:00
|
|
|
foreach ($partition in $config[0]) {
|
|
|
|
foreach ($property in $config[1]) {
|
|
|
|
$partitionNode = $partition.SelectSingleNode("./ua:$property", $namespace);
|
|
|
|
$partitionID = [int]$partitionNode.InnerText;
|
|
|
|
$newID = $partitionID;
|
|
|
|
|
|
|
|
if (($newID -ge $From) -and (($null -eq $To) -or ($newID -le $To))) {
|
|
|
|
$newID += $By;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($partitionID -ne $newID) {
|
|
|
|
$partitionNode.InnerText = "$newID";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function Add-Partition {
|
|
|
|
param (
|
|
|
|
[int] $Disk = (Get-InstallDisk),
|
2024-10-06 19:25:34 +00:00
|
|
|
[Parameter(Position = 0)]
|
2024-07-28 23:44:12 +00:00
|
|
|
[int] $Index,
|
2024-10-06 19:25:34 +00:00
|
|
|
[Parameter(Position = 1)]
|
2024-07-28 23:44:12 +00:00
|
|
|
[int] $Size,
|
2024-10-06 19:25:34 +00:00
|
|
|
[Parameter(Position = 2)]
|
2024-07-28 23:44:12 +00:00
|
|
|
[string] $Type = "Primary"
|
|
|
|
)
|
|
|
|
|
|
|
|
$diskInfo = Get-DiskConfig $Disk;
|
|
|
|
Move-PartitionRange -Disk $Disk -From $Index -By 1;
|
|
|
|
|
|
|
|
$configs = @(
|
|
|
|
@(
|
|
|
|
$diskInfo.PartitionCreations,
|
|
|
|
0,
|
|
|
|
@(
|
|
|
|
@("Order", "$Index"),
|
|
|
|
@("Type", "$Type"),
|
|
|
|
@("Size", "$Size"))),
|
|
|
|
@(
|
|
|
|
$diskInfo.PartitionModifications,
|
|
|
|
2,
|
|
|
|
@(
|
|
|
|
@("Order", "$Index"),
|
|
|
|
@("PartitionID", "$Index")))
|
|
|
|
);
|
|
|
|
|
|
|
|
foreach ($config in $configs) {
|
|
|
|
$partition = $config[0][$config[1]];
|
|
|
|
$newPartition = $partition.CloneNode($true);
|
|
|
|
|
|
|
|
foreach ($entry in $config[2]) {
|
|
|
|
$newPartition.SelectSingleNode("./ua:$($entry[0])", $namespace).InnerText = $entry[1];
|
|
|
|
}
|
|
|
|
|
|
|
|
$null = $partition.ParentNode.AppendChild($newPartition);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function Move-Partition {
|
|
|
|
param (
|
|
|
|
[int] $Disk = (Get-InstallDisk),
|
2024-10-06 19:25:34 +00:00
|
|
|
[Parameter(Position = 0)]
|
2024-07-28 23:44:12 +00:00
|
|
|
[int] $From,
|
2024-10-06 19:25:34 +00:00
|
|
|
[Parameter(Position = 1)]
|
2024-07-28 23:44:12 +00:00
|
|
|
[int] $To
|
|
|
|
)
|
|
|
|
|
|
|
|
Move-PartitionRange -Disk $Disk $From $From (-1 * ($From + 1));
|
|
|
|
|
|
|
|
if ($From -gt $To) {
|
|
|
|
Move-PartitionRange -Disk $Disk $To ($From - 1);
|
|
|
|
}
|
|
|
|
elseif ($From -lt $To) {
|
|
|
|
Move-PartitionRange -Disk $Disk ($From + 1) $To - 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
Move-PartitionRange -Disk $Disk -1 -1 ($To + 1)
|
|
|
|
}
|
|
|
|
|
2024-08-15 16:34:48 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2024-07-28 23:44:12 +00:00
|
|
|
# Collect necessary variables
|
|
|
|
$winpePass = Get-PassSettings "windowsPE";
|
|
|
|
$setupConfig = Get-Component $winpePass "Microsoft-Windows-Setup";
|
|
|
|
$disks = $setupConfig.SelectNodes("./ua:DiskConfiguration/ua:Disk", $namespace);
|
|
|
|
|
|
|
|
$installTarget = & {
|
|
|
|
$target = $setupConfig.SelectSingleNode("./ua:ImageInstall/ua:OSImage/ua:InstallTo", $namespace);
|
|
|
|
|
|
|
|
@{
|
2024-10-06 19:25:34 +00:00
|
|
|
Disk = $target.SelectSingleNode("./ua:DiskID", $namespace);
|
2024-07-28 23:44:12 +00:00
|
|
|
Partition = $target.SelectSingleNode("./ua:PartitionID", $namespace);
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2024-07-28 18:52:07 +00:00
|
|
|
# Adjust unattended settings
|
2024-07-28 23:44:12 +00:00
|
|
|
$computerName = (Get-Component (Get-PassSettings "specialize") "Microsoft-Windows-Shell-Setup").SelectSingleNode("./ua:ComputerName", $namespace);
|
2024-09-19 21:45:19 +00:00
|
|
|
$computerName.InnerText = $valhallaConfig.hostname;
|
2024-07-28 18:52:07 +00:00
|
|
|
|
|
|
|
# Execute corresponding installer script after startup
|
2024-08-06 08:22:50 +00:00
|
|
|
$oobeSettings = (Get-Component (Get-PassSettings "oobeSystem") "Microsoft-Windows-Shell-Setup");
|
|
|
|
|
|
|
|
foreach ($xpath in @("./ua:AutoLogon/ua:Username",
|
2024-10-06 19:25:34 +00:00
|
|
|
"./ua:UserAccounts/ua:LocalAccounts/ua:LocalAccount/ua:Name",
|
|
|
|
"./ua:UserAccounts/ua:LocalAccounts/ua:LocalAccount/ua:DisplayName")) {
|
2024-08-25 01:58:28 +00:00
|
|
|
$oobeSettings.SelectSingleNode($xpath, $namespace).InnerText = $valhallaConfig.setupUser.name;
|
2024-08-06 08:22:50 +00:00
|
|
|
}
|
|
|
|
|
2024-08-15 16:34:48 +00:00
|
|
|
Add-StartupCommand `
|
2024-10-06 19:25:34 +00:00
|
|
|
-Script (
|
|
|
|
"powershell -Command " +
|
|
|
|
($env:DEBUG ? "`$env:DEBUG = $([int]$env:DEBUG);" : "") +
|
|
|
|
"`$env:VALHALLA_ROOT = $(Get-PathInjection $env:REMOTE_PROJECT_PATH);" +
|
|
|
|
"`$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";
|
2024-07-28 18:52:07 +00:00
|
|
|
|
2024-07-28 23:44:12 +00:00
|
|
|
if ($valhallaConfig.dualboot.enable) {
|
|
|
|
$diskSize = [long](ConvertFrom-Csv (wmic diskdrive where "Index=$(Get-InstallDisk)" get Size | ForEach-Object { "$_".Trim(); })).Size;
|
|
|
|
|
|
|
|
# Calculate Linux size
|
|
|
|
$linuxSize = ([System.Math]::Floor(($diskSize * ($valhallaConfig.dualboot.linuxPercentage / 100)) / 1024 / 1024 / 1024)) * 1024;
|
|
|
|
|
|
|
|
# Resize EFI partition to 1GB (for GRUB)
|
|
|
|
(Get-DiskConfig (Get-InstallDisk)).PartitionCreations[1].SelectSingleNode("./ua:Size", $namespace).InnerText = "$(1024)";
|
|
|
|
|
|
|
|
# Move boot partition to the beginning
|
|
|
|
Move-Partition 2 1;
|
|
|
|
|
|
|
|
# Add a Swap spacer
|
|
|
|
$swapSpacer = 100;
|
|
|
|
Add-Partition 2 $swapSpacer;
|
|
|
|
Add-Partition 3 ($linuxSize - $swapSpacer);
|
2024-07-28 18:52:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
$unattendedConfigFile = "X:\unattend.xml";
|
|
|
|
$unattendedConfig.PreserveWhitespace = $true;
|
|
|
|
$unattendedConfig.Save($unattendedConfigFile);
|
|
|
|
|
2024-10-06 19:25:34 +00:00
|
|
|
Write-Warning "Attention: This program will completely wipe your current disk #1 and install Windows on it. Are you sure you want to do this?";
|
|
|
|
Read-Host -Prompt "Hit enter to continue or CTRL+C to abort";
|
2024-07-28 18:52:07 +00:00
|
|
|
& "$SETUP_DRIVE\setup.exe" /Unattend:$unattendedConfigFile;
|
2024-07-27 16:59:47 +00:00
|
|
|
}
|
|
|
|
|
2024-09-08 15:09:01 +00:00
|
|
|
Start-Setup @args;
|