<#
.SYNOPSIS
Thorough removal of Node.js, npm, global modules, shims, and n8n.
.DESCRIPTION
Removes all Node.js and npm-related components from Windows.
Backs up ~/.n8n before removing it.
Safe to run repeatedly. Fully idempotent.
#>
$ErrorActionPreference = "Stop"
Write-Host "=== Full Uninstall: Node.js, npm, n8n ==="
# ---------------------------------------------------------------
# PRE-CLEANUP STATE REPORT
# ---------------------------------------------------------------
function Get-SystemState {
Write-Host ""
Write-Host "=== System State Before Cleanup ==="
# 1. Node.js MSI entries
$unKeys = @(
"HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*",
"HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*"
)
$msiEntries = Get-ItemProperty -Path $unKeys -ErrorAction SilentlyContinue |
Where-Object { $_.DisplayName -like "*Node.js*" }
Write-Host "Node MSI entries: $($msiEntries.Count)"
# 2. Node folders
$nodeFolders = @(
"C:\Program Files\nodejs",
"C:\Program Files (x86)\nodejs",
"$env:LOCALAPPDATA\Programs\nodejs"
) | Where-Object { Test-Path $_ }
Write-Host "Node folders: $($nodeFolders.Count)"
# 3. npm folders
$npmFolders = @(
"$env:APPDATA\npm",
"$env:APPDATA\npm-cache",
"$env:USERPROFILE\.npm"
) | Where-Object { Test-Path $_ }
Write-Host "npm folders: $($npmFolders.Count)"
# 4. Shims in PATH
$shimNames = @("npm.cmd","npm.ps1","npx.cmd","npx.ps1","corepack.cmd","corepack.ps1","n8n.cmd","n8n.ps1")
$shimHits = @()
foreach ($dir in ($env:PATH -split ";")) {
foreach ($name in $shimNames) {
$cand = Join-Path $dir $name
if (Test-Path $cand) { $shimHits += $cand }
}
}
Write-Host "Shims in PATH: $($shimHits.Count)"
# 5. Stray executables
$exeNames = @("node","npm","npx","corepack","n8n")
$exeHits = @()
foreach ($name in $exeNames) {
$cmd = Get-Command $name -ErrorAction SilentlyContinue
if ($cmd) { $exeHits += $cmd.Source }
}
Write-Host "Stray executables: $($exeHits.Count)"
# 6. .n8n folder
$n8nDir = Join-Path $env:USERPROFILE ".n8n"
$exists = Test-Path $n8nDir
Write-Host ".n8n directory: $([bool]$exists)"
Write-Host "==================================="
# If nothing requires removal, exit immediately.
if (
$msiEntries.Count -eq 0 -and
$nodeFolders.Count -eq 0 -and
$npmFolders.Count -eq 0 -and
$shimHits.Count -eq 0 -and
$exeHits.Count -eq 0 -and
-not (Test-Path $n8nDir)
) {
Write-Host "Nothing to remove. System is already clean."
exit
}
# Otherwise ask user before performing destructive cleanup.
$choice = Read-Host "Proceed with aggressive cleanup? (Y/N)"
if ($choice -notmatch "^[Yy]$") {
Write-Host "Aborted by user."
exit
}
}
# Run diagnostic before uninstall begins
Get-SystemState
# ---------------------------------------------------------------
# BACKUP .n8n BEFORE REMOVAL
# ---------------------------------------------------------------
function Backup-N8N {
$n8nDir = Join-Path $env:USERPROFILE ".n8n"
if (-not (Test-Path $n8nDir)) {
Write-Host "No .n8n directory found. Skipping backup."
return
}
Write-Host "Backing up .n8n before removal..."
$timestamp = Get-Date -Format "yyyy-MM-dd_HH-mm-ss"
$backupRoot = Join-Path $env:USERPROFILE "Desktop\n8n-backups"
$zipPath = Join-Path $backupRoot "n8n-backup-$timestamp.zip"
$tempCopy = Join-Path $env:TEMP "n8n-backup-$timestamp"
if (-not (Test-Path $backupRoot)) {
New-Item -ItemType Directory -Path $backupRoot | Out-Null
}
if (Test-Path $tempCopy) {
Remove-Item $tempCopy -Recurse -Force
}
New-Item -ItemType Directory -Path $tempCopy | Out-Null
try {
Copy-Item "$n8nDir\*" $tempCopy -Recurse -Force
Compress-Archive -Path $tempCopy -DestinationPath $zipPath -Force
}
finally {
if (Test-Path $tempCopy) {
Remove-Item $tempCopy -Recurse -Force
}
}
$sizeMB = [math]::Round((Get-Item $zipPath).Length / 1MB, 1)
Write-Host "Backup complete ($sizeMB MB) --> $zipPath"
Write-Host "Removing .n8n directory..."
Remove-Item $n8nDir -Recurse -Force -ErrorAction SilentlyContinue
}
# ---------------------------------------------------------------
# REMOVE n8n (GLOBAL MODULE + SHIMS)
# ---------------------------------------------------------------
function Remove-N8N {
Write-Host ""
Write-Host "Removing n8n..."
$npm = Get-Command npm -ErrorAction SilentlyContinue
if ($npm) {
try { npm uninstall -g n8n 2>$null } catch {}
}
$paths = @(
(Join-Path $env:APPDATA "npm\node_modules\n8n")
(Join-Path $env:APPDATA "npm\n8n.cmd")
(Join-Path $env:APPDATA "npm\n8n.ps1")
)
foreach ($p in $paths) {
if (Test-Path $p) {
Write-Host "Deleting: $p"
Remove-Item $p -Recurse -Force -ErrorAction SilentlyContinue
}
}
Write-Host "n8n removal complete."
}
# ---------------------------------------------------------------
# REMOVE NODE.JS MSI INSTALLATIONS
# ---------------------------------------------------------------
function Remove-NodeMSI {
Write-Host ""
Write-Host "Removing Node.js MSI installations..."
$unKeys = @(
"HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*",
"HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*"
)
$products = Get-ItemProperty -Path $unKeys -ErrorAction SilentlyContinue |
Where-Object { $_.DisplayName -like "*Node.js*" }
foreach ($p in $products) {
$u = $p.UninstallString
if ($u -match "{[0-9A-Fa-f\-]+}") {
$guid = [regex]::Match($u, "{[0-9A-Fa-f\-]+}").Value
Write-Host "Uninstalling Node.js MSI: $guid"
Start-Process msiexec.exe -Wait -ArgumentList "/x $guid /quiet /norestart"
}
elseif ($u) {
Write-Host "Running uninstall command: $u"
Start-Process cmd.exe -Wait -ArgumentList "/c `"$u`""
}
}
Write-Host "Node MSI removal complete."
}
# ---------------------------------------------------------------
# REMOVE ALL NODE AND NPM FOLDERS
# ---------------------------------------------------------------
function Remove-NodeFolders {
Write-Host ""
Write-Host "Removing Node.js and npm folders..."
$folders = @(
"C:\Program Files\nodejs",
"C:\Program Files (x86)\nodejs",
"$env:LOCALAPPDATA\Programs\nodejs",
"$env:APPDATA\npm",
"$env:APPDATA\npm-cache",
"$env:USERPROFILE\.npm",
"$env:USERPROFILE\.node-gyp",
"$env:USERPROFILE\.node_repl_history"
)
foreach ($f in $folders) {
if (Test-Path $f) {
Write-Host "Deleting folder: $f"
Remove-Item $f -Recurse -Force -ErrorAction SilentlyContinue
}
}
Write-Host "Folder cleanup complete."
}
# ---------------------------------------------------------------
# REMOVE SHIMS (npm, npx, corepack, n8n)
# ---------------------------------------------------------------
function Remove-Shims {
Write-Host ""
Write-Host "Removing npm, npx, corepack, and n8n shims..."
$names = @(
"npm.cmd","npm.ps1",
"npx.cmd","npx.ps1",
"corepack.cmd","corepack.ps1",
"n8n.cmd","n8n.ps1"
)
$searchDirs = ($env:PATH -split ";")
foreach ($dir in $searchDirs) {
foreach ($name in $names) {
$cand = Join-Path $dir $name
if (Test-Path $cand) {
Write-Host "Removing shim: $cand"
Remove-Item $cand -Force -ErrorAction SilentlyContinue
}
}
}
}
# ---------------------------------------------------------------
# CLEAN PATH ENTRIES
# ---------------------------------------------------------------
function Remove-PathEntries {
Write-Host ""
Write-Host "Cleaning PATH entries..."
$patterns = @("nodejs","npm","node","corepack","n8n")
$clean = {
param($scope)
$path = [Environment]::GetEnvironmentVariable("Path",$scope)
if (-not $path) { return }
$parts = $path -split ";"
$filtered = $parts | Where-Object {
$remove = $false
foreach ($p in $patterns) {
if ($_ -match $p) { $remove = $true }
}
-not $remove
}
$new = ($filtered -join ";")
[Environment]::SetEnvironmentVariable("Path",$new,$scope)
Write-Host "Cleaned $scope PATH."
}
$clean.Invoke("Machine")
$clean.Invoke("User")
$env:PATH = (
[Environment]::GetEnvironmentVariable("Path","Machine") + ";" +
[Environment]::GetEnvironmentVariable("Path","User")
)
}
# ---------------------------------------------------------------
# REMOVE STRAY EXECUTABLES ANYWHERE IN PATH
# ---------------------------------------------------------------
function Remove-StrayExecutables {
Write-Host ""
Write-Host "Checking for leftover executables..."
$names = @("node","npm","npx","corepack","n8n")
foreach ($exe in $names) {
$cmd = Get-Command $exe -ErrorAction SilentlyContinue
if ($cmd) {
Write-Host "Deleting stray executable: $($cmd.Source)"
try { Remove-Item $cmd.Source -Force -ErrorAction SilentlyContinue } catch {}
}
}
}
# ---------------------------------------------------------------
# EXECUTE ALL STEPS
# ---------------------------------------------------------------
Backup-N8N
Remove-N8N
Remove-NodeMSI
Remove-NodeFolders
Remove-Shims
Remove-PathEntries
Remove-StrayExecutables
Write-Host ""
Write-Host "All components removed."
Write-Host "System is clean and ready for fresh installation tests."
Comments
0 B
|👍
/👎
0 B
|👍
/👎
0 B
|👍
/👎
0 B
|👍
/👎
0 B
|👍
/👎
0 B
|👍
/👎
0 B
|👍
/👎
0 B
|👍
/👎
0 B
|👍
/👎
0 B
|👍
/👎
0 B
|👍
/👎
0 B
|👍
/👎
0 B
|0 👍
/0 👎
0 B
|0 👍
/0 👎
0 B
|👍
/👎
0 B
|👍
/👎
0 B
|👍
/👎
0 B
|👍
/👎
0 B
|👍
/👎
0 B
|0 👍
/0 👎