Skip to content

Latest commit

 

History

History
1987 lines (1396 loc) · 221 KB

File metadata and controls

1987 lines (1396 loc) · 221 KB

System Module

The System module handles Windows system configuration, environment setup, and OS-level operations.

  • Description: Loads the System.Windows.Forms assembly into the current PowerShell session via Add-Type -AssemblyName System.Windows.Forms. Safe to call multiple times. Used as a helper by functions that open file-picker dialogs or rely on Windows Forms controls. Pass -Quiet to suppress the status output messages.
  • Parameters: -Quiet
  • Usage: Add-WindowsFormsType, Add-WindowsFormsType -Quiet
  • Description: Clears all pinned taskbar items by removing the taskbar pin values from the Taskband registry key (HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Taskband). Restarts Explorer to apply the change unless -SkipExplorerRestart is specified. Requires administrator privileges.
  • Parameters: -SkipExplorerRestart
  • Usage: Clear-TaskbarPins, Clear-TaskbarPins -SkipExplorerRestart

Removes the Favorites, FavoritesResolve, FavoritesChanges, FavoritesVersion, FavoritesRemovedChanges, and LayoutXMLLastModified values under the Taskband key, reporting how many were cleared. LayoutXMLLastModified is Explorer's "this layout file is already applied" marker - it records the layout file's timestamp and silently skips re-applying a file whose timestamp matches, so clearing it alongside the pins guarantees the next Explorer start re-applies whatever layout the policy points at, even one that an interrupted apply left half-done. If the registry path or pin data is missing it reports that there is nothing to clear and returns without error. By default it then restarts Explorer so the empty taskbar takes effect; pass -SkipExplorerRestart when the caller (for example Unpin-TaskbarApps) will restart Explorer itself, to avoid restarting it twice.

Parameter Description
-SkipExplorerRestart Skips the Explorer restart after clearing pins. Use when Explorer will be restarted by the calling function.
# Clear all taskbar pins and restart Explorer to apply
Clear-TaskbarPins

# Clear pins but leave the Explorer restart to the caller
Clear-TaskbarPins -SkipExplorerRestart
  • Description: Clears WhatsApp Desktop local storage to resolve startup issues. Stops WhatsApp if it is running, lists the contents and total size of the storage directory, then (after confirmation) deletes everything under the path configured in Configuration.Universal.WhatsAppLocalStoragePath. Requires administrator privileges.
  • Usage: Clear-WhatsAppLocalStorage

Runs Test-AdminPrivileges first, so it must be invoked from an elevated session. If WhatsApp is running it is force-stopped; if the configured storage path no longer exists the function reports that storage is already cleared and returns. Before deleting, it prints a per-directory size breakdown (MB/GB) plus a total, then prompts for confirmation (Enter defaults to Yes). Choosing Yes removes the directory recursively; any other response cancels the operation.

# Stop WhatsApp and clear its local storage directory (run elevated)
Clear-WhatsAppLocalStorage
  • Description: Gracefully closes previously discovered browser windows by posting WM_CLOSE directly to each supplied native window handle. Operates on the window objects collected by Get-BrowserWindowsByTarget, and is used by Terminate-AllBrowserProcesses after exclusion filtering has been applied.
  • Parameters: -WindowsToClose
  • Usage: Close-BrowserWindows -WindowsToClose $windows

Iterates over each supplied window object and posts WM_CLOSE to its native Handle through the Window module's Close-Window. Because the message is posted directly to each handle, the foreground is never touched, so windows excluded upstream are never accidentally closed by a misfired keystroke.

Parameter Type Default Description
-WindowsToClose object[] - Browser window objects containing a native Handle property (typically produced by Get-BrowserWindowsByTarget).
# Close every browser window collected for the target PIDs
$windows = Get-BrowserWindowsByTarget -TargetPids @(1234) -TitlePattern "Google Chrome"
Close-BrowserWindows -WindowsToClose $windows
  • Description: Installs and configures a Nerd Font. Reads the available fonts from NerdFonts in Configuration.psd1; when given a font name it installs that font, and when called without arguments it shows an interactive menu (Enter selects the DefaultNerdFont). Requires administrator privileges.
  • Parameters: -FontName
  • Usage: Configure-NerdFont, Configure-NerdFont -FontName "JetBrainsMono"

Copies the matching .ttf/.otf files from the font's source folder under the WinuX root into the Windows fonts directory and registers them under HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts. The operation is idempotent: if the target font is already present in both the filesystem and the registry it is skipped, and individual font files that already exist are not re-copied. The font's SearchPattern and FolderName come from its entry in NerdFonts.

Parameter Description
-FontName Nerd Font name as defined in NerdFonts in Configuration.psd1 (e.g. "JetBrainsMono"). Omit to show the interactive selection menu.
# Show the interactive Nerd Font selection menu (Enter picks DefaultNerdFont)
Configure-NerdFont

# Install a specific Nerd Font by its configured name
Configure-NerdFont -FontName "JetBrainsMono"
  • Description: Configures NuGet package source settings for the GitHub Package Registry by copying a NuGet.config template from the WinuX repository to the user's AppData NuGet folder. Source and destination paths are read from MachineSpecificPaths.NuGetConfig. If the destination already exists, it compares package sources against the repository template and reconfigures only on a mismatch; otherwise it skips the copy unless -Override is set. When a copy is performed it prompts securely for the GitHub username and personal access token (PAT), substituting them into the template.
  • Parameters: -Override
  • Usage: Configure-NuGetConfig, Configure-NuGetConfig -Override

Reads MachineSpecificPaths.NuGetConfig.SourcePath and .DestinationPath. When the destination exists, it parses both XML files and diffs the packageSources entries by key and URL: any missing, extra, or differing source triggers reconfiguration. If the sources match, it reports success and returns without changes. During reconfiguration it prompts for the GitHub username and PAT (entered as a secure string), replaces the [Username] and [Token] placeholders in the template, creates the destination directory if needed, and writes the resulting file as UTF-8.

Parameter Description
-Override Force reconfiguration of NuGet settings even if the destination already exists and matches the template.
# Configure NuGet only if not already correctly set up
Configure-NuGetConfig

# Force a full reconfigure, overwriting the existing config
Configure-NuGetConfig -Override
  • Description: Changes the postgres user password across every installed PostgreSQL version found on the machine. Prompts for the current and new passwords, or with -Auto reads them from PostgreSqlPasswords in Configuration.psd1 and applies them without prompting. Already-configured installations are detected and skipped (idempotent); a manual-instructions file is written to the Desktop only for installations that fail.
  • Parameters: -DefaultOrCurrentPassword, -NewPassword, -Auto
  • Usage: Configure-PostgreSqlPasswords, Configure-PostgreSqlPasswords -Auto, Configure-PostgreSqlPasswords -DefaultOrCurrentPassword foo -NewPassword bar

Scans C:\Program Files\PostgreSQL and C:\Program Files (x86)\PostgreSQL for every version's bin\psql.exe. For each installation it tries ports 5432, 5433, 5434, and 5435: it first checks whether the new password already authenticates (skip if so), otherwise runs ALTER USER postgres WITH PASSWORD '<new>' via a temporary SQL file. A call with no arguments defaults to the configuration values (same as -Auto); explicit -DefaultOrCurrentPassword / -NewPassword override the configuration. If any version fails on all attempted ports (or an unexpected error occurs), step-by-step manual instructions are written to the Desktop via Write-ManualInstructionsToDesktop.

Parameter Description
-DefaultOrCurrentPassword The current PostgreSQL password, used to authenticate before the change.
-NewPassword The new password to set on the postgres user.
-Auto Reads DefaultOrCurrent and New from PostgreSqlPasswords in Configuration.psd1 instead of prompting.
# Use the passwords from Configuration.psd1 (PostgreSqlPasswords key)
Configure-PostgreSqlPasswords -Auto

# Equivalent: no arguments defaults to the configuration values
Configure-PostgreSqlPasswords

# Override the configuration with explicit current/new passwords
Configure-PostgreSqlPasswords -DefaultOrCurrentPassword foo -NewPassword bar
  • Description: Configures the Windows taskbar pins from configuration. When TaskbarConfiguration is not configured (the empty base default), it warns and leaves the existing pins as-is - the destructive clearing never runs on an empty section. When it is configured, it clears all existing pins (via Unpin-TaskbarApps) and rebuilds the icon cache up front, builds an XML layout from TaskbarConfiguration in Configuration.psd1, then applies it with an unlock -> apply -> lock -> restart Explorer sequence optimized for Windows 11. Requires administrator privileges.
  • Parameters: -FromBootstrap
  • Usage: Configure-Taskbar, Configure-Taskbar -FromBootstrap

Resolves the current machine type (via DetermineMachineType) and states in the output which machine the pins are being configured for (or that the hostname is unmapped and the default set is used). Reads the pin list from TaskbarConfiguration (each entry is either an AUMID or a Path, with {User} tokens expanded to the current profile), keeping only rows whose Machine scope matches the machine type - the same Test-MachineTypeScope gate the app CSVs use; a row without Machine defaults to All. A Path row may carry an Aumid key for apps that register their own AppUserModelID at runtime and would otherwise open as a second, separate icon next to their pin (Eclipse/SWT apps such as DBeaver): the row is then pinned through a shortcut stamped with that identity via Set-ShortcutAumid - a .lnk Value is stamped in place, an .exe Value gets a machine-local shortcut generated under TaskbarPins\<Name>.lnk next to the layout file (falling back to the raw path with a warning if stamping fails). It writes the generated layout directly to the machine-local TaskbarLayoutFile (C:\ProgramData\provisioning\taskbar_layout.xml) - not versioned in the repo and needing no symlink - and sets the StartLayoutFile and LockedStartLayout registry policies under HKLM:\SOFTWARE\Policies\Microsoft\Windows\Explorer. Explorer applies a pin list asynchronously for several seconds after it starts, and it records the layout file's timestamp in Taskband\LayoutXMLLastModified so a file it has already seen is never re-applied - which makes any Explorer restart landing mid-apply a permanent truncation of the pins rather than a retried one. The Explorer-touching steps are ordered around that: the icon cache rebuild (Rebuild-IconCache) runs up front and provides the single bounce that clears the old pins from the screen (Unpin-TaskbarApps is called with -SkipExplorerRestart so it does not add another), and the final Restart-Explorer is the last thing the function does - preceded by a reset of the applied-layout marker and the layout file's timestamp so that start is guaranteed to re-apply, and given an 8-second settle so control does not return while pins are still being written. With -FromBootstrap, it skips the 5-second Explorer-initialization wait and leaves the layout unlocked so the Bootstrap script can lock it after its own Explorer restart.

Parameter Description
-FromBootstrap Skips the 5-second wait for Explorer initialization and leaves the layout unlocked for the Bootstrap sequence to lock later. Used internally during setup.
# Clear and reconfigure the taskbar pins (interactive use)
Configure-Taskbar

# Internal use during the bootstrap sequence (skips the init delay, leaves layout unlocked)
Configure-Taskbar -FromBootstrap

See also: Clear-TaskbarPins, Get-PinnedApps, Set-ShortcutAumid

  • Description: Enables the Windows Subsystem for Linux optional feature (if not already enabled) and installs the default WSL distribution read from DefaultWSLDistribution in Configuration.psd1 (if not already installed). The base ships that key empty, so the function warns and skips WSL setup until a distribution is set in Configuration.local.psd1. On first installation it sets up the WSL user account - non-interactively when DefaultWSLUsername is configured, otherwise via the distribution's interactive first-launch wizard. Requires administrator privileges.
  • Parameters: -Force (alias -Override)
  • Usage: Configure-WSL, Configure-WSL -Force

Checks Test-WSLEnabled and enables the Microsoft-Windows-Subsystem-Linux optional feature with -NoRestart when needed. It then checks Test-WSLDistributionInstalled and, if the distribution is missing, runs wsl --install -d <distro> --no-launch followed by the user account setup:

  • With DefaultWSLUsername configured (lowercased automatically - Linux usernames are lowercase), the account is created non-interactively with useradd (home directory, bash shell, adm/sudo groups), you are prompted once for its sudo password (passwords never live in configuration), and the account is written as default under [user] in /etc/wsl.conf followed by a distro restart so it takes effect.
  • Without it, a bare wsl launch runs the interactive first-launch wizard (username and sudo password); use exit to let setup continue.

Both stages are idempotent and report when WSL or the distribution is already present. Whenever the distribution is installed, it is also pinned as the WSL default (wsl --set-default) on every run - Docker Desktop and podman machines routinely steal the default, which silently redirects bare wsl invocations (and Windows Terminal's default WSL profile) into the wrong distro.

The shipped Windows Terminal payloads (Windows/WindowsTerminal/settings_*.json) define the Ubuntu profile statically (commandline: wsl.exe -d Ubuntu --cd ~, fixed GUID) and disable the dynamic WSL profile generators via disabledProfileSources (Microsoft.WSL, Windows.Terminal.Wsl). Dynamically generated profiles get a new GUID on every distro registration, so each -Force reinstall would append a fresh Ubuntu entry to the settings file and orphan the previous one; the static profile makes reinstalls invisible to Windows Terminal. The trade-off: newly installed distros no longer auto-appear in the new-tab menu - add a static profile for them the same way.

Parameter Description
-Force Redoes the whole WSL setup even when the distribution is already installed: unregisters it (deleting everything inside the distribution), reinstalls, recreates the user, then re-runs Initialize-WSLEnvironment, SymbolicLinkMaker -Scope WSL (restoring only the WSL symlinks the reinstall wiped), and Configure-WSLSSH. Alias: -Override.

See also: Configure-WSLSSH, Initialize-WSLEnvironment

  • Description: Configures SSH inside WSL for proper security. Copies the Windows .ssh directory into the WSL user's home directory, sets ownership, and applies appropriate Unix permissions: directory 700 (rwx------), config file and private keys 600 (rw-------), and public keys 644 (rw-r--r--). No-ops until DefaultWSLDistribution is configured.
  • Usage: Configure-WSLSSH

Every wsl call targets the configured DefaultWSLDistribution explicitly (wsl -d <distro>) - Docker Desktop and podman machines routinely steal the WSL default, which would otherwise send the keys into the wrong distro. The WSL username and home directory are derived from inside that distribution (id -un / $HOME), never from $env:USERNAME - Linux is case-sensitive and WSL accounts are lowercase by convention (Windows Ivan vs WSL ivan), so assuming the Windows name would silently build a root-owned /home/<WrongCase> tree that SSH never reads. If the user cannot be determined (uninitialized distribution), the function reports it and skips.

Removes any existing .ssh in the WSL home directory, recreates it, then copies the SSH files over from the Windows profile. Ownership is reset to the WSL user, after which permissions are tightened (all as root): 700 on the directory, 600 on the config file and all private keys (everything that is not *.pub, known_hosts*, authorized_keys*, or config), and 644 on public keys. This avoids the strict-permission errors SSH raises when keys carried over from Windows are world-readable. Exit codes are checked along the way - the closing message reports failure instead of claiming success when any command failed.

  • Description: Scans a directory tree for .NET projects and lists their dependencies. Recursively finds project files (.csproj, .fsproj, .vbproj), parses their target frameworks, compares the required modern .NET versions against the installed SDKs and runtimes, and reports which required SDKs are present or missing. For any missing SDKs it prints ready-to-use installation commands in both WinGet and WinGetApps.csv formats.
  • Parameters: -SearchPath, -ExcludePaths, -ListProjects
  • Usage: Determine-DotnetDependencies, Determine-DotnetDependencies -ListProjects, Determine-DotnetDependencies -SearchPath C:\repos -ListProjects

The search path defaults to MachineSpecificPaths.DotnetProjectsSearchPath, falling back to $env:USERPROFILE\Development when that key is not configured. Common build and cache folders (node_modules, bin, obj, .git, .vs, packages) are excluded by default. Only modern .NET target frameworks are evaluated against the installed SDKs; missing versions are surfaced with Microsoft.DotNet.SDK.<major> package commands.

Parameter Description
-SearchPath Root directory to scan for .NET projects. Defaults to MachineSpecificPaths.DotnetProjectsSearchPath or $env:USERPROFILE\Development if not configured.
-ExcludePaths Array of directory names to exclude from scanning. Defaults to common build/cache folders.
-ListProjects Also outputs the list of .NET projects found, grouped per target framework.
# Scan the configured .NET projects directory for dependencies
Determine-DotnetDependencies

# Scan a specific folder and list each project under its target framework
Determine-DotnetDependencies -SearchPath C:\repos -ListProjects
  • Description: Displays the current system language, locale, and culture settings. Prints three sections: Display Language(s) from Get-WinUserLanguageList, System Locale from Get-WinSystemLocale, and User Culture from Get-Culture.
  • Usage: Display-SystemLanguageSettings
  • Description: Enables Windows Developer Mode by setting the registry value AllowDevelopmentWithoutDevLicense to 1 under HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\AppModelUnlock. Developer Mode allows running unsigned scripts and unpacked UWP apps, and is required for creating symlinks without admin (used by SymbolicLinkMaker for Windows symlinks outside Bootstrap; WSL symlinks do not require it). Requires administrator privileges.
  • Usage: Enable-DeveloperMode

The function first calls Test-AdminPrivileges, then checks whether AllowDevelopmentWithoutDevLicense under HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\AppModelUnlock is already set to 1. If not, it creates the key as needed and sets the value. The optional Tools.DeveloperMode capability (Device Portal / SSH for remote UWP debugging) is deliberately not installed - it needs online Windows Update servicing and can stall bootstrap for minutes on fresh machines; install it manually with Get-WindowsCapability -Online -Name "Tools.DeveloperMode*" | Add-WindowsCapability -Online if ever needed. The operation is idempotent: if Developer Mode is already enabled it reports so and makes no changes. As a Bootstrap step (BootstrapConfig.Steps.DeveloperMode) it is off by default - it changes a machine-wide security posture the moment it runs, so a vanilla bootstrap leaves Developer Mode alone; opt in via Steps or Bootstrap -Include DeveloperMode.

# Enable Windows Developer Mode (run from an elevated session)
Enable-DeveloperMode
  • Description: Restyles onefetch's output as it streams past, reaching the two parts of its appearance that cannot be configured at all. onefetch has no configuration file - unlike fastfetch, which reads a config.jsonc - and its command line cannot express either a true color (--text-colors takes ANSI indices 0-15 and rejects anything above with "33 is not in 0..16") or a separator other than the hardcoded : (in --text-colors "colon" is a color slot, not a string, and --number-separator is the thousands separator inside numbers). Both are reachable afterwards, in the SGR escape sequences onefetch writes and keeps writing when piped: this maps the ANSI indices it was told to use onto true-color codes, and swaps the colon for a separator of your choosing. A pure text transform - no binary, no terminal, no configuration lookup - so it is testable on a string and safe in front of any onefetch invocation, including the measuring one: it emits exactly one line per line, so a measured panel keeps its height. A line that matches nothing passes through untouched, which is also what an uncolored stream gets (onefetch honors NO_COLOR). Driven by TerminalGreeting.Onefetch.Style through the global onefetch wrapper in the all-hosts profile, which also hands a bare onefetch the configured Arguments - the way a bare fastfetch gets its configuration file - so that the indices Style.Colors remaps are the ones --text-colors actually asked for.
  • Parameters: -Line, -Separator, -Colors
  • Usage: onefetch | Format-OnefetchPanel -Separator " -> ", onefetch | Format-OnefetchPanel -Colors @{ "12" = "38;2;30;144;255" }

The colon is matched structurally - a color, the colon, a reset - rather than against one particular color code, so it is found whatever --text-colors was set to.

Alignment is the subtle part. A separator wider than the : it replaces pushes every value right, while onefetch's own continuation lines - the second author, the extra churn entries, the language chips - are already padded and would be left behind. Those are re-padded by the difference, and the padding is inserted at the info column rather than at column 0, so the rows of the ASCII logo that share a line with a language chip keep their own columns instead of acquiring a slant. The info column is measured once, off the first field line, as the last run of two spaces before the separator - the gap between logo and info is more than one space, while the words inside a field name are separated by exactly one. Three kinds of line are never padded: anything above the first field (the title and its underline are not in the value column), anything carrying a background color (the color palette row, the language bar - both drawn to a width of their own), and anything too short to reach the info column.

Parameter Type Default Description
-Line string - A line of onefetch output. Takes the whole stream from the pipeline.
-Separator string - Replaces the hardcoded : and the single space after it. $null or empty leaves the colon alone.
-Colors hashtable - Maps an ANSI index (0-15) onto the SGR parameters to paint it with instead. An index out of range, or an empty replacement, is skipped with a debug line.
# The panel with fastfetch's separator in place of the colon
onefetch | Format-OnefetchPanel -Separator " -> "

# Repaint everything onefetch drew in bright blue as exact dodger blue
onefetch --text-colors 12 9 9 12 9 15 | Format-OnefetchPanel -Colors @{ "12" = "38;2;30;144;255" }

# Both at once, which is what TerminalGreeting.Onefetch.Style drives
onefetch | Format-OnefetchPanel -Separator " -> " -Colors @{ "12" = "38;2;30;144;255"; "9" = "38;2;255;0;0" }

See also: Invoke-Onefetch, Resolve-TerminalGreetingSettings, Show-TerminalGreeting, Format-OnefetchPanel configuration guide

  • Description: Returns the window title regex that identifies a browser's main windows, keyed by browser name from Configuration.Universal.Browsers (Firefox, Tor, Chrome, Edge, Brave); unknown names return $null. The single source of truth for browser window identification, shared by Terminate-AllBrowserProcesses (to find the windows to close) and Open-Browser's -Instances mode (to count only the target browser's existing windows - Firefox and Tor Browser share the firefox.exe process name, so a process-level count cannot tell them apart).
  • Parameters: -BrowserName
  • Usage: Get-BrowserTitlePattern -BrowserName "Edge"

The Edge pattern (Microsoft.{0,2}Edge) deliberately allows up to two arbitrary characters between "Microsoft" and "Edge": real Edge window titles embed a zero-width space (U+200B) before the regular space, and U+200B is a format character rather than whitespace, so neither a literal space nor \s matches it.

Parameter Type Description
-BrowserName string Browser name as configured in Configuration.Universal.Browsers (e.g. "Firefox", "Edge").
# Regex matching Microsoft Edge window titles (zero-width-space tolerant)
Get-BrowserTitlePattern -BrowserName "Edge"

# Regex distinguishing Tor Browser windows from regular Firefox ones
Get-BrowserTitlePattern -BrowserName "Tor"

See also: Get-BrowserWindowsByTarget, Terminate-AllBrowserProcesses

  • Description: Reads the Window module's window enumeration (Get-CachedWindows, which already keeps only visible, titled top-level windows) and returns every window owned by the supplied browser process IDs; -TitlePattern sets a MatchesPattern flag on each rather than filtering. Used to distinguish browser main windows from child/helper processes (GPU / renderer / utility) that do not own a top-level window.
  • Parameters: -TargetPids, -TitlePattern
  • Usage: Get-BrowserWindowsByTarget -TargetPids @(1234) -TitlePattern "Google Chrome"

Filters Get-CachedWindows by owning process ID and returns each match as a PSCustomObject with Handle, Title, ProcessId and MatchesPattern properties. Titles come back as Unicode, so the zero-width space Edge embeds in "Microsoft Edge" survives the round trip and the brand pattern can match it.

Parameter Type Description
-TargetPids int[] Process IDs whose top-level windows should be enumerated.
-TitlePattern string Regex used to keep only the intended browser brand main windows.
# Return visible Chrome windows owned by process 1234
Get-BrowserWindowsByTarget -TargetPids @(1234) -TitlePattern "Google Chrome"

See also: Close-BrowserWindows

  • Description: Returns the machine's SMBIOS chassis type codes (Win32_SystemEnclosure.ChassisTypes - 3 for a desktop, 9 or 10 for a laptop), from the hardware on the first call and from a per-machine cache file (%LOCALAPPDATA%\WinuX\ChassisTypes.txt, one code per line) on every later one. The CIM query loads the CimCmdlets module and was the largest part of Test-PowerPlan's cost on every shell start, for a value that never changes on a given machine. -Refresh queries the hardware again and rewrites the cache; a cache that is missing, empty or not integers is ignored and re-created, and one that cannot be written just means the hardware is queried every time. Returns an empty list when neither answered.
  • Parameters: [-Refresh] [-CachePath]
  • Usage: Get-ChassisType, Get-ChassisType -Refresh

See also: Test-PowerPlan

  • Description: Reads the console window size in character cells - an object with Width and Height taken from [Console]::WindowWidth / WindowHeight, the number of columns and rows the terminal shows at its current font size. Throws in hosts that have no console window (automation, some IDE hosts), which is the signal Invoke-Fastfetch uses to skip its font auto-fit; the read is deliberately not wrapped so a caller can choose between degrading gracefully and seeing the failure.
  • Usage: Get-ConsoleWindowSize

It exists as a function rather than an inline property read so callers that react to the window changing - Wait-ConsoleReflow polls it after every font keystroke - can be driven by a scripted sequence of sizes in tests.

# Compare a measured panel against the live window
$window = Get-ConsoleWindowSize
if ($panelWidth -gt $window.Width) { "too wide" }

See also: Wait-ConsoleReflow, Invoke-Fastfetch

  • Description: Builds the fastfetch arguments that render an image logo in the current terminal, returning an empty array whenever an image is not possible so the caller runs fastfetch exactly as configured. Opt-in: returns nothing until Universal.FastFetchImageLogo names an image - either one path for every machine, or a hashtable keyed by machine type, where a machine with no entry gets no image. Dispatches per terminal: WezTerm gets --logo-type iterm (the OSC 1337 inline-image protocol, which WezTerm scales itself), Windows Terminal gets --logo-type raw over a sixel that Get-TerminalCellSize and New-SixelImage have already sized to fit, and every other host gets nothing. Reserves a fixed block of character cells and fits the image inside it preserving the aspect ratio, so the panel has the geometry it would have with a text logo of the same dimensions; -ReferenceLogoPath defaults to the deployed fastfetch text logo (PathTemplates.SymbolicLinks.FastFetch.Logo), so the block is measured from the very logo the image replaces. Returns nothing when output is redirected, so a shell whose whole stdout is a file or a pipe gets text rather than 50KB of sixel. Never throws.
  • Parameters: [-ImagePath] [-ReferenceLogoPath] [-CellWidth] [-CellHeight] [-PaddingRight] [-OutputRedirected]
  • Usage: Get-FastfetchLogoArgument, Get-FastfetchLogoArgument -ImagePath $logo -CellWidth 30 -CellHeight 15

This exists because fastfetch cannot render an image logo on Windows by itself. Its getCharacterPixelDimensions() has two implementations and the Windows one calls GetCurrentConsoleFontEx(), which its own source notes "only works for ConHost"; the escape-sequence measurement is compiled only on Unix. Under Windows Terminal the call fails and every image logo type that has to SCALE the image (sixel, chafa, kitty, iterm) degrades to a placeholder block of slashes with Logo: getCharacterPixelDimensions() failed on stderr. The types that PASS THE IMAGE THROUGH for the terminal to scale (iterm, kitty-direct) need no measurement and work fine, but Windows Terminal implements neither protocol - it renders sixel instead. Pre-encoding the sixel and handing it over with --logo-type raw is the workaround fastfetch's own maintainer recommends for Windows, and it is what this function automates.

The wiring is the all-hosts profile (Windows/PowerShell/profile.ps1), an opt-in symbolic link that defines a global fastfetch function. PowerShell resolves functions before external applications, so the profile's startup panel and every Invoke-Fastfetch call pick the image up without either of those files changing. Two opt-ins therefore gate the feature: the symbolic link and the configuration key.

Parameter Description
-ImagePath The image to use as the logo. Anything ImageMagick can decode. Omit it and the value comes from Universal.FastFetchImageLogo - the whole string, or this machine's entry when that key is a per-machine hashtable. With neither set the function returns an empty array.
-ReferenceLogoPath Text logo whose dimensions define the cell block: its line count becomes the height, its longest line - fastfetch's $1-$9 color placeholders removed - becomes the width. Defaults to PathTemplates.SymbolicLinks.FastFetch.Logo. Overrides -CellWidth and -CellHeight when readable.
-CellWidth Width of the reserved block in cells, used when no reference logo is readable. Default 36.
-CellHeight Height of the reserved block in cells, used when no reference logo is readable. Default 16.
-PaddingRight Blank columns between the logo block and the module list. Default 4.
-OutputRedirected Whether this process's own output is redirected rather than going to a terminal. Defaults to the real console state; a parameter so the per-terminal branches are testable without a terminal.
# What the all-hosts profile's `fastfetch` wrapper does on every call
& $fastfetchExe @(Get-FastfetchLogoArgument)

# Override both the image and the cell block, ignoring the configured values
Get-FastfetchLogoArgument -ImagePath "C:\Logos\Flag.png" -CellWidth 30 -CellHeight 15

See also: Get-TerminalCellSize, New-SixelImage, Invoke-Fastfetch, Get-FastfetchLogoArgument configuration guide

  • Description: Enumerates all installed Windows applications (both 64-bit and 32-bit) by scanning the registry's Uninstall keys, then exports the results to installed_apps.txt on the Desktop.
  • Usage: Get-InstalledApps

For each application found it records DisplayName, DisplayVersion, Publisher, InstallDate, UninstallString, Bits, and the registry Path, writing the formatted list to C:\Users\<User>\Desktop\installed_apps.txt. Any existing file at that location is cleared before the export.

# Enumerate all installed apps and export to Desktop\installed_apps.txt
Get-InstalledApps
  • Description: Returns the version-pinned apps of one app list, machine-local overlay included. Reads the list through Import-AppCsv and returns the App of every row whose Version is a real version rather than the "track the latest" value. The single definition of "what counts as pinned", used by Sync-AppPins to decide which apps to lock in each package manager.
  • Parameters: -DataFileKey, -VersionExcludeValue
  • Usage: Get-PinnedApps -DataFileKey WinGetApps, Get-PinnedApps -DataFileKey ScoopApps -VersionExcludeValue "latest"

Apps whose version equals the exclude value (default "Latest") are treated as unpinned and are omitted from the results. Comment and blank rows are dropped: a # line containing commas parses into a bogus row with a non-"Latest" Version, and feeding that to winget pin add once hung an unattended upgrade.

Reading through Import-AppCsv rather than the committed CSV directly is what makes the pin honour the machine-local overlay, and it matters in both directions: a version pinned only in the overlay is invisible in the base file, so a direct reader would let Upgrade-All upgrade straight past the pin - the exact outcome pinning exists to prevent - and an app the overlay removed would still be reported as pinned.

Parameter Description
-DataFileKey Which list to read: WinGetApps, ScoopApps or ChocolateyApps. Mandatory, positional; resolved through BootstrapConfig.DataFiles, the same way the installers resolve it.
-VersionExcludeValue The Version value that means "not pinned". Defaults to "Latest" (WinGet); Scoop writes "latest", and Chocolatey leaves the cell empty, so its caller passes $null.
# Return WinGet apps locked to a specific version (Version other than "Latest")
Get-PinnedApps -DataFileKey WinGetApps

# Same for Scoop, excluding the lowercase "latest" sentinel
Get-PinnedApps -DataFileKey ScoopApps -VersionExcludeValue "latest"

See also: Import-AppCsv, Sync-AppPins, Upgrade-All

  • Description: Flattens a (possibly nested) SymbolicLinks configuration hashtable into a flat list of link entry objects, optionally filtered by -Scope and -Name. Pure discovery and selection - nothing is created or touched; SymbolicLinkMaker consumes the result and does the linking.
  • Parameters: -SymbolicLinks, -Scope (All, Windows, WSL), -Name
  • Usage: Get-SymbolicLinkEntries -SymbolicLinks $MachineSpecificPaths.SymbolicLinks -Scope WSL

Each returned object carries Key (the entry's own key), FullKey (the dotted path from the root, e.g. PowerToys.Settings), Path, Target, and IsWSL ($true when Path or Target contains a forward slash). -Name patterns are matched with wildcards against the bare keys and dotted paths at every level, so a group match carries down to everything beneath it.

Parameter Description
-SymbolicLinks The SymbolicLinks hashtable to flatten (normally MachineSpecificPaths.SymbolicLinks).
-Scope Which link flavor to return: All (default), Windows (backslash paths only), or WSL (forward-slash paths only).
-Name Wildcard patterns (e.g. PowerToys, PowerToys.Settings, WSL*) selecting specific entries; matching a group selects everything beneath it. Omit for all.

See also: SymbolicLinkMaker, New-WindowsSymbolicLink, New-WSLSymbolicLink

  • Description: Reports the pixel width and height of one character cell by asking the terminal itself, with the XTWINOPS "report cell size" query (CSI 16 t), parsing the CSI 6 ; height ; width t reply. Returns $null - never throws - when the host has no console, when input or output is redirected, when no reply arrives before the timeout, or when the reply is degenerate. The reply is read from the console input buffer, which is drained first: keystrokes typed into a Windows Terminal tab before its shell was ready would otherwise sit in front of the reply, and the read stops only on the complete CSI 6 ; height ; width t report - never on a stray t inside a typed word - so typing ahead can no longer fail the measurement or leak the reply onto the prompt. The typed-ahead characters are discarded, and the debug log records how many.
  • Parameters: [-TimeoutMilliseconds]
  • Usage: Get-TerminalCellSize, Get-TerminalCellSize -TimeoutMilliseconds 500

Nothing else can answer this question. A terminal image protocol places an image sized in PIXELS into a grid measured in CELLS, so the encoder has to know the conversion factor or the image lands on a fractional number of cells and overlaps whatever is drawn beside it. The query is the only portable source of that factor: there is no environment variable, and no Windows console API reports it correctly under a modern terminal - GetCurrentConsoleFontEx() works for ConHost only, which is exactly why fastfetch cannot do this itself on Windows. Windows Terminal answers since 1.22.2362.0, as do WezTerm, xterm and mlterm; everything else stays silent, costs the timeout once, and yields $null.

The input buffer is not assumed to be empty. A Windows Terminal tab opened with Win+ accepts keystrokes long before the profile runs, so anything typed while the tab was loading is queued ahead of the reply. The function drains that input before it sends the query and then reads until the whole report has arrived; the alternative - a read that stops on the first t - turned github typed into a loading tab into a failed measurement, the text logo instead of the image, and hub[6;20;10t printed at the prompt. Losing the typed-ahead characters is the deliberate price of a clean panel; the shell is ready to type into the moment the prompt appears.

Parameter Description
-TimeoutMilliseconds How long to wait for the reply. Default 200 - generous for a local terminal, short enough to be unnoticeable when nothing answers.
# Convert a 36-cell logo width into the pixel width an image has to be encoded at
$cell = Get-TerminalCellSize
if ($cell) { $pixelWidth = 36 * $cell.Width }

See also: Get-FastfetchLogoArgument, New-SixelImage

  • Description: Lists every process that owns at least one visible, titled application window - the discovery step behind Terminate-AllProcessesWithVisibleWindows and the Kill-All survivor audit. It answers "which processes have a window on screen" from the window side: every visible, titled top-level window is enumerated (EnumWindows, through the Window module's Get-CachedWindows after a cache clear) and grouped by owning process, so a process is a candidate as soon as any of its windows is on screen. Shell windows (the same title list Move-Windows and Center-Windows skip) and the shell processes Get-ShellProcessName lists (the desktop itself and the hosts of other apps' windows) are never returned. Without the Window module it falls back to Get-Process and MainWindowTitle with the same shell filter.
  • Usage: Get-VisibleWindowProcess, Get-VisibleWindowProcess | Where-Object { $_.WindowTitles.Count -gt 1 }

This replaces the classic Get-Process | Where-Object MainWindowTitle test, which skipped windows at random. .NET's MainWindowHandle is the FIRST visible, unowned top-level window of the process in z-order, titled or not: a process whose untitled helper window happened to sit above its real window (Electron and Chromium apps create such windows) reported an empty MainWindowTitle and was passed over, and because z-order follows focus history the same app was seen on one run and missed on the next. Packaged (UWP) apps were missed the same way, since their visible frames belong to ApplicationFrameHost while the app's own process reports no main window. Enumerating the windows sidesteps both. Each returned object carries ProcessName, Id, WindowTitles (every visible titled window of the process), MainWindowTitle (the first of those - what exclusion matching and log lines use) and Source (EnumWindows or MainWindowTitle).

# What a Kill-All run would consider
Get-VisibleWindowProcess | Format-Table ProcessName, Id, MainWindowTitle

# Multi-window processes only
Get-VisibleWindowProcess | Where-Object { $_.WindowTitles.Count -gt 1 }

See also: Terminate-AllProcessesWithVisibleWindows, Report-KillAllSurvivors

  • Description: Resolves the oh-my-posh binary and initializes the prompt theme for the current session - the robust form of the classic profile one-liner oh-my-posh init pwsh --config <theme> | Invoke-Expression. Resolution order: PATH (Get-Command), then the known install locations (winget EXE per-user and machine scope, WinGet portable links, Store alias). When a fallback location hits, its directory is prepended to the session PATH so oh-my-posh also resolves as a plain command afterwards. When the binary is genuinely absent, prints a single install hint instead of erroring on every prompt. The theme file is read from Universal.OhMyPoshThemeFile in Configuration.psd1.
  • Usage: . Initialize-OhMyPosh (dot-invoked)

Called by the PowerShell profile on every shell start. Must be dot-invoked (. Initialize-OhMyPosh): the theme init script defines the prompt in the caller's scope, so a normal call would discard it when the function returns. On a provisioned machine the PATH lookup succeeds immediately - Bootstrap persists the Oh My Posh install locations onto the User PATH via AutoPathAdditions (see Set-EnvironmentVariables) - and the function degenerates to the one-liner. The fallback resolution exists for shells opened before provisioning finished or when an installer's PATH registration did not reach the session.

# Initialize the prompt theme (profile usage - note the leading dot)
. Initialize-OhMyPosh
  • Description: Applies every PSReadLine editing, history and prediction option from the PSReadLine section of Configuration.psd1 to the current session. It replaces the block of hardcoded Set-PSReadLineOption / Set-PSReadLineKeyHandler calls the profile used to carry, so a fork tunes the interactive shell in Configuration.local.psd1 instead of editing the shared profile. Every key is optional: $null (or a missing key) is skipped and PSReadLine keeps what it already had, which for a vanilla install is its own default. That is also how a fork drops a base key binding - set that key to $null under KeyHandlers. The order is fixed and load-bearing: EditMode first, because -EditMode installs a whole key map and resets every binding made before it; then the KeyHandlers; then the history options; then PredictionSource and PredictionViewStyle last, inside their own try/catch, because those two are the only calls that throw on a console without virtual-terminal support and a cosmetic feature must never break shell startup. MaximumHistoryCount drives two limits with one number - PSReadLine's recall cap (arrow keys, Ctrl+R) and the session $MaximumHistoryCount (Get-History), the latter clamped to PowerShell's 32767 ceiling. A value that is not a positive integer is reported with Write-LogWarning and both limits are left alone. HistorySavePath accepts %ENV% variables.
  • Usage: Initialize-PSReadLine [-Settings <hashtable>]
Parameter Description
-Settings The section to apply. Defaults to $global:Configuration.PSReadLine. $null or empty logs at debug level and applies nothing.

Called by the PowerShell profile on every interactive shell start, after Import-Module PSReadLine and before Initialize-OhMyPosh: a theme carrying a transient_prompt binds Enter, and an -EditMode call after that binding would reset it to AcceptLine. A plain call, not dot-invoked - PSReadLine options are process-global, nothing has to land in the caller's scope. PSReadLine never trims its history file; it appends every command and loads the newest MaximumHistoryCount lines at startup, so the cap is what is recallable, not what is stored. HistoryNoDuplicates likewise hides repeated commands during recall only - every invocation is still written.

# Profile usage - applies Configuration.PSReadLine
Initialize-PSReadLine

# Raise both recall limits for this session only
Initialize-PSReadLine -Settings @{ MaximumHistoryCount = 32767 }

# Confirm what took
Get-PSReadLineOption | Select-Object EditMode, MaximumHistoryCount, HistoryNoDuplicates, PredictionSource, PredictionViewStyle
$MaximumHistoryCount
Get-PSReadLineKeyHandler -Bound | Where-Object Key -in UpArrow, DownArrow

See also: Initialize-OhMyPosh, the PSReadLine section of the configuration reference, and the configuration guide.

  • Description: Initializes the configured WSL distribution with shell tooling. Installs the fastfetch system info tool via apt and adds it to .bashrc so it runs on shell startup, then installs unzip and oh-my-posh and wires oh-my-posh into .profile with the configured theme. Each step is idempotent, detecting existing installs and configuration before acting. No-ops until DefaultWSLDistribution is configured.
  • Usage: Initialize-WSLEnvironment

Every wsl call targets the configured DefaultWSLDistribution explicitly (wsl -d <distro>) rather than the WSL default - Docker Desktop and podman machines routinely steal the default distribution, which would otherwise silently provision the wrong distro. First it checks whether fastfetch is present (command -v fastfetch); if missing it adds the fastfetch PPA, runs apt update, and installs the package as root, then appends fastfetch to ~/.bashrc unless already present. It then provisions a temporary setup script in /tmp that installs unzip (if not already installed) and oh-my-posh (via the official install script), appends the oh-my-posh init bash line to ~/.profile referencing the configured theme, reloads the profile, and is removed afterward.

# Install and configure fastfetch and oh-my-posh inside the configured WSL distribution
Initialize-WSLEnvironment
  • Description: Clears the terminal screen with Clear-Host, unless TerminalGreeting.Clear.Enabled is $false. The first step of Show-TerminalGreeting, and thin by design: it exists so that all three greeting steps - clear, fastfetch, onefetch - are switched on and off the same way, from the same configuration section, and mocked the same way in the orchestrator's tests. A Clear-Host written inline in the orchestrator would need its own if, its own configuration lookup and its own mocking seam, and would be the one step that could not be run or skipped on its own.
  • Parameters: [-Settings]
  • Usage: Invoke-Clear, Invoke-Clear -Settings $settings
Parameter Type Default Description
-Settings psobject Resolve-TerminalGreetingSettings The resolved greeting settings. Show-TerminalGreeting resolves once and passes the tree down; omitted, this resolves for itself.
# Clear the screen, unless the greeting's clear step is turned off
Invoke-Clear

# Why did it not clear?
Set-LogLevel Verbose { Invoke-Clear }

See also: Show-TerminalGreeting, Resolve-TerminalGreetingSettings, Invoke-Clear configuration guide

  • Description: Displays the fastfetch system info panel, shrinking the font step by step until the panel fits the window. It does NOT clear the screen - Invoke-Clear is the step that does, so each part of the greeting can be switched off on its own. Inside Windows Terminal it first measures the panel by capturing fastfetch's output (in pipe mode fastfetch emits one line per visual row, so the captured line count is the panel height and the longest line is its width), then sends Ctrl+0 ("reset font size") so the panel is always judged against - and returns to - the default font. While Test-FastfetchPanelOverflow says the panel still overflows it sends Ctrl+Minus ("decrease font size") one step at a time through Send-TerminalFontKey, waiting for the terminal to reflow with Wait-ConsoleReflow after each step, until the panel fits, MaxShrinkSteps steps have been taken, or the terminal stops changing size (its minimum font); then it renders the colored panel. Resetting first keeps the result deterministic (default font when it fits, the fewest steps below it that fit when it does not) and avoids oscillating on repeated calls, and the loop needs no per-machine value: a small laptop display, a high DPI scale, a wide fastfetch configuration and a tall one are all absorbed the same way. -ExtraRows adds rows to the height the panel is judged by, which is how the greeting fits the fastfetch and onefetch panels together. The knobs come from the TerminalGreeting.Fastfetch.AutoFit configuration section through Resolve-TerminalGreetingSettings; an explicit parameter overrides the configured value for that one call. The measuring run invokes the fastfetch BINARY rather than the fastfetch command name, so a profile-defined fastfetch function cannot distort the measurement with a decoration that has no measurable width - an inline-image logo is a single enormous line. The displaying run goes through the command name as usual, so such a wrapper still decorates what you see.
  • Parameters: -NoResize, -ExtraRows, -PromptReserve, -MaxShrinkSteps, -ReflowTimeoutMilliseconds, [-Settings]
  • Usage: Invoke-Fastfetch, Invoke-Fastfetch -NoResize, Invoke-Fastfetch -MaxShrinkSteps 0, Invoke-Fastfetch -ExtraRows 12, Invoke-Fastfetch -PromptReserve 2

Because measuring and displaying are separate steps, fastfetch runs twice when auto-fit is active; use -NoResize, or TerminalGreeting.Fastfetch.AutoFit.Enabled = $false, to keep the single-run behavior. Auto-fit is Windows Terminal specific (the Ctrl+0 / Ctrl+Minus bindings) and is skipped automatically outside Windows Terminal and in non-interactive hosts with no console window (Get-ConsoleWindowSize throws there). Any failure while measuring or sending the keystrokes degrades gracefully to a plain single run, and a machine without fastfetch installed is a silent no-op with one debug line, so a freshly cloned machine starts without an error at the prompt. A profile-defined fastfetch wrapper that swaps the logo for an inline image should size that image to the same cell block the text logo occupies, so the measured panel and the displayed one have identical geometry - the shipped wrapper does, and re-reads the cell size at display time, so the image follows whatever font step the loop lands on.

Every shrink step returns as soon as the terminal has reflowed. The one wait that can run to its timeout is the reset when the font is already at the default, because nothing changes and the function has no way to know the current font size beforehand.

Parameter Type Default Description
-NoResize switch - Skip auto-fit; run fastfetch once.
-ExtraRows int 0 Rows to add to the measured panel height - the height of whatever will be printed below it. Show-TerminalGreeting passes onefetch's row count here.
-PromptReserve int TerminalGreeting.Fastfetch.AutoFit.PromptReserve (ships 1) Rows kept free below the panel for the upcoming prompt when checking vertical overflow (0-20).
-MaxShrinkSteps int TerminalGreeting.Fastfetch.AutoFit.MaxShrinkSteps (ships 10) Upper bound on the Ctrl+Minus steps taken below the default font (0-50). 0 resets to the default and never shrinks.
-ReflowTimeoutMilliseconds int TerminalGreeting.Fastfetch.AutoFit.ReflowTimeoutMilliseconds (ships 10) How long to wait for the window size to change after each keystroke before assuming the terminal will not reflow. Any positive integer.
-Settings psobject Resolve-TerminalGreetingSettings The resolved greeting settings. Omitted, this resolves for itself.
# Show the system info panel, auto-fitting it to the window
Invoke-Fastfetch

# Show the panel without ever resizing the font
Invoke-Fastfetch -NoResize

# Reset to the default font and shrink nothing - does the panel fit at all at the default size?
Invoke-Fastfetch -MaxShrinkSteps 0

# Fit the panel with twelve rows left free below it
Invoke-Fastfetch -ExtraRows 12

# Verbose diagnostic output: panel size, default window, steps taken, final window and fit
Set-LogLevel Verbose { Invoke-Fastfetch }

See also: Show-TerminalGreeting, Invoke-Onefetch, Resolve-TerminalGreetingSettings, Test-FastfetchPanelOverflow, Wait-ConsoleReflow, Send-TerminalFontKey, Get-ConsoleWindowSize, Invoke-Fastfetch configuration guide

  • Description: Displays the onefetch repository info panel when the shell is inside a git repository, and does nothing at all - silently, with one debug line saying why - in any of the four cases where it would be noise: TerminalGreeting.Onefetch.Enabled is $false (the shipped default, because the panel is only meaningful inside a repository and not every machine has the binary), the onefetch binary is not installed, the current directory is not inside a repository (Test-GitRepository walks up looking for a .git entry, without spawning a process), or onefetch itself exits non-zero, which is what an empty repository with no commits looks like. Silence is the point: this runs on every c and every shell start, including in directories that have nothing to do with git, and a greeting is the wrong place to learn that a binary is missing. -Measure captures the output instead of displaying it and returns the number of rows it would occupy - 0 in every case where the display run would print nothing - so Show-TerminalGreeting can add that height to the fit budget it hands Invoke-Fastfetch.
  • Parameters: -Measure, -Arguments, -Path, [-Settings]
  • Usage: Invoke-Onefetch, Invoke-Onefetch -Measure, Invoke-Onefetch -Arguments "--no-art", Invoke-Onefetch -Path "C:\Development\WinuX"

Like fastfetch, onefetch emits one line per visual row when its output is redirected, so the captured line count is the panel height. -Measure returns an [int]; the display form returns nothing.

Parameter Type Default Description
-Measure switch - Return the row count of the panel instead of displaying it. 0 when nothing would be shown.
-Arguments string[] TerminalGreeting.Onefetch.Arguments Arguments passed through to the onefetch binary.
-Path string $PWD.Path The directory to test and run in.
-Settings psobject Resolve-TerminalGreetingSettings The resolved greeting settings. Omitted, this resolves for itself.
# Show the repository panel, if onefetch is enabled, installed, and this is a repository
Invoke-Onefetch

# How many rows would it take? Nothing is printed.
Invoke-Onefetch -Measure

# Without the ASCII language logo, whatever the configuration says
Invoke-Onefetch -Arguments "--no-art"

# Why was nothing shown?
Set-LogLevel Verbose { Invoke-Onefetch }

See also: Show-TerminalGreeting, Invoke-Fastfetch, Format-OnefetchPanel, Test-GitRepository, Invoke-Onefetch configuration guide

  • Description: Starts one child PowerShell in the current console - a plain call, not Start-Process, so the child inherits WT_SESSION, the interactive console and the terminal that answers the cell-size query, and the image logo and sixel path are measured for real - with the given skip list in WINUX_STARTUP_SKIP and a fresh trace file in WINUX_STARTUP_TRACE, times it from launch to exit, reads the trace back through Read-ShellStartupTrace and returns an object with Milliseconds (wall time) and Stages (stage name to milliseconds). -Bare launches with -NoProfile instead: the floor no profile can go under. Both environment variables are restored afterwards and the trace file is deleted. One sample for Measure-ShellStartup.
  • Parameters: [-Skip] [-Bare] [-Executable]
  • Usage: Invoke-ShellStartupSample, Invoke-ShellStartupSample -Skip "Greeting,Terminal-Icons", Invoke-ShellStartupSample -Bare

See also: Measure-ShellStartup, Read-ShellStartupTrace

  • Description: Executes the scriptable exit seam used by Terminate-WindowsTerminalTabs during -IncludeCurrent cleanup. Invokes the configured script-scoped exit action when a test seam is present, otherwise releases stuck keyboard modifiers (via Reset-KeyboardModifiers, when available) and exits the current process cleanly with code 0.
  • Usage: Invoke-TerminateWindowsTerminalTabsExit

This helper centralizes the process-exit step of the -IncludeCurrent shutdown path so it can be overridden in tests. When $script:TerminateWindowsTerminalTabsExitAction is set it runs that action; otherwise it releases stuck keyboard modifiers via Reset-KeyboardModifiers (when available) as its last act and then calls [Environment]::Exit(0) - Exit skips every finally block in the process, so callers' cleanup (notably the keyboard-modifier self-heal in Open-Workspace's finally) never runs, and stuck-modifier state is OS-global and would survive the process. Keeping the exit behind this seam lets the -IncludeCurrent path be exercised without forcing the calling test session to terminate.

See also: Invoke-TerminateWindowsTerminalTabsIncludeCurrentCleanup, Terminate-WindowsTerminalTabs

  • Description: Finalizes the -IncludeCurrent cleanup path for Terminate-WindowsTerminalTabs. Prints the final closed-tab summary, restores the original host window title, optionally waits before closing the current tab so the final status stays visible, spawns a safety-net PowerShell process to force-close the hosting Windows Terminal instance if it lingers, and then invokes the exit seam.
  • Parameters: -ClosedTabs, -StartingTitle, -OriginalHostTitle, -CloseWaitSeconds
  • Usage: Invoke-TerminateWindowsTerminalTabsIncludeCurrentCleanup -ClosedTabs @("TabA") -StartingTitle "CurrentTab" -OriginalHostTitle "OriginalTitle", Invoke-TerminateWindowsTerminalTabsIncludeCurrentCleanup -ClosedTabs @("TabA") -StartingTitle "CurrentTab" -OriginalHostTitle "OriginalTitle" -CloseWaitSeconds 5

Internal helper invoked by Terminate-WindowsTerminalTabs when -IncludeCurrent is used. It reports the total count of closed tabs (the already-closed -ClosedTabs plus the current tab's -StartingTitle), restores -OriginalHostTitle on the PowerShell host, and starts a hidden background PowerShell process as a safety net that force-closes the hosting WindowsTerminal process should it fail to exit on its own. Control then passes to the deterministic process-exit seam.

Parameter Type Default Description
-ClosedTabs string[] - Titles of tabs already closed before the current tab cleanup step.
-StartingTitle string - Original title of the current terminal tab.
-OriginalHostTitle string - Original host title to restore before exiting.
-CloseWaitSeconds int 0 Waits this many seconds (0-300) before closing the current tab so the summary stays readable.
# Finalize cleanup and exit the current terminal tab
Invoke-TerminateWindowsTerminalTabsIncludeCurrentCleanup -ClosedTabs @("TabA") -StartingTitle "CurrentTab" -OriginalHostTitle "OriginalTitle"

# Same, but hold the final status on screen for 5 seconds before the tab closes
Invoke-TerminateWindowsTerminalTabsIncludeCurrentCleanup -ClosedTabs @("TabA") -StartingTitle "CurrentTab" -OriginalHostTitle "OriginalTitle" -CloseWaitSeconds 5
  • Description: Orchestrates a full desktop cleanup as a sequence of configurable steps. Removes all virtual desktops except the first (VirtualDesktops), stops Docker Desktop cleanly via DockerWizard -Stop before generic process termination (Docker), gracefully closes all configured browser processes via WM_CLOSE (Browsers), terminates remaining processes with visible windows except browsers and the Universal.VisibleWindowExclusions list (VisibleWindows) and the configured Universal.TerminateProcessNames processes (NamedProcesses), then waits a short RPC/DCOM quiescence window (500 ms) before closing extra Windows Terminal tabs (TerminalTabs) so subsequent commands (e.g. Open-Workspace) do not hit 0x800706BA from DCOM churn. Unless -IncludeCurrent is given, the surviving Windows Terminal is then centered on the primary monitor via Center-Windows -OnPrimary (CenterTerminal) and refocused via Focus-TerminalTab (FocusTerminal), so the run always ends on the terminal. Can optionally reload the PowerShell profile (ReloadProfile, off by default). Every step can be toggled persistently via KillAll.Steps in Configuration.psd1 / Configuration.local.psd1 (plain booleans or per-machine-type hashtables with a Default fallback) and per invocation via -Skip / -Include.
  • Parameters: -Exclude (wildcard/regex patterns), -Skip (step names), -Include (step names), -IncludeCurrent, -ReloadPowerShellProfile
  • Usage: Kill-All, Kill-All -Exclude "*YouTube*", Kill-All -Skip Docker, Kill-All -Skip Docker, Browsers, Kill-All -Include ReloadProfile, Kill-All -IncludeCurrent, Kill-All -ReloadPowerShellProfile

Coordinates desktop cleanup as a sequence of terminators. If virtual desktop cleanup cannot recover from a VirtualDesktop/RPC failure, Remove-VirtualDesktops owns the failure reporting while Kill-All suppresses its nested $false return value so process cleanup continues. PowerToys (PowerToys, PowerToys.FancyZones, PowerToys.Settings) is excluded from the visible-window terminator by the default Universal.VisibleWindowExclusions configuration, since partially killing it leaves the FancyZones supervisor in a "running but FancyZones absent" half-state that breaks the next workspace layout application.

Step resolution is tri-state: -Skip beats -Include beats the KillAll.Steps config (see Configuration Reference: Kill-All Step Toggles) beats the built-in defaults (everything on except ReloadProfile). With no KillAll section configured, behavior is identical to the classic full run. -IncludeCurrent suppresses CenterTerminal and FocusTerminal regardless of config, since there is no surviving tab to restore.

The run ends with a survivor audit. When Browsers, VisibleWindows and NamedProcesses all ran, Report-KillAllSurvivors re-enumerates the visible, titled application windows and lists every one that is neither a configured exclusion nor an -Exclude match, and the closing line then says how many windows are still open instead of reporting success. The two window-taking steps verify their own work first - Terminate-AllBrowserProcesses waits for the windows it closed to disappear and posts WM_CLOSE again to any that did not, Terminate-AllProcessesWithVisibleWindows waits for the processes it killed to exit - so a window named by the audit is one that genuinely refused to go, typically a dialog waiting for an answer.

The open-workspace tracker is cleared too, but only when Browsers, VisibleWindows and NamedProcesses all ran. A full run leaves nothing a workspace opened, so a populated tracker would have Close-Workspace go on offering workspaces that are long gone and then report every one of their windows as already closed. Skip any of those three steps and the tracker is kept: staleness is merely noisy (an item it cannot find is reported as already closed), whereas clearing too eagerly is a real capability loss, because the windows that did survive a partial run become unclosable. The clear happens before the tab termination, since -IncludeCurrent ends the process outright, and is guarded with Get-Command because Workflow is a separate module that need not be loaded.

| Parameter | Description | | -------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------ | | -Exclude | One or more window title patterns to spare from termination. Supports both wildcard ("*YouTube*", "Chrome - *") and regex ("^Chrome", "(._Gmail._ | ._Inbox._)") patterns, same format as layout .psd1 files. | | -Skip | Step names to skip for this invocation, overriding config. Valid: VirtualDesktops, Docker, Browsers, VisibleWindows, NamedProcesses, TerminalTabs, CenterTerminal, FocusTerminal, ReloadProfile. Wins over -Include. | | -Include | Step names to run for this invocation even if config disables them. Same valid names as -Skip. | | -IncludeCurrent | Also closes the current Windows Terminal tab. | | -ReloadPowerShellProfile | Reloads the PowerShell profile after terminating processes. Equivalent to -Include ReloadProfile. |

# Full cleanup: closes most GUI apps and extra terminal tabs
Kill-All

# Keep windows whose titles match the given patterns (wildcard and regex)
Kill-All -Exclude "*YouTube*", "*Obsidian*", "(.*Notion.*|.*Inbox.*)"

# Leave Docker running for this cleanup only
Kill-All -Skip Docker

# Run a step this once even though config disables it
Kill-All -Include Docker

# Clean up and reload the shell afterward
Kill-All -ReloadPowerShellProfile

See also: Resolve-KillAllSteps, Remove-VirtualDesktops, Terminate-AllProcessesWithVisibleWindows, Close-Workspace, Save-WorkspaceState

  • Description: Lists all FileSystem PSDrives (mounted drives). A thin alias for Get-PSDrive -PSProvider FileSystem, showing all mounted drives including local disks, network drives, and removable media along with their Name, Used (GB), Free (GB), Provider, and Root.
  • Usage: List-Drives
  • Description: Measures how long a shell takes to reach its first prompt, stage by stage. The profile guards every startup stage with Test-StartupStage / Complete-StartupStage, so a child shell can be told which stages to leave out (WINUX_STARTUP_SKIP) and reports what each stage cost inside the shell (WINUX_STARTUP_TRACE). -Mode Cumulative (default) starts from a bare pwsh -NoProfile, then Core alone, then adds one stage at a time in profile order - the Delta column is the wall time the added stage costs, InShell what the stage measured for itself. -Mode Isolated starts from the full start and drops one stage at a time, so Delta is what skipping that stage alone would save. Every configuration runs -Runs times (default 5) and is reported as min / median / max; deltas are computed from medians so one slow run never decides a stage's cost. The children share the console, so run it from the terminal whose start you want to measure and expect the screen to be redrawn once per child; the table is printed at the end. Warns outside Windows Terminal, where the image logo and the cell-size query are not part of what is measured. Stages: Schema, Greeting, FastfetchImageLogo, OnefetchStyle, PSReadLine, Terminal-Icons, PSReadLineOptions, OhMyPosh, Aliases, PowerPlan, LogMaintenance, RepositoryUpdate; Core is always present.
  • Parameters: [-Runs] [-Mode] [-Stages] [-PassThru]
  • Usage: Measure-ShellStartup, Measure-ShellStartup -Mode Isolated -Runs 3, Measure-ShellStartup -Stages Greeting, FastfetchImageLogo -PassThru
Column Meaning
Configuration bare (-NoProfile), Core, then + Stage (Cumulative) or full, then - Stage (Isolated)
Min / Median / Max wall time of the child shell, launch to exit, in ms
Delta Cumulative: median minus the previous row. Isolated: median minus the full start (negative is a saving)
InShell the stage's own median as the profile measured it - the difference to Delta is the harness overhead and whatever the stage pulled in for later stages
# The whole ladder, five runs per configuration, from a Windows Terminal tab on the Desktop
Measure-ShellStartup

# What would skipping each stage save on its own?
Measure-ShellStartup -Mode Isolated

# Only the greeting and the image logo, as objects
Measure-ShellStartup -Stages Greeting, FastfetchImageLogo -PassThru | Format-Table

See also: Invoke-ShellStartupSample, Read-ShellStartupTrace, Test-StartupStage, Slow profile load

  • Description: Encodes an image as a cached DEC sixel file - the one inline-image protocol Windows Terminal renders - scaled to fit a pixel box with its aspect ratio preserved, never stretched and never cropped, so a caller can reserve a fixed block of character cells and know the image cannot spill out of it. Transparency survives: the encoder writes the sixel background-select parameter, so a logo with an alpha channel does not arrive on a black rectangle. Caching is keyed on the box AND on the source file's length and last-write time, so editing or replacing the source invalidates the cache with no bookkeeping; ImageMagick is looked for only on a miss, so a warm cache keeps working on a machine that does not have it. Returns $null - never throws - when ImageMagick is absent, the source is missing, or the conversion produces nothing.
  • Parameters: -Path -MaxPixelWidth -MaxPixelHeight [-CachePath] [-Force]
  • Usage: New-SixelImage -Path $logo -MaxPixelWidth 360 -MaxPixelHeight 320, New-SixelImage -Path $logo -MaxPixelWidth 360 -MaxPixelHeight 320 -Force

A cache hit costs two file stats; a miss costs one ImageMagick invocation, around 120ms for a small logo. That matters because the caller runs on every shell start and on every c, and because the box changes with the terminal's font size - each size gets its own cache entry rather than re-encoding whenever the font changes back. Requires ImageMagick on PATH for the first encode of each size (winget install ImageMagick.ImageMagick).

Parameter Description
-Path The source image. Anything ImageMagick can decode (PNG, JPEG, SVG, ICO, WEBP).
-MaxPixelWidth Width of the box to fit the image into, in pixels.
-MaxPixelHeight Height of the box to fit the image into, in pixels.
-CachePath Directory holding the generated sixel files, created if missing. Defaults to $env:LOCALAPPDATA\WinuX\SixelCache.
-Force Re-encode even when a valid cache entry exists.
# A 36x16 cell block on a terminal reporting 10x20 pixel cells
New-SixelImage -Path $logo -MaxPixelWidth (36 * 10) -MaxPixelHeight (16 * 20)

See also: Get-FastfetchLogoArgument, Get-TerminalCellSize

  • Description: Creates a single native Windows symbolic link at Path pointing to Target, backing up whatever it replaces. The parent directory is created via Initialize-Directory if missing. A real file or directory already sitting at the path is copied via Backup-RepositoryItem into <Repo>\Backups\Windows\SymbolicLinks\<DisplayName>\<yyyy-MM-dd_HH-mm-ss>\ before it is removed - gitignored, never committed - so linking over a hand-written PowerShell profile or an existing PowerToys settings file never loses it; when the backup cannot be written the link is skipped and the existing item is left untouched. An existing symlink at the path is removed without a backup: it carries no content of its own, so archiving it would only pile up copies of WinuX's own links on every re-run. A missing target is skipped with a warning instead of linked - that would delete the real file at Path and leave a dangling link; the call self-heals on the next run once the target exists. The creation branch of SymbolicLinkMaker. Requires administrator privileges (or Developer Mode).
  • Parameters: -Path, -Target, -DisplayName, -BackupRoot
  • Usage: New-WindowsSymbolicLink -Path "$env:USERPROFILE\.gitconfig" -Target "C:\Repo\Git\.gitconfig"

-DisplayName is the label used in log messages and the backup subfolder name (SymbolicLinkMaker passes the entry's dotted key, e.g. PowerToys.Settings); it defaults to Path, with the characters a path carries but a folder name cannot hold replaced by _. -BackupRoot overrides the sink root replaced items are copied into (under SymbolicLinks\<DisplayName>\<timestamp>) and defaults to <Repo>\Backups\Windows: one subfolder per entry, one timestamped folder per replacement, so every version ever replaced stays side by side with the newest last. A real directory is removed with -Recurse; a directory symlink deliberately is not, because -Recurse there follows the link and deletes the target's contents. Creation failures are logged, never thrown.

See also: SymbolicLinkMaker, New-WSLSymbolicLink, Get-SymbolicLinkEntries

  • Description: Creates a single symlink inside a WSL distribution (ln -s) at Path pointing to Target, backing up whatever it replaces. The parent directory is created with mkdir -p if missing. A real file already sitting at the path is copied out to <Repo>\Backups\Windows\SymbolicLinks\<DisplayName>\<yyyy-MM-dd_HH-mm-ss>\ on the Windows side (the timestamped folder created by Backup-RepositoryItem, the copy done in-distro with cp -a) before it is removed - gitignored, never committed - so linking over a shell profile or an SSH config that only ever existed inside the distro never loses it; when the backup cannot be written the link is skipped and the existing item is left untouched. An existing symlink at the path is removed without a backup: it carries no content of its own, so archiving it would only pile up copies of WinuX's own links on every re-run. A missing target is skipped with a warning instead of linked (self-heals once the target exists). Every wsl.exe call targets the given distribution explicitly (wsl -d) - Docker Desktop and podman machines routinely steal the WSL default, and a bare wsl would create the link inside the wrong distro. The WSL creation branch of SymbolicLinkMaker.
  • Parameters: -Path, -Target, -Distribution, -DisplayName, -BackupRoot
  • Usage: New-WSLSymbolicLink -Path "/home/user/.ssh/config" -Target "/mnt/c/Users/User/.ssh/config" -Distribution "Ubuntu"

-DisplayName is the label used in log messages and the backup subfolder name (SymbolicLinkMaker passes the entry's dotted key); it defaults to Path, with the characters a path carries but a folder name cannot hold replaced by _. -BackupRoot overrides the sink root replaced items are copied into and defaults to <Repo>\Backups\Windows; it is a Windows path, translated into the distribution with wslpath -a so the in-distro cp -a can write to it. A backup that cannot be translated or copied skips the entry rather than removing a file it could not save. Creation failures are logged, never thrown.

See also: SymbolicLinkMaker, New-WindowsSymbolicLink, Get-SymbolicLinkEntries

  • Description: Reads the file a shell start wrote through WINUX_STARTUP_TRACE - one tab-separated line per stage, name and milliseconds, appended by Complete-StartupStage - into a hashtable of stage name to milliseconds ([double]). A missing or empty file is an empty table, a line that does not parse is dropped, and a stage that appears twice keeps its last value (a profile re-run in the same shell appends a second set of lines). Parses with an invariant decimal point.
  • Parameters: -Path
  • Usage: Read-ShellStartupTrace -Path "$env:TEMP\startup.trace"

See also: Invoke-ShellStartupSample, Complete-StartupStage

  • Description: Clears the Windows icon cache and restarts Explorer to fix missing or corrupted desktop/taskbar icons. Stops Explorer, deletes the icon cache database (IconCache.db) plus any iconcache* files from the paths configured in Configuration.Universal.IconCacheDb and Configuration.Universal.IconCacheFolder, then restarts Explorer. Requires administrator privileges.
  • Usage: Rebuild-IconCache
# Clear the icon cache and restart Explorer (run as administrator)
Rebuild-IconCache

See also: Configuration: Machine Types

  • Description: Reloads all WinuX modules and the PowerShell profile. First calls Reload-WinuXModules to re-import every WinuX module, then dot-sources the profile files to pick up profile-level changes without restarting the terminal.
  • Usage: Reload-PowerShellProfile

After re-importing the WinuX modules, the function dot-sources each of the AllUsersAllHosts, AllUsersCurrentHost, CurrentUserAllHosts, and CurrentUserCurrentHost profile scripts that exist, so any profile-level edits take effect in the current session.

Under verbose logging (Set-LogLevel Verbose) the [Reloading PowerShell Profile] header and the success message are suppressed. Add -Verbose to also log each profile file as it is sourced.

# Reload all modules and profile scripts
Reload-PowerShellProfile

# Suppress the header/success banner and log each profile file as it is sourced
Reload-PowerShellProfile -Verbose
  • Description: Removes and re-imports all WinuX PowerShell modules to pick up code changes. Scans the Modules/ directory (and the Modules/Custom fork area, when populated) for folders containing both a .psd1 manifest and a .psm1 loader, removes any currently loaded version, and force-reimports each module globally. Folders missing either file are skipped with a verbose message.
  • Usage: Reload-WinuXModules

Iterates every folder under Modules/ (plus Modules/Custom/ for whole fork-owned modules), and for each one expecting a matching <ModuleName>.psd1 and <ModuleName>.psm1 pair runs Import-Module -Force -Global so edited functions are reloaded into the current session without restarting PowerShell. Custom mirror payload folders carry no manifest and are skipped here - their function files reload with the Custom module itself. Modules that fail to import are reported in red but do not stop the loop.

# Re-import every WinuX module after editing function source
Reload-WinuXModules

See also: Reload-PowerShellProfile, Fork Model: the Custom area

  • Description: Removes virtual desktops - by default all except desktop 0, resetting to a single-desktop state. With -EmptyOnly, removes only desktops that have no visible windows, which keeps workspace setups (e.g. alongside mode) idempotent on retry. With -Index, removes exactly the named desktops whether or not anything is still on them. At least one desktop is always preserved. All three modes return nothing on success and $false on failure.
  • Parameters: -EmptyOnly, -Index
  • Usage: Remove-VirtualDesktops, Remove-VirtualDesktops -EmptyOnly, Remove-VirtualDesktops -Index 3, 4, 5

In default mode it removes every desktop except desktop 0. In -EmptyOnly mode it builds the set of desktops that have at least one visible window and removes only the empty ones, iterating right-to-left so remaining indices stay stable; if desktop 0 is empty but others have windows, desktop 0 is removed last and Windows shifts the rest left. Window detection prefers Get-WindowHandle (EnumWindows-based, from the Window module) so it captures every visible window - including multiple browser or VSCode windows - and falls back to Get-Process MainWindowHandle when that module isn't loaded, though the fallback sees only one window per process and may treat desktops with secondary windows as empty.

Every desktop-manager call runs through the Window module's seam, Invoke-VirtualDesktopOperation (5 attempts / 250 ms initial delay): the first count carries -Probe, so the live RPC endpoint is verified and repaired once, up front, rather than only checking that Windows RPC services are running; an RPC failure during the cleanup (a stale COM session after heavy desktop churn or an Explorer restart, classified via Test-RpcUnavailableError, which also catches wrapped and localized errors) reconnects the session's COM proxies with Reset-VirtualDesktopState and retries with backoff inside the seam, so stale sessions recover without a fresh shell; any other error comes straight back. The function itself carries no retry or recovery block and calls Reset-VirtualDesktopState nowhere. Desktop counts come from Get-DesktopCount, not Get-DesktopList: only the count is ever used, and the list pays a registry name lookup plus a wallpaper query per desktop over COM for data this function discards.

In -EmptyOnly mode the occupancy scan is retried as a whole rather than per window. A lookup that fails on its own merits - a window closed mid-scan, or a shell window such as Windows Input Experience that always answers TYPE_E_ELEMENTNOTFOUND - can never succeed on a retry, so it is skipped immediately; putting each one through the backoff ladder cost roughly 3.7 s per unplaceable window on every run, which is why one such window dominated the whole operation. Only a genuine RPC failure restarts the scan - the whole scan is one operation handed to the seam, which resets the session's COM state between attempts - and if RPC is still unavailable once the seam's attempts are exhausted the cleanup aborts and returns $false rather than treating unknowable occupancy as "empty". The scan also resolves each distinct desktop's index once instead of once per window (Get-DesktopIndex re-enumerates every desktop over COM on each call) and stops as soon as every desktop is known to hold a window.

-Index is the third mode, and the one Close-Workspace uses: it removes exactly the 0-based indexes named, highest first so the remaining targets do not shift. It takes precedence over -EmptyOnly, skips an index that no longer exists, and still refuses to remove the last desktop. Supplying -Index with nothing usable in it (an empty array, or only negative values) removes nothing - the mode is chosen by whether -Index was passed, not by whether it resolved to anything, so asking for nothing can never fall through to the default mode and mean "remove every desktop". Unlike -EmptyOnly it does not care whether the desktop is occupied - Windows relocates whatever is still there to an adjacent desktop rather than closing it. That is deliberate: the one window a workspace teardown cannot close before removing its desktops is the shell it is running in, and when the workspace opened that shell its desktop is never empty at sweep time, so an -EmptyOnly pass would leave it stranded on a desktop nothing ever tidies.

Parameter Type Default Description
-EmptyOnly switch - Removes only desktops that have no visible windows, iterating from the rightmost toward desktop 0; at least one desktop is always kept.
-Index int[] - 0-based desktop indexes to remove outright, occupied or not, highest first. Wins over -EmptyOnly.
# Reset to a single desktop (removes all except desktop 0)
Remove-VirtualDesktops

# Remove only empty desktops, keeping any with visible windows
Remove-VirtualDesktops -EmptyOnly

# Remove a workspace's own desktops, occupied or not
Remove-VirtualDesktops -Index 3, 4, 5

# Verbose diagnostic output
Set-LogLevel Verbose { Remove-VirtualDesktops -EmptyOnly }
  • Description: Sets the machine hostname from Configuration.psd1 or interactively prompts for a new name. If the current hostname matches a configured name it skips the operation (idempotent); with -Override it allows re-entering a new hostname even when already configured. Enforces Windows naming rules. Requires administrator privileges.
  • Parameters: -Override
  • Usage: Rename-Machine, Rename-Machine -Override

Reads the configured hostnames from HostnameToMachineType in Configuration.psd1 and compares them against the current COMPUTERNAME. When run without -Override and the name already matches, it reports the configured hostname and returns. Otherwise it prompts for a new name and validates it against Windows rules (max 63 characters, not all-numeric, only letters, digits, and hyphens) before calling Rename-Computer. A restart is required for the change to take effect.

Parameter Description
-Override Force reconfiguration of the hostname even if it is already set, prompting to keep or enter a new name.
# Set the hostname if not already configured; report it if it is
Rename-Machine

# Re-enter a new hostname even when already configured
Rename-Machine -Override

See also: Configuration: Machine Types

  • Description: Attempts to recover a broken RPC/COM session when Test-RpcServerHealth -Probe reports it unhealthy - stale VirtualDesktop proxies after an Explorer restart, or a genuinely hung endpoint (0x800706BA / 0x800706BE). Runs a bounded retry loop (default 5 attempts, exponential backoff starting at 500 ms and capped at 8 s); each attempt first reconnects the session's VirtualDesktop COM state via Reset-VirtualDesktopState (the recovery that actually repairs the common failure mode, no admin required), then does best-effort Restart-Service RpcSs/DcomLaunch/RpcEptMapper -Force when elevated, and from the second attempt on force-stops PowerToys* as escalation, before re-probing. Returns $true as soon as the probe reports healthy, $false once attempts are exhausted - callers continue their normal flow afterwards (no reboot message).
  • Parameters: -ProbeTimeoutMs (default 2500), -MaxAttempts (default 5), -InitialBackoffMs (default 500)
  • Usage: Repair-RpcServer, Repair-RpcServer -MaxAttempts 10

Used as a pre-flight by workspace layout commands (e.g. Set-WorkspaceWindowLayout and the rerun helper) when an RPC probe fails before expensive work. The service restart is genuinely best-effort: RpcSs is normally marked non-stoppable on a live Windows session, so the call typically no-ops (and requires admin), and a true RPC restart almost always demands a reboot. The recovery that actually works without admin is the session-side reconnect: Reset-VirtualDesktopState rebuilds the compiled DesktopManager type's cached COM proxies via reflection (Reset-VirtualDesktopComProxy) and reloads the module, which repairs the post-Explorer-restart state in place. PowerToys is only terminated from the second attempt on, so a session whose own proxies were stale recovers without collateral damage; when the Window module is unavailable, the legacy fallback (unloading the cached VirtualDesktop module) is used instead.

Per-attempt sequence:

  1. Reconnects the session's VirtualDesktop COM state via Reset-VirtualDesktopState (falls back to unloading the cached VirtualDesktop module when the helper is unavailable).
  2. When elevated, attempts Restart-Service RpcSs/DcomLaunch/RpcEptMapper -Force (best-effort, caught per-service to keep the loop alive).
  3. From attempt 2 on, force-stops all PowerToys* processes so stale COM client state is dropped (escalation only).
  4. Waits the current backoff window for DCOM to settle.
  5. Re-runs Test-RpcServerHealth -Probe and exits the loop on success.
Parameter Type Default Description
-ProbeTimeoutMs int 2500 Hard timeout for each post-recovery RPC probe (ms).
-MaxAttempts int 5 Maximum recovery attempts before giving up.
-InitialBackoffMs int 500 Initial inter-attempt delay; doubles each attempt, 8 s cap.
# Pre-flight guard: only repair when the probe says the endpoint is hung
if (-not (Test-RpcServerHealth -Probe)) {
    [void](Repair-RpcServer)
}

# More aggressive retry budget
Repair-RpcServer -MaxAttempts 10

# Verbose diagnostic output
Set-LogLevel Verbose { Repair-RpcServer }

Even when Repair-RpcServer returns $false, callers continue their normal flow (the workspace rerun still spawns) rather than aborting; there is no reboot prompt. Running from an elevated shell gives the service-restart step better odds.

  • Description: The closing audit of Kill-All. Once the Browsers, VisibleWindows and NamedProcesses steps have all run, nothing that is not deliberately excluded should still own a window. This re-enumerates the visible, titled application windows (Get-VisibleWindowProcess), drops the ones the run was told to leave alone - processes named in Universal.VisibleWindowExclusions and windows matching an -Exclude pattern (by title or process name through Test-WindowTitleMatch) - and reports whatever remains as a warning with one line per window (title (process, PID n)). Returns the survivors so Kill-All can end on a warning instead of its success line; prints nothing when the desktop is clean.
  • Parameters: -Exclude
  • Usage: Report-KillAllSurvivors, Report-KillAllSurvivors -Exclude "*YouTube*"

Browser windows are not exempt: Terminate-AllBrowserProcesses closes them gracefully and waits for them to go, so a browser window still standing here is a genuine survivor - typically a dialog waiting for an answer ("close all tabs?", unsaved form data, a download in progress) - and the user should see it named rather than read a success line.

# Ends on a warning listing every window still open, or prints nothing
$survivors = @(Report-KillAllSurvivors -Exclude "*YouTube*")

See also: Kill-All, Get-VisibleWindowProcess

  • Description: Resolves which Kill-All cleanup steps should run, in a single pass. A thin wrapper over the Helper module's generic Resolve-Steps. Returns an ordered hashtable of step name → boolean, in Kill-All execution order. Per step, tri-state resolution: -Skip beats -Include beats config (KillAll.Steps.<Name> in $global:Configuration - a plain boolean, or a per-machine-type hashtable with a Default fallback, the BootstrapConfig.Steps.WSL shape) beats the built-in defaults (everything on except ReloadProfile). $false is a real config value, so booleans resolve with explicit $null checks rather than truthiness. Kill-All calls this exactly once per invocation; the only side effect is a warning per step that appears in both -Skip and -Include (the step is skipped), so it is also safe to call ad hoc to inspect what a Kill-All invocation would do with the current config.
  • Parameters: -Skip (step names forced off), -Include (step names forced on)
  • Usage: Resolve-KillAllSteps, Resolve-KillAllSteps -Skip Docker, Browsers
Parameter Type Default Description
-Skip string[] - Step names forced off for this invocation; wins over -Include.
-Include string[] - Step names forced on for this invocation, overriding config.
# What would a parameterless Kill-All do with the current config?
Resolve-KillAllSteps

# Parameter override beats a config-disabled step
Resolve-KillAllSteps -Include Docker

See also: Kill-All, Configuration Reference: Kill-All Step Toggles

  • Description: Resolves which Set-SystemTheme follow-up steps should run - the actions taken after the theme registry values are written. A thin wrapper over the Helper module's generic Resolve-Steps. Returns an ordered hashtable of step name → boolean, in Set-SystemTheme execution order (RefreshBrowserTabs, RestartExplorer, SetWallpaper, SetLockScreenWallpaper). Per step, tri-state resolution: -Skip beats -Include beats config (SystemTheme.Steps.<Name> in $global:Configuration - a plain boolean, or a per-machine-type hashtable with a Default fallback, the BootstrapConfig.Steps.WSL shape) beats the built-in defaults (everything on except RefreshBrowserTabs). $false is a real config value, so booleans resolve with explicit $null checks rather than truthiness. Set-SystemTheme calls this exactly once per invocation; the only side effect is a warning per step that appears in both -Skip and -Include (the step is skipped), so it is also safe to call ad hoc to inspect what a Set-SystemTheme invocation would do with the current config.
  • Parameters: -Skip (step names forced off), -Include (step names forced on)
  • Usage: Resolve-SystemThemeSteps, Resolve-SystemThemeSteps -Skip SetWallpaper, SetLockScreenWallpaper, Resolve-SystemThemeSteps -Include RefreshBrowserTabs
Parameter Type Default Description
-Skip string[] - Step names forced off for this invocation; wins over -Include.
-Include string[] - Step names forced on for this invocation, overriding config.
# What would a parameterless Set-SystemTheme do with the current config?
Resolve-SystemThemeSteps

# Parameter override beats the off-by-default step
Resolve-SystemThemeSteps -Include RefreshBrowserTabs

See also: Set-SystemTheme, Configuration Reference: Set-SystemTheme Step Toggles

  • Description: Resolves the settings Show-TerminalGreeting and its three steps run with, merging three layers per key: an explicit parameter beats the TerminalGreeting configuration section, which beats the built-in default. The tree it returns is the whole greeting, not one step of it, so every caller reads the same object and the section is parsed exactly once per greeting. A value that is not an integer in range - from either layer - is reported through Write-LogWarning and the default is used for that key, so a typo in Configuration.local.psd1 degrades the greeting to its defaults rather than throwing at the prompt; $null or a missing key means "use the default" silently, and a missing TerminalGreeting section behaves exactly like the shipped values. Booleans are read with PowerShell's own truthiness rather than a parser, because a psd1 can only write $true / $false / a number / a string there and every one of those has an obvious reading; Arguments accepts a single string or an array and is normalized to [string[]] with blank entries dropped.
  • Parameters: [-Settings], [-MaxShrinkSteps], [-ReflowTimeoutMilliseconds], [-PromptReserve]
  • Usage: Resolve-TerminalGreetingSettings, Resolve-TerminalGreetingSettings -MaxShrinkSteps 0, (Resolve-TerminalGreetingSettings).Onefetch

Show-TerminalGreeting calls it exactly once per invocation, passing only the parameters that were actually bound so an unpassed one leaves the configured value alone, and hands the result to each step - so a bad value is reported once rather than three times. It has no side effect beyond the warnings, so it is also safe to call ad hoc to see what c would run with under the current configuration.

The resolved tree, with the shipped defaults:

Key Type Default Range
Clear.Enabled bool $true -
Fastfetch.Enabled bool $true -
Fastfetch.AutoFit.Enabled bool $true -
Fastfetch.AutoFit.MaxShrinkSteps int 10 0-50
Fastfetch.AutoFit.ReflowTimeoutMilliseconds int 10 any positive integer
Fastfetch.AutoFit.PromptReserve int 1 0-20
Onefetch.Enabled bool $false -
Onefetch.IncludeInAutoFit bool $true -
Onefetch.InProjectTerminals bool $true -
Onefetch.Arguments string[] @() -
Parameter Type Default Description
-Settings hashtable $global:Configuration.TerminalGreeting The configuration section. $null or empty falls through to the defaults.
-MaxShrinkSteps int - Explicit override, 0-50.
-ReflowTimeoutMilliseconds int - Explicit override, any positive integer.
-PromptReserve int - Explicit override, 0-20.
# What would `c` use right now?
Resolve-TerminalGreetingSettings

# Is the repository panel on, does it count towards the fit, and what arguments does it get?
(Resolve-TerminalGreetingSettings).Onefetch

# Warns that MaxShrinkSteps is out of range and returns the default 10 for it
Resolve-TerminalGreetingSettings -Settings @{ Fastfetch = @{ AutoFit = @{ MaxShrinkSteps = 99 } } }

See also: Show-TerminalGreeting, Invoke-Fastfetch, Invoke-Onefetch, Resolve-TerminalGreetingSettings configuration guide

  • Description: Restarts Windows Explorer by stopping the explorer.exe process and waiting for it to auto-restart. An optional message is shown with an animated loading spinner during the wait. Useful after theme, icon, or taskbar changes. When the session has VirtualDesktop COM types loaded, it proactively reconnects them afterwards via Reset-VirtualDesktopState - an Explorer restart severs those cached proxies, and without the reconnect every later VirtualDesktop call in the session would fail with "The RPC server is unavailable" (0x800706BA).
  • Parameters: -Message, -Delay
  • Usage: Restart-Explorer, Restart-Explorer -Message "Waiting for changes to apply...", Restart-Explorer -Message "Processing..." -Delay 3

Stops the Explorer process and waits via Loading-Spinner before continuing (Explorer auto-restarts). When -Message is provided, the spinner displays that label; otherwise it spins without a label. The wait length is controlled by -Delay (defaults to 1 second). The post-restart VirtualDesktop reconnect retries up to 5 times with growing delays, riding out the window where the fresh Explorer instance has not finished re-registering its COM classes; sessions that never used VirtualDesktop skip it entirely.

Parameter Description
-Message Label to display in the loading spinner during the delay. Omit for no label.
-Delay Seconds to wait after stopping Explorer before continuing. Defaults to 1.
# Restart Explorer with the default 1-second delay
Restart-Explorer

# Restart Explorer and show a spinner with a message for 3 seconds
Restart-Explorer -Message "Waiting for changes to apply..." -Delay 3
  • Description: Prompts for confirmation and restarts the machine. Shows a Yes/No prompt via Resolve-Selection; if confirmed, displays a 5-second countdown then calls Restart-Computer.
  • Parameters: -Selection
  • Usage: Restart-Machine, Restart-Machine -Selection "Yes"
Parameter Description
-Selection Pre-selected answer ("Yes" or "No") to skip the interactive prompt. Pressing Enter at the prompt defaults to "No".
# Show the Yes/No confirmation prompt
Restart-Machine

# Restart immediately without prompting
Restart-Machine -Selection "Yes"
  • Description: Sends one of Windows Terminal's font-size keystrokes to the active window through SendKeys: Reset is Ctrl+0 ("reset font size"), Decrease is Ctrl+Minus ("decrease font size"), both Windows Terminal default bindings. Windows Terminal exposes no API for the font size of a running session, so the bindings are the only way to change it from inside the shell, which is what Invoke-Fastfetch's auto-fit is built on. The function does not (and cannot) check that the bindings still exist; the caller detects a keystroke that changed nothing by reading the window size before and after with Wait-ConsoleReflow. Honours -WhatIf: the mapping is logged and nothing is sent.
  • Parameters: -Action
  • Usage: Send-TerminalFontKey -Action Reset, Send-TerminalFontKey -Action Decrease, Send-TerminalFontKey -Action Decrease -WhatIf

The keystroke lands in whatever window has focus, which for a shell running this function is its own tab. Its own tests run entirely under -WhatIf, and Invoke-Fastfetch's suite mocks it outright, so running the test suite interactively never changes the font of the terminal it runs in.

Parameter Type Default Description
-Action string - Reset (Ctrl+0) or Decrease (Ctrl+Minus).
# Return the font to the profile default
Send-TerminalFontKey -Action Reset

# Shrink one step and wait for the terminal to reflow
$before = Get-ConsoleWindowSize
Send-TerminalFontKey -Action Decrease
$after = Wait-ConsoleReflow -Before $before -TimeoutMilliseconds 10

See also: Wait-ConsoleReflow, Invoke-Fastfetch

  • Description: Sends Wake-on-LAN magic packets to one or more machines configured in WakeOnLanConfig in Configuration.psd1. Called with machine names it wakes those machines; called bare it shows an interactive selection menu. When a machine has an Address (IP or hostname) configured, it uses Test-MachineOnline to make waking reliable instead of fire-and-forget: it pings first and skips the machine if already online, then polls after sending until the machine responds or -TimeoutSeconds elapses, so the result reflects whether it actually woke. Machines without an Address fall back to fire-and-forget behaviour.
  • Parameters: -Machine, -TimeoutSeconds, -NoWait
  • Usage: Send-WakeOnLan, Send-WakeOnLan -Machine "MyMachine", Send-WakeOnLan -Machine "MyMachine" -NoWait

Each machine entry specifies a MAC address, subnet-specific broadcast address and port, and optionally an Address for verification. With -NoWait the function sends the packet only, with no online pre-check or post-send verification (the original fire-and-forget behaviour). Verification is delegated to Test-MachineOnline. Machines are configured as an ordered list of single-key hashtables, which is also the order the menu offers them in; All and None are appended by the function and never configured. The base ships WakeOnLanConfig empty; both functions warn and no-op until it is set in Configuration.local.psd1 - no packet is ever sent from an empty config.

Parameter Description
-Machine One or more machine names as defined in Configuration.psd1. Omit to show the interactive menu.
-TimeoutSeconds Maximum seconds to wait for a machine to come online after the packet is sent (verification phase). Default 120.
-NoWait Switch. Send the magic packet without the online pre-check or post-send verification.
# Interactive menu of configured machines
Send-WakeOnLan

# Skip if already online (ping check), send the packet, then poll
# until it responds or -TimeoutSeconds (default 120) elapses
Send-WakeOnLan -Machine "MyMachine"

# Fire-and-forget: send the packet only, no ping check or verification
Send-WakeOnLan -Machine "MyMachine" -NoWait

Example WakeOnLanConfig entry in Configuration.psd1:

WakeOnLanConfig = @{
    MyMachine = @{
        MacAddress                     = "00:11:22:33:44:55"
        SubNetSpecificBroadcastAddress = "192.0.2.255"
        Address                        = "192.0.2.10"  # IP/hostname; "" to disable ping checks
        Port                           = 9
    }
}

See also: Test-MachineOnline

  • Description: Sets the PowerShell execution policy to Bypass for a specified scope by calling Set-ExecutionPolicy -ExecutionPolicy Bypass, allowing unsigned scripts to run within that scope without user prompts.
  • Parameters: -Scope
  • Usage: Set-CustomExecutionPolicy, Set-CustomExecutionPolicy -Scope CurrentUser
  • Scopes: Process, CurrentUser, LocalMachine
Parameter Description
-Scope The scope for the execution policy. Valid values: Process (current session only), CurrentUser (all sessions for the current user), LocalMachine (all users, all sessions). Defaults to Process.
# Bypass for the current process only (default)
Set-CustomExecutionPolicy

# Bypass for all sessions of the current user
Set-CustomExecutionPolicy -Scope CurrentUser
  • Description: Sets the Windows display language. Reads available languages from DisplayLanguages in Configuration.psd1; pass a language code to set it directly, or call with no arguments to pick from an interactive menu (Enter selects the configured DefaultDisplayLanguage). Requires administrator privileges.
  • Parameters: -Language
  • Usage: Set-DisplayLanguage, Set-DisplayLanguage -Language "en-US"

Resolves the chosen language to its tag from DisplayLanguages and moves it to the front of the Windows user language list (adding it first if not already installed), then verifies the change took effect. If the requested language is already the active display language it is left unchanged. A sign-out and sign-in is required for the change to take full effect.

Parameter Description
-Language Language code as defined in Configuration.psd1 (e.g. "en-US", "hr-HR"). Omit to show the interactive menu.
# Show the interactive display language selection menu
Set-DisplayLanguage

# Set the display language directly to English (US)
Set-DisplayLanguage -Language "en-US"
  • Description: Sets user environment variables from the configuration or manually. With -Auto, reads all variables from AutoEnvironmentVariables in Configuration.psd1, expands placeholder paths ({Dev}, {User}, {MachineType}), and sets them; it also appends any entries from AutoPathAdditions to the user PATH. Manual mode accepts -Name and -Value to set an individual variable. Requires administrator privileges.
  • Parameters: -Name, -Value, -Auto
  • Usage: Set-EnvironmentVariables -Auto, Set-EnvironmentVariables -Name "MY_VAR" -Value "C:\Tools"

In -Auto mode, each configured variable is path-expanded via Expand-Hashtable (resolving {Dev}, {User}, and {MachineType} placeholders against the current machine's base paths) and written to the User scope. Existing variables are skipped when already correct, updated when the value differs, and created otherwise (idempotent). Entries in AutoPathAdditions are then expanded and appended to the user PATH only if not already present. In manual mode, both -Name and -Value are required; the value is path-expanded the same way. After any run, all User-scope variables are refreshed into the current session via env:.

Parameter Description
-Name Variable name for manual mode (e.g. "MY_VAR").
-Value Variable value for manual mode (e.g. "C:\Tools"); placeholder paths are expanded.
-Auto Reads all variables from AutoEnvironmentVariables (and PATH entries from AutoPathAdditions) in the configuration and sets them automatically.
# Set all configured variables and PATH additions automatically
Set-EnvironmentVariables -Auto

# Set a single variable manually
Set-EnvironmentVariables -Name "MY_VAR" -Value "C:\Tools"
  • Description: Configures Windows File Explorer display and behavior options. Reads the desired registry settings from ExplorerOptions in Configuration.psd1 and applies them (file extension visibility, hidden files, and similar). Takes no parameters - all settings come from the configuration.
  • Usage: Set-ExplorerOptions

Compares the current registry values against the desired settings in ExplorerOptions; if everything already matches it reports that Explorer is already configured and does nothing. Otherwise it writes each setting (creating the registry key path when missing) and runs Restart-Explorer so the changes take effect. Typical settings applied include showing hidden files, showing file extensions, opening Explorer to "This PC" instead of Quick Access, and disabling recent files in Quick Access.

# Apply all configured Explorer options to the registry
Set-ExplorerOptions
  • Description: Configures keyboard layouts from predefined layout sets read from KeyboardLayoutSets in Configuration.psd1 (e.g. "Gaming", "Development"). Each set is a named collection of keyboard layout codes. Passing a set name installs all its layouts; calling it without arguments shows an interactive menu of available sets (Enter selects the configured default). Idempotent: skips reconfiguration when the requested set is already active unless -Override is given.
  • Parameters: -LayoutSet, -Override
  • Usage: Set-KeyboardLayouts, Set-KeyboardLayouts -LayoutSet "Gaming", Set-KeyboardLayouts -LayoutSet "Development" -Override

Resolves the target set from KeyboardLayoutSets, maps each layout name to its code via KeyboardLayouts, and applies the configuration through the live Windows input system (Get-WinUserLanguageList / Set-WinUserLanguageList) rather than relying solely on the legacy registry. It rebuilds input method tips per language tag, removes stale input methods from languages not in the target set, and reorders the language list so the first target layout's language is primary. The HKCU:\Keyboard Layout\Preload registry is also updated for legacy application compatibility. After applying, the final configuration is printed and verified from the actual input system. A log off / log on may be required for changes to take full effect.

Parameter Description
-LayoutSet Name of the layout set to install (e.g. "Gaming"). Omit to show the interactive menu.
-Override Force reconfiguration even if the layout set is already active.
# Interactive layout-set selection menu (Enter picks the configured default)
Set-KeyboardLayouts

# Install a specific layout set
Set-KeyboardLayouts -LayoutSet "Gaming"

# Force reapply even if the set is already active
Set-KeyboardLayouts -LayoutSet "Development" -Override
  • Description: Sets the system locale (user culture and home location). Reads available locales from Locales in Configuration.psd1. When given a locale name it sets that locale; called without arguments it shows an interactive menu of available locales. Requires administrator privileges.
  • Parameters: -Locale
  • Usage: Set-Locale, Set-Locale -Locale "en-US", Set-Locale -Locale "hr-HR"

Validates admin privileges first, then resolves the target locale either from the -Locale argument or via an interactive selection menu (pressing Enter selects the configured DefaultLocale). The chosen locale's Code and GeoId are read from Configuration.psd1; the function applies the culture with Set-Culture and the home location with Set-WinHomeLocation (falling back to the HKCU:\Control Panel\International\Geo registry key if the cmdlet fails). If the current culture already matches the target, no change is made. Some settings may require a system restart to take full effect.

Parameter Description
-Locale Locale name as defined in Configuration.psd1 (e.g. "en-US", "hr-HR"). Omit to show the interactive menu.
# Show the interactive locale selection menu (Enter picks the default)
Set-Locale

# Set the system locale to US English
Set-Locale -Locale "en-US"

# Set the system locale to Croatian
Set-Locale -Locale "hr-HR"
  • Description: Sets the Windows lock screen background image to match the active theme and machine type via native registry settings. Resolves the image from the same WallpaperLightSettings / WallpaperDarkSettings configuration in Configuration.psd1 as Set-Wallpaper (for multi-monitor configs the first monitor's file is used). With -Theme Auto (the default) it detects the current system theme from the registry; disables Windows Spotlight / rotating lock screen so the custom image is shown. Writes to the PersonalizationCSP key under elevation and falls back to per-user registry otherwise. Requires administrator privileges.
  • Parameters: -Theme [Light | Dark | Auto]
  • Usage: Set-LockScreenWallpaper, Set-LockScreenWallpaper -Theme Dark, Set-LockScreenWallpaper -Theme Light

Resolves the image path from the same WallpaperDarkSettings / WallpaperLightSettings configuration as Set-Wallpaper, picking the entry for the current machine type (falling back to Default). It then disables Windows Spotlight / rotating lock screen (RotatingLockScreenEnabled, RotatingLockScreenOverlayEnabled) and sets the lock screen image via the PersonalizationCSP registry key (HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\PersonalizationCSP) when elevated; if the CSP write fails it falls back to per-user registry under HKCU. Set-SystemTheme calls this automatically alongside Set-Wallpaper, so you typically don't need to invoke it directly.

Parameter Type Default Description
-Theme string "Auto" Light, Dark, or Auto (detect from system registry).
# Apply the lock screen image matching the current system theme (auto-detected)
Set-LockScreenWallpaper

# Force a specific theme variant
Set-LockScreenWallpaper -Theme Dark
Set-LockScreenWallpaper -Theme Light

# Verbose diagnostic output
Set-LogLevel Verbose { Set-LockScreenWallpaper }

See also: Set-Wallpaper, Set-SystemTheme

  • Description: Configures what happens when the power button is pressed, the sleep button is pressed, or the laptop lid is closed, for both battery and plugged-in states. Also controls Fast Startup, Sleep, and Hibernate visibility in the Power menu. With -Auto it reads per-machine settings from PowerButtonActions in Configuration.psd1; otherwise it accepts individual parameters with hardcoded defaults. Applies settings to ALL power schemes and enforces them via the registry to prevent Windows from reverting them. Idempotent - skips settings already at the desired value. Requires administrator privileges.
  • Parameters: -Auto, -PowerButtonOnBattery, -PowerButtonPluggedIn, -SleepButtonOnBattery, -SleepButtonPluggedIn, -LidCloseOnBattery, -LidClosePluggedIn, -DisableFastStartup, -DisableSleep, -DisableHibernate
  • Usage: Set-PowerButtonActions -Auto, Set-PowerButtonActions, Set-PowerButtonActions -PowerButtonPluggedIn "ShutDown" -PowerButtonOnBattery "Sleep", Set-PowerButtonActions -Auto -LidCloseOnBattery Hibernate

With -Auto, the function determines the machine type and reads its block from PowerButtonActions in Configuration.psd1; explicit parameters override the configured values, and missing nullable toggles are left unmanaged. When PowerButtonActions is not configured (the empty base default) or has no entry for the machine type, a bare -Auto warns and leaves the power settings as-is - it no longer applies hardcoded defaults; only explicitly passed parameters are applied (over the built-in defaults as base). Without -Auto, omitted action parameters fall back to hardcoded defaults. The six button/lid actions are written through powercfg and reinforced directly in the registry across every power scheme, then the active scheme is re-activated to force the changes to take effect.

Parameter Description
-Auto Reads all button and lid actions from Configuration.psd1 per machine type.
-PowerButtonOnBattery Action when the power button is pressed on battery. One of DoNothing, Sleep, Hibernate, ShutDown.
-PowerButtonPluggedIn Action when the power button is pressed while plugged in. Same value set.
-SleepButtonOnBattery Action when the sleep button is pressed on battery. Same value set.
-SleepButtonPluggedIn Action when the sleep button is pressed while plugged in. Same value set.
-LidCloseOnBattery Action when the laptop lid is closed on battery. Same value set.
-LidClosePluggedIn Action when the laptop lid is closed while plugged in. Same value set.
-DisableFastStartup [bool] toggle for Windows Fast Startup (hybrid sleep).
-DisableSleep [bool] toggle for Sleep visibility in the Power menu.
-DisableHibernate [bool] toggle for hibernation and its Power-menu entry.
# Read and apply all configured button actions for this machine type
Set-PowerButtonActions -Auto

# Apply hardcoded defaults without touching configuration
Set-PowerButtonActions

# Read from config but override a single behavior
Set-PowerButtonActions -Auto -LidCloseOnBattery Hibernate

# Set the power button action for both power states explicitly
Set-PowerButtonActions -PowerButtonPluggedIn "ShutDown" -PowerButtonOnBattery "Sleep"

See also: Set-PowerPlan, Get-ChassisType

  • Description: Sets the Windows power plan to Balanced, HighPerformance, or UltimatePerformance. With -Auto, reads the plan for the current machine type from PowerPlans[MachineType] in Configuration.psd1 and applies it; when PowerPlans is not configured (the empty base default) or has no entry for the machine type, -Auto warns and leaves the active plan as-is (there is no Balanced fallback). Without -Auto and without an explicit -Mode, prompts for interactive selection (defaults to Balanced). Idempotent - skips if the plan is already active. Requires administrator privileges.
  • Parameters: -Auto, -Mode [Balanced | HighPerformance | UltimatePerformance]
  • Usage: Set-PowerPlan -Auto, Set-PowerPlan, Set-PowerPlan -Mode UltimatePerformance

Resolves the target mode from configuration (-Auto), the explicit -Mode parameter, or an interactive menu, then activates the matching powercfg scheme. For UltimatePerformance it duplicates the hidden Ultimate Performance scheme if one is not already present. Before switching it checks the active scheme and returns early when the requested plan is already active.

Parameter Description
-Auto Reads the power plan for the current machine type from PowerPlans in Configuration.psd1.
-Mode Power plan mode: Balanced, HighPerformance, or UltimatePerformance. Ignored if -Auto is set.
# Auto mode - reads the plan for this machine type from configuration
Set-PowerPlan -Auto

# Interactive selection (Enter for default => Balanced)
Set-PowerPlan

# Explicit mode
Set-PowerPlan -Mode UltimatePerformance

PowerPlans in Configuration.psd1 maps each machine type to a plan, for example:

PowerPlans = @{
    "PC"     = "UltimatePerformance"
    "Laptop" = "HighPerformance"
    "Work"   = "Balanced"
    "Test"   = "Balanced"
}
  • Description: Creates or updates a .lnk shortcut and stamps an explicit AppUserModelID (the System.AppUserModel.ID shell property) on it. The taskbar groups a pinned icon with a running window only when the two share an application identity: an app that registers its own AUMID at runtime via SetCurrentProcessExplicitAppUserModelID (Eclipse/SWT apps such as DBeaver, some Java and Electron apps) never docks onto a pin created from its exe path, and instead opens as a second, separate taskbar icon. Stamping the pin's shortcut with the app's runtime AUMID gives both sides one identity - the same property the manual "Pin to taskbar" flow records. Throws on any COM failure.
  • Parameters: -LinkPath, -TargetPath, -Aumid
  • Usage: Set-ShortcutAumid -LinkPath <path.lnk> -TargetPath <path.exe> -Aumid <id>, Set-ShortcutAumid -LinkPath <existing.lnk> -Aumid <id>

With -TargetPath, the shortcut is created first when missing (parent folder included) and its target and working directory are set; without it, -LinkPath must already exist. The property is written through the shell's IPropertyStore on the shortcut file and persisted into the .lnk itself, so it travels with any copy Explorer makes when applying a taskbar layout. Consumed by Configure-Taskbar for TaskbarConfiguration rows carrying an Aumid key.

Parameter Description
-LinkPath Full path of the .lnk file to stamp (and create, when -TargetPath is given).
-TargetPath Executable the shortcut should launch. When given, the shortcut is created if missing; when omitted, -LinkPath must exist.
-Aumid The explicit AppUserModelID to stamp - the identity the running app registers.
# Generate a shortcut for DBeaver and stamp its runtime identity on it
Set-ShortcutAumid -LinkPath "C:\ProgramData\provisioning\TaskbarPins\DBeaver.lnk" -TargetPath "$env:LOCALAPPDATA\DBeaver\dbeaver.exe" -Aumid "DBeaver"

# Stamp an existing Start Menu shortcut in place
Set-ShortcutAumid -LinkPath "$env:APPDATA\Microsoft\Windows\Start Menu\Programs\DBeaver Community\DBeaver.lnk" -Aumid "DBeaver"

To discover an app's runtime AUMID, check Get-StartApps first; when the app is not listed there (typical for the apps that need this), see the jump-list hash technique in Taskbar Configuration.

See also: Configure-Taskbar

  • Description: Redirects Windows special folders (such as Downloads and Screenshots) to custom paths defined in the SpecialFolders key of Configuration.psd1. Placeholder paths (e.g. {Dev}, {User}) are expanded before the redirections are written via registry entries. Requires administrator privileges.
  • Usage: Set-SpecialFolders

Reads the redirection list from SpecialFolders in Configuration.psd1, expands any placeholders against the current machine's base paths, and applies each one through the User Shell Folders registry key. It first compares the current registry values to the desired ones and skips writing if everything is already correctly mapped (idempotent). The base ships the section empty; the function warns and leaves the folder redirections as-is until it is set in Configuration.local.psd1 (the commented examples redirect Downloads and Screenshots to the Desktop).

# Redirect all configured special folders (run as administrator)
Set-SpecialFolders
  • Description: Sets the Windows system theme (Dark or Light) by modifying the relevant registry entries, then runs a configurable sequence of follow-up steps: reload open browser tabs (RefreshBrowserTabs, off by default), restart Explorer (RestartExplorer), apply the matching desktop wallpaper (SetWallpaper) and the matching lock screen image (SetLockScreenWallpaper). With -Auto it reads the theme for the current machine type from Configuration.Themes[MachineType]; when Themes is not configured (the empty base default) or has no entry for the machine type, -Auto warns and leaves the system theme as-is (there is no Dark fallback). With -Theme it applies an explicit theme; with no argument at all it defaults to Dark. Idempotent: if the theme is already configured it still runs the enabled follow-up steps. Every step can be toggled persistently via SystemTheme.Steps in Configuration.psd1 / Configuration.local.psd1 (plain booleans or per-machine-type hashtables with a Default fallback) and per invocation via -Skip / -Include. Requires administrator privileges.
  • Parameters: -Theme [Dark | Light], -Auto, -Skip (step names), -Include (step names), -KeepTerminalOpen
  • Usage: Set-SystemTheme -Auto, Set-SystemTheme -Auto -KeepTerminalOpen, Set-SystemTheme -Theme Dark, Set-SystemTheme -Theme Light, Set-SystemTheme -Auto -Include RefreshBrowserTabs, Set-SystemTheme -Theme Dark -Skip RestartExplorer, SetLockScreenWallpaper

Writes AppsUseLightTheme, SystemUsesLightTheme, and ColorPrevalence under HKCU:\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize (value 0 for Dark, 1 for Light). It then calls Set-Wallpaper (via the IDesktopWallpaper COM interface) and Set-LockScreenWallpaper so both backgrounds match the selected theme. When run inside Windows Terminal, the current tab is closed 5 seconds after a successful run unless -KeepTerminalOpen is set (useful for longer-running admin workflows such as Bootstrap).

Step resolution is tri-state: -Skip beats -Include beats the SystemTheme.Steps config (see Configuration Reference: Set-SystemTheme Step Toggles) beats the built-in defaults - everything on except RefreshBrowserTabs. Restarting Explorer is what makes the new theme visible on shell chrome, so it belongs to applying a theme rather than being collateral of it; skip it and the taskbar and open Explorer windows keep the old theme until Explorer restarts on its own or you sign out. The wallpaper steps are on because both functions no-op on the empty base config. Reloading every browser tab is the one action with real collateral - it takes focus per window and hard-reloads pages, discarding unsaved page state - so it is the only opt-in step. RestartExplorer runs before the wallpaper updates and must stay there, because restarting Explorer after a wallpaper change can cause Windows to reload stale wallpaper cache data and revert the desktop image. RefreshBrowserTabs only runs when the theme actually changed: tabs that already render the requested theme have nothing to pick up from a reload.

Parameter Type Description
-Theme string Explicit theme to apply: Dark or Light. Omit when using -Auto.
-Auto switch Reads the theme for the detected machine type from Configuration.Themes[MachineType]; warns and leaves the theme as-is when unconfigured.
-Skip string[] Step names to skip for this invocation, overriding config. Valid: RefreshBrowserTabs, RestartExplorer, SetWallpaper, SetLockScreenWallpaper. Wins over -Include.
-Include string[] Step names to run for this invocation even if config disables them. Same valid names as -Skip.
-KeepTerminalOpen switch Skips the default delayed close of the current Windows Terminal tab after a successful run.
# Apply the configured theme for the current machine type
Set-SystemTheme -Auto

# Keep the current elevated terminal open after the theme update (e.g. mid-Bootstrap)
Set-SystemTheme -Auto -KeepTerminalOpen

# Force a specific theme regardless of configuration
Set-SystemTheme -Theme Dark
Set-SystemTheme -Theme Light

# Reload every open browser tab this once, even though config leaves the step off
Set-SystemTheme -Auto -Include RefreshBrowserTabs

# Theme and desktop wallpaper only, leaving Explorer and the lock screen alone
Set-SystemTheme -Theme Dark -Skip RestartExplorer, SetLockScreenWallpaper

# Verbose diagnostic output (lists the steps being skipped)
Set-LogLevel Verbose { Set-SystemTheme -Auto }

See also: Resolve-SystemThemeSteps, Set-Wallpaper

  • Description: Applies the Settings > Personalisation > Taskbar page from the TaskbarSettings section in the configuration - the programmatic equivalent of walking that page top to bottom. Every key mirrors one control one-to-one: checkbox and toggle controls take $true (on) or $false (off), dropdown controls take one of the named tokens listed for them (case insensitive, PascalCase of the dropdown label). Keys left out of the configuration are not touched, and when the section is absent or empty the function changes nothing - the vanilla default. Every control is a per-user HKCU registry value - mostly DWords, whose keys are created when missing, plus "Automatically hide the taskbar", which is one bit inside Explorer's StuckRects3 binary blob and is rewritten in place - and Restart-Explorer runs once when at least one value was actually written. Idempotent - returns early when every configured control already matches; when changes are applied, each managed control is reported on its own row (green = toggle on, red = toggle off, white = the selected dropdown token, yellow [skipped] = already at the configured value). Unknown keys, non-boolean values on a toggle, and unrecognised dropdown tokens are each skipped with a warning naming the key. Takes no parameters - all settings come from the configuration.
  • Usage: Set-TaskbarSettings

Called during Bootstrap (after Configure-Taskbar), making the taskbar page an opt-in provisioning step: the base configuration ships the TaskbarSettings section fully commented, so a vanilla bootstrap leaves the page alone. Configure-Taskbar owns a different surface entirely - which apps are pinned to the taskbar - and the two do not overlap.

The commented lines are not placeholders. They are the taskbar WinuX recommends and its author runs on every machine - search hidden, task view off, buttons combined, the bar auto-hidden - so the window layouts do the work instead of the shell chrome. Uncomment the lot to get exactly that, cherry-pick individual controls, or override the section in Configuration.local.psd1.

Because most of these controls have no registry value until you change them in the Settings app, a missing value counts as a mismatch and is written explicitly. The first run on a machine therefore writes the implicit defaults too, making the state deterministic rather than "whatever this Windows build ships"; every run after that is a no-op. AutomaticallyHideTheTaskbar is the exception: Explorer owns the surrounding bytes of StuckRects3, which cannot be synthesized, so an unreadable value skips that control with a warning instead of fabricating a blob.

Controls

Advanced below is HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced. Note that the same token maps to a different number per control (WhenTaskbarIsFull is 1 for the combine dropdowns but 2 for the button-size dropdown), which is why each control carries its own map.

Config key Control on the page Accepted values Mechanism
Search Search Hide, SearchIconOnly, SearchBox, SearchIconAndLabel ...CurrentVersion\Search\SearchboxTaskbarMode
TaskView Task view $true / $false Advanced\ShowTaskViewButton
Resume Resume $true / $false ...CurrentVersion\CrossDeviceResume\Configuration\IsResumeAllowed
EmojiAndMore Emoji and more Never, WhileTyping, Always HKCU:\Software\Microsoft\TabletTip\1.7\EmojiAndMoreIconVisibilityState
PenMenu Pen Menu $true / $false ...CurrentVersion\PenWorkspace\PenWorkspaceButtonDesiredVisibility
TouchKeyboard Touch keyboard Never, Always, WhenNoKeyboardAttached HKCU:\Software\Microsoft\TabletTip\1.7\TipbandDesiredVisibility
TaskbarAlignment Taskbar alignment Left, Centre (Center also accepted) Advanced\TaskbarAl
AutomaticallyHideTheTaskbar Automatically hide the taskbar $true / $false ...Explorer\StuckRects3\Settings byte 8, bit 0x01
ShowBadgesOnTaskbarApps Show badges on taskbar apps $true / $false Advanced\TaskbarBadges
ShowFlashingOnTaskbarApps Show flashing on taskbar apps $true / $false Advanced\TaskbarFlashing
ShowTaskbarOnAllDisplays Show my taskbar on all displays $true / $false Advanced\MMTaskbarEnabled
TaskbarAppsOnMultipleDisplays When using multiple displays, show my taskbar apps on AllTaskbars, MainTaskbarAndTaskbarWhereWindowIsOpen, TaskbarWhereWindowIsOpen Advanced\MMTaskbarMode
ShareAnyWindowFromTaskbar Share any window from my taskbar $true / $false Advanced\TaskbarSn
SelectFarCornerToShowDesktop Select the far corner of the taskbar to show the desktop $true / $false Advanced\TaskbarSd
CombineTaskbarButtonsAndHideLabels Combine taskbar buttons and hide labels Always, WhenTaskbarIsFull, Never Advanced\TaskbarGlomLevel
CombineTaskbarButtonsAndHideLabelsOnOtherTaskbars Combine taskbar buttons and hide labels on other taskbars Always, WhenTaskbarIsFull, Never Advanced\MMTaskbarGlomLevel
ShowSmallerTaskbarButtons Show smaller taskbar buttons Always, Never, WhenTaskbarIsFull Advanced\IconSizePreference

TaskbarAlignment accepts both spellings because the dropdown label follows the Windows display language (Centre on en-GB, Center on en-US); both write 1.

AutomaticallyHideTheTaskbar is deliberately NOT applied through SHAppBarMessage, which is what the settings page uses. That call sets the state inside the running Explorer process, and Explorer only writes it back to StuckRects3 on a graceful exit - so the Restart-Explorer this function performs for the other controls (a Stop-Process, not a graceful exit) would throw the change away, and the setting would need a second run to stick. Writing the bit and letting the restart pick it up is both durable and a genuine one-shot. The setting itself is purely cosmetic: FancyZones zone geometry is computed from the monitor work area, so window snapping is correct whether the taskbar is visible or auto-hidden.

The Resume, EmojiAndMore, and ShowSmallerTaskbarButtons controls only exist on recent Windows 11 builds. Writing their values on an older build is harmless: the value is simply ignored until the build that reads it.

# Apply every control configured in the TaskbarSettings section
Set-TaskbarSettings

See also: Set-VisualEffects, Configure-Taskbar, Restart-Explorer

  • Description: Applies the Performance Options "Visual Effects" settings (System Properties > Performance Options > Visual Effects tab) from the VisualEffects section in the configuration. Every key mirrors one dialog checkbox one-to-one ($true = effect on / appearance, $false = effect off / performance); keys left out of the configuration are not touched, and when the section is absent or empty the function changes nothing - the vanilla default. Explorer/DWM-backed effects are written to the registry; the remaining effects go through SystemParametersInfo (the dialog's own mechanism), which persists them to the user profile and applies them live. Sets the dialog's radio button to "Custom" (VisualFXSetting = 3) whenever at least one effect is managed, and runs Restart-Explorer only when a registry-backed effect actually changed. Idempotent - returns early when every configured effect already matches; when changes are applied, every managed effect is reported on its own colored row (green = enabled, red = disabled, yellow [skipped] = already at the configured value). Unknown keys are skipped with a warning. Takes no parameters - all settings come from the configuration.
  • Usage: Set-VisualEffects

Called during Bootstrap (after Set-TaskbarSettings), making visual effects an opt-in provisioning step: the base configuration ships the VisualEffects section fully commented (no effects touched) and a fork defines its preferences in Configuration.local.psd1. Valid keys: AnimateControlsAndElementsInsideWindows, AnimateWindowsWhenMinimisingAndMaximising, AnimationsInTheTaskbar, EnablePeek, FadeOrSlideMenusIntoView, FadeOrSlideToolTipsIntoView, FadeOutMenuItemsAfterClicking, SaveTaskbarThumbnailPreviews, ShowShadowsUnderMousePointer, ShowShadowsUnderWindows, ShowThumbnailsInsteadOfIcons, ShowTranslucentSelectionRectangle, ShowWindowContentsWhileDragging, SlideOpenComboBoxes, SmoothEdgesOfScreenFonts, SmoothScrollListBoxes, UseDropShadowsForIconLabelsOnTheDesktop.

# Apply all effects configured in the VisualEffects section
Set-VisualEffects

See also: Set-ExplorerOptions, Set-TaskbarSettings

  • Description: Sets the desktop wallpaper based on MachineType and theme. With -Auto it reads paths from WallpaperDarkSettings/WallpaperLightSettings in Configuration.psd1 (selecting the entry for the current machine type, falling back to Default); without -Auto it presents an interactive picker of available wallpapers and styles. Supports multi-monitor configurations with per-monitor wallpaper and style assignment via the IDesktopWallpaper COM interface, automatically filtering out disconnected/phantom monitors so only active displays are configured. When the VirtualDesktop module is available it applies the wallpaper across all virtual desktops, hopping through them with the Window module's Switch-VirtualDesktop (confirmed switches, stale-session reconnect and backoff live in that seam, not here) and returning to the desktop read with Get-CurrentVirtualDesktopIndex; otherwise only the current desktop. Wallpaper style (Fill, Fit, Stretch, Tile, Center, Span) is read from WallpaperStyles. Requires administrator privileges, retries the IDesktopWallpaper COM calls for transient failures, and is idempotent - skipping when wallpaper, style, and tile values are already correct.
  • Parameters: -Auto, -Theme [Light | Dark | Auto]
  • Usage: Set-Wallpaper -Auto, Set-Wallpaper -Auto -Theme Dark, Set-Wallpaper (interactive)

Requires administrator privileges. In -Auto mode the theme defaults to Auto, which detects the current system theme from the registry (HKCU:\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize\AppsUseLightTheme), defaulting to Dark if detection fails. It then resolves the wallpaper entry for the current machine type, applying per-monitor images for multi-monitor configs or a single image otherwise, and propagates the result to every virtual desktop when the VirtualDesktop module is loaded - each switch through Switch-VirtualDesktop, with no desktop retry logic of its own. Without -Auto, it lists wallpapers from the WinuX Wallpapers folder and prompts for a wallpaper and a style (defaulting to Fill).

The Monitors array does not have to match the display count. Active displays are enumerated through IDesktopWallpaper and paired with the array by index; a display past the end of the array cycles back to the start, so a 2-entry array on 3 displays gives the third display the first entry, and a single warning reports the mismatch. Displays past the end were previously skipped in silence and kept whatever wallpaper they already had - no warning, no fallback. Cycling applies to all three per-monitor passes (the idempotency check, the initial apply, and the per-virtual-desktop reapply). Only an empty Monitors array leaves a display on the Windows default.

Parameter Description
-Auto Auto-detect the system theme and apply the matching configured wallpaper. Omit for an interactive picker.
-Theme Theme to use: Light, Dark, or Auto. Defaults to Auto (reads from the registry).
# Apply configured wallpaper, auto-detecting the current system theme
Set-Wallpaper -Auto

# Force a specific theme variant
Set-Wallpaper -Auto -Theme Dark
Set-Wallpaper -Auto -Theme Light

# Interactive selection from available wallpapers and styles
Set-Wallpaper

# Verbose diagnostic output
Set-LogLevel Verbose { Set-Wallpaper -Auto }

See also: Set-LockScreenWallpaper, Set-SystemTheme

  • Description: Prints a yellow warning listing apps that are pinned (version-locked) to a specific version and will be skipped by the upgrade functions. Helper used by the upgrade routines (e.g. Upgrade-All).
  • Parameters: -PinnedApps, -Message
  • Usage: Show-PinnedAppsWarning -PinnedApps @("git", "nodejs"), Show-PinnedAppsWarning -PinnedApps @("git") -Message "Version-locked packages"
Parameter Description
-PinnedApps Array of pinned app names to display. Nothing is printed when the array is empty.
-Message Custom warning message prefix. Defaults to "Skipping version-pinned packages".
# Warn about the default set of version-pinned packages
Show-PinnedAppsWarning -PinnedApps @("git", "nodejs")

# Use a custom message prefix
Show-PinnedAppsWarning -PinnedApps @("git", "nodejs") -Message "Version-locked packages"
  • Description: The greeting a shell opens with, and what the c alias redraws: three steps, each its own exported function and each independently switchable from configuration or from a switch on the call - Invoke-Clear (on by default), Invoke-Fastfetch (on by default) and Invoke-Onefetch (off by default). Onefetch is opt-in because it is only meaningful inside a repository and not every machine has the binary; enabled, it is still silently skipped outside a repository, so there is no directory where the greeting prints an error or an empty panel. Settings are resolved exactly once, by Resolve-TerminalGreetingSettings, and handed to each step, so a value out of range is reported once per greeting rather than three times. A configuration with no TerminalGreeting section falls through to the built-in defaults, which are the values the base ships - so a fork that has not migrated its Configuration.local.psd1 gets the previous behavior: clear, then a font-fitted fastfetch.
  • Parameters: -NoClear, -NoFastfetch, -NoOnefetch, -NoResize, -PromptReserve, -MaxShrinkSteps, -ReflowTimeoutMilliseconds
  • Usage: c, Show-TerminalGreeting, Show-TerminalGreeting -NoOnefetch, Show-TerminalGreeting -NoResize, Show-TerminalGreeting -MaxShrinkSteps 0
  • Alias: c

The order is deliberate. Onefetch is MEASURED first, before anything is drawn, so its height can be added to the budget Invoke-Fastfetch fits the font to - the font is then chosen for both panels together rather than for fastfetch alone, which would fit and then scroll off the top as soon as onefetch printed below it. Set TerminalGreeting.Onefetch.IncludeInAutoFit to $false to fit fastfetch on its own. The screen is cleared before the shrink keystrokes rather than after, so the Ctrl+0 / Ctrl+Minus steps happen on an empty screen; the alternative - clearing last - would mean drawing the panel onto whatever was already there.

The profile calls it at shell start with -NoResize: a fresh shell has nothing on screen to redraw, and the keystroke round trips would only delay the first prompt. c does fit.

Parameter Type Default Description
-NoClear switch - Skip the clear step for this call.
-NoFastfetch switch - Skip the fastfetch step for this call.
-NoOnefetch switch - Skip the onefetch step for this call, including its measurement, so the font is fitted to fastfetch alone.
-NoResize switch - Skip the font auto-fit. What the profile passes at shell start.
-PromptReserve int TerminalGreeting.Fastfetch.AutoFit.PromptReserve (ships 1) Rows kept free below the panel for the upcoming prompt (0-20).
-MaxShrinkSteps int TerminalGreeting.Fastfetch.AutoFit.MaxShrinkSteps (ships 10) Upper bound on the Ctrl+Minus steps taken below the default font (0-50). 0 resets and never shrinks.
-ReflowTimeoutMilliseconds int TerminalGreeting.Fastfetch.AutoFit.ReflowTimeoutMilliseconds (ships 10) How long to wait for the window size to change after each keystroke. Any positive integer.
# The whole greeting, as configured
c

# Clear and show the system info panel only, fitted to itself
Show-TerminalGreeting -NoOnefetch

# The greeting without the font auto-fit - what the profile runs at shell start
Show-TerminalGreeting -NoResize

# Do the panels fit at all at the default font size?
Show-TerminalGreeting -MaxShrinkSteps 0

# What was measured, how many steps were taken, and why was a step skipped?
Set-LogLevel Verbose { Show-TerminalGreeting }

See also: Invoke-Clear, Invoke-Fastfetch, Invoke-Onefetch, Resolve-TerminalGreetingSettings, Test-GitRepository, Show-TerminalGreeting configuration guide

  • Description: Creates symbolic links defined in SymbolicLinks under MachineSpecificPaths in Configuration.psd1 for the current machine type. The orchestrator of a three-part pipeline: Get-SymbolicLinkEntries flattens the nested configuration and applies the -Scope/-Name filters, then each entry is created via New-WindowsSymbolicLink (backslash paths) or New-WSLSymbolicLink (forward-slash paths). Modular: -Scope limits a run to the Windows or WSL flavor and -Name to specific entries, so one relink never has to redo every link. A real file or directory already sitting at an entry's path is backed up into <Repo>\Backups\Windows\SymbolicLinks\<entry key>\<timestamp>\ before the link replaces it, so a first run over a machine that already has its own PowerShell profile or PowerToys settings loses nothing. Requires administrator privileges.
  • Parameters: -Scope (All, Windows, WSL), -Name
  • Usage: SymbolicLinkMaker, SymbolicLinkMaker -Scope WSL, SymbolicLinkMaker -Name PowerToys

The machine type is resolved via DetermineMachineType, then Get-SymbolicLinkEntries flattens the SymbolicLinks hashtable and applies the -Scope/-Name filters up front. The maker itself only iterates the selected entries: it prints the group headers (each ancestor once, derived from the entries' dotted keys), skips entries with empty or null Path/Target with an error, and dispatches each entry to New-WSLSymbolicLink (passing the configured DefaultWSLDistribution) or New-WindowsSymbolicLink, which own the target-missing guard, parent-directory creation, and the back-up-then-remove-then-link sequence (an entry whose backup cannot be written is skipped instead of replaced). WSL entries are skipped with a warning when no WSL distribution is available; the availability probe only runs when the selection actually contains WSL entries.

Entries filtered out by -Scope/-Name are skipped silently (no warnings, no empty group headers): a filtered run was simply asked not to touch them. A -Scope Windows run never invokes wsl.exe at all, and a filter matching nothing warns and returns.

Parameter Description
-Scope Which link flavor to process: All (default), Windows (backslash paths only), or WSL (forward-slash paths only). Configure-WSL -Force uses -Scope WSL to restore the links a distro reinstall wiped.
-Name One or more entry keys, matched with wildcards against both the bare key and the full dotted path (e.g. PowerToys, PowerToys.Settings, WSL*). Matching a group processes everything beneath it. Combines with -Scope. Omit for all entries.
# Create all configured symbolic links for the current machine type (run elevated)
SymbolicLinkMaker

# Only the WSL symlinks (e.g. after a distro reinstall)
SymbolicLinkMaker -Scope WSL

# Only specific entries - a top-level group, a nested entry, or a wildcard
SymbolicLinkMaker -Name PowerToys
SymbolicLinkMaker -Name "WindowsTerminal.Settings", "FastFetch*"
  • Description: Reconciles a package manager's own version pins with the effective app list, in both directions, so a bulk upgrade cannot move a version-locked app. All three managers are handled through their native pin mechanism. Called by Upgrade-All before the upgrade runs.
  • Parameters: -PackageManager (WinGet, Scoop or Chocolatey)
  • Usage: Sync-AppPins -PackageManager WinGet, Sync-AppPins -PackageManager Scoop
Manager Pin Unpin Current state read
WinGet winget pin add --blocking winget pin remove winget pin list --id
Scoop scoop hold scoop unhold scoop export (Info)
Chocolatey choco pin add choco pin remove choco pin list -r

Both halves of the pin lifecycle matter:

  • Every row carrying a real version is pinned. This is what stops winget upgrade --all, scoop update * and choco upgrade all from walking straight past a deliberate version lock.
  • Every row back to tracking the latest that is still pinned from an earlier run has its pin removed. Without this half a pin outlives the decision behind it: unpinning an app in the CSV would leave the manager's own pin in place and the app frozen forever, with nothing in WinuX left to explain why it stopped updating. Install-WinGetApps already reconciles this way per app at install time; this is the same reconciliation for the upgrade path.

Recording the pin in the manager itself - rather than merely excluding the app from the list WinuX passes to the upgrade - is what makes the lock hold outside WinuX too: a hand-run winget upgrade --all, scoop update * or choco upgrade all respects it as well.

Only apps WinuX manages are touched - the removal side considers exactly the apps in the effective list that are not pinned, so a pin somebody added by hand for an app outside the list is left alone. Pinned apps come from Get-PinnedApps and the managed set from Import-AppCsv, so the machine-local <name>.local.csv overlay counts on both sides.

Two Scoop specifics, both consequences of how scoop stores a hold (in the installed app's install.json):

  • A hold only exists on an installed app, so a version-locked row that is not installed yet is reported and left to Install-ScoopApps, which installs it at the pinned version. WinGet and Chocolatey accept a pin ahead of installation.
  • scoop hold/unhold need -g for a globally installed app, and the flag follows the installed scope read from scoop export, not the CSV's Global column - an app may have been installed the other way by hand, and the hold has to land where the app actually is. The single scoop export call reports installed, held and global state together, since its Info column is the comma-joined marker set scoop list builds.
Parameter Description
-PackageManager Which manager's pins to reconcile: WinGet (unpinned value is Latest), Scoop (lower-case latest), or Chocolatey (an empty Version cell means latest, so any version counts as a pin).
# Pin every version-locked WinGet app and clear pins for apps back to "Latest"
Sync-AppPins -PackageManager WinGet

# The same through scoop hold / unhold, so a later `scoop update *` skips the held apps
Sync-AppPins -PackageManager Scoop

See also: Upgrade-All, Get-PinnedApps, Show-PinnedAppsWarning

  • Description: Gracefully terminates every browser declared in Configuration.Universal.Browsers (Firefox, Tor, Chrome, Edge, Brave) by posting WM_CLOSE to each browser's visible top-level windows. Browsers are disambiguated by both process name (derived from the configured Exe filename) and a brand-specific window title regex, so browsers that share a process name (Firefox vs. Tor, both firefox.exe) and chromium child processes (GPU/renderer/utility) are handled correctly. With -Exclude, WM_CLOSE is posted only to non-matching windows - kept windows are never touched, so there is no foreground-focus race.
  • Parameters: -Exclude
  • Usage: Terminate-AllBrowserProcesses, Terminate-AllBrowserProcesses -Exclude "*YouTube*", Terminate-AllBrowserProcesses -Exclude "*YouTube*", "*Gmail*"

Browser identification is two-staged: the process name is resolved from each browser's configured executable (firefox.exe -> firefox, chrome.exe -> chrome), and a brand-specific title regex from Get-BrowserTitlePattern attributes each window to a brand for logging. The regex no longer decides WHICH windows are closed: every visible, titled window of a targeted browser process is closed, including the ones without the brand suffix - an undocked DevTools window, a Picture-in-Picture player, an installed web app (PWA), a print or download dialog - that used to be left standing after every cleanup. A window reachable through two targets that share a process name (Firefox and Tor Browser) is closed once. WM_CLOSE is posted directly to each non-excluded window handle (per handle, not via SendKeys), so it does not touch the foreground and excluded windows are never accidentally closed by a misfired keystroke.

The close is verified. WM_CLOSE is posted, not sent, so the function then waits for the windows to disappear (Wait-BrowserWindowsClosed, four seconds), posts WM_CLOSE once more to whatever is still standing, waits again (two seconds), and reports the survivors by title as a warning instead of printing its success line. Browsers are never force-killed: a window that ignores two WM_CLOSE rounds is holding a dialog - unsaved form data, a download in progress, "close all tabs?" - that the user has to answer, and killing the process would answer it for them.

Parameter Description
-Exclude One or more window title patterns to keep open. Supports wildcard (*YouTube*) and regex (.*YouTube.*, (.*Gmail.*|.*Inbox.*)) patterns, same format as the layout .psd1 files. Browser windows matching any pattern are kept; all other browser windows are closed.
# Close every configured browser
Terminate-AllBrowserProcesses

# Close all browser windows except a kept YouTube tab
Terminate-AllBrowserProcesses -Exclude "*YouTube*"

# Verbose diagnostic output
Set-LogLevel Verbose { Terminate-AllBrowserProcesses -Exclude "*YouTube*", "*Gmail*" }
  • Description: Forcefully terminates every process named in the Universal.TerminateProcessNames configuration list using Stop-Process -Force. Missing processes are silently ignored, and the function warns and terminates nothing when the list is absent or empty. Processes whose windows match an exclusion pattern are skipped. Docker is intentionally handled separately by DockerWizard before this function runs.
  • Parameters: -Exclude
  • Usage: Terminate-AllProcessesByName, Terminate-AllProcessesByName -Exclude "*Important Project*"

Iterates the configured target process list (the base configuration ships a minimal example - keep your real cleanup targets in Configuration.local.psd1, which replaces the array wholesale on merge) and, for each, separates the running instances into those to terminate and those to exclude. -Exclude patterns are matched against each process's name and main window title (via Test-WindowTitleMatch), so a single match spares that instance while the rest are still killed. Under Set-LogLevel Verbose it prints the target list, per-process found/excluded/terminated counts, and PID/window details for excluded instances.

Parameter Description
-Exclude Array of window title patterns to exclude from termination. Supports both wildcard ("*YouTube*") and regex (".*YouTube.*", "(.*Gmail.*|.*Inbox.*)") patterns, using the same format as the layout .psd1 files.
# Terminate every configured named process
Terminate-AllProcessesByName

# Spare any VS Code / chat window whose title matches the pattern
Terminate-AllProcessesByName -Exclude "*Important Project*"

# Verbose diagnostic output
Set-LogLevel Verbose { Terminate-AllProcessesByName }
  • Description: Forcefully terminates all processes that expose a visible, titled top-level window (discovered window-side through Get-VisibleWindowProcess, not via MainWindowTitle), waits for them to exit and reports any that survive, preserving the default exclusions used by the desktop cleanup flow: every browser declared in Configuration.Universal.Browsers (handled gracefully by Terminate-AllBrowserProcesses instead) plus every process named in the Universal.VisibleWindowExclusions configuration list (Rainmeter, WindowsTerminal, Docker Desktop, obs64, and the PowerToys supervisor/FancyZones/Settings processes by default). Warns and terminates nothing when the exclusion list is absent or empty, since running without it would force-kill WindowsTerminal - the shell running the cleanup. Additional windows can be spared via the -Exclude parameter.
  • Parameters: -Exclude
  • Usage: Terminate-AllProcessesWithVisibleWindows, Terminate-AllProcessesWithVisibleWindows -Exclude "*YouTube*", Terminate-AllProcessesWithVisibleWindows -Exclude "*YouTube*", "*Obsidian*"

Candidates come from the window side: Get-VisibleWindowProcess enumerates every visible, titled top-level window and groups them by owning process, so a process is a candidate as soon as any of its windows is on screen. The classic Get-Process | Where-Object MainWindowTitle test this replaces skipped windows at random - .NET's main window is the first visible unowned window in z-order, titled or not, so a process whose untitled helper window happened to sit on top reported an empty title and survived one run while dying the next, and packaged (UWP) apps, whose frames belong to ApplicationFrameHost, were never seen at all. The default-excluded process names (from Universal.VisibleWindowExclusions) are then dropped. Browser process names are pulled dynamically from Configuration.Universal.Browsers so this stays in sync with Terminate-AllBrowserProcesses, which has already closed those windows gracefully via WM_CLOSE - force-killing the underlying browser processes here would race that flow and also tear down deliberately-kept tabs. A process is spared when ANY of its windows matches an -Exclude pattern (via Test-WindowTitleMatch): a force-kill is per process, so the kept window cannot survive without its siblings. The rest are stopped with Stop-Process -Force.

The kill is verified. Stop-Process -Force returns once the terminate request is issued, not once the process is gone, so the function waits for the targeted processes to exit (Wait-Process, five seconds) and then looks again. A process still alive - access denied on an elevated app, a hung teardown - is reported as a warning naming the process, PID and window instead of being counted as terminated, and the success line is printed only when nothing survived.

| Parameter | Description | | ---------- | ----------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- | | -Exclude | Array of window-title patterns to spare from termination. Supports both wildcard ("*YouTube*") and regex (".*YouTube.*", "(._Gmail._ | ._Inbox._)") forms, the same format used by layout .psd1 files. Windows matching any pattern are not closed. |

Warning

The PowerToys exclusions are intentional. Killing only the visible PowerToys.Settings window leaves the supervisor in a "running but FancyZones absent" half-state that breaks subsequent workspace layout application and forces an expensive Start-FancyZones -ForceRestart. Never remove these from Universal.VisibleWindowExclusions.

# Close every visible-window process except the built-in default exclusions
Terminate-AllProcessesWithVisibleWindows

# Additionally keep specific windows open (wildcard patterns)
Terminate-AllProcessesWithVisibleWindows -Exclude "*YouTube*", "*Obsidian*"

# Verbose diagnostic output
Set-LogLevel Verbose { Terminate-AllProcessesWithVisibleWindows }
  • Description: Closes Windows Terminal tabs. It temporarily renames the current tab to a unique ID, then closes every other tab via UI Automation - each tab's close button is invoked directly, with no focus changes and no synthesized keystrokes. When UI Automation cannot read or close the tabs, the legacy pass takes over automatically: cycling with Ctrl+Tab and closing any tab that does not match the marker with Ctrl+C/Ctrl+W. Detection across all open Windows Terminal windows is supported (not just the hosting one), and --suppressApplicationTitle is handled by falling back to the original tab title when the marker is not reflected in the tab titles. With -IncludeCurrent the current tab is also closed at the end via a clean process exit; with -OnlyCurrent it closes only the calling tab through the same deterministic exit seam.
  • Parameters: -IncludeCurrent, -OnlyCurrent, -CloseWaitSeconds
  • Usage: Terminate-WindowsTerminalTabs, Terminate-WindowsTerminalTabs -IncludeCurrent, Terminate-WindowsTerminalTabs -OnlyCurrent, Terminate-WindowsTerminalTabs -OnlyCurrent -CloseWaitSeconds 5

In main mode it identifies the Windows Terminal process actually hosting this shell by walking the parent-process chain via PS7's Process.Parent (no WMI/CIM roundtrips; the walk is skipped entirely for -OnlyCurrent, whose early exit never needed it), so the right window is targeted even when several Windows Terminal processes are running (elevated and non-elevated, or multiple user windows). It marks the current tab with a unique title and identifies it from the UIA tab titles when available - so the marked tab is found even when it is not the active one - then closes every non-marked tab via its close button (Close-WindowsTerminalTab). The legacy pass (cycle with Ctrl+Tab, close with Ctrl+C then Ctrl+W, consecutive marker detection to know when all tabs have been cycled) runs only when UI Automation cannot read or close the tabs. Additional Windows Terminal windows are processed separately, UIA-first with the same fallback, and the SendKeys retry-verification pass re-checks and closes survivors only when a close failure was recorded or something survived the main passes - when everything is verified closed it is skipped entirely. Each close attempt is verified to have actually changed the active tab or window, and a warning is emitted when tabs or windows remain open after cleanup.

Parameter Type Default Description
-IncludeCurrent switch - Also closes the current calling tab after all other tabs are processed.
-OnlyCurrent switch - Closes only the current (calling) tab without affecting any others. Useful when a new window has been opened and the original calling tab is redundant.
-CloseWaitSeconds int (0-300) 0 Waits this many seconds before closing the current tab when -OnlyCurrent or -IncludeCurrent is used, giving time to read the final status output.
# Close every other Windows Terminal tab, keeping the current one
Terminate-WindowsTerminalTabs

# Close all tabs, including the current calling tab, then exit cleanly
Terminate-WindowsTerminalTabs -IncludeCurrent

# Close only the current (redundant) tab, after a 5-second pause to read output
Terminate-WindowsTerminalTabs -OnlyCurrent -CloseWaitSeconds 5

# Verbose diagnostic output
Set-LogLevel Verbose { Terminate-WindowsTerminalTabs }
  • Description: Tells whether a fastfetch panel of the given size overflows a window of the given size - the fit rule Invoke-Fastfetch judges by, in one place. The panel overflows when it is wider than the window, or taller than the window minus one row for the line the cursor ends on and minus -PromptReserve rows for the upcoming prompt. A panel exactly as wide as the window fits. Pure: no console access, no side effects, returns [bool].
  • Parameters: -PanelWidth, -PanelHeight, -WindowWidth, -WindowHeight, [-PromptReserve]
  • Usage: Test-FastfetchPanelOverflow -PanelWidth 106 -PanelHeight 22 -WindowWidth 120 -WindowHeight 30

Being pure is what lets the auto-fit loop be tested against scripted window sizes, and lets a user check by hand whether a given panel would fit a given window.

Parameter Type Default Description
-PanelWidth int - Longest panel row, in cells.
-PanelHeight int - Number of panel rows.
-WindowWidth int - Window width, in cells.
-WindowHeight int - Window height, in rows.
-PromptReserve int 1 Rows kept free below the panel for the prompt.
# $false: 106 columns fit in 120, and 22 rows leave the cursor row and one prompt row free in 30
Test-FastfetchPanelOverflow -PanelWidth 106 -PanelHeight 22 -WindowWidth 120 -WindowHeight 30

# $true: wider than the window
Test-FastfetchPanelOverflow -PanelWidth 106 -PanelHeight 22 -WindowWidth 100 -WindowHeight 30

See also: Invoke-Fastfetch, Get-ConsoleWindowSize

  • Description: Tests whether a machine is online (reachable via ICMP ping) and returns a boolean for use in conditional logic. The target is resolved from the Address field of WakeOnLanConfig in Configuration.psd1 by machine name, or supplied directly as an IP address / hostname. Supports a single check (default) or a wait-for-online mode (-WaitForOnline) that polls until the host responds or -TimeoutSeconds elapses. Used by Send-WakeOnLan for its "already on" skip and to verify a machine has finished booting after a magic packet. Returns $false if no Address is configured.
  • Parameters: -Machine, -Address, -DisplayName, -WaitForOnline, -TimeoutSeconds (default 120), -IntervalSeconds (default 3), -PingTimeoutMilliseconds (default 1000), -Quiet
  • Usage: Test-MachineOnline -Machine "MyMachine", Test-MachineOnline -Address 192.0.2.10 -WaitForOnline -TimeoutSeconds 90, if (Test-MachineOnline -Machine "MyMachine" -Quiet) { "MyMachine is up" }

Pings a target to determine whether it is currently powered on and reachable. With -Machine, the target is looked up by name in WakeOnLanConfig and its Address field is used; when WakeOnLanConfig is not configured (the empty base default), the lookup warns and returns $false. With -Address, the given IP/hostname is pinged directly (this is the path Send-WakeOnLan uses). In single-check mode it pings once and reports the result. In wait-for-online mode it polls at -IntervalSeconds intervals, printing a live countdown, until the host responds or the timeout elapses.

Parameter Description
-Machine Machine name as defined in WakeOnLanConfig; its Address field is used as the ping target.
-Address Explicit IP address or hostname to ping. Use instead of -Machine when the address is already known.
-DisplayName Friendly name used in console messages. Defaults to -Machine or -Address.
-WaitForOnline Poll repeatedly until the machine responds or -TimeoutSeconds is reached.
-TimeoutSeconds Maximum time to wait when -WaitForOnline is used. Default 120.
-IntervalSeconds Delay between ping attempts when -WaitForOnline is used. Default 3.
-PingTimeoutMilliseconds Per-ping timeout in milliseconds. Default 1000.
-Quiet Suppress all console output and only return the boolean result.
# Single ICMP ping by configured machine name; reports and returns online/offline
Test-MachineOnline -Machine "MyMachine"

# Poll an explicit address until it responds or 90s elapses
Test-MachineOnline -Address 192.0.2.10 -WaitForOnline -TimeoutSeconds 90

# Use the result in a condition with no console output
if (Test-MachineOnline -Machine "MyMachine" -Quiet) { "MyMachine is up" }

See also: Send-WakeOnLan

  • Description: Checks whether the active power plan is set to the optimal performance mode for the current machine type. Reads the chassis type through Get-ChassisType - the hardware once, a per-machine cache on every later start - to determine if the machine is a laptop or desktop, then verifies High Performance for laptops/portables or Ultimate Performance for desktops, and warns if not optimally configured. Chassis types are defined in Configuration.LaptopChassisTypes. -Refresh re-reads the chassis from the hardware.
  • Usage: Test-PowerPlan

Reads the active scheme via powercfg /getactivescheme and compares it against the expected plan for the detected machine type. If the active plan is wrong, it prints a yellow warning suggesting Set-PowerPlan -Auto to fix it. Any failure during the check is reported as a red error. Commonly run at shell startup from the PowerShell profile.

# Verify the active power plan matches the optimal mode for this machine
Test-PowerPlan

See also: Set-PowerPlan, Get-ChassisType

  • Description: Verifies that required Remote Procedure Call (RPC) infrastructure services are running and, optionally, that this session's live RPC/COM state actually responds. Essential for FancyZones, virtual desktop management, and other system operations that depend on RPC. With -Probe it runs a lightweight VirtualDesktop COM roundtrip via Test-VirtualDesktopComHealth - in-process, under a timeout - catching both the "service is Running but the endpoint is hung" failure mode and the "this session's cached COM proxies are stale after an Explorer restart" failure mode (0x800706BA / 0x80010108) that a status check or a child-process probe cannot detect. Successful -Probe results are cached for 8 seconds so the several preflights of one workspace open pay for a single probe; failures are never cached, so recovery paths always re-verify.
  • Parameters: -ServiceNames (defaults to @("RpcSs", "DcomLaunch", "RpcEptMapper")), -Probe, -ProbeTimeoutMs (default 5000)
  • Usage: Test-RpcServerHealth, Test-RpcServerHealth -Probe, Test-RpcServerHealth -ServiceNames @("RpcSs", "DcomLaunch")

A healthy live probe is cached for 30 seconds, long enough to span the two layout calls of one workspace open (the prepare step before the launch actions and the full call after them); failures are never cached. Checks that each required RPC service is present and in Running state, returning $false on the first one that is missing or stopped. With -Probe, after confirming services are running it runs a live roundtrip against the CURRENT session's VirtualDesktop COM state on a background runspace (Test-VirtualDesktopComHealth). If the call times out (hung endpoint) or fails with an RPC availability error (classified via Test-RpcUnavailableError), the function returns $false. A successful probe result is cached for 8 seconds and short-circuits the whole check - one workspace open runs this preflight several times seconds apart (layout entry, desktop remove/ensure, alongside cleanup), and each probe spins up a fresh runspace plus service checks - while failures are never cached, so recovery paths always re-verify against live state. The probe deliberately runs in-process: the previous Start-Job child-process design created its own fresh COM proxies, so after an Explorer restart it reported healthy while the current session stayed broken. Non-RPC probe failures (e.g. the VirtualDesktop module missing) are treated as healthy so they don't trigger unnecessary recovery, and when the probe helper itself is unavailable (Window module not loaded) the function falls back to service status only. Returns $true only when all checks pass.

Parameter Type Default Description
-ServiceNames string[] @("RpcSs", "DcomLaunch", "RpcEptMapper") RPC service names to verify.
-Probe switch - Run a live in-process VirtualDesktop COM roundtrip under a timeout to detect stale or hung session state.
-ProbeTimeoutMs int 5000 Hard timeout for the live probe (ms). A healthy warm probe returns in milliseconds; the timeout only bounds the genuinely-hung-endpoint case.

Required services: RpcSs (Remote Procedure Call System service - core RPC transport), DcomLaunch (DCOM Server Process Launcher - distributed component initialization), RpcEptMapper (RPC Endpoint Mapper - service discovery and connectivity).

# Test default RPC services (RpcSs, DcomLaunch, RpcEptMapper)
Test-RpcServerHealth                          # $true if all running, else $false

# Live readiness probe - catches "Running but endpoint hung" failures
Test-RpcServerHealth -Probe

# Verbose diagnostic output
Set-LogLevel Verbose { Test-RpcServerHealth -Probe }

# Verify only a specific subset of services
Test-RpcServerHealth -ServiceNames @("RpcSs", "DcomLaunch")

Used by Start-FancyZones, Set-WorkspaceWindowLayout, and Initialize-WorkspaceWindowLayoutRerun as the gate before expensive recovery actions. A plain status check is not enough: RPC services can sit in Running state while the endpoint is hung after heavy DCOM churn (mass Stop-Process -Force, repeated COM calls), so use -Probe when the decision to run a costly recovery depends on real responsiveness.

See also: Repair-RpcServer

  • Description: Tests whether a window/process matches any of the provided patterns, returning a boolean. It first checks for a case-insensitive exact match against the process name, then matches the window title against each pattern as either a wildcard or a regex. Used internally by Kill-All and Terminate-* functions for exclusion filtering.
  • Parameters: -WindowTitle, -ProcessName, -Patterns (required)
  • Usage: Test-WindowTitleMatch -WindowTitle "YouTube - Google Chrome" -Patterns @("*YouTube*"), Test-WindowTitleMatch -ProcessName "Code" -WindowTitle "file.ps1 - Visual Studio Code" -Patterns @("Code"), Test-WindowTitleMatch -WindowTitle "Gmail Inbox" -Patterns @("(.*Gmail.*|.*Inbox.*)")

Iterates over -Patterns and returns $true on the first match. For each pattern it first attempts a case-insensitive exact match against -ProcessName. If that fails (and a -WindowTitle is present) the pattern is treated as a regex; when it is not valid regex but looks like a wildcard, it is converted (* to .*, ? to .) before matching against the title. Blank patterns are skipped, and $false is returned when nothing matches. Pattern format mirrors Get-WindowHandle and the window-layout .psd1 files.

| Parameter | Description | | -------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------- | | -WindowTitle | The actual window title to test against the patterns. May be empty. | | -ProcessName | The process name to test against the patterns for exact (case-insensitive) matching. Optional. | | -Patterns | Required array of patterns. Each entry may be an exact process name (e.g. "Code", "firefox"), a wildcard (e.g. "*YouTube*", "Chrome - *"), or a regex (e.g. "^Chrome", "(._Gmail._ | ._Inbox._)"). |

# Wildcard match against the window title -> $true
Test-WindowTitleMatch -WindowTitle "YouTube - Google Chrome" -Patterns @("*YouTube*")

# Exact, case-insensitive match against the process name -> $true
Test-WindowTitleMatch -ProcessName "Code" -WindowTitle "file.ps1 - Visual Studio Code" -Patterns @("Code")

# No pattern matches -> $false
Test-WindowTitleMatch -WindowTitle "My Document - Word" -Patterns @("*YouTube*", "*Gmail*")

# Regex alternation against the window title -> $true
Test-WindowTitleMatch -WindowTitle "Gmail Inbox" -Patterns @("(.*Gmail.*|.*Inbox.*)")
  • Description: Clears all taskbar pins and applies an XML layout policy that prevents further taskbar modifications. It first calls Clear-TaskbarPins to remove pin data directly from the registry, then writes an empty TaskbarLayout XML and deploys it via Group Policy under HKLM:\SOFTWARE\Policies\Microsoft\Windows\Explorer, locking the layout until the policy registry key is removed. Restarts Explorer to apply the changes. Requires administrator privileges.
  • Parameters: -SkipExplorerRestart, -FromBootstrap
  • Usage: Unpin-TaskbarApps, Unpin-TaskbarApps -SkipExplorerRestart

Optimized for Windows 11 (Build 26100+). The empty layout XML is written directly to the machine-local TaskbarLayoutFile (C:\ProgramData\provisioning\taskbar_layout.xml), registered as StartLayoutFile, and the layout is locked via LockedStartLayout - no repo file and no symlink are involved. -FromBootstrap is used internally during bootstrap: it skips the Explorer restart, defers the layout lock to the caller, and passes -SkipExplorerRestart down to Clear-TaskbarPins.

Parameter Description
-SkipExplorerRestart Skips the Explorer restart after clearing pins.
-FromBootstrap Internal use during bootstrap; skips the Explorer restart and defers locking the layout to the caller.
# Clear taskbar pins and apply the locking policy (restarts Explorer)
Unpin-TaskbarApps

# Clear and apply the policy without restarting Explorer (caller handles restart)
Unpin-TaskbarApps -SkipExplorerRestart

See also: Configure-Taskbar, Clear-TaskbarPins

  • Description: Scans directories under a given path for names ending in a date suffix (YYYY_MM_DD) and renames them so the date becomes today's date. Use -WhatIf to preview changes without renaming. Directories already carrying today's date are reported as up to date.
  • Parameters: -Path, -WhatIf
  • Usage: Update-DirectoryNames, Update-DirectoryNames -Path "C:\My Folders", Update-DirectoryNames -Path "C:\My Folders" -WhatIf

Only directories whose name ends in three underscore-separated segments matching YYYY, MM, and DD are considered. The trailing date is replaced with the current date while any leading name segments are preserved (for example MyDocs_2024_01_15 becomes MyDocs_2026_06_24). Rename failures are caught and reported per directory, and when nothing needs changing a summary line confirms all directories are up to date.

Parameter Description
-Path Root directory to scan for dated subdirectory names. Defaults to the current location.
-WhatIf Shows what would be renamed without performing any changes.
# Update all dated directories in the current location
Update-DirectoryNames

# Preview changes for a specific path without renaming anything
Update-DirectoryNames -Path "C:\My Folders" -WhatIf
  • Description: Upgrades all packages across the package managers WinuX actually uses on this machine, resolved by Resolve-PackageManagers: listed in PackageManagers in Configuration.psd1 and holding at least one app for this machine type. Version-pinned apps are never upgraded. Without -PackageManager it upgrades every manager in play; with -PackageManager it upgrades exactly the manager(s) named. Bootstrap does not run this by default: BootstrapConfig.Steps.UpgradeAll is opt-in (see Resolve-BootstrapSteps), because the bulk upgrade below touches every package the manager knows about on the machine, not only the ones WinuX installs. Requires administrator privileges.
  • Parameters: -PackageManager
  • Usage: Upgrade-All, Upgrade-All -PackageManager "WinGet", Upgrade-All -PackageManager "WinGet", "Scoop"

For each manager in play the function first confirms the manager's CLI is actually present - a manager this machine never installed is skipped with a warning rather than driven into a guaranteed failure - then follows the same two steps for every manager alike:

  1. Sync-AppPins reconciles that manager's own pin mechanism (winget pin, scoop hold, choco pin) with the app list, pinning version-locked apps and clearing pins for apps back to tracking the latest.
  2. The manager's bulk upgrade runs unconditionally - winget upgrade --all, scoop update *, or choco upgrade all -y - and the manager itself skips what it has pinned.

Success or the failing exit code is reported per manager. The pinned set comes from Get-PinnedApps, which reads the effective list, so a version pinned in a machine-local <name>.local.csv overlay counts too.

Parameter Description
-PackageManager Manager(s) to upgrade: WinGet, Scoop, or Chocolatey. Accepts more than one. Omit to upgrade every manager in play.
# Upgrade every package manager in play on this machine (run as admin)
Upgrade-All

# Upgrade only WinGet packages
Upgrade-All -PackageManager "WinGet"

# Upgrade WinGet and Scoop, leaving Chocolatey alone
Upgrade-All -PackageManager "WinGet", "Scoop"

See also: Sync-AppPins, Get-PinnedApps, Resolve-PackageManagers

Testing

[!NOTE]

  • Description: Waits for browser windows that were sent WM_CLOSE to actually disappear. Close-BrowserWindows POSTS the message, which is asynchronous - the call returns before the browser has even seen it - so Terminate-AllBrowserProcesses used to report success while a window was still standing (a "close all tabs?" or beforeunload dialog waiting for an answer, a download-in-progress prompt, a browser that had not processed the message yet). This polls the supplied handles through Test-WindowVisible until none is a live, visible window any more or the timeout expires, and returns the windows still standing so the caller can retry or report them.
  • Parameters: -Windows, -TimeoutMs (default 4000), -PollIntervalMs (default 100), -Clock
  • Usage: Wait-BrowserWindowsClosed -Windows $windowsToClose, Wait-BrowserWindowsClosed -Windows $survivors -TimeoutMs 2000

Only the windows still open on the previous poll are probed again, and an empty input returns immediately without touching user32. The default budget of four seconds is what a browser with many tabs needs to save its session and exit. The poll is a Wait-Until that reads time and sleeps through the wait clock passed as -Clock (a real New-WaitClock by default), so a test injects a fake clock and asserts the exact poll count with no real waiting.

Parameter Description
-Windows Window objects with a Handle property, as returned by Get-BrowserWindowsByTarget.
-TimeoutMs How long to wait for every window to go. Default 4000.
-PollIntervalMs Delay between checks. Default 100.
-Clock The wait clock (New-WaitClock) to read and sleep through. Defaults to a real one; tests hand in a fake.
$survivors = Wait-BrowserWindowsClosed -Windows $windowsToClose
if ($survivors) { Close-BrowserWindows -WindowsToClose $survivors }

See also: Terminate-AllBrowserProcesses, Test-WindowVisible, Close-BrowserWindows

  • Description: Waits for the console window size to change and returns the new size. After a font-size keystroke Windows Terminal reflows asynchronously, so the size read immediately afterwards is often still the old one; this polls Get-ConsoleWindowSize every -PollIntervalMilliseconds until it differs from -Before, or until -TimeoutMilliseconds passes, and returns the last size read. A timeout is not an error - it is how a keystroke that changed nothing reports itself (Ctrl+0 at the default font, Ctrl+Minus at the minimum font), and the returned size then equals -Before.
  • Parameters: -Before, -TimeoutMilliseconds, [-PollIntervalMilliseconds], [-Clock]
  • Usage: Wait-ConsoleReflow -Before $before -TimeoutMilliseconds 10

It replaces the fixed sleep Invoke-Fastfetch used to take after each keystroke: a fixed wait is either too long on a fast machine or too short on a slow one, where the pre-reflow size was read and the fit misjudged. Polling returns the moment the terminal has moved, and a debug line records either the change and how long it took or the timeout. The poll is a Wait-Until that reads time and sleeps through the wait clock passed as -Clock (a real New-WaitClock by default), so a test injects a fake clock and asserts the exact poll count with no real waiting.

Parameter Type Default Description
-Before object - The size read before the keystroke (Width, Height), from Get-ConsoleWindowSize.
-TimeoutMilliseconds int - How long to keep polling before returning the unchanged size (1-10000).
-PollIntervalMilliseconds int 10 Pause between two reads (1-1000).
-Clock object - The wait clock (New-WaitClock) to read and sleep through. Defaults to a real one; tests hand in a fake.
$before = Get-ConsoleWindowSize
Send-TerminalFontKey -Action Decrease
$after = Wait-ConsoleReflow -Before $before -TimeoutMilliseconds 10
if ($after.Width -eq $before.Width -and $after.Height -eq $before.Height) { "the terminal did not shrink" }

See also: Get-ConsoleWindowSize, Send-TerminalFontKey, Invoke-Fastfetch

System functions are covered by Pester tests in Windows/PowerShell/Modules/Tests/Modules/System/. Use Run-Tests -TestName "System" (or Run-Tests) to validate current behavior after changes.