Skip to content

Instantly share code, notes, and snippets.

@raysubham
Last active May 28, 2026 11:14
Show Gist options
  • Select an option

  • Save raysubham/5330119da4d1b886461f3846fd22d330 to your computer and use it in GitHub Desktop.

Select an option

Save raysubham/5330119da4d1b886461f3846fd22d330 to your computer and use it in GitHub Desktop.
StepSecurity Dev Machine Guard - Windows uninstall script. Cleans agent binary, launcher, loader, scheduled task, ProgramData config + logs, and per-user .stepsecurity dir. See https://github.com/step-security/dev-machine-guard
#Requires -Version 5.1
<#
.SYNOPSIS
Uninstalls StepSecurity Dev Machine Guard from a Windows endpoint.
.DESCRIPTION
Production uninstall delivered via Intune Platform Script (or manual
elevated RDP run). Cleans both install layouts produced by the
PowerShell loader:
Elevated (machine-wide):
C:\Program Files\StepSecurity\
C:\ProgramData\StepSecurity\
Non-elevated (per-user, ALL user profiles on the box):
C:\Users\*\.stepsecurity\
Also removes the scheduled task "StepSecurity Dev Machine Guard" and
stops any running agent + launcher processes.
Logs to %TEMP%\stepsecurity-uninstall.log (kept after uninstall - the
ProgramData log location is itself removed).
Exits non-zero if any tracked artifact survives, so Intune surfaces
the failure in the portal.
.PARAMETER LogPath
Override the log file location. Defaults to
%TEMP%\stepsecurity-uninstall.log.
.NOTES
Deploy as an Intune Platform Script with:
Run as logged-on user : Yes (matches install elevation flow)
Enforce signature check : No (script is unsigned in this repo)
Run script in 64-bit host : Yes
All strings are ASCII-only to survive PS 5.1 ANSI codepage parsing
on non-BOM downloads.
#>
[CmdletBinding()]
param(
[string]$LogPath = (Join-Path $env:TEMP "stepsecurity-uninstall.log")
)
$ErrorActionPreference = 'Continue'
# Fail fast if not running elevated. C:\Program Files + ProgramData removal
# and schtasks /delete all require admin token. PowerShell launched without
# "Run as administrator" gets a UAC-filtered token even for local admins.
$_principal = New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent())
if (-not $_principal.IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator)) {
Write-Host "[FATAL] Run elevated. Right-click PowerShell -> Run as administrator, then rerun." -ForegroundColor Red
exit 2
}
$TASK_NAME = 'StepSecurity Dev Machine Guard'
$PROCESS_NAMES = @(
'stepsecurity-dev-machine-guard',
'stepsecurity-dev-machine-guard-task'
)
$MACHINE_DIRS = @(
'C:\Program Files\StepSecurity',
'C:\ProgramData\StepSecurity'
)
function Get-UserProfileDirs {
# Enumerate all user profile dirs under C:\Users. Skip system + service
# accounts (Public, Default, Default User, All Users) which never hold
# an interactive .stepsecurity install.
$skip = @('Public', 'Default', 'Default User', 'All Users')
Get-ChildItem -LiteralPath 'C:\Users' -Directory -ErrorAction SilentlyContinue |
Where-Object { $skip -notcontains $_.Name } |
ForEach-Object { Join-Path $_.FullName '.stepsecurity' }
}
function Write-Log {
param([string]$Message, [string]$Level = 'INFO')
$line = "[{0}] [{1}] {2}" -f (Get-Date -Format 'yyyy-MM-ddTHH:mm:ssK'), $Level, $Message
Write-Host $line
Add-Content -Path $LogPath -Value $line -ErrorAction SilentlyContinue
}
function Stop-AgentProcesses {
foreach ($name in $PROCESS_NAMES) {
$procs = Get-Process -Name $name -ErrorAction SilentlyContinue
if ($procs) {
Write-Log "Stopping process: $name ($($procs.Count) instance(s))"
$procs | Stop-Process -Force -ErrorAction SilentlyContinue
}
}
}
function Invoke-AgentSelfUninstall {
# Best-effort: let the agent run its own uninstall hooks before we
# blow away the binary. Tolerates missing binary and non-zero exits.
$candidates = @('C:\Program Files\StepSecurity\bin\stepsecurity-dev-machine-guard.exe')
foreach ($u in Get-UserProfileDirs) {
$candidates += (Join-Path $u 'bin\stepsecurity-dev-machine-guard.exe')
}
foreach ($exe in $candidates) {
if (Test-Path -LiteralPath $exe) {
Write-Log "Invoking agent self-uninstall: $exe uninstall"
try {
& $exe uninstall 2>&1 | ForEach-Object { Write-Log " $_" 'AGENT' }
} catch {
Write-Log "Agent self-uninstall threw: $($_.Exception.Message)" 'WARN'
}
}
}
}
function Remove-ScheduledTask {
& schtasks.exe /query /tn $TASK_NAME 2>&1 | Out-Null
if ($LASTEXITCODE -ne 0) {
Write-Log "Scheduled task '$TASK_NAME' not present"
return
}
& schtasks.exe /delete /tn $TASK_NAME /f 2>&1 | ForEach-Object { Write-Log " $_" 'SCHTASKS' }
if ($LASTEXITCODE -eq 0) {
Write-Log "Removed scheduled task: $TASK_NAME"
} else {
Write-Log "Failed to remove scheduled task: $TASK_NAME (exit $LASTEXITCODE)" 'WARN'
}
}
function Remove-Tree {
param([string]$Path)
if (-not (Test-Path -LiteralPath $Path)) {
Write-Log "Not present: $Path"
return
}
try {
Remove-Item -LiteralPath $Path -Recurse -Force -ErrorAction Stop
Write-Log "Removed: $Path"
} catch {
Write-Log "Failed to remove '$Path': $($_.Exception.Message)" 'WARN'
}
}
function Assert-Clean {
$residuals = @()
foreach ($d in $MACHINE_DIRS) {
if (Test-Path -LiteralPath $d) { $residuals += $d }
}
foreach ($u in Get-UserProfileDirs) {
if (Test-Path -LiteralPath $u) { $residuals += $u }
}
& schtasks.exe /query /tn $TASK_NAME 2>&1 | Out-Null
if ($LASTEXITCODE -eq 0) { $residuals += "scheduled task: $TASK_NAME" }
return $residuals
}
# --- main ----------------------------------------------------------------
Write-Log "==== StepSecurity Dev Machine Guard uninstall ===="
Write-Log "User: $env:USERNAME Computer: $env:COMPUTERNAME PSVersion: $($PSVersionTable.PSVersion)"
Stop-AgentProcesses
Invoke-AgentSelfUninstall
Stop-AgentProcesses # second pass: self-uninstall may have spawned children
Remove-ScheduledTask
foreach ($d in $MACHINE_DIRS) { Remove-Tree -Path $d }
foreach ($u in Get-UserProfileDirs) { Remove-Tree -Path $u }
$residuals = Assert-Clean
if ($residuals.Count -gt 0) {
Write-Log "Residual artifacts after uninstall:" 'ERROR'
foreach ($r in $residuals) { Write-Log " - $r" 'ERROR' }
Write-Log "Uninstall FAILED. See $LogPath" 'ERROR'
exit 1
}
Write-Log "Uninstall complete - host is clean."
exit 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment