using namespace System.Management.Automation.Host; using namespace System.Security.Principal; $null = New-Module { . "$PSScriptRoot/Deployment.ps1"; . "$PSScriptRoot/Registry.ps1"; . "$PSScriptRoot/System.ps1"; . "$PSScriptRoot/../Types/OneShotTask.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; exit; } } } Set-UserStage $null; } 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"; } } };