- PowerShell 100%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
| .forgejo/workflows | ||
| config | ||
| modules | ||
| tests | ||
| tools | ||
| wiki | ||
| .gitignore | ||
| AGENTS.md | ||
| flake.lock | ||
| flake.nix | ||
| README.md | ||
| start.ps1 | ||
TechWizard
TechWizard is the Reinitialized.net TechTools launcher for Windows 11 workstation provisioning, repair, cleanup, profile migration, RMM agent maintenance, and OneDrive duplicate resolution.
The single entry point is start.ps1. It can run from a local checkout or be
launched directly from Forgejo with PowerShell.
TechWizard v2 keeps start.ps1 as a thin bootstrap. Tool metadata now lives in
modules/TechTools.Manifest.psm1, and launcher behavior lives in
modules/TechTools.Launcher.psm1. Domain modules and tool scripts continue to
own the workstation operations.
Contributors can run the portable Pester suite with
nix develop --no-write-lock-file -c pwsh -File ./tests/run-tests.ps1. Forgejo
also runs the full suite under the production Windows PowerShell 5.1 runtime;
both gates must remain green. See AGENTS.md for architecture and
safety contracts.
Quick Start From Forgejo
Open Windows Terminal or PowerShell as Administrator, then run:
Set-ExecutionPolicy Bypass -Scope Process -Force; $RepoBaseUrl = 'https://git.ds.reinitialized.net/reinitialized.net/TechWizard/raw/branch/indev'; & ([scriptblock]::Create((irm "$RepoBaseUrl/start.ps1"))) -RepoBaseUrl $RepoBaseUrl
Set-ExecutionPolicy Bypass -Scope Process -Force relaxes the policy for the
current PowerShell process only, so a strict machine or user Execution Policy
does not block the remote launch. It is not persisted and does not change the
configured Execution Policy.
This downloads start.ps1 from Forgejo, opens the interactive tool menu, and
loads the selected tool, modules, and config files from the same branch.
On a fresh interactive menu launch TechWizard offers to pivot the session into
a temporary superadministrator (it creates the account, signs you out, and the
menu relaunches under that account with maximum privileges). It always asks
first — Proceed? [y/N], where plain Enter declines — and answering n simply
continues in the current session. The pivot is never offered for -Tool or
-AcceptAll launches.
The canonical raw launch examples use
https://git.ds.reinitialized.net/reinitialized.net/TechWizard. If a
reinitialized.studio/TechWizard URL is published for operators, treat it as an
alias only when it resolves to the same repository and branch; otherwise keep
-RepoBaseUrl aligned to the canonical namespace to avoid duplicate cache roots.
To launch a specific tool without the menu:
Set-ExecutionPolicy Bypass -Scope Process -Force
$RepoBaseUrl = 'https://git.ds.reinitialized.net/reinitialized.net/TechWizard/raw/branch/indev'
& ([scriptblock]::Create((irm "$RepoBaseUrl/start.ps1"))) `
-RepoBaseUrl $RepoBaseUrl `
-Tool Repair-Workstation
To run unattended and suppress confirmation prompts, use -AcceptAll with a
specific tool:
Set-ExecutionPolicy Bypass -Scope Process -Force
$RepoBaseUrl = 'https://git.ds.reinitialized.net/reinitialized.net/TechWizard/raw/branch/indev'
& ([scriptblock]::Create((irm "$RepoBaseUrl/start.ps1"))) `
-RepoBaseUrl $RepoBaseUrl `
-Tool Prepare-System `
-AcceptAll
To run only a specific phase, pass -ToolArgs:
Set-ExecutionPolicy Bypass -Scope Process -Force
$RepoBaseUrl = 'https://git.ds.reinitialized.net/reinitialized.net/TechWizard/raw/branch/indev'
& ([scriptblock]::Create((irm "$RepoBaseUrl/start.ps1"))) `
-RepoBaseUrl $RepoBaseUrl `
-Tool Repair-Workstation `
-ToolArgs @{ Phase = 'Cleanup'; Force = $true }
To validate inputs and view the manifest-backed run plan without executing the
tool, add -Preview:
Set-ExecutionPolicy Bypass -Scope Process -Force
$RepoBaseUrl = 'https://git.ds.reinitialized.net/reinitialized.net/TechWizard/raw/branch/indev'
& ([scriptblock]::Create((irm "$RepoBaseUrl/start.ps1"))) `
-RepoBaseUrl $RepoBaseUrl `
-Tool Repair-Workstation `
-ToolArgs @{ Phase = 'Cleanup' } `
-Preview
The interactive menu is a single screen: a TechWizard masthead with host
context (computer, operator, run source, client overlay, elevated-session
badges), the tools grouped by category with continuous numbering and human
display titles, and the recommended new-workstation sequence. You can pick a
tool by number or just type its name or an alias. Interactive launch defaults
to -UiMode Auto, which uses the guided wizard variant where practical:
-UiMode Wizard adds each tool's when-to-use guidance and its
time/data-loss/reboot tag under every entry, while -UiMode Classic keeps one
compact line per tool.
Every menu-driven launch ends in a pre-flight card (what will run, estimated
time, reboot/data-loss expectations, the ordered phase plan with destructive
markers) followed by a gate. When the run includes no destructive phase, Enter
starts it; when it does, the destructive phases are listed and you must type
Y — a bare Enter is refused. E changes your answers, Q returns to the
menu. Because an unexpanded All or Auto selection counts every destructive
phase as in play, the Y form is what you see for a default Repair-Workstation,
Prepare-System or Factory-Reset run. After a run finishes the launcher offers to
return to the menu so you can chain tools without relaunching. The gate and
the return-to-menu prompt only appear on a live interactive console —
-Tool, -AcceptAll, force mode, resume runs, and headless sessions never
see them, so automation behaves exactly as before.
Simple enable/disable utilities (for example Web Sign-In and the Windows Hello
PIN policy) appear as a single menu entry; selecting one opens a small
second-level menu to choose Enable or Disable before the run starts. Launching
those tools directly with -Tool still takes the action from -ToolArgs. Each
tool has its own vocabulary: Web Sign-In takes
-ToolArgs @{ Mode = 'Enable' } or 'Disable', while the Windows Hello PIN
policy takes -ToolArgs @{ Mode = 'Allow' } or 'Prevent'.
Available Tools
The menu is edition-aware: it shows only the tools supported by the current Windows edition (client vs. server / domain controller). On a workstation the client tools below appear; on a domain controller or an RSAT-equipped admin workstation the Active Directory tools appear.
| Tool | Purpose |
|---|---|
Repair-Workstation |
Deep-analyzes the OS and auto-runs only the repair phases a problem was found for — Windows image repair, OEM/Windows updates plus third-party software currency (winget), device-driver detection and repair, profile repair, cleanup, and RMM agent validation and install/repair. A deep Event Viewer analysis (with best-practice maintenance checks) runs as part of Auto only; it is not a hand-selectable phase. |
Factory-Reset |
Resets a workstation to the MSP baseline, preserving RMM while removing non-whitelisted apps and stale profiles. Defaults to Auto: a read-only analysis (image health, updates, bloatware/UI baseline, the app removal plan, break-glass admin state, the account/profile cleanup plan, disk space, RMM health) picks only the phases whose baseline goal is not already satisfied; All forces the full reset. |
Prepare-System |
Analyzes the OS (incl. Event Logs) and auto-runs only the provisioning phases not already satisfied. Its SecurityAgents phase runs first: approved endpoint-security products are retained only after health validation; approved but misconfigured and non-approved supported products are removal targets; unsupported, inconclusive, or failed teardown blocks provisioning. Successful retention or teardown hands off to Debloat, then Apps; any required endpoint-security re-installation remains an external RMM/MDM responsibility. |
Remove-SecurityAgents |
Classifies detected endpoint security as ApprovedHealthy, ApprovedMisconfigured, Unauthorized, Unsupported, or Inconclusive, with a validation-only option. Approved healthy products remain installed; approved but misconfigured products are removed for external re-installation; non-approved supported products are removed. ESET and consumer McAfee use the native teardown engine, while SentinelOne remains detection-only except for its disabled-by-default, externally configured verified vendor-cleaner adapter. Removal requires elevation, dangerous default-No confirmation that -Force cannot bypass, and ShouldProcess. |
SolveOnedriveDuplicates |
Scans and resolves OneDrive duplicate, conflict, and near-duplicate files with backups. |
Restore-OneDriveBackup |
Reverts OneDrive duplicate-resolution operations from a timestamped backup folder. |
Migrate-UserProfile |
Uses USMT hard-link migration to move one local Windows profile into a fresh local account. Must run as NT AUTHORITY\SYSTEM for real migrations (e.g. psexec.exe -i -s powershell.exe -ExecutionPolicy Bypass -File .\tools\Process\Migrate-UserProfile.ps1); an elevated-but-non-SYSTEM launch stops at the SYSTEM gate with that guidance. |
Enable-WebSignIn |
Enables or disables the Web Sign-In credential provider for Entra-joined Windows 11 workstations. |
Set-WindowsHelloPinPolicy |
Allows or prevents Windows from requesting/requiring a Windows Hello PIN (toggles Windows Hello for Business provisioning at the device scope). |
Clear-WindowsHelloPin |
Forcefully clears a selected user profile's Windows Hello PIN (NGC container) — e.g. a leftover PIN enrolled during TAP-based white-glove setup — with backup and best-effort per-SID targeting. |
Set-Microsoft365Apps |
Fully customizes the Microsoft 365 installation per app: add or remove individual Office applications (Word, Excel, Access, Publisher, Teams, OneNote, classic Outlook, ...) via the Office Deployment Tool, or fresh-install a custom app set on a machine without Office. Unattended runs change nothing unless apps are named explicitly; removals and classic-Outlook re-adds require dangerous confirmation. Running Office apps must be closed for the change to apply (Click-to-Run otherwise cancels the silent pass with exit 17006), so detected running apps are force-closed after an explicit dangerous confirmation. |
Test-InternetHealth |
Traces the path to a target and live-monitors every hop's latency, loss, and jitter, PingPlotter-style, on a flicker-free console dashboard with a per-hop latency-history graph. A running point-of-failure diagnosis separates real end-to-end loss from routers that merely rate-limit their ICMP replies (the classic traceroute false positive), names the segment where a real failure enters the path (local network / ISP handoff / internet / destination), and distinguishes problems happening right now from an earlier episode. Q / Esc / Ctrl+C stop it cleanly — final statistics, the diagnosis, and the optional per-hop CSV export survive the stop even in continuous mode. Read-only. |
Repair-MappedDrives |
Makes a user's mapped network drives survive VPN/network reconnects — the permanent fix for "an error occurred while reconnecting X: ... the local device name is already in use" and for "system error 1219" credential conflicts. Discovers the target user's mappings from their registry hive (works from an elevated run-as-different-admin session), converts them to non-persistent, and drives them from two scheduled tasks running under the user's own interactive token (no stored password, no elevation, and fully hidden — the batch scripts run through a wscript launcher so no console window ever flashes on the user's desktop when the network churns): remap at logon and on network/VPN connect (NetworkProfile event 10000, VPN-client-agnostic) with quoted UNC paths and a settle delay, release all drive letters on disconnect (event 10001). Optional per-reconnect saved-credential cleanup for the mapped file servers (the 1219 fix, confirmed separately), a GPO Drive Maps conflict warning, Status and Uninstall modes, and an uninstall rollback that restores classic persistent mappings at the user's next sign-in. |
Clean-ADStaleObjects |
Safely retires stale on-prem AD computer/user objects: scan → report → disable → quarantine, with opt-in permanent purge and a reversible transaction log. (domain controller / RSAT only) |
Clear-ADDisabledAccountGroups |
Strips group memberships from disabled on-prem AD user accounts (their primary group is never touched), with a reversible transaction log so removed memberships can be restored. (domain controller / RSAT only) |
Export-ADGroupMembers |
Exports the members of an on-prem AD group (direct members) to CSV for documentation and access reviews. Read-only. (domain controller / RSAT only) |
Install-Software |
Installs a chosen subset of the supported software catalog (required-tools.psd1) on demand — winget first with the manifest's direct-download fallback — without running the full provisioning flow. |
Find-NetworkAssets |
Discovers and classifies the devices on a network with nmap — printers, servers, domain controllers, hypervisors, NAS, switches/firewalls/APs, VoIP phones, cameras, and workstations — for on-site setup when the documentation is missing. Auto-detects the local subnet (or takes an explicit CIDR/range/host), fingerprints open services and guesses the OS, and exports a grouped inventory as CSV, JSON, and a shareable HTML report. Installs nmap (with the Npcap driver) on demand via winget. Read-only against scanned devices; it is an active scan, so only run it on networks you are authorized to scan. |
Endpoint Security Removal
TechTools.SecurityAgent owns endpoint-security detection, validation, and
removal. TechTools.Debloat never removes endpoint security itself; when its
optional security hook is enabled, it delegates the decision and teardown to
the security-agent module.
Every detected product is assigned one of five fail-closed classifications:
ApprovedHealthy— the product is explicitly listed inApprovedEndpointSecurityProductsand every required health check passes. It remains installed and provisioning may continue.ApprovedMisconfigured— the product is approved to remain, but a conclusive health check finds it unhealthy. It is removed so the approved product can be re-installed cleanly by the external management system.Unauthorized— detection is conclusive, the configured approved list is non-empty, and the supported product is not approved to remain. It becomes a removal target.Unsupported— TechWizard detects endpoint security that its configured teardown path cannot safely handle, including enterprise McAfee/Trellix overlap. It is not removed and later provisioning phases are blocked.Inconclusive— approval, detection, or health cannot be established safely. It is never removed implicitly and later provisioning phases are blocked.
Approval alone is not a health result. For an approved product, validation
requires Windows SecurityCenter2 to report real-time protection enabled and
definitions current; configured vendor services to be present and running (and
Automatic when required); expected install-directory and registry integrity;
driver-service registration where applicable; and configured definition-age
and minimum-version floors. ConsoleVerification can additionally require a
verified external vendor/RMM probe to confirm console connectivity or
enrollment. Inventory and analysis output reports only the existing sanitized
evidence categories and health reason codes; it does not expose paths, command
lines, artifact metadata, or private values.
The lifecycle is configured through an external security-agents.psd1 overlay:
ApprovedEndpointSecurityProductsis the explicit list of products allowed to remain when healthy. An empty list is fail-closed: detected products becomeInconclusive, not implicitly unauthorized, and are not removed.HealthPolicysupplies each approved product'sRequiredServices,RequireAutomaticStart,MaxDefinitionAgeDays, andMinimumVersion. Missing, incomplete, or invalid policy data makes healthInconclusive.ConsoleVerificationoptionally enables a no-argument, externally supplied and verified enrollment/connectivity probe usingEnabled,ArtifactId, andTimeoutSeconds. Disabled verification is optional; enabled but incomplete, unavailable, timed-out, or failed verification makes healthInconclusive. URLs, hashes, signers, tokens, credentials, and client-specific metadata stay in external overlays or the client-artifacts catalog and are not committed to this repository.
Security Center and Add/Remove Programs probes are mandatory for a conclusive
inventory. If either probe is unavailable, incomplete, or errors—or if an
enabled console verification probe cannot complete—the affected detection is
Inconclusive and cannot authorize removal. Configuration overlays may only
narrow the built-in ESET/McAfee artifact catalog; the
UnsupportedUninstallPatterns, UnsupportedServices, and UnsupportedPaths
refusal rules remain immutable.
For supported removal, ESET and consumer McAfee use the product's
registered silent uninstaller when available, followed by catalog-constrained
service, driver, directory, registry, and Security Center cleanup using in-box
Windows facilities. The tool does not bundle or require ESETUninstaller.exe
or MCPR. On attended runs, destructive removal always requires a dangerous,
default-No confirmation that -Force cannot bypass, and mutation remains behind
ShouldProcess. If teardown fails or leaves unexplained evidence, product
metadata is preserved for retry and later provisioning phases remain blocked.
If known artifacts are staged for boot-time deletion, reboot/resume completes
and verifies teardown before provisioning continues.
SentinelOne remains detection-only in the native engine. TechWizard does not apply the ESET/McAfee teardown primitives to it or bypass vendor authorization. A separate, disabled-by-default adapter may invoke only the verified official vendor cleaner when complete metadata is supplied externally through the security overlay and client-artifacts catalog. Missing or invalid adapter data fails closed.
The provisioning order is an explicit contract: SecurityAgents runs first,
Resolve-TechToolsPhaseOrder keeps Debloat before Apps, and only
ApprovedHealthy retention or successfully verified teardown permits those
later phases to run. A removed ApprovedMisconfigured product records an
external re-install handoff; deployment or re-enrollment of approved endpoint
security remains the responsibility of external RMM/MDM tooling, not
TechWizard.
Common Examples
Run workstation repair in automatic mode (the default). Repair-Workstation,
Prepare-System, and Factory-Reset default to Phase = Auto: they first perform
a read-only analysis of the operating system — including Event Logs, image health,
device-driver problems, pending reboot, free disk space, profile corruption, RMM
agent health, OEM, bloatware, required tools, UI defaults, domain/Entra-join state,
and (for Factory-Reset) the non-whitelisted app removal plan, break-glass
administrator state, and the account/profile cleanup plan — print a report, and
then run only the phases whose goal is not already satisfied, in the canonical
dependency order. When a probe is inconclusive the phase still runs, so analysis
never silently skips needed work. Use Phase = 'All' to force every selectable
phase, or name individual phases (Repair, Updates, Drivers, Profile,
Cleanup, RMMAgent) to run exactly those. The deep Event Viewer analysis runs
only as part of Repair-Workstation's Auto; it is not selectable by name and
All does not run it.
Set-ExecutionPolicy Bypass -Scope Process -Force
$RepoBaseUrl = 'https://git.ds.reinitialized.net/reinitialized.net/TechWizard/raw/branch/indev'
& ([scriptblock]::Create((irm "$RepoBaseUrl/start.ps1"))) `
-RepoBaseUrl $RepoBaseUrl `
-Tool Repair-Workstation
Force every repair phase regardless of analysis:
Set-ExecutionPolicy Bypass -Scope Process -Force
$RepoBaseUrl = 'https://git.ds.reinitialized.net/reinitialized.net/TechWizard/raw/branch/indev'
& ([scriptblock]::Create((irm "$RepoBaseUrl/start.ps1"))) `
-RepoBaseUrl $RepoBaseUrl `
-Tool Repair-Workstation `
-ToolArgs @{ Phase = 'All' }
Run only updates and cleanup:
Set-ExecutionPolicy Bypass -Scope Process -Force
$RepoBaseUrl = 'https://git.ds.reinitialized.net/reinitialized.net/TechWizard/raw/branch/indev'
& ([scriptblock]::Create((irm "$RepoBaseUrl/start.ps1"))) `
-RepoBaseUrl $RepoBaseUrl `
-Tool Repair-Workstation `
-ToolArgs @{ Phase = @('Updates', 'Cleanup') }
Prepare a workstation, including debloat and UI standardization:
Set-ExecutionPolicy Bypass -Scope Process -Force
$RepoBaseUrl = 'https://git.ds.reinitialized.net/reinitialized.net/TechWizard/raw/branch/indev'
& ([scriptblock]::Create((irm "$RepoBaseUrl/start.ps1"))) `
-RepoBaseUrl $RepoBaseUrl `
-Tool Prepare-System `
-ToolArgs @{ Phase = @('Debloat', 'Apps', 'UI') }
Customize the Microsoft 365 app set on one machine — drop Publisher and Access, add OneNote — without prompts (unattended changes require naming the apps; force mode alone never removes anything):
Set-ExecutionPolicy Bypass -Scope Process -Force
$RepoBaseUrl = 'https://git.ds.reinitialized.net/reinitialized.net/TechWizard/raw/branch/indev'
& ([scriptblock]::Create((irm "$RepoBaseUrl/start.ps1"))) `
-RepoBaseUrl $RepoBaseUrl `
-Tool Set-Microsoft365Apps `
-ToolArgs @{ RemoveApps = @('Publisher', 'Access'); AddApps = @('OneNote'); Force = $true }
Run it with no arguments for an interactive review of the current per-app state
and add/remove menus; -ToolArgs @{ StatusOnly = $true } reports the state and
changes nothing.
Inventory stale Active Directory objects without making any changes (run on a domain controller or RSAT-equipped admin workstation):
Set-ExecutionPolicy Bypass -Scope Process -Force
$RepoBaseUrl = 'https://git.ds.reinitialized.net/reinitialized.net/TechWizard/raw/branch/indev'
& ([scriptblock]::Create((irm "$RepoBaseUrl/start.ps1"))) `
-RepoBaseUrl $RepoBaseUrl `
-Tool Clean-ADStaleObjects `
-ToolArgs @{ Phase = @('Scan', 'Report') }
The full pipeline disables then quarantines stale objects; permanent deletion is
opt-in and only runs with AllowHardDelete:
& ([scriptblock]::Create((irm "$RepoBaseUrl/start.ps1"))) `
-RepoBaseUrl $RepoBaseUrl `
-Tool Clean-ADStaleObjects `
-ToolArgs @{ Phase = @('All'); AllowHardDelete = $true }
Discover and classify the devices on the local network (auto-detected) with a
standard scan — installs nmap on demand and writes CSV/JSON/HTML inventories
under C:\TechWizard\Logs\Find-NetworkAssets:
Set-ExecutionPolicy Bypass -Scope Process -Force
$RepoBaseUrl = 'https://git.ds.reinitialized.net/reinitialized.net/TechWizard/raw/branch/indev'
& ([scriptblock]::Create((irm "$RepoBaseUrl/start.ps1"))) `
-RepoBaseUrl $RepoBaseUrl `
-Tool Find-NetworkAssets
Scan a specific subnet thoroughly and skip all prompts (Force authorizes the
scan and accepts the on-demand nmap install):
& ([scriptblock]::Create((irm "$RepoBaseUrl/start.ps1"))) `
-RepoBaseUrl $RepoBaseUrl `
-Tool Find-NetworkAssets `
-ToolArgs @{ Target = '192.168.10.0/24'; Profile = 'Thorough'; Force = $true }
Fast host-discovery sweep of two subnets (host list + MAC/vendor, no port scan):
& ([scriptblock]::Create((irm "$RepoBaseUrl/start.ps1"))) `
-RepoBaseUrl $RepoBaseUrl `
-Tool Find-NetworkAssets `
-ToolArgs @{ Target = '10.0.0.0/24 10.0.1.0/24'; Profile = 'Discovery' }
Debloat Coverage (All Accounts, Aggressive)
The Debloat phase removes detected UWP and Win32 bloat with the coverage of an aggressive "scan all Windows accounts" uninstaller pass:
- AppX/UWP: matching packages are removed for every user account
(
Remove-AppxPackage -AllUsers) and deprovisioned so new users never get them; leftover per-userAppData\Local\Packages\<family>state folders for removed families are scrubbed across all profiles. An explicit target profile keeps removal scoped to that one account. - Win32: the Uninstall hives of the machine, every logged-on user, and —
by default — every offline profile (their
NTUSER.DATis loaded for the pass and unloaded afterwards) are enumerated. Silent uninstall is attempted first (MSI/qn,QuietUninstallString, optional winget fallback); after a successful uninstall, remnants (orphaned Uninstall key, leftover install directory, dead Start Menu shortcuts) are cleaned. When no silent uninstaller exists or it fails, the program is force-removed (its services stopped, disabled, and deregistered; its processes stopped; its install directory deleted within approved roots — falling back to the uninstaller's own directory when the entry records no install location; its Uninstall key and shortcuts removed) — confirmed once per run as a dangerous action, auto-approved only in force/unattended mode. Locked or ACL-protected leftovers escalate automatically: ownership/ACL reset and retry, then per-item deletion, and finally reboot-time deletion via the Windows pending-file-rename mechanism, which runs at early boot before any service can re-lock its files. The Uninstall registry entry is never deleted while a program's files remain un-handled (unless its own uninstaller already ran), so the official uninstall path always stays available.
Every safety layer still applies: the essential AppX and Win32 allowlists,
the publisher allowlist, the SystemComponent guard, product-wide sibling
protection, the RMM no-touch policy, and a strict approved-deletion-root
check that refuses to delete anything outside Program Files,
Program Files (x86), ProgramData, or a profile's AppData (and never
OS-owned subtrees such as Windows, WindowsApps, Windows Defender, or
ProgramData\Microsoft). The toggles live in config/debloat-settings.psd1
(AppxRemoveAllUsers, AppxRemoveLeftoverData, Win32ScanAllUserProfiles,
Win32LeftoverCleanup, Win32ForcedRemovalFallback), all enabled by default.
Local Checkout
git clone https://git.ds.reinitialized.net/reinitialized.net/TechWizard.git
cd TechWizard
powershell -ExecutionPolicy Bypass -File .\start.ps1
Launch a specific local tool:
powershell -ExecutionPolicy Bypass -File .\start.ps1 -Tool Repair-Workstation
Requirements
- Run from an elevated PowerShell session.
- Target runtime is Windows PowerShell 5.1, which ships in-box with every
supported build of Windows. No separate PowerShell runtime is downloaded or
installed;
start.ps1runs directly under the host shell. - TechWizard runs on every platform that supports Windows PowerShell 5.1 — Windows 7 SP1 / Server 2008 R2 (via WMF 5.1) through current Windows 11 / Server 2025. Features tied to a newer NT release (AppX removal, DISM component-store repair, winget, pnputil device rescans, Entra join, Windows Hello, Web sign-in, local-account cmdlets, Windows 11 taskbar alignment) are gated by release feature flags resolved during the read-only analysis pass: on an older release each gated step is skipped with a warning (or fails loudly up front when the work is required), and the analysis report lists which features the host lacks. Nothing hard-fails mid-phase because the OS predates a feature.
- Target workstations must be able to reach
https://git.ds.reinitialized.net/reinitialized.net/TechWizard/raw/branch/indev. - If the Forgejo repository is private, use a local checkout or expose a read-only raw URL reachable by the workstation before launching remotely.
Branches And Overrides
The examples above use the indev branch. To launch another branch, change the
branch segment in RepoBaseUrl:
Set-ExecutionPolicy Bypass -Scope Process -Force
$RepoBaseUrl = 'https://git.ds.reinitialized.net/reinitialized.net/TechWizard/raw/branch/main'
& ([scriptblock]::Create((irm "$RepoBaseUrl/start.ps1"))) -RepoBaseUrl $RepoBaseUrl
-RepoBaseUrl is intentionally included in the remote commands so every
downloaded script, module, and config file comes from the same Forgejo branch.
Version Banner
Every launch prints a banner naming the product version, branch, and running commit, then compares the running commit to the branch tip via the Forgejo commits API:
- Local checkout: the running commit is read from
.gitand compared to the branch tip. A warning is printed when the checkout is behind. - Remote
irm/iexlaunch: there is no.gitdirectory. When every bootstrap module was freshly downloaded, the running code is the branch tip by construction; the tip SHA is adopted, reported, and stamped into the module cache (commit.jsonin the cache root). When a later launch cannot reach the repository and falls back to cached modules, that stamp names the running commit. A cached snapshot that was validated against the branch tip is reported as up to date; only a cache that is behind, or that could not be validated, is reported as a warning. The check is best-effort and never blocks a launch: with no network and no stamp, the banner says the version could not be verified.
Client Configuration Overlays
Org- and client-specific values — real RMM SERVERADDRESS/SERVERPASS, the
managed ScreenConnect ExpectedInstanceHost/ExpectedInstanceId, location
ids — are secrets and must never be committed to this repository. They live in
an external config root (a mapped work Google Drive letter, a UNC share, or
the local drop C:\TechWizard\client-config) with this layout:
<root>\generic\rmm-agent.psd1 org-wide overrides
<root>\clients\AcmeCorp\rmm-agent.psd1 per-client overrides
Overlay files mirror the repo's config/*.psd1 names and contain only the
keys being overridden; they are deep-merged over the repo defaults (generic
first, then the selected client) every time a config file is loaded, so all
tools pick them up automatically. Scalars and arrays in an overlay replace the
base value; nested hashtables merge.
Select the root and client at launch:
& ([scriptblock]::Create((irm "$RepoBaseUrl/start.ps1"))) -RepoBaseUrl $RepoBaseUrl `
-ClientConfigPath 'G:\TechWizard' -Client 'AcmeCorp'
Example G:\TechWizard\generic\rmm-agent.psd1 overlay that fills in the real
Automate install values and pins the managed ScreenConnect instance without
touching the repo:
@{
Agents = @{
Automate = @{
InstallArgs = @{
SERVERADDRESS = 'https://automate.example.com'
SERVERPASS = 'RealEncryptedServerPassword'
LOCATION = '42'
}
RequiredComponents = @(
@{
DisplayName = 'Managed ScreenConnect Access Agent'
Type = 'ScreenConnect'
ServiceNamePattern = 'ScreenConnect Client*'
RequiredRole = 'Access'
ExpectedInstanceHost = 'instance-abc123.screenconnect.example.com'
ExpectedInstanceId = ''
}
)
}
}
}
Notes:
- Only a pointer (root path + client name) is persisted locally in
C:\TechWizard\client-context.jsonso reboot/resume finds the same context; secret values are read from the external root at load time and are never copied there in cleartext. A run that reboots does persist the secrets it already resolved toC:\TechWizard\resume-secrets.json, DPAPI-protected and ACL'd to SYSTEM plus Administrators, so the resumed run can finish; that file is removed with the rest of the resume state byRemove-ResumeState. - A per-user mapped drive letter may be absent in a resumed session; prefer a
UNC path, or copy the overlays to
C:\TechWizard\client-configfor runs that reboot. RMM install values resolved before a reboot are already carried through resume by the existing runtime-value capture. - A configured-but-unreachable root logs a warning and the run continues on repo defaults; RMM readiness checks still fail loudly on unresolved placeholders, so a lost overlay cannot silently install with dummy values.
- Access to the overlay store is governed by the drive/share ACLs; keep the root readable only by technicians.
- Overlays are a convenience, not a requirement: on an attended run without an
overlay (an independent run), Prepare-System keeps the RMM phase in its
Autoplan, asks which supported RMM agent to install when more than one is configured, prompts for the missing install values, and carries both the choice and the values through reboot resume. Unattended runs without resolvable values still skip an optional agent (and fail loudly on a required one).
Logs And Resume
TechWizard writes logs, downloads, backups, and reboot resume state under
C:\TechWizard\. Tools that require a reboot save resume state and relaunch
through start.ps1 after Windows restarts.
The default unattended resume path writes C:\TechWizard\resume-state.json,
writes C:\TechWizard\resume.ps1, and registers the startup scheduled task
TechToolsResumeAsSystem as NT AUTHORITY\SYSTEM. This is intended for
unattended/session-0 resume and can be visible in RMM Backstage when the RMM
exposes session 0.
When Prepare-System must reboot after domain/Entra join and the active RMM agent
cannot be verified, TechWizard requests the visible-console fallback instead:
it creates a temporary local administrator, configures one AutoAdminLogon,
registers TechToolsResumeOnTempAdminLogon, clears the AutoAdminLogon password
as soon as the bootstrap starts, and cleans up the temporary account after the
resumed run.
Before arming AutoAdminLogon, TechWizard temporarily neutralizes the settings
that make Windows silently ignore it — the Windows 11 "require Windows Hello
sign-in" enforcement (DevicePasswordLessBuildVersion) and any legal-notice
sign-in banner — recording the originals in
C:\TechWizard\autologon-blockers.json and restoring them when the resume
starts (or on teardown/failure recovery). The armed Winlogon values are read
back and verified; if arming cannot be verified the reboot is refused instead
of stranding the machine. AutoAdminLogon is armed with an AutoLogonCount of 3
(not 1) because Windows Update servicing can consume auto-logon counts on
intermediate boot transitions; the bootstrap clears all remaining auto-logon
state the moment it runs, so no surplus logon ever fires. Every
resume-carrying auto-logon arming also
registers TechToolsResumeWatchdog, a SYSTEM startup task delayed 10 minutes
past boot: if the interactive auto-logon never signs in (GPO banner re-applied,
sign-in blocked by policy), the watchdog picks the run up — and when the resume
was armed for a visible temporary-admin session, it first RE-ARMS the
auto-logon (fresh password, blockers re-suspended) and reboots so the run
comes back on the visible console; only after the re-arm attempt cap (2) does
it fall back to resuming headless in session 0, so a blocked logon can no
longer strand a half-provisioned machine at the sign-in screen.
If the auto-logon fails and a technician signs into a DIFFERENT admin account
and relaunches TechWizard, the pending resume is no longer silently adopted by
that account: the launcher detects the mismatch and offers to sign the
technician out and hand the run back to the TechWizard temporary account
(Enter declines and continues the resume in the current session instead). If
the resume is already running live in another session (for example the SYSTEM
watchdog picked it up), a relaunch reports where it is running instead of
starting a second copy. Re-launching with -CancelResume still abandons a
pending resume entirely.
Manual resume validation checklist:
- Trigger a controlled reboot-required condition or mock the resume handoff.
- Before reboot, verify
Get-ScheduledTask -TaskName TechToolsResumeAsSystem,Test-Path C:\TechWizard\resume-state.json, andTest-Path C:\TechWizard\resume.ps1. - Reboot and do not log in.
- From RMM Backstage/session 0, verify a
powershellprocess starts and the new log containsResuming previous TechTools session. - Verify the remaining phases run and cleanup removes
resume-state.json,resume.ps1, and the scheduled task after success.
Visible-console fallback validation:
- Trigger a domain/Entra reboot handoff without a healthy active RMM agent.
- Before reboot, verify
C:\TechWizard\temp-admin.json,C:\TechWizard\resume-state.json,C:\TechWizard\resume.ps1,TechToolsResumeOnTempAdminLogon, and the one-time Winlogon AutoAdminLogon values. - After reboot, verify the temporary administrator signs in, a visible
PowerShell console resumes TechWizard, and the new log contains
Resuming previous TechTools session. - Verify cleanup removes the resume files, scheduled tasks, Winlogon password, and temporary administrator.
Phase Outcomes And Retry Policy
Every phase of a multi-phase tool reports one canonical outcome. The outcome decides whether the phase is retried, whether the run continues, and what the technician is told — so the vocabulary distinguishes why a phase did not succeed, not merely that it didn't.
| Outcome | Meaning | Retried? |
|---|---|---|
Completed |
The phase goal was achieved. | — |
CompletedWithWarnings |
Goal achieved; something optional was skipped or degraded. | — |
Skipped |
Nothing to do, or an earlier critical phase stopped it. | — |
Deferred |
A precondition this run can satisfy itself is unmet — most often a pending reboot ahead of an MSI install. | Yes, after the reboot. |
Blocked |
A deterministic condition outside the run's control is unmet. Re-running unattended produces the identical result. Carries an operator remedy. | No. |
Failed |
The goal failed for a reason that may be transient. | Yes, up to the attempt limit. |
RebootInitiated |
The phase armed a reboot and handed off. | — |
Unverified |
The phase returned nothing a canonical outcome could be read from. Any unrecognised status grades here. | No. |
Blocked and Deferred are not completions and never count toward the
session's completed phases.
Bounded retries
C:\TechWizard\resume-state.json carries a per-phase attempt ledger. A Failed
phase is retried after the next reboot; once it has spent 2 attempts it
converts to Blocked, stops being the resume continuation point, and the run
proceeds through its remaining phases instead of retrying it forever.
This exists because a deterministic environmental failure previously retried
without limit. A real provisioning session met a client network doing TLS
inspection, which broke every winget install; the Apps phase failed and was
re-queued on every following reboot. A failed phase cannot arm a reboot itself,
so it rode along on other phases' reboots — six reboots and three identical
failures, ending only because the last run happened to contain no phase that
requested a seventh. A blocked phase now states its remedy once and gets out of
the way.
A global reboot budget (12 automatic reboots per session, also tracked in the resume state) is the outer backstop. It is a runaway guard rather than a schedule, so it sits well above the worst legitimate run; when it is exhausted TechWizard refuses to arm another reboot and names the phases still outstanding.
Preconditions
Phases that drive MSI installs — Apps and RMMAgent — do not start while a
reboot is pending. Windows Installer fails such installs with the generic fatal
error 1603 (MsiSystemRebootPending=1), which previously looked like a broken
installer or resident security software. They now report Deferred, take one
reboot, and run cleanly.
Reading the summary
The execution summary reports each outcome as its own bucket, separates the current run from the whole session, and always prints the remedy for a blocked phase:
Apps : Blocked: winget cannot verify its source's pinned TLS certificate
Remedy: SSL/TLS inspection on this network breaks the winget source.
Exempt the winget CDN from inspection, or supply DownloadURL
fallbacks for the required tools, then re-run -Phase Apps.
Completed phases (this run): Updates, Debloat. Completed with warnings: none.
Blocked phases: Apps. Deferred phases: none. Failed phases: none.
Skipped phases: none. Completed phases (session total): SecurityAgents, Updates,
Debloat, UI.
Earlier versions derived the summary only from the current run's phase table, so
the final run of a multi-reboot session could report "Completed phases: none"
after five phases had in fact completed in earlier runs. A hard RMM install
failure was also reported under "Completed phases", because
CompletedWithWarnings was folded into that bucket.
Required tools
Required in config/required-tools.psd1 decides whether a tool's absence is a
phase failure. The shipped baseline marks Microsoft Edge, 7-Zip, Adobe Acrobat
Reader and VLC as required, along with Microsoft 365 (config/microsoft-365.psd1)
and the RMM agent (config/rmm-agent.psd1). Redistributables, .NET runtimes,
Temurin JREs and Zoom stay optional.
A required tool that cannot be installed for an environmental reason — a
proxy breaking the package source, no network — reports Blocked, not Failed:
retrying on the same network cannot succeed, so the run reports the remedy and
continues. Only a genuine, non-environmental failure of a required tool fails the
phase.
Resume state schema
resume-state.json is versioned (SchemaVersion) and carries a RunId
identifying one logical provisioning session across all of its reboots. State
written by a newer build than the one reading it is refused rather than guessed
at field by field. The completed-phase history is matched on RunId; it
previously relied on an exact ordered match of the saved phase list, so any
change to the phase set silently discarded the whole session history.
Domain join targets
The -OUPath target is structurally checked during the initial preflight. On a
workgroup machine the directory bind may remain inconclusive until the join
credential is available; TechWizard says so explicitly, then validates the
target with that credential before calling Add-Computer. An OU or container
proved not to exist reports Blocked with the exact remedy instead of failing
inside Add-Computer with The system cannot find the file specified (0x2),
which is also mapped to an actionable diagnosis.
When a technician is at the console, an invalid target opens the directory
browser instead so the correct destination can be selected. The browser lists
both organizational units and containers — CN=Computers is the most common
legitimate target and was previously unselectable — and shows each entry's object
class. TechWizard never silently substitutes the domain's default computer
container.