using namespace Microsoft.Win32; 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 Edits the `HKEY_CURRENT_USER` key of the default user using the specified action. .PARAMETER Action The action to execute on the key. #> function Edit-DefaultUserKey { param( [scriptblock] $Action ) $rootPath = "HKLM:\DefaultUser"; $regRootPath = $rootPath -replace "^(\w+):([\\/]|$)","`$1`$2"; $hivePath = "$env:SystemDrive\Users\Default\NTUSER.dat"; $null = & reg load $regRootPath $hivePath; [RegistryKey] $root = Get-Item $rootPath; & $Action -Key $root; $root.Handle.Close(); [System.GC]::Collect(); & reg unload $regRootPath; } <# .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 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 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. .PARAMETER Value The value to set the finished state to. #> function Set-IsFinished { param( $Value ) Set-SetupOption $finishedOption $true; } }