Files
SAMY/docs/samy.functions.md

11 KiB
Raw Permalink Blame History

samy.functions.ps1 (3-in-1)

This file groups three core categories of functionality used by SAMY:

  1. Bootstrap: prepares PowerShell package tooling (NuGet provider, PowerShellGet, PackageManagement, PSGallery).
  2. Registry Helpers: reusable functions to write registry values for current user, default user (future profiles), and existing user profiles.
  3. 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
  • Task + validation helpers
    • Test-ComputerName
    • Get-TaskHandlerName
  • Registry helpers
    • Set-RegistryValueInHkuRoot
    • Set-RegistryValueForCurrentAndAllUsers
    • Restart-ExplorerIfInteractive
  • UI Handlers (examples included in file)
    • Invoke-Install1Password
    • Invoke-DisableAnimations
    • Invoke-EnableNumLock
    • Invoke-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:
    • PackageManagement
    • PowerShellGet
  • Optionally marks PSGallery as 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 throw in the final catch block (PackageManagement/PowerShellGet setup).
  • If you need TLS 1.3+: be careful, many older environments still require TLS 1.2 compatibility.

Task + validation helpers

Test-ComputerName

Purpose Validates a proposed computer name before applying it (typically from UI input).

Rules enforced

  • Must not be null/empty/whitespace.
  • Must be 15 characters or fewer (NetBIOS computer name limit).
  • Must match: ^[A-Za-z0-9-]+$ (letters, numbers, hyphen only).

Returns

  • $true if name is valid
  • $false if name fails any rule

Where its used

  • Typically in handlers such as rename/computer identity workflows, to prevent invalid names from being applied.

Maintenance notes

  • If you want stricter rules (common):
    • disallow leading or trailing hyphen
    • disallow all-numeric names
  • Keep any rule changes consistent with your environment (AD join rules, naming standards, etc.).

Get-TaskHandlerName

Purpose Resolves the PowerShell function name that should execute for a given task object.

This supports two patterns:

  1. Explicit handler name stored on the task object (preferred when set)
  2. Convention-based handler name derived from task Name

Resolution order

  1. Checks the task object for one of these properties (first match wins):
    • HandlerFn
    • Handler
    • Fn
  2. If none are present/usable, falls back to:
    • "Invoke-$Task.Name"

Normalization When a handler value is found:

  • Converts to string
  • Trims whitespace
  • Removes a leading / (in case the value is stored like a URL path)

Returns

  • A string function name (e.g. Invoke-RenameComputer) when resolved
  • $null if no usable handler or name exists

Where its used

  • The HTTP router / request dispatcher uses this to map a requested task route to the correct handler function.

Why it exists

  • Allows tasks to follow a simple convention (Invoke-<TaskName>) while still supporting overrides for:
    • legacy handler names
    • special routing cases
    • tasks that map to a shared/common handler

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 root
  • Name: value name
  • Type: value type (String, DWord, etc.)
  • Value: value data

Behavior

  • Ensures the key exists.
  • Uses New-ItemProperty with -Force so 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:

  1. Current user (HKCU) if meaningful/available
  2. Default user profile hive (C:\Users\Default\NTUSER.DAT) so future users inherit the setting
  3. All existing user profiles by enumerating ProfileList and mounting each NTUSER.DAT as needed

High-level flow

  1. Try write to HKCU (best-effort; may be skipped under SYSTEM).
  2. Default User:
    • Loads C:\Users\Default\NTUSER.DAT into HKEY_USERS\SVS_DefaultUser (if not already loaded)
    • Writes the setting
    • Unloads the hive (only if this function loaded it)
  3. 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.DAT to a temporary key, writes, then unloads

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 SYSTEM to avoid breaking non-interactive phases.
  • Stops explorer.exe and 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\Keyboard
    • InitialKeyboardIndicators = "2" (string)

Notes

  • Uses .DEFAULT so 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:

  • Bootstrap
  • Tweaks
  • SVSApps
  • UI

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

  1. Create Invoke-<TaskName> function.
  2. Parse POST JSON if needed (checkedValues pattern).
  3. Use Write-LogHybrid for logging.
  4. Use Send-Text for responses.
  5. Ensure the router maps a route/task name to this handler.

Add a new per-user tweak

  • Prefer using Set-RegistryValueForCurrentAndAllUsers to 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','.')