8.8 KiB
samy.functions.ps1 (3-in-1)
This file groups three core categories of functionality used by SAMY:
- Bootstrap: prepares PowerShell package tooling (NuGet provider, PowerShellGet, PackageManagement, PSGallery).
- Registry Helpers: reusable functions to write registry values for current user, default user (future profiles), and existing user profiles.
- UI Handlers: endpoint/task handlers invoked by the web UI (e.g., install 1Password, apply tweaks).
The goal of this file is to provide “daily driver” functions SAMY needs across onboarding/offboarding workflows.
Encoding rule: save as UTF-8 without BOM.
Contents overview
- Bootstrap
Initialize-NuGetProvider
- Registry helpers
Set-RegistryValueInHkuRootSet-RegistryValueForCurrentAndAllUsersRestart-ExplorerIfInteractive
- UI Handlers (examples included in file)
Invoke-Install1PasswordInvoke-DisableAnimationsInvoke-EnableNumLockInvoke-ClassicContextMenu
Bootstrap
Initialize-NuGetProvider
Purpose
Ensures SAMY can install/update PowerShell modules and providers without interactive prompts (critical for unattended runs and iwr | iex style execution).
Key behaviors
- Forces TLS 1.2 for network operations.
- Silences progress + confirmation prompts to keep runs unattended.
- Ensures provider folder paths exist:
- Current user provider assemblies path
- All users provider assemblies path (may fail without admin; handled)
- Ensures the NuGet package provider is installed at a minimum version.
- Imports NuGet provider after install.
- Imports/updates:
PackageManagementPowerShellGet
- Optionally marks
PSGalleryas trusted to prevent prompts.
Why it matters Many PowerShell module installs trigger interactive prompts, especially on fresh machines. This function makes module installation reliable for SAMY's automation.
Common failure modes
- No internet / proxy blocks PSGallery or NuGet endpoints.
- Running under restricted execution policy or locked-down environment.
- Running without elevation when trying to write to system-wide locations (handled as “warning” for folder creation).
Logging
Uses Write-LogHybrid with -LogToEvent to record bootstrap state and failures.
Modification notes
- If you need stricter behavior: choose whether to
throwin the final catch block (PackageManagement/PowerShellGet setup). - If you need TLS 1.3+: be careful, many older environments still require TLS 1.2 compatibility.
Registry Helpers
Set-RegistryValueInHkuRoot
Purpose
Writes a registry value relative to a given HKEY_USERS hive root.
Parameters
HkuRoot: registry root path (e.g.Registry::HKEY_USERS\S-1-5-21-...)RelativeKeyPath: relative key path under the rootName: value nameType: value type (String, DWord, etc.)Value: value data
Behavior
- Ensures the key exists.
- Uses
New-ItemPropertywith-Forceso it can create or overwrite.
When to use When you already have the target user hive loaded and you want a consistent writer.
Set-RegistryValueForCurrentAndAllUsers
Purpose Applies the same registry setting to:
- Current user (HKCU) if meaningful/available
- Default user profile hive (
C:\Users\Default\NTUSER.DAT) so future users inherit the setting - All existing user profiles by enumerating ProfileList and mounting each
NTUSER.DATas needed
High-level flow
- Try write to HKCU (best-effort; may be skipped under SYSTEM).
- Default User:
- Loads
C:\Users\Default\NTUSER.DATintoHKEY_USERS\SVS_DefaultUser(if not already loaded) - Writes the setting
- Unloads the hive (only if this function loaded it)
- Loads
- Existing profiles:
- Enumerates
HKLM:\...\ProfileList - Identifies user SIDs (
S-1-5-21-...) - If hive already loaded under
HKEY_USERS\<SID>, writes directly - Otherwise mounts
NTUSER.DATto a temporary key, writes, then unloads
- Enumerates
Why it matters Many Windows customizations are stored per-user. To make onboarding consistent, SAMY must update:
- the active user (if running interactively)
- the default profile (future logins)
- every existing profile on the machine (shared devices, re-used devices)
Important safety notes
- Loading/unloading hives is sensitive:
- A loaded hive can't always be unloaded if something else is holding a handle.
- The function tracks whether it loaded the hive (
$didLoad) to avoid unloading someone else's mount.
- Profile iteration excludes non-standard SIDs by regex filter.
- Some profiles may not have
NTUSER.DAT(system profiles, corrupt profiles, etc.). Those are skipped safely.
Logging
Uses Write-LogHybrid to record default hive load/unload outcomes and per-setting success.
Modification notes
- If you add more settings, prefer calling this helper rather than duplicating hive logic.
- If you need to write to HKLM machine-wide instead, do that outside this helper.
- If you ever see “unload failed”, it's usually because something still holds a handle to the loaded hive.
Restart-ExplorerIfInteractive
Purpose Restarts Explorer to apply UI-related registry changes (taskbar, context menu, shell tweaks).
Behavior
- Skips restart when running as
SYSTEMto avoid breaking non-interactive phases. - Stops
explorer.exeand restarts it.
Modification notes
- If this ever runs during OOBE/Autopilot contexts, you may want stronger checks than
$env:USERNAME -ne 'SYSTEM'.
UI Handlers
These functions are designed to be invoked by the SAMY web UI through task routing. Each handler:
- parses optional JSON POST body (e.g., selected options)
- executes the requested action
- logs results via
Write-LogHybrid - returns a response to the UI via
Send-Text
Invoke-Install1Password
Purpose Installs 1Password desktop app and optionally forces browser extension install for Chrome and/or Edge.
Inputs
- Defaults to installing the desktop app if no UI selection is provided.
- If POST JSON contains
checkedValues, uses that list.
Actions
- Desktop app via
winget(AgileBits.1Password) - Chrome extension by setting policy:
HKLM:\SOFTWARE\Policies\Google\Chrome\ExtensionInstallForcelist
- Edge extension by setting policy:
HKLM:\SOFTWARE\Policies\Microsoft\Edge\ExtensionInstallForcelist
Notes
- Forcelist policy requires admin to write HKLM policies.
- Browser extension IDs must remain correct; update if vendor changes.
Invoke-DisableAnimations
Purpose Applies UI “reduced motion” style tweaks by writing registry values across all users.
Default selection If no options are provided, defaults to enabling all:
window,taskbar,menus
Settings applied
- Window animation:
MinAnimate - Taskbar animations:
TaskbarAnimations - Menu delay:
MenuShowDelay
Post-action
- Restarts Explorer if taskbar changes were applied.
Invoke-EnableNumLock
Purpose Turns NumLock on by default (affects logon screen + default profile behavior).
Where it writes
Registry::HKEY_USERS\.DEFAULT\Control Panel\KeyboardInitialKeyboardIndicators = "2"(string)
Notes
- Uses
.DEFAULTso it impacts the logon screen and baseline behavior. - This does not guarantee every vendor keyboard/BIOS setting, but covers the Windows side.
Invoke-ClassicContextMenu
Purpose Enables Windows 11 classic right-click context menu behavior.
Where it writes
HKCU:\Software\Classes\CLSID\{86ca1aa0-34aa-4e8b-a509-50c905bae2a2}\InprocServer32- Default value set to blank
Post-action
- Restarts Explorer to apply immediately.
Notes
- This is per-user (HKCU). If you want it for all users, use the registry helpers to apply across profiles.
Logging expectations
All functions log via Write-LogHybrid using categories like:
BootstrapTweaksSVSAppsUI
When -LogToEvent is enabled, events are also written to the configured Windows Event Log (e.g., SVSMSP Events) using the project's Event Log binding logic.
Common maintenance tasks
Add a new UI handler
- Create
Invoke-<TaskName>function. - Parse POST JSON if needed (
checkedValuespattern). - Use
Write-LogHybridfor logging. - Use
Send-Textfor responses. - Ensure the router maps a route/task name to this handler.
Add a new per-user tweak
- Prefer using
Set-RegistryValueForCurrentAndAllUsersto apply it to:- current user (HKCU)
- Default User hive
- existing profiles
Debug “it works the second time” issues
That often means initialization happens after first use (especially Event Logs and provider bootstrap). Ensure bootstrap/init happens before first call site that depends on it.
Quick troubleshooting commands
Check Event Log source binding
[System.Diagnostics.EventLog]::LogNameFromSourceName('SVMSP_Module','.')