Files
SAMY/src/samy.functions.ps1

331 lines
14 KiB
PowerShell
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
function Initialize-NuGetProvider {
[CmdletBinding()]
param()
# Silent defaults
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
$ProgressPreference = 'SilentlyContinue'
$ConfirmPreference = 'None'
# Extra guardrails for "ShouldContinue" style prompts
$PSDefaultParameterValues['*:Confirm'] = $false
# Ensure provider folders exist (CurrentUser and AllUsers locations)
$userProvPath = Join-Path $env:LOCALAPPDATA 'PackageManagement\ProviderAssemblies'
$allProvPath = Join-Path ${env:ProgramFiles} 'PackageManagement\ProviderAssemblies'
foreach ($p in @($userProvPath, $allProvPath)) {
try {
if ($p -and -not (Test-Path $p)) {
New-Item -Path $p -ItemType Directory -Force -ErrorAction Stop | Out-Null
Write-LogHybrid "Ensured provider folder exists: $p" Info Bootstrap -LogToEvent
}
} catch {
# AllUsers path can fail without admin. That's OK.
Write-LogHybrid "Could not create provider folder: $p ($($_.Exception.Message))" Warning Bootstrap -LogToEvent
}
}
# 1) Install NuGet provider FIRST, silently, so Install-Module never prompts
try {
$existing = Get-PackageProvider -Name NuGet -ListAvailable -ErrorAction SilentlyContinue |
Sort-Object Version -Descending | Select-Object -First 1
if (-not $existing -or $existing.Version -lt [Version]'2.8.5.201') {
Write-LogHybrid "Installing NuGet provider (min 2.8.5.201)..." Info Bootstrap -LogToEvent
# ForceBootstrap helps avoid interactive bootstrap prompts
Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 `
-Force -ForceBootstrap -Confirm:$false `
-Scope CurrentUser -ErrorAction Stop | Out-Null
$existing = Get-PackageProvider -Name NuGet -ListAvailable -ErrorAction SilentlyContinue |
Sort-Object Version -Descending | Select-Object -First 1
}
if ($existing) {
Import-PackageProvider -Name NuGet -Force -ErrorAction Stop | Out-Null
Write-LogHybrid "NuGet provider ready (v$($existing.Version))" Success Bootstrap -LogToEvent
} else {
throw "NuGet provider still not available after install attempt."
}
}
catch {
Write-LogHybrid "NuGet provider install/import failed: $($_.Exception.Message)" Error Bootstrap -LogToEvent
throw
}
# 2) Now it is safe to update / install modules without NuGet prompts
try {
Import-Module PackageManagement -Force -ErrorAction SilentlyContinue | Out-Null
Import-Module PowerShellGet -Force -ErrorAction SilentlyContinue | Out-Null
$pkgMgmtVersion = (Get-Module PackageManagement -ListAvailable | Sort-Object Version -Descending | Select-Object -First 1).Version
if ($pkgMgmtVersion -and $pkgMgmtVersion -lt [Version]'1.3.1') {
Install-Module PackageManagement -Force -AllowClobber -Confirm:$false -ErrorAction Stop
Write-LogHybrid "Updated PackageManagement to latest version" Info Bootstrap -LogToEvent
}
if (-not (Get-Module PowerShellGet -ListAvailable)) {
Install-Module PowerShellGet -Force -AllowClobber -Confirm:$false -ErrorAction Stop
Write-LogHybrid "Installed PowerShellGet module" Info Bootstrap -LogToEvent
}
# Trust PSGallery (optional, but common)
$gallery = Get-PSRepository -Name PSGallery -ErrorAction SilentlyContinue
if ($gallery -and $gallery.InstallationPolicy -ne 'Trusted') {
Set-PSRepository -Name PSGallery -InstallationPolicy Trusted -ErrorAction Stop
Write-LogHybrid "PSGallery marked as Trusted" Info Bootstrap -LogToEvent
}
}
catch {
Write-LogHybrid "PackageManagement/PowerShellGet setup failed: $($_.Exception.Message)" Warning Bootstrap -LogToEvent
# You can choose to throw here if you want hard-fail behavior
}
}
#region re-usable unction
function Set-RegistryValueForCurrentAndAllUsers {
[CmdletBinding()]
param(
[Parameter(Mandatory)] [string] $RelativeKeyPath, # e.g. "Software\...\Explorer\Advanced"
[Parameter(Mandatory)] [string] $Name,
[Parameter(Mandatory)] [ValidateSet('String','ExpandString','DWord','QWord','Binary','MultiString')] [string] $Type,
[Parameter(Mandatory)] $Value
)
# Helper: write to a specific HKU root (SID or temp mount)
function _SetValueInHkuRoot {
param([Parameter(Mandatory)] [string] $HkuRoot) # e.g. "Registry::HKEY_USERS\S-1-5-21-..."
$k = Join-Path $HkuRoot $RelativeKeyPath
if (-not (Test-Path $k)) { New-Item -Path $k -Force | Out-Null }
if ($Type -in @('String','ExpandString','MultiString','Binary')) {
New-ItemProperty -Path $k -Name $Name -PropertyType $Type -Value $Value -Force | Out-Null
} elseif ($Type -in @('DWord','QWord')) {
New-ItemProperty -Path $k -Name $Name -PropertyType $Type -Value ([int64]$Value) -Force | Out-Null
} else {
# Fallback
New-ItemProperty -Path $k -Name $Name -PropertyType $Type -Value $Value -Force | Out-Null
}
}
# 1) Current user (HKCU) - if meaningful in this context
try {
$hkcuKey = "HKCU:\$RelativeKeyPath"
if (-not (Test-Path $hkcuKey)) { New-Item -Path $hkcuKey -Force | Out-Null }
New-ItemProperty -Path $hkcuKey -Name $Name -PropertyType $Type -Value $Value -Force | Out-Null
} catch {
# Common during SYSTEM runs; ignore
}
# 2) Default User (future users)
$defaultDat = "C:\Users\Default\NTUSER.DAT"
if (Test-Path $defaultDat) {
$mount = "HKU\SVS_DefaultUser"
& reg.exe load $mount $defaultDat 2>$null | Out-Null
try {
_SetValueInHkuRoot -HkuRoot "Registry::HKEY_USERS\SVS_DefaultUser"
} finally {
& reg.exe unload $mount 2>$null | Out-Null
}
}
# 3) All existing user profiles
$profileList = "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList"
Get-ChildItem $profileList -ErrorAction SilentlyContinue | ForEach-Object {
$sid = $_.PSChildName
if ($sid -notmatch '^S-1-5-21-\d+-\d+-\d+-\d+$') { return }
# If hive is already loaded (user logged in), write directly to HKU:\SID
$loaded = Test-Path "Registry::HKEY_USERS\$sid"
if ($loaded) {
try { _SetValueInHkuRoot -HkuRoot "Registry::HKEY_USERS\$sid" } catch {}
return
}
# Otherwise load NTUSER.DAT from profile path
$profilePath = (Get-ItemProperty $_.PSPath -ErrorAction SilentlyContinue).ProfileImagePath
if (-not $profilePath) { return }
$ntuser = Join-Path $profilePath "NTUSER.DAT"
if (-not (Test-Path $ntuser)) { return }
$tempMount = "HKU\SVS_$sid"
& reg.exe load $tempMount $ntuser 2>$null | Out-Null
try {
_SetValueInHkuRoot -HkuRoot "Registry::HKEY_USERS\SVS_$sid"
} finally {
& reg.exe unload $tempMount 2>$null | Out-Null
}
}
}
function Restart-ExplorerIfInteractive {
[CmdletBinding()]
param()
# Dont kill Explorer during SYSTEM/unboxing contexts where it may not exist or may be harmful
$isSystem = ($env:USERNAME -eq 'SYSTEM')
if (-not $isSystem) {
Stop-Process -Name explorer -Force -ErrorAction SilentlyContinue
Start-Process explorer.exe
}
}
#rendegion re-usable function
#region App handlers
function Invoke-Install1Password {
param($Context)
try {
# Default if called without suboptions
$selected = @('desktop')
# If JS POSTs { checkedValues: [...] }, use that
if ($Context -and $Context.Request -and $Context.Request.HttpMethod -eq 'POST') {
$raw = (New-Object IO.StreamReader $Context.Request.InputStream).ReadToEnd()
if (-not [string]::IsNullOrWhiteSpace($raw)) {
$data = $raw | ConvertFrom-Json
if ($data.checkedValues) { $selected = @($data.checkedValues) }
}
}
# Extension IDs from official store listings
$chromeExtId = 'aeblfdkhhhdcdjpifhhbdiojplfjncoa' # Chrome Web Store :contentReference[oaicite:1]{index=1}
$edgeExtId = 'dppgmdbiimibapkepcbdbmkaabgiofem' # Edge Add-ons :contentReference[oaicite:2]{index=2}
if ($selected -contains 'desktop') {
winget install -e --id AgileBits.1Password --silent --accept-package-agreements --accept-source-agreements
Write-LogHybrid "Installed 1Password desktop app via winget" Success SVSApps -LogToEvent
}
if ($selected -contains 'chromeExt') {
$chromeKey = "HKLM:\SOFTWARE\Policies\Google\Chrome\ExtensionInstallForcelist"
New-Item -Path $chromeKey -Force | Out-Null
New-ItemProperty -Path $chromeKey -Name "1" -PropertyType String -Force `
-Value "$chromeExtId;https://clients2.google.com/service/update2/crx" | Out-Null
Write-LogHybrid "Forced 1Password extension install for Chrome" Success SVSApps -LogToEvent
}
if ($selected -contains 'edgeExt') {
$edgeKey = "HKLM:\SOFTWARE\Policies\Microsoft\Edge\ExtensionInstallForcelist"
New-Item -Path $edgeKey -Force | Out-Null
New-ItemProperty -Path $edgeKey -Name "1" -PropertyType String -Force `
-Value "$edgeExtId;https://edge.microsoft.com/extensionwebstorebase/v1/crx" | Out-Null
Write-LogHybrid "Forced 1Password extension install for Edge" Success SVSApps -LogToEvent
}
Send-Text $Context "1Password processed: $($selected -join ', ')"
}
catch {
Write-LogHybrid "1Password install failed: $($_.Exception.Message)" Error SVSApps -LogToEvent
Send-Text $Context "ERROR: $($_.Exception.Message)"
}
}
function Invoke-DisableAnimations {
param($Context)
try {
$selected = @()
if ($Context -and $Context.Request -and $Context.Request.HttpMethod -eq 'POST') {
$raw = (New-Object IO.StreamReader $Context.Request.InputStream).ReadToEnd()
if (-not [string]::IsNullOrWhiteSpace($raw)) {
$data = $raw | ConvertFrom-Json
if ($data.checkedValues) { $selected = @($data.checkedValues) }
}
}
if ($selected.Count -eq 0) {
$selected = @('window','taskbar','menus')
}
if ($selected -contains 'window') {
Set-RegistryValueForCurrentAndAllUsers `
-RelativeKeyPath "Control Panel\Desktop\WindowMetrics" `
-Name "MinAnimate" -Type String -Value "0"
}
if ($selected -contains 'taskbar') {
Set-RegistryValueForCurrentAndAllUsers `
-RelativeKeyPath "Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" `
-Name "TaskbarAnimations" -Type DWord -Value 0
}
if ($selected -contains 'menus') {
Set-RegistryValueForCurrentAndAllUsers `
-RelativeKeyPath "Control Panel\Desktop" `
-Name "MenuShowDelay" -Type String -Value "50"
}
if ($selected -contains 'taskbar') {
Restart-ExplorerIfInteractive
}
Write-LogHybrid "Disable Animations applied (Current + All Existing + Default User). Selected: $($selected -join ', ')" Success Tweaks -LogToEvent
Send-Text $Context "Disable Animations applied: $($selected -join ', ')"
}
catch {
Write-LogHybrid "Disable Animations failed: $($_.Exception.Message)" Error Tweaks -LogToEvent
Send-Text $Context "ERROR: $($_.Exception.Message)"
}
}
function Invoke-EnableNumLock {
param($Context)
try {
# .DEFAULT affects the logon screen + default profile behavior
$path = "Registry::HKEY_USERS\.DEFAULT\Control Panel\Keyboard"
New-Item -Path $path -Force | Out-Null
# Common value: "2" = NumLock on at startup (Windows uses string here)
Set-ItemProperty -Path $path -Name "InitialKeyboardIndicators" -Value "2" -Type String
Write-LogHybrid "NumLock default enabled (HKEY_USERS\.DEFAULT)" Success Tweaks -LogToEvent
Send-Text $Context "NumLock default enabled."
}
catch {
Write-LogHybrid "Enable NumLock failed: $($_.Exception.Message)" Error Tweaks -LogToEvent
Send-Text $Context "ERROR: $($_.Exception.Message)"
}
}
function Invoke-ClassicContextMenu {
param($Context)
try {
$key = "HKCU:\Software\Classes\CLSID\{86ca1aa0-34aa-4e8b-a509-50c905bae2a2}\InprocServer32"
New-Item -Path $key -Force | Out-Null
# Default value must be blank
Set-ItemProperty -Path $key -Name "(default)" -Value "" -Force
# Restart Explorer so it takes effect
Stop-Process -Name explorer -Force -ErrorAction SilentlyContinue
Start-Process explorer.exe
Write-LogHybrid "Classic context menu enabled (Win11)" Success Tweaks -LogToEvent
Send-Text $Context "Classic context menu enabled (Explorer restarted)."
}
catch {
Write-LogHybrid "Classic context menu tweak failed: $($_.Exception.Message)" Error Tweaks -LogToEvent
Send-Text $Context "ERROR: $($_.Exception.Message)"
}
}
#endregion App handlers