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() # Don’t 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