# deprovision-kiosk.ps1 — remove the Vestibule kiosk session from this # machine (Windows). The inverse of provision-kiosk.ps1, applied in # reverse order: # # 1. AssignedAccess / Shell Launcher kiosk configuration # 2. Automatic logon registry values (only if they point at the kiosk # account — an unrelated autologon is never touched) # 3. The Start Menu kiosk shortcut # 4. Vestibule's merged policies.json — each directory is reset to its # pre-Vestibule baseline (the backed-up operator file is reinstalled # where one exists, Vestibule's generated file is deleted where one # does not) # 5. C:\ProgramData\Vestibule # 6. Optionally the kiosk account and the Program Files install # # Exit codes: # 0 success # 10 success, reboot required to fully clear kiosk mode # 2 unsupported platform / not elevated # 5 removal failure # # Usage: # powershell -ExecutionPolicy Bypass -File deprovision-kiosk.ps1 ` # -RemoveKioskAccount -RemoveInstall param( [string]$KioskUser = "VestibuleKiosk", [string]$InstallRoot = "C:\Program Files\Vestibule", [switch]$RemoveKioskAccount, [switch]$RemoveInstall, [switch]$Quiet, [switch]$Check, [switch]$Restart ) $ErrorActionPreference = "Stop" $AUMID = "Vestibule.Kiosk" function Fail([int]$code, [string]$msg) { Write-Host "" Write-Host "ERROR: $msg" -ForegroundColor Red Write-Host " exiting with code $code" exit $code } function Info($msg) { Write-Host $msg } function Ok($msg) { Write-Host " [ok] $msg" -ForegroundColor Green } function Step($msg) { Write-Host ""; Write-Host "==> $msg" -ForegroundColor Cyan } if ($env:OS -ne "Windows_NT") { Fail 2 "Windows-only; on Linux use scripts/deprovision-kiosk.sh" } $id = [Security.Principal.WindowsIdentity]::GetCurrent() if (-not ([Security.Principal.WindowsPrincipal]$id).IsInRole( [Security.Principal.WindowsBuiltInRole]::Administrator)) { Fail 2 "must run elevated" } $rebootNeeded = $false # ─── Discover current state ─────────────────────────────────────────── $lnkPath = Join-Path $env:ProgramData "Microsoft\Windows\Start Menu\Programs\Vestibule Kiosk.lnk" $wl = "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" $autologonUser = (Get-ItemProperty $wl -ErrorAction SilentlyContinue).DefaultUserName $autologonOn = (Get-ItemProperty $wl -ErrorAction SilentlyContinue).AutoAdminLogon -eq "1" $weslPresent = [bool](Get-CimClass -Namespace "root\standardcimv2\embedded" ` -ClassName "WESL_UserSetting" -ErrorAction SilentlyContinue) $accountPresent = [bool](Get-LocalUser -Name $KioskUser -ErrorAction SilentlyContinue) Step "Current state" Info "kiosk account : $(if ($accountPresent) {'present'} else {'absent'})" Info "autologon : $(if ($autologonOn) {"on (user: $autologonUser)"} else {'off'})" Info "Shell Launcher WMI : $(if ($weslPresent) {'present'} else {'absent'})" Info "kiosk shortcut : $(if (Test-Path $lnkPath) {'present'} else {'absent'})" if ($Check) { Info "(check only — no changes made)" exit 0 } if (-not $Quiet) { $answer = Read-Host "Proceed with removal? [y/N]" if ($answer -notmatch '^[Yy]') { Info "aborted"; exit 0 } } # ─── 1. Lockdown removal ────────────────────────────────────────────── Step "Remove kiosk lockdown" if ($weslPresent) { $wesl = [wmiclass]"\\.\root\standardcimv2\embedded:WESL_UserSetting" $removed = $false foreach ($call in @( { $wesl.RemoveCustomShell($KioskUser) }, { $wesl.RemoveCustomShell() } )) { try { $r = & $call if ($r.ReturnValue -eq 0) { $removed = $true; break } } catch { } } if ($removed) { Ok "Shell Launcher custom shell removed for '$KioskUser'" } else { Info "Shell Launcher: no custom shell to remove (or already clean)" } } # AssignedAccess removal: call any Remove* method the bridge exposes on # this build. Bridge method availability varies by build; on some builds # the only clean removal is deleting the kiosk account (which orphans and # neutralizes the config) — handled below, and reported honestly. try { $class = Get-CimClass -Namespace "root\cimv2\mdm\dmmap" -ClassName "MDM_AssignedAccess" ` -ErrorAction Stop $removeMethods = @($class.CimClassMethods | Where-Object { $_.Name -like "Remove*" }) foreach ($m in $removeMethods) { try { $instances = @(Get-CimInstance -Namespace "root\cimv2\mdm\dmmap" ` -ClassName "MDM_AssignedAccess" -ErrorAction Stop) foreach ($inst in $instances) { $res = Invoke-CimMethod -InputObject $inst -MethodName $m.Name -ErrorAction Stop if ($res.ReturnValue -eq 0) { Ok "AssignedAccess cleared via $($m.Name)" } } $rebootNeeded = $true } catch { Info "bridge method $($m.Name) present but call failed: $($_.Exception.Message)" } } } catch { Info "MDM bridge not reachable — AssignedAccess config (if any) is cleared by removing the kiosk account below" if ($accountPresent) { $rebootNeeded = $true } } # ─── 2. Automatic logon ─────────────────────────────────────────────── Step "Remove automatic logon" if ($autologonOn -and $autologonUser -eq $KioskUser) { Set-ItemProperty $wl -Name "AutoAdminLogon" -Value "0" -Type String Remove-ItemProperty $wl -Name "DefaultUserName" -ErrorAction SilentlyContinue Remove-ItemProperty $wl -Name "DefaultDomainName" -ErrorAction SilentlyContinue Remove-ItemProperty $wl -Name "DefaultPassword" -ErrorAction SilentlyContinue Ok "autologon disabled and credentials cleared" } elseif ($autologonOn) { Info "autologon is configured for '$autologonUser' (not ours) — left untouched" } else { Info "autologon already off" } # ─── 3. Shortcut ────────────────────────────────────────────────────── Step "Remove kiosk shortcut" if (Test-Path $lnkPath) { Remove-Item $lnkPath -Force Ok "removed $lnkPath" } else { Info "already absent" } # ─── 4. Policies ────────────────────────────────────────────────────── Step "Reset browser policies to baseline" # LibreWolf and Firefox share the distribution/policies.json mechanism; # cover every install location for both browsers. Step-down per # directory: backup present -> reinstall it; ours -> delete; else leave. foreach ($browserExe in @( "${env:ProgramFiles}\LibreWolf\librewolf.exe", "${env:ProgramFiles(x86)}\LibreWolf\librewolf.exe", "${env:LOCALAPPDATA}\Programs\LibreWolf\librewolf.exe", "${env:ProgramFiles}\Mozilla Firefox\firefox.exe", "${env:ProgramFiles}\Mozilla Firefox ESR\firefox.exe", "${env:ProgramFiles(x86)}\Mozilla Firefox\firefox.exe", "${env:ProgramFiles(x86)}\Mozilla Firefox ESR\firefox.exe", "${env:LOCALAPPDATA}\Mozilla Firefox\firefox.exe")) { if (-not (Test-Path $browserExe)) { continue } $distDir = Join-Path (Split-Path -Parent $browserExe) "distribution" $policiesPath = Join-Path $distDir "policies.json" $bak = "$policiesPath.vestibule-bak" if (Test-Path $bak) { Move-Item $bak $policiesPath -Force Ok "baseline policies.json reinstalled in $distDir (from vestibule-bak)" } elseif (Test-Path $policiesPath) { $content = Get-Content $policiesPath -Raw if ($content -match "vestibule@vestibule\.kiosk") { Remove-Item $policiesPath -Force Ok "Vestibule-generated policies.json deleted in $distDir (no baseline on record)" } else { Info "policies.json in $distDir exists but is not ours — left untouched" } } # librewolf.overrides.cfg is LibreWolf-only; harmless no-op for Firefox. $cfg = Join-Path (Split-Path -Parent $browserExe) "librewolf.overrides.cfg" if (Test-Path $cfg) { Remove-Item $cfg -Force; Ok "removed librewolf.overrides.cfg" } } # ─── 5. ProgramData ─────────────────────────────────────────────────── Step "Remove deployment config" $pdDir = Join-Path $env:ProgramData "Vestibule" if (Test-Path $pdDir) { Remove-Item $pdDir -Recurse -Force Ok "removed $pdDir" } else { Info "already absent" } # ─── 6. Optional: account + install tree ────────────────────────────── if ($RemoveKioskAccount) { Step "Remove kiosk account" if ($accountPresent) { # Ensure the account is not mid-logon (fast user switching) first. try { Remove-LocalUser -Name $KioskUser -ErrorAction Stop Ok "removed local account '$KioskUser'" $rebootNeeded = $true } catch { Fail 5 "could not remove account: $($_.Exception.Message)" } } else { Info "account '$KioskUser' already absent" } } if ($RemoveInstall) { Step "Remove install tree" if (Test-Path $InstallRoot) { Remove-Item $InstallRoot -Recurse -Force Ok "removed $InstallRoot" } else { Info "already absent" } } # ─── Summary ────────────────────────────────────────────────────────── Step "Deprovisioning complete" Info "verify in Settings > Accounts > Other users that no kiosk entry remains" if ($rebootNeeded) { Info "reboot recommended to fully clear kiosk mode." if ($Restart) { shutdown.exe /r /t 10 /c "Vestibule kiosk removal" exit 0 } exit 10 } exit 0