260 lines
8.8 KiB
PowerShell
260 lines
8.8 KiB
PowerShell
# 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`
|
||
- 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.
|
||
|
||
---
|
||
|
||
## 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
|
||
```powershell
|
||
[System.Diagnostics.EventLog]::LogNameFromSourceName('SVMSP_Module','.')
|