Move scripts properly
This commit is contained in:
parent
36336e332d
commit
2dfb9d58bf
66 changed files with 75 additions and 76 deletions
134
scripts/Common/Scripts/BrowserAutomation.ps1
Normal file
134
scripts/Common/Scripts/BrowserAutomation.ps1
Normal file
|
@ -0,0 +1,134 @@
|
|||
#!/bin/bash
|
||||
. "$PSScriptRoot/Context.ps1";
|
||||
|
||||
$null = New-Module {
|
||||
. "$PSScriptRoot/System.ps1";
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Runs an action involving browser automation.
|
||||
|
||||
.PARAMETER Action
|
||||
The action to execute.
|
||||
#>
|
||||
function Start-BrowserAutomation {
|
||||
param(
|
||||
[scriptblock] $Action
|
||||
)
|
||||
|
||||
if (-not ("OpenQA.Selenium.Firefox.FirefoxDriver" -as [type])) {
|
||||
$zipFile = [System.IO.Compression.ZipFile]::OpenRead((Get-Package Selenium.WebDriver).Source);
|
||||
$webDriver = ($zipFile.Entries | Where-Object { $_.FullName -like "lib/net6.0/WebDriver.dll" })[0];
|
||||
$stream = [System.IO.MemoryStream]::new();
|
||||
$reader = [System.IO.StreamReader]($webDriver).Open();
|
||||
$reader.BaseStream.CopyTo($stream);
|
||||
[byte[]]$bytes = $stream.ToArray();
|
||||
$reader.Close();
|
||||
$reader.Dispose();
|
||||
$stream.Close();
|
||||
$stream.Dispose();
|
||||
$zipFile.Dispose();
|
||||
$null = [System.Reflection.Assembly]::Load($bytes);
|
||||
}
|
||||
|
||||
& $Action;
|
||||
}
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Downloads a file from the specified url using browser automation.
|
||||
|
||||
.PARAMETER URL
|
||||
The url to download the file from.
|
||||
|
||||
.PARAMETER Action
|
||||
The action to execute in the browser for initiating the download.
|
||||
|
||||
.PARAMETER OutDir
|
||||
The directory to download the file to.
|
||||
#>
|
||||
function Start-CustomBrowserDownload {
|
||||
param(
|
||||
[string] $URL,
|
||||
[scriptblock] $Action,
|
||||
[string] $OutDir
|
||||
)
|
||||
|
||||
if (-not $OutDir) {
|
||||
$OutDir = ".";
|
||||
}
|
||||
|
||||
$dir = New-TemporaryDirectory;
|
||||
Write-Host "Downloading ``$URL`` using browser automation…";
|
||||
$options = [OpenQA.Selenium.Firefox.FirefoxOptions]::new();
|
||||
$options.SetPreference("browser.download.folderList", 2);
|
||||
$options.SetPreference("browser.download.dir", "$dir");
|
||||
|
||||
$downloadChecker = {
|
||||
$files = Get-ChildItem $dir;
|
||||
|
||||
if ((@($files)).Count -gt 0) {
|
||||
foreach ($file in $files) {
|
||||
try {
|
||||
$stream = [System.IO.File]::Open($file.FullName, [System.IO.FileMode]::Open, [System.IO.FileAccess]::ReadWrite, [System.IO.FileShare]::None);
|
||||
|
||||
if ($stream) {
|
||||
$stream.Close();
|
||||
}
|
||||
}
|
||||
catch {
|
||||
return $true;
|
||||
}
|
||||
}
|
||||
|
||||
return $false;
|
||||
} else {
|
||||
return $true;
|
||||
}
|
||||
};
|
||||
|
||||
$browser = [OpenQA.Selenium.Firefox.FirefoxDriver]::new($options);
|
||||
$browser.Navigate().GoToUrl($URL);
|
||||
& $Action -Browser $browser;
|
||||
|
||||
while (& $downloadChecker) {
|
||||
Write-Host "Waiting for the download to finish…";
|
||||
Start-Sleep 1;
|
||||
}
|
||||
|
||||
$file = Get-ChildItem $dir;
|
||||
$result = Move-Item $file $OutDir -PassThru;
|
||||
$browser.Quit();
|
||||
Remove-Item -Recurse $dir;
|
||||
$result;
|
||||
}
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Downloads a file from the specified url using browser automation.
|
||||
|
||||
.PARAMETER URL
|
||||
The url to download the file from.
|
||||
|
||||
.PARAMETER ButtonSelector
|
||||
The jQuery selector for finding the download button.
|
||||
|
||||
.PARAMETER OutDir
|
||||
The directory to download the file to.
|
||||
#>
|
||||
function Start-BrowserDownload {
|
||||
param(
|
||||
[string] $URL,
|
||||
[string] $ButtonSelector,
|
||||
[string] $OutDir = $null
|
||||
)
|
||||
|
||||
Start-CustomBrowserDownload @PSBoundParameters -Action {
|
||||
param(
|
||||
[OpenQA.Selenium.Firefox.FirefoxDriver] $Browser
|
||||
)
|
||||
|
||||
$Browser.FindElement([OpenQA.Selenium.By]::CssSelector($ButtonSelector)).Click();
|
||||
};
|
||||
}
|
||||
};
|
233
scripts/Common/Scripts/Config.ps1
Normal file
233
scripts/Common/Scripts/Config.ps1
Normal file
|
@ -0,0 +1,233 @@
|
|||
using namespace Microsoft.Win32;
|
||||
using namespace System.Security.AccessControl;
|
||||
using namespace System.Security.Principal;
|
||||
|
||||
enum SetupStage {
|
||||
Initialize
|
||||
Configure
|
||||
Install
|
||||
}
|
||||
|
||||
$null = New-Module {
|
||||
[string] $configRoot = "HKLM:\Software\PortValhalla";
|
||||
[string] $stageOption = "Stage";
|
||||
[string] $finishedOption = "Finished";
|
||||
[RegistryKey] $key = $null;
|
||||
|
||||
<#
|
||||
.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
|
||||
)
|
||||
|
||||
$job = Start-Job {
|
||||
$env:Value = Resolve-Path $Using:Path;
|
||||
$env:WSLENV = "Value/p";
|
||||
$result = wsl -- bash -c 'echo "$Value"';
|
||||
wsl -e printf "%q" "$result";
|
||||
};
|
||||
|
||||
Receive-Job -Wait $job;
|
||||
}
|
||||
|
||||
<#
|
||||
.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";
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Gets a configuration option.
|
||||
|
||||
.PARAMETER Name
|
||||
The name of the option to get.
|
||||
#>
|
||||
function Get-Config {
|
||||
param(
|
||||
[string] $Name
|
||||
)
|
||||
|
||||
Invoke-ConfigScript "getConfig $Name --json";
|
||||
}
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Gets the names of the users to create.
|
||||
#>
|
||||
function Get-Users {
|
||||
Invoke-ConfigScript "getUsers";
|
||||
}
|
||||
|
||||
<#
|
||||
.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;
|
||||
$null = Set-ItemProperty ($key.PSPath) -Name $Name -Value $Value;
|
||||
}
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Gets the name of the current setup stage.
|
||||
#>
|
||||
function Get-Stage {
|
||||
$stage = Get-SetupOption $stageOption;
|
||||
|
||||
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-Stage {
|
||||
param(
|
||||
$Name
|
||||
)
|
||||
|
||||
if (-not (($null -eq $Name) -or ($Name -is [string]))) {
|
||||
$Name = ([SetupStage]$Name).ToString();
|
||||
}
|
||||
|
||||
$null = Set-SetupOption $stageOption $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 specified software collection is enabled.
|
||||
|
||||
.PARAMETER Name
|
||||
The name of the collection to check.
|
||||
#>
|
||||
function Test-Collection {
|
||||
param(
|
||||
[string] $Name
|
||||
)
|
||||
|
||||
Get-Config "valhalla.software.$Name";
|
||||
}
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Checks whether the current user is the setup user.
|
||||
#>
|
||||
function Test-SetupUser {
|
||||
$env:UserName -eq (Get-Config "valhalla.windows.setupUser");
|
||||
}
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Checks whether the active session is executed with admin rights.
|
||||
#>
|
||||
function Test-Admin {
|
||||
net session 2> $null | Out-Null;
|
||||
return $?;
|
||||
}
|
||||
}
|
417
scripts/Common/Scripts/Context.ps1
Normal file
417
scripts/Common/Scripts/Context.ps1
Normal file
|
@ -0,0 +1,417 @@
|
|||
#!/bin/pwsh
|
||||
. "$PSScriptRoot/../../Common/Scripts/Entrypoints.ps1";
|
||||
. "$PSScriptRoot/../../Common/Software/PowerShell/profile.ps1";
|
||||
|
||||
class Context {
|
||||
[string]$EntryPoint;
|
||||
[string]$RootDir;
|
||||
[string]$BackupName;
|
||||
[string[]]$UserNames;
|
||||
[string]$AdminName = "Admin";
|
||||
[string]$ConfigRoot = "HKLM:\Software\PortValhalla";
|
||||
[string]$RunOnceName = "PortValhalla";
|
||||
[string]$StagePropertyName = "Stage";
|
||||
|
||||
Context() {
|
||||
try {
|
||||
$this.EntryPoint = Get-Entrypoint;
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
[string] ProjectRoot() {
|
||||
return Resolve-Path (Join-Path $PSScriptRoot ".." ".." "..");
|
||||
}
|
||||
|
||||
[string] BackupRoot() {
|
||||
if (-not $this.RootDir)
|
||||
{
|
||||
return Join-Path $this.ProjectRoot() "backup" $this.BackupName;
|
||||
}
|
||||
else
|
||||
{
|
||||
return $this.RootDir;
|
||||
}
|
||||
}
|
||||
|
||||
[void] RemoveDesktopIcon($pattern) {
|
||||
Remove-Item "$env:PUBLIC/Desktop/$pattern";
|
||||
Remove-Item "~/Desktop/$pattern";
|
||||
}
|
||||
|
||||
[void] RemoveTaskbarItem($pattern) {
|
||||
Import-Module -UseWindowsPowerShell PinnedItem;
|
||||
Get-PinnedItem -Type TaskBar | Where-Object { $_.Name -like "$pattern" } | Remove-PinnedItem;
|
||||
}
|
||||
|
||||
[void] AddPowerShellProfileStatement([string] $statement) {
|
||||
$this.AddPowerShellProfileStatement($true, $statement);
|
||||
}
|
||||
|
||||
[void] AddPowerShellProfileStatement([string] $category, [string] $statement) {
|
||||
$this.AddPowerShellProfileStatement($true, $category, $statement);
|
||||
}
|
||||
|
||||
[void] AddPowerShellProfileStatement([bool] $system, [string] $statement) {
|
||||
$this.AddPowerShellProfileStatement($system, $null, $statement);
|
||||
}
|
||||
|
||||
[void] AddPowerShellProfileStatement([bool] $system, [string] $category, [string] $statement) {
|
||||
if ($category) {
|
||||
$overwrite = $true;
|
||||
} else {
|
||||
$overwrite = $false;
|
||||
}
|
||||
|
||||
$this.AddPowerShellProfileStatement($system, $category, $statement, $overwrite);
|
||||
}
|
||||
|
||||
[void] AddPowerShellProfileStatement([bool] $system, [string] $category, [string] $statement, [bool] $overwrite) {
|
||||
if ($system) {
|
||||
Add-PowerShellProfileStatement -System -Category $category -Statement $statement -Overwrite $overwrite;
|
||||
} else {
|
||||
Add-PowerShellProfileStatement -Category $category -Statement $statement -Overwrite $overwrite;
|
||||
}
|
||||
}
|
||||
|
||||
[Microsoft.Win32.RegistryKey] EnsureConfigKey() {
|
||||
if (-not (Test-Path $this.ConfigRoot)) {
|
||||
$null = New-Item $this.ConfigRoot;
|
||||
$acl = Get-Acl $this.ConfigRoot;
|
||||
|
||||
$acl.AddAccessRule(
|
||||
[System.Security.AccessControl.RegistryAccessRule]::new(
|
||||
[System.Security.Principal.SecurityIdentifier]::new([System.Security.Principal.WellKnownSidType]::BuiltinUsersSid, $null),
|
||||
[System.Security.AccessControl.RegistryRights]::FullControl,
|
||||
[System.Security.AccessControl.InheritanceFlags]::ObjectInherit -bor [System.Security.AccessControl.InheritanceFlags]::ContainerInherit,
|
||||
[System.Security.AccessControl.PropagationFlags]::None,
|
||||
[System.Security.AccessControl.AccessControlType]::Allow));
|
||||
|
||||
Set-Acl $this.ConfigRoot $acl;
|
||||
}
|
||||
|
||||
return Get-Item $this.ConfigRoot;
|
||||
}
|
||||
|
||||
[object] Get([string] $key) {
|
||||
$configKey = $this.EnsureConfigKey();
|
||||
if ($configKey.GetValueNames().Contains($key)) {
|
||||
return $configKey.GetValue($key);
|
||||
} else {
|
||||
return $null;
|
||||
}
|
||||
}
|
||||
|
||||
[void] Set([string] $key, $value) {
|
||||
$this.Set($key, $value, "ExpandString");
|
||||
}
|
||||
|
||||
[void] Set([string] $key, $value, [Microsoft.Win32.RegistryValueKind] $type) {
|
||||
$configKey = $this.EnsureConfigKey();
|
||||
$null = Set-ItemProperty -Path $configKey.PSPath -Name $key -Value $value -Type $type;
|
||||
}
|
||||
|
||||
[void] Remove([string] $key) {
|
||||
$configKey = $this.EnsureConfigKey();
|
||||
$null = Remove-ItemProperty -Path $configKey.PSPath -Name $key;
|
||||
}
|
||||
|
||||
[void] SetStage([string] $name) {
|
||||
$this.Set($this.StagePropertyName, $name);
|
||||
}
|
||||
|
||||
[string] GetStage() {
|
||||
return $this.Get($this.StagePropertyName);
|
||||
}
|
||||
|
||||
[void] RemoveStage() {
|
||||
$this.Remove($this.StagePropertyName);
|
||||
}
|
||||
|
||||
[string] ArchivePath($name) {
|
||||
return Join-Path $this.BackupRoot() "$name.7z";
|
||||
}
|
||||
|
||||
[string] FileArchivePath($name) {
|
||||
return $this.ArchivePath($(Join-Path "Files" $name));
|
||||
}
|
||||
|
||||
[string] SoftwareArchive([string]$softwareName) {
|
||||
return $this.ArchivePath($softwareName);
|
||||
}
|
||||
|
||||
[void] Backup([string]$sourcePath, [string]$archivePath) {
|
||||
$this.Backup($sourcePath, $archivePath, @());
|
||||
}
|
||||
|
||||
[void] Backup([string]$sourcePath, [string]$archivePath, [string[]]$arguments) {
|
||||
$this.Backup($sourcePath, $archivePath, $arguments, $true);
|
||||
}
|
||||
|
||||
[void] Backup([string]$sourcePath, [string]$archivePath, [string[]]$arguments, [bool]$split) {
|
||||
if (Test-Path $archivePath) {
|
||||
Remove-Item -Recurse $archivePath;
|
||||
}
|
||||
|
||||
if (Test-Path "$archivePath.*") {
|
||||
Remove-Item -Recurse "$archivePath.*";
|
||||
}
|
||||
|
||||
Start-Process -WorkingDirectory "$sourcePath" `
|
||||
-FilePath "7z" `
|
||||
-ArgumentList (
|
||||
@(
|
||||
"a",
|
||||
"-xr!desktop.ini",
|
||||
"-xr!thumbs.db",
|
||||
"-xr!Thumbs.db",
|
||||
"-slp",
|
||||
$archivePath) + $arguments + $(
|
||||
if ($split) {
|
||||
@("-v2g");
|
||||
} else {
|
||||
@();
|
||||
}
|
||||
)) `
|
||||
-Wait `
|
||||
-NoNewWindow;
|
||||
}
|
||||
|
||||
[void] Restore([string]$archivePath, [string]$destinationPath) {
|
||||
$this.Restore($archivePath, $destinationPath, @());
|
||||
}
|
||||
|
||||
[void] Restore([string]$archivePath, [string]$destinationPath, [string[]] $arguments) {
|
||||
if (-not (Test-Path -PathType Leaf $archivePath)) {
|
||||
$archivePath = "$archivePath.001";
|
||||
}
|
||||
|
||||
if (-not (Test-Path -PathType Leaf $archivePath)) {
|
||||
Write-Information (
|
||||
[string]::Join(
|
||||
"`n",
|
||||
@(
|
||||
"An archive at the specified path $archivePath does not exist.",
|
||||
"No restoration will be performed.")));
|
||||
}
|
||||
else {
|
||||
if (-not (Test-Path -PathType Container $destinationPath)) {
|
||||
New-Item -ItemType Directory "$destinationPath";
|
||||
}
|
||||
|
||||
Start-Process -WorkingDirectory "$destinationPath" `
|
||||
-FilePath "7z" `
|
||||
-ArgumentList @("x", "$archivePath") + $arguments `
|
||||
-Wait `
|
||||
-NoNewWindow;
|
||||
}
|
||||
}
|
||||
|
||||
[string] GetTempDirectory() {
|
||||
$tempDir = Join-Path $([System.IO.Path]::GetTempPath()) $([System.IO.Path]::GetRandomFileName());
|
||||
$null = New-Item -ItemType Directory $tempDir;
|
||||
return $tempDir;
|
||||
}
|
||||
|
||||
[void] ProcessDefaultUserKey([System.Action[Microsoft.Win32.RegistryKey]] $action) {
|
||||
$rootPath = "HKLM:\DefaultUser";
|
||||
$regRootPath = $rootPath.Replace(":", "");
|
||||
$hivePath = "$env:SystemDrive\Users\Default\NTUSER.dat"
|
||||
$null = & reg load $regRootPath $hivePath;
|
||||
$root = Get-Item $rootPath;
|
||||
$action.Invoke($root);
|
||||
$root.Handle.Close();
|
||||
[System.GC]::Collect();
|
||||
& reg unload $regRootPath;
|
||||
}
|
||||
|
||||
[void] ProcessLogonKey([System.Action[Microsoft.Win32.RegistryKey]] $action) {
|
||||
$key = Get-Item "HKLM:\Software\Microsoft\Windows NT\CurrentVersion\Winlogon";
|
||||
$action.Invoke($key);
|
||||
}
|
||||
|
||||
[Microsoft.Win32.RegistryKey] GetSystemPolicyKey() {
|
||||
$keyPath = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System";
|
||||
return Get-Item "$keyPath";
|
||||
}
|
||||
|
||||
[Microsoft.Win32.RegistryKey] GetRunOnceKey() {
|
||||
return $this.GetRunOnceKey($null);
|
||||
}
|
||||
|
||||
[Microsoft.Win32.RegistryKey] GetRunOnceKey([Microsoft.Win32.RegistryKey] $userKey) {
|
||||
if (-not $userKey) {
|
||||
$userKey = Get-Item "HKCU:\";
|
||||
}
|
||||
|
||||
Push-Location $userKey.PSPath;
|
||||
$runOncePath = "Software\Microsoft\Windows\CurrentVersion\RunOnce";
|
||||
|
||||
if (-not (Test-Path $runOncePath)) {
|
||||
New-Item $runOncePath;
|
||||
}
|
||||
|
||||
$result = Get-Item $runOncePath;
|
||||
Pop-Location;
|
||||
return $result;
|
||||
}
|
||||
|
||||
[bool] GetUACState() {
|
||||
return [bool](Get-ItemPropertyValue -Path ($this.GetSystemPolicyKey().PSPath) -Name "EnableLUA");
|
||||
}
|
||||
|
||||
[void] SetUACState([bool] $value) {
|
||||
$null = Set-ItemProperty -Path ($this.GetSystemPolicyKey().PSPath) -Name "EnableLUA" -Value ([int]$value);
|
||||
}
|
||||
|
||||
[void] RegisterReboot() {
|
||||
$this.RegisterReboot($null);
|
||||
}
|
||||
|
||||
[void] RegisterReboot([Microsoft.Win32.RegistryKey] $userKey) {
|
||||
$runOnceKey = $this.GetRunOnceKey($userKey);
|
||||
Set-ItemProperty -Path $runOnceKey.PSPath -Name $this.RunOnceName -Value "pwsh `"$($this.EntryPoint)`"" -Type "ExpandString";
|
||||
$runOnceKey.Handle.Close();
|
||||
}
|
||||
|
||||
[void] RegisterNewUserReboot() {
|
||||
$this.ProcessDefaultUserKey({ param ($root) $this.RegisterReboot($root); });
|
||||
}
|
||||
|
||||
[void] DeregisterNewUserReboot() {
|
||||
$this.ProcessDefaultUserKey({ param ($root) Remove-Item -Path $this.GetRunOnceKey($root).PSPath });
|
||||
}
|
||||
|
||||
[void] SetAutologin($user, $pw) {
|
||||
$this.ProcessLogonKey(
|
||||
{
|
||||
param ($logon)
|
||||
$path = $logon.PSPath;
|
||||
Set-ItemProperty $path -Name "AutoAdminLogon" 1;
|
||||
Set-ItemProperty $path -Name "DefaultUserName" $user;
|
||||
|
||||
if ($pw) {
|
||||
Set-ItemProperty $path -Name "DefaultPassword" $pw;
|
||||
} else {
|
||||
Remove-ItemProperty $path -Name "DefaultPassword";
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
[void] RemoveAutologin() {
|
||||
$this.ProcessLogonKey(
|
||||
{
|
||||
param ($logon)
|
||||
$path = $logon.PSPath;
|
||||
Set-ItemProperty $path -Name "AutoAdminLogon" 0;
|
||||
Remove-ItemProperty $path -Name "DefaultDomainName" -ErrorAction SilentlyContinue;
|
||||
Remove-ItemProperty $path -Name "DefaultUserName" -ErrorAction SilentlyContinue;
|
||||
Remove-ItemProperty $path -Name "DefaultPassword" -ErrorAction SilentlyContinue;
|
||||
});
|
||||
}
|
||||
|
||||
[string] GetNextcloudConfigFile() {
|
||||
return "$env:APPDATA/Nextcloud/nextcloud.cfg";
|
||||
}
|
||||
|
||||
[void] AddNextcloudSync([string] $localPath, [string] $targetPath) {
|
||||
$this.AddNextcloudSync($localPath, $targetPath, $false);
|
||||
}
|
||||
|
||||
[void] AddNextcloudSync([string] $localPath, [string] $targetPath, [bool] $virtualFiles) {
|
||||
Write-Host "Adding a Nextcloud sync";
|
||||
Write-Information "$targetPath <=> $localPath";
|
||||
$pattern = "^\d+\\Folders(?:WithPlaceholders)?\\(\d+)";
|
||||
|
||||
$folderID = (
|
||||
Get-Content $($this.GetNextcloudConfigFile()) | `
|
||||
Where-Object { $_ -match "$pattern" } | `
|
||||
ForEach-Object { $_ -replace "$pattern.*$","`$1" } | `
|
||||
Sort-Object -Unique | `
|
||||
Measure-Object -Maximum).Maximum + 1;
|
||||
|
||||
$configName = "Folders";
|
||||
$localPath = $localPath.Replace("\", "/");
|
||||
$targetPath = $targetPath.Replace("\", "/");
|
||||
|
||||
if ($virtualFiles) {
|
||||
$configName += "WithPlaceholders";
|
||||
}
|
||||
|
||||
Write-Information "Stopping Nextcloud process";
|
||||
$nextcloudProcess = Get-Process nextcloud;
|
||||
$nextcloudPath = [string]$nextcloudProcess[0].Path;
|
||||
$nextcloudProcess | Stop-Process -Force;
|
||||
|
||||
$accountSectionEntered = $false;
|
||||
$accountSectionLeft = $false;
|
||||
|
||||
$newSettings = [string]::Join(
|
||||
"`n",
|
||||
@(
|
||||
"0\$configName\$folderID\localPath=$localPath",
|
||||
"0\$configName\$folderID\targetPath=$targetPath"));
|
||||
|
||||
$oldContent = Get-Content ($this.GetNextcloudConfigFile());
|
||||
|
||||
$(
|
||||
for ($i = 0; $i -lt $oldContent.Count; $i++) {
|
||||
$line = $oldContent[$i];
|
||||
|
||||
if ($line -eq "[Accounts]") {
|
||||
$accountSectionEntered = $true;
|
||||
}
|
||||
|
||||
if ($line -eq "" -and $accountSectionEntered) {
|
||||
$accountSectionLeft = $true;
|
||||
$newSettings;
|
||||
}
|
||||
|
||||
$line;
|
||||
|
||||
if (
|
||||
(-not $accountSectionLeft) -and
|
||||
($i -eq ($oldContent.Count - 1)))
|
||||
{
|
||||
$newSettings;
|
||||
}
|
||||
}) | Set-Content ($this.GetNextcloudConfigFile());
|
||||
|
||||
Write-Information "New nextcloud config:";
|
||||
Write-Information (Get-Content $($this.GetNextcloudConfigFile()) | Out-String);
|
||||
|
||||
Write-Information "Restarting Nextcloud";
|
||||
Start-Process $nextcloudPath;
|
||||
}
|
||||
|
||||
[void] Reboot() {
|
||||
Write-Host "Restarting Computer...";
|
||||
$this.RegisterReboot();
|
||||
Restart-Computer -Force;
|
||||
exit;
|
||||
}
|
||||
|
||||
[void] PreventSleepMode() {
|
||||
$performanceScheme = "8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c";
|
||||
$currentScheme = [regex]::Match((powercfg /GETACTIVESCHEME), "Power Scheme GUID: ([0-9a-f-]+) ").Groups[1].Value;
|
||||
|
||||
if ($currentScheme -ne $performanceScheme) {
|
||||
Write-Information "Disabling Power Save mode";
|
||||
$this.Set("Power Scheme", $currentScheme);
|
||||
powercfg /S 8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c;
|
||||
}
|
||||
}
|
||||
|
||||
[void] Cleanup() {
|
||||
$this.DeregisterNewUserReboot();
|
||||
$this.RemoveAutologin();
|
||||
$this.SetUACState($true);
|
||||
$originalScheme = $this.Get("Power Scheme");
|
||||
Remove-Item $($this.EnsureConfigKey().PSPath);
|
||||
|
||||
if ($originalScheme) {
|
||||
Write-Information "Reset power plan to original state";
|
||||
powercfg /S $originalScheme;
|
||||
}
|
||||
}
|
||||
}
|
14
scripts/Common/Scripts/Entrypoints.ps1
Normal file
14
scripts/Common/Scripts/Entrypoints.ps1
Normal file
|
@ -0,0 +1,14 @@
|
|||
function Get-Entrypoint() {
|
||||
$trace = Get-PSCallStack
|
||||
$call = $trace[$trace.Count - 1];
|
||||
|
||||
if ($null -ne $call.ScriptName) {
|
||||
return $call.ScriptName;
|
||||
} else {
|
||||
$call = $CallStack[$CallStack.Count - 2];
|
||||
return $call.ScriptName;
|
||||
}
|
||||
|
||||
|
||||
throw "No PowerShell entry point script could be found.";
|
||||
}
|
14
scripts/Common/Scripts/Operations.ps1
Normal file
14
scripts/Common/Scripts/Operations.ps1
Normal file
|
@ -0,0 +1,14 @@
|
|||
function Start-Operation {
|
||||
param(
|
||||
[scriptblock] $Action
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Inquire';
|
||||
$env:WSLENV = "CONFIG_MODULE/p";
|
||||
|
||||
if ($env:CONFIG_MODULE) {
|
||||
$env:CONFIG_MODULE = Resolve-Path $env:CONFIG_MODULE;
|
||||
}
|
||||
|
||||
& $Action;
|
||||
}
|
62
scripts/Common/Scripts/Scripting.ps1
Normal file
62
scripts/Common/Scripts/Scripting.ps1
Normal file
|
@ -0,0 +1,62 @@
|
|||
<#
|
||||
.SYNOPSIS
|
||||
Converts the specified value into a form to safle inject it into a script.
|
||||
|
||||
.PARAMETER value
|
||||
The value to convert for injection.
|
||||
#>
|
||||
function ConvertTo-Injection {
|
||||
param(
|
||||
$Value
|
||||
)
|
||||
|
||||
"([System.Text.Encoding]::Default.GetString([System.Convert]::FromBase64String('$(
|
||||
[System.Convert]::ToBase64String([System.Text.Encoding]::Default.GetBytes($value))
|
||||
)')))"
|
||||
}
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Writes a PowerShell script to a specified location.
|
||||
|
||||
.PARAMETER FileName
|
||||
The name of the file to write the script to.
|
||||
|
||||
.PARAMETER Script
|
||||
The script to write to the file.
|
||||
|
||||
.PARAMETER Replace
|
||||
A value indicating whether the file should be overwritten if it exists.
|
||||
|
||||
.PARAMETER Append
|
||||
A value indicating whether the content should be appended if the file already exists.
|
||||
#>
|
||||
function Write-PSScript {
|
||||
param(
|
||||
[string] $FileName,
|
||||
[string] $Script,
|
||||
[Parameter(ParameterSetName="Replace")]
|
||||
[switch] $Replace,
|
||||
[Parameter(ParameterSetName="Append")]
|
||||
[switch] $Append
|
||||
)
|
||||
|
||||
Import-Module PSScriptAnalyzer;
|
||||
$dirName = Split-Path -Parent $FileName;
|
||||
$content = Invoke-Formatter -ScriptDefinition $Script;
|
||||
$exists = Test-Path -PathType Leaf $FileName;
|
||||
|
||||
if (-not (Test-Path -PathType Container $dirName)) {
|
||||
$null = New-Item -ItemType Directory $dirName;
|
||||
}
|
||||
|
||||
if ($exists -and ($Append.IsPresent)) {
|
||||
Add-Content -Force $FileName "`n$content";
|
||||
} else {
|
||||
if ((-not $exists) -or $Replace.IsPresent) {
|
||||
Set-Content -Force $FileName $content;
|
||||
} else {
|
||||
Write-Host "The file ``$FileName`` already exists!";
|
||||
}
|
||||
}
|
||||
}
|
196
scripts/Common/Scripts/Software.ps1
Normal file
196
scripts/Common/Scripts/Software.ps1
Normal file
|
@ -0,0 +1,196 @@
|
|||
. "$PSScriptRoot/Config.ps1";
|
||||
. "$PSScriptRoot/Operations.ps1";
|
||||
. "$PSScriptRoot/System.ps1";
|
||||
. "$PSScriptRoot/../Types/InstallerAction.ps1";
|
||||
|
||||
$null = New-Module {
|
||||
. "$PSScriptRoot/BrowserAutomation.ps1";
|
||||
. "$PSScriptRoot/SoftwareManagement.ps1";
|
||||
. "$PSScriptRoot/../Types/InstallerAction.ps1";
|
||||
$userArgument = "name";
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Installs the specified packages using chocolatey.
|
||||
|
||||
.PARAMETER Names
|
||||
The names of the packages to install.
|
||||
#>
|
||||
function Install-ChocoPackage {
|
||||
param(
|
||||
[switch] $Force,
|
||||
[string[]] $ArgumentList,
|
||||
[Parameter(Position=0)]
|
||||
[string] $Name,
|
||||
[Parameter(ValueFromRemainingArguments = $true)]
|
||||
[string[]] $AdditionalNames = @()
|
||||
)
|
||||
|
||||
[System.Collections.ArrayList] $Names = @();
|
||||
$null = $Names.Add($Name);
|
||||
$Names.AddRange($AdditionalNames);
|
||||
|
||||
if (-not ($Force.IsPresent)) {
|
||||
for ($i = $Names.Count - 1; $i -ge 0; $i--) {
|
||||
if (Test-ChocoPackage $Names[$i]) {
|
||||
$Names.RemoveAt($i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($Names.Count -ge 1) {
|
||||
choco install -y $ArgumentList $Names;
|
||||
}
|
||||
}
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Installs the specified packages using `winget`.
|
||||
|
||||
.PARAMETER Names
|
||||
The names of the packages to install.
|
||||
#>
|
||||
function Install-WingetPackage {
|
||||
param(
|
||||
[switch] $Force,
|
||||
[Parameter(ValueFromRemainingArguments = $true)]
|
||||
[string[]] $Names
|
||||
)
|
||||
|
||||
foreach ($name in $Names) {
|
||||
if ($Force.IsPresent -and -not (Test-WingetPackage $name)) {
|
||||
winget install --accept-source-agreements --accept-package-agreements -e --id $name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Installs a package downloaded from ASUS.
|
||||
|
||||
.PARAMETER URL
|
||||
The URL to download the package from.
|
||||
#>
|
||||
function Install-AsusPackage {
|
||||
param(
|
||||
[string] $URL
|
||||
)
|
||||
|
||||
$file = "AsusPackage.zip";
|
||||
$dir = New-TemporaryDirectory;
|
||||
$unpackDir = New-TemporaryDirectory;
|
||||
|
||||
$null = Push-Location $dir;
|
||||
Invoke-WebRequest $URL -OutFile $file;
|
||||
Expand-Archive $file $unpackDir;
|
||||
$null = Pop-Location;
|
||||
Remove-Item -Recurse $dir;
|
||||
|
||||
$null = Start-Process -Wait -WorkingDirectory $unpackDir -FilePath (Join-Path $unpackDir "AsusSetup.exe") -ArgumentList "/S";
|
||||
Remove-Item -Recurse $unpackDir;
|
||||
}
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Downloads and installs a package from the AMD website.
|
||||
|
||||
.PARAMETER URL
|
||||
The URL to download the package from.
|
||||
#>
|
||||
function Install-AmdPackage {
|
||||
param(
|
||||
[string] $URL
|
||||
)
|
||||
|
||||
$dir = New-TemporaryDirectory;
|
||||
$cookieBannerSelector = "#onetrust-consent-sdk";
|
||||
$osSelector = "div[id$='oscategory']>div[id$='-0']";
|
||||
$downloadSelector = "$osSelector div[id$='panel'] .button a";
|
||||
|
||||
$file = Start-CustomBrowserDownload @PSBoundParameters -OutDir $dir -Action {
|
||||
param(
|
||||
[OpenQA.Selenium.Firefox.FirefoxDriver] $Browser
|
||||
)
|
||||
|
||||
$osContainer = $Browser.FindElement([OpenQA.Selenium.By]::CssSelector($osSelector));
|
||||
|
||||
if (-not ([bool] $osContainer.GetAttribute("cmp-expanded"))) {
|
||||
$osContainer.Click();
|
||||
}
|
||||
|
||||
$download = {
|
||||
$browser.FindElement([OpenQA.Selenium.By]::CssSelector($downloadSelector)).Click();
|
||||
};
|
||||
|
||||
try {
|
||||
& $download;
|
||||
} catch {
|
||||
$Browser.ExecuteScript("document.querySelector('$cookieBannerSelector').remove()");
|
||||
& $download;
|
||||
}
|
||||
};
|
||||
|
||||
Start-Process -Wait -WorkingDirectory $dir -FilePath $file -ArgumentList "/S";
|
||||
Remove-Item -Recurse $dir;
|
||||
}
|
||||
|
||||
function Start-SoftwareInstaller {
|
||||
param(
|
||||
[string] $Name,
|
||||
[scriptblock] $Installer = { },
|
||||
[scriptblock] $Configurator = { },
|
||||
[scriptblock] $UserConfigurator = { },
|
||||
[InstallerAction] $Action = [InstallerAction]::Install,
|
||||
[hashtable] $Arguments
|
||||
)
|
||||
|
||||
if (-not $Name) {
|
||||
$Name = Split-Path -Leaf (Split-Path -Parent ((Get-PSCallStack)[1].ScriptName));
|
||||
}
|
||||
|
||||
Start-Operation {
|
||||
if ($null -ne $Name) {
|
||||
$Name = "``$Name``";
|
||||
} else {
|
||||
$Name = "unknown software";
|
||||
}
|
||||
|
||||
$installHandler = {
|
||||
param(
|
||||
[InstallerAction] $Action,
|
||||
[hashtable] $Arguments
|
||||
)
|
||||
|
||||
$Arguments ??= @{ };
|
||||
|
||||
$argumentList = @{
|
||||
installer = $installHandler;
|
||||
arguments = $Arguments;
|
||||
};
|
||||
|
||||
if ($action -eq ([InstallerAction]::Install)) {
|
||||
Write-Host "Installing $Name…";
|
||||
& $Installer @argumentList;
|
||||
} elseif ($Action -eq ([InstallerAction]::Configure)) {
|
||||
Write-Host "Configuring $Name…";
|
||||
& $Configurator @argumentList;
|
||||
|
||||
foreach ($user in Get-Users) {
|
||||
$Arguments.Add($userArgument, $user);
|
||||
$argumentList.Add("action", [InstallerAction]::ConfigureUser);
|
||||
& $installHandler @argumentList;
|
||||
}
|
||||
} elseif ($Action -eq ([InstallerAction]::ConfigureUser)) {
|
||||
if ((-not $Arguments.ContainsKey($userArgument)) -or ($null -eq $Arguments[$userArgument])) {
|
||||
$argumentList.Add($userArgument, ($env:UserName));
|
||||
}
|
||||
|
||||
Write-Host "Configuring $Name for user ``$($Arguments[$userArgument])``…";
|
||||
& $UserConfigurator @argumentList;
|
||||
}
|
||||
};
|
||||
|
||||
& $installHandler -Action $Action -Arguments $Arguments;
|
||||
};
|
||||
}
|
||||
}
|
100
scripts/Common/Scripts/SoftwareManagement.ps1
Normal file
100
scripts/Common/Scripts/SoftwareManagement.ps1
Normal file
|
@ -0,0 +1,100 @@
|
|||
. "$PSScriptRoot/Context.ps1";
|
||||
|
||||
function Install-SoftwarePackage([Context] $context, [string] $location, [string[]] $argumentList = @("/S"), [switch]$local) {
|
||||
[string]$filePath = "";
|
||||
[string]$tempDir = $null;
|
||||
|
||||
if (-not ($local.IsPresent)) {
|
||||
$tempDir = $context.GetTempDirectory();
|
||||
Write-Information "Determining the file name of $location";
|
||||
$fileName = ([uri]$location).Segments[-1];
|
||||
Write-Information "$fileName";
|
||||
$filePath = Join-Path $tempDir $fileName;
|
||||
|
||||
Write-Information "Downloading setup file from $location";
|
||||
Invoke-WebRequest $location -OutFile $filePath;
|
||||
} else {
|
||||
$filePath = $location;
|
||||
}
|
||||
|
||||
$fileName = [System.IO.Path]::GetFileName($filePath);
|
||||
Write-Information "Starting installation of $fileName";
|
||||
Start-Process -Wait -FilePath $filePath -ArgumentList $argumentList;
|
||||
|
||||
if ($tempDir) {
|
||||
Remove-Item -Recurse $tempDir;
|
||||
}
|
||||
}
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Checks whether the specified package has been installed using Chocolatey.
|
||||
|
||||
.PARAMETER Name
|
||||
The name of the package to check.
|
||||
#>
|
||||
function Test-ChocoPackage {
|
||||
[OutputType([bool])]
|
||||
param(
|
||||
[string] $Name
|
||||
);
|
||||
|
||||
-not [string]::IsNullOrEmpty((choco list --limit-output --exact $name));
|
||||
}
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Checks whether a `winget` package with the specified id is installed.
|
||||
|
||||
.PARAMETER ID
|
||||
The id of the package to check.
|
||||
#>
|
||||
function Test-WingetPackage {
|
||||
[OutputType([bool])]
|
||||
param(
|
||||
[string] $ID
|
||||
)
|
||||
|
||||
-not (& { $null = winget list --accept-source-agreements -e --id $ID; $?; });
|
||||
}
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Checks whether a command with the specified name exists.
|
||||
|
||||
.PARAMETER Name
|
||||
The name of the command to check.
|
||||
#>
|
||||
function Test-Command {
|
||||
param (
|
||||
[string] $Name
|
||||
)
|
||||
|
||||
[bool] (Get-Command $Name -ErrorAction SilentlyContinue);
|
||||
}
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Checks whether `winget` is working properly.
|
||||
#>
|
||||
function Test-Winget {
|
||||
(Test-Command winget) -and -not (
|
||||
[System.Linq.Enumerable]::Any(
|
||||
[string[]](winget source update winget),
|
||||
[System.Func[string,bool]]{ param($line) $line -eq "Cancelled"; }));
|
||||
}
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Checks whether a package with the specified name is installed.
|
||||
|
||||
.PARAMETER Name
|
||||
The name of the package to check.
|
||||
#>
|
||||
function Test-PSPackage {
|
||||
param(
|
||||
[string] $Name
|
||||
)
|
||||
|
||||
[bool] (Get-Package $Name -ErrorAction SilentlyContinue);
|
||||
}
|
31
scripts/Common/Scripts/System.ps1
Normal file
31
scripts/Common/Scripts/System.ps1
Normal file
|
@ -0,0 +1,31 @@
|
|||
<#
|
||||
.SYNOPSIS
|
||||
Creates a new temporary directory.
|
||||
#>
|
||||
function New-TemporaryDirectory {
|
||||
$path = Join-Path ([System.IO.Path]::GetTempPath()) ([System.IO.Path]::GetRandomFileName());
|
||||
New-Item -ItemType Directory $path;
|
||||
}
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Removes desktop icons which apply to the specified pattern.
|
||||
|
||||
.PARAMETER Pattern
|
||||
The pattern to match the icons to delete.
|
||||
#>
|
||||
function Remove-DesktopIcon {
|
||||
param(
|
||||
[string] $Pattern
|
||||
)
|
||||
|
||||
$path = "Desktop/$Pattern";
|
||||
|
||||
foreach ($userDir in @("~", $env:PUBLIC, "$env:SystemDrive/Users/Default")) {
|
||||
$fullName = "$userDir/$path";
|
||||
|
||||
if (Test-Path -PathType Leaf $fullName) {
|
||||
Remove-Item $fullName;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue