Automating Uninstalls with NSIS Media Remover: Sample Scripts
Uninstall automation saves time, reduces human error, and ensures a clean system state after software removal. NSIS Media Remover is a lightweight approach to removing media files and related components during uninstall processes using NSIS (Nullsoft Scriptable Install System). This article provides practical sample scripts and best practices for integrating NSIS Media Remover into your uninstallers.
When to use NSIS Media Remover
- Clarity: Use it when your installer places media files (audio, video, images) in user-accessible locations or shared folders.
- Safety: Use it if you need selective removal (keep user-created files, remove only installed media).
- Automation: Use in unattended or scripted uninstalls where prompts should be minimal.
Key considerations before automating uninstalls
- Do not delete user-generated content by default. Only remove files the installer placed (track installed files via a manifest or registry keys).
- Respect user choice: Provide an option to preserve user media.
- Permissions: Ensure the uninstaller runs with the required privileges to remove protected files.
- Backup/rollback: Consider offering a simple backup of removed files or a log of deletions.
Example 1 — Basic removal by manifest file
This script removes files listed in a manifest created at install time (manifest.txt), placed under the install directory. It preserves folders and only deletes entries found in the manifest.
nsis
; Basic NSIS uninstall script using a manifest of installed media files Name “MyApp Uninstaller” OutFile “uninstall.exe” RequestExecutionLevel user Section “Uninstall” SetOutPath “\(INSTDIR"</span><span> </span><span> </span><span class="token" style="color: rgb(0, 128, 0); font-style: italic;">; read manifest line-by-line and delete files</span><span> </span><span> </span><span class="token" style="color: rgb(0, 0, 255);">Push</span><span> </span><span class="token" style="color: rgb(163, 21, 21);">"\)INSTDIR\manifest.txt” Call DeleteFilesFromManifest SectionEnd Function DeleteFilesFromManifest Exch \(R0</span><span> </span><span class="token" style="color: rgb(0, 128, 0); font-style: italic;">; manifest path</span><span> </span><span> </span><span class="token" style="color: rgb(0, 0, 255);">ClearErrors</span><span> </span><span> </span><span class="token" style="color: rgb(0, 128, 0); font-style: italic;">; open manifest</span><span> </span><span> </span><span class="token" style="color: rgb(0, 0, 255);">FileOpen</span><span> </span><span class="token" style="color: rgb(54, 172, 170);">\)R1 \(R0</span><span> r </span><span> </span><span class="token" style="color: rgb(0, 0, 255);">StrCmp</span><span> </span><span class="token" style="color: rgb(54, 172, 170);">\)R1 ”” done loop: FileRead \(R1</span><span> </span><span class="token" style="color: rgb(54, 172, 170);">\)R2 IfErrors close ; trim whitespace (simple) \({Trim}</span><span> </span><span class="token" style="color: rgb(54, 172, 170);">\)R2 \(R2</span><span> </span><span> </span><span class="token" style="color: rgb(0, 128, 0); font-style: italic;">; build full path if relative</span><span> </span><span> </span><span class="token" style="color: rgb(0, 0, 255);">StrCpy</span><span> </span><span class="token" style="color: rgb(54, 172, 170);">\)R3 \(R2</span><span> </span><span> </span><span class="token" style="color: rgb(54, 172, 170);">\){If} \({FileExists}</span><span> </span><span class="token" style="color: rgb(163, 21, 21);">"\)R3” Delete “\(R3"</span><span> </span><span> </span><span class="token" style="color: rgb(54, 172, 170);">\){EndIf} Goto loop close: FileClose \(R1</span><span> </span><span> done</span><span class="token" style="color: rgb(57, 58, 52);">:</span><span> </span><span> </span><span class="token" style="color: rgb(0, 0, 255);">Pop</span><span> </span><span class="token" style="color: rgb(54, 172, 170);">\)R0 FunctionEnd
Notes:
- Create manifest at install time by enumerating bundled media and writing absolute paths to manifest.txt.
- Use robust trim and path-handling UDFs (user-defined functions) for production.
Example 2 — Remove only files with a specific extension in target folders
Use this when you want to remove media types (e.g., .mp3, .mp4) but not other files.
nsis
Name “MyApp Uninstaller” OutFile “uninstall.exe” RequestExecutionLevel user Section “Uninstall” ; target folders to search StrCpy \(R0</span><span> </span><span class="token" style="color: rgb(163, 21, 21);">"\)INSTDIR\media” StrCpy \(R1</span><span> </span><span class="token" style="color: rgb(163, 21, 21);">"\)APPDATA\MyApp\cache” Call DeleteMediaInFolder ; repeat for other folders as needed SectionEnd Function DeleteMediaInFolder ; expects \(R0 = folder path, \)R2 = file patterns (comma-separated optional) Push \(R0</span><span> </span><span> </span><span class="token" style="color: rgb(0, 128, 0); font-style: italic;">; patterns hardcoded for brevity</span><span> </span><span> </span><span class="token" style="color: rgb(0, 0, 255);">StrCpy</span><span> </span><span class="token" style="color: rgb(54, 172, 170);">\)R3 “.mp3;.mp4;.wav;.jpg;.png” ; enumerate files FindFirst \(R4</span><span> </span><span class="token" style="color: rgb(54, 172, 170);">\)R5 ”$R0*.“ StrCmp \(R4</span><span> </span><span class="token" style="color: rgb(163, 21, 21);">""</span><span> done </span><span> loop</span><span class="token" style="color: rgb(57, 58, 52);">:</span><span> </span><span> </span><span class="token" style="color: rgb(0, 128, 0); font-style: italic;">; \)R5 contains filename ; check extension against patterns ; simple check using wildcard compare (implement or use UDF) \({If}</span><span> </span><span class="token" style="color: rgb(54, 172, 170);">\){MatchesPatterns} ”\(R5"</span><span> </span><span class="token" style="color: rgb(163, 21, 21);">"\)R3” Delete “\(R0\\)R5” \({EndIf}</span><span> </span><span> </span><span class="token" style="color: rgb(0, 0, 255);">FindNext</span><span> </span><span class="token" style="color: rgb(54, 172, 170);">\)R4 \(R5</span><span> </span><span> </span><span class="token" style="color: rgb(0, 0, 255);">StrCmp</span><span> </span><span class="token" style="color: rgb(54, 172, 170);">\)R4 ”” done loop done: FindClose \(R4</span><span> </span><span> </span><span class="token" style="color: rgb(0, 0, 255);">Pop</span><span> </span><span class="token" style="color: rgb(54, 172, 170);">\)R0 FunctionEnd
Notes:
- Implement or include reliable pattern-matching macros (\({MatchesPatterns}) and ensure recursive traversal if needed.</li> <li>Be careful with wildcard deletion — confirm paths and patterns before running.</li> </ul> <h3>Example 3 — Registry-tracked installed files (recommended)</h3> <p>Track installed files in registry keys during install; the uninstaller reads the registry to delete only those files.</p> <p>Installer writes entries:</p> <ul> <li>HKCU\Software\MyApp\InstalledFiles\1 = "C:\Program Files\MyApp\media\song.mp3"</li> <li>HKCU\Software\MyApp\InstalledFiles\2 = "C:\Users\Me\AppData\Roaming\MyApp\image.jpg"</li> </ul> <p>Uninstaller reads and deletes:</p> <pre><div class="XG2rBS5V967VhGTCEN1k"><div class="nHykNMmtaaTJMjgzStID"><div class="HsT0RHFbNELC00WicOi8"><i><svg width="16" height="16" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill="currentColor" fill-rule="evenodd" clip-rule="evenodd" d="M15.434 7.51c.137.137.212.311.212.49a.694.694 0 0 1-.212.5l-3.54 3.5a.893.893 0 0 1-.277.18 1.024 1.024 0 0 1-.684.038.945.945 0 0 1-.302-.148.787.787 0 0 1-.213-.234.652.652 0 0 1-.045-.58.74.74 0 0 1 .175-.256l3.045-3-3.045-3a.69.69 0 0 1-.22-.55.723.723 0 0 1 .303-.52 1 1 0 0 1 .648-.186.962.962 0 0 1 .614.256l3.541 3.51Zm-12.281 0A.695.695 0 0 0 2.94 8a.694.694 0 0 0 .213.5l3.54 3.5a.893.893 0 0 0 .277.18 1.024 1.024 0 0 0 .684.038.945.945 0 0 0 .302-.148.788.788 0 0 0 .213-.234.651.651 0 0 0 .045-.58.74.74 0 0 0-.175-.256L4.994 8l3.045-3a.69.69 0 0 0 .22-.55.723.723 0 0 0-.303-.52 1 1 0 0 0-.648-.186.962.962 0 0 0-.615.256l-3.54 3.51Z"></path></svg></i><p class="li3asHIMe05JPmtJCytG wZ4JdaHxSAhGy1HoNVja cPy9QU4brI7VQXFNPEvF">nsis</p></div><div class="CF2lgtGWtYUYmTULoX44"><button type="button" class="st68fcLUUT0dNcuLLB2_ ffON2NH02oMAcqyoh2UU MQCbz04ET5EljRmK3YpQ CPXAhl7VTkj2dHDyAYAf" data-copycode="true" role="button" aria-label="Copy Code"><svg viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill="currentColor" fill-rule="evenodd" clip-rule="evenodd" d="M9.975 1h.09a3.2 3.2 0 0 1 3.202 3.201v1.924a.754.754 0 0 1-.017.16l1.23 1.353A2 2 0 0 1 15 8.983V14a2 2 0 0 1-2 2H8a2 2 0 0 1-1.733-1H4.183a3.201 3.201 0 0 1-3.2-3.201V4.201a3.2 3.2 0 0 1 3.04-3.197A1.25 1.25 0 0 1 5.25 0h3.5c.604 0 1.109.43 1.225 1ZM4.249 2.5h-.066a1.7 1.7 0 0 0-1.7 1.701v7.598c0 .94.761 1.701 1.7 1.701H6V7a2 2 0 0 1 2-2h3.197c.195 0 .387.028.57.083v-.882A1.7 1.7 0 0 0 10.066 2.5H9.75c-.228.304-.591.5-1 .5h-3.5c-.41 0-.772-.196-1-.5ZM5 1.75v-.5A.25.25 0 0 1 5.25 1h3.5a.25.25 0 0 1 .25.25v.5a.25.25 0 0 1-.25.25h-3.5A.25.25 0 0 1 5 1.75ZM7.5 7a.5.5 0 0 1 .5-.5h3V9a1 1 0 0 0 1 1h1.5v4a.5.5 0 0 1-.5.5H8a.5.5 0 0 1-.5-.5V7Zm6 2v-.017a.5.5 0 0 0-.13-.336L12 7.14V9h1.5Z"></path></svg>Copy Code</button><button type="button" class="st68fcLUUT0dNcuLLB2_ WtfzoAXPoZC2mMqcexgL ffON2NH02oMAcqyoh2UU MQCbz04ET5EljRmK3YpQ GnLX_jUB3Jn3idluie7R"><svg fill="none" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path fill="currentColor" fill-rule="evenodd" d="M20.618 4.214a1 1 0 0 1 .168 1.404l-11 14a1 1 0 0 1-1.554.022l-5-6a1 1 0 0 1 1.536-1.28l4.21 5.05L19.213 4.382a1 1 0 0 1 1.404-.168Z" clip-rule="evenodd"></path></svg>Copied</button></div></div><div class="mtDfw7oSa1WexjXyzs9y" style="color: var(–sds-color-text-01); font-family: var(–sds-font-family-monospace); direction: ltr; text-align: left; white-space: pre; word-spacing: normal; word-break: normal; font-size: var(–sds-font-size-label); line-height: 1.2em; tab-size: 4; hyphens: none; padding: var(–sds-space-x02, 8px) var(–sds-space-x04, 16px) var(–sds-space-x04, 16px); margin: 0px; overflow: auto; border: none; background: transparent;"><code class="language-nsis" style="color: rgb(57, 58, 52); font-family: Consolas, "Bitstream Vera Sans Mono", "Courier New", Courier, monospace; direction: ltr; text-align: left; white-space: pre; word-spacing: normal; word-break: normal; font-size: 0.9em; line-height: 1.2em; tab-size: 4; hyphens: none;"><span class="token" style="color: rgb(0, 0, 255);">Section</span><span> </span><span class="token" style="color: rgb(163, 21, 21);">"Uninstall"</span><span> </span><span> </span><span class="token" style="color: rgb(0, 128, 0); font-style: italic;">; read registry count</span><span> </span><span> </span><span class="token" style="color: rgb(0, 0, 255);">ReadRegStr</span><span> </span><span class="token" style="color: rgb(54, 172, 170);">\)R0 HKCU “Software\MyApp” “InstallCount”
IntCmp \(R0</span><span> </span><span class="token" style="color: rgb(54, 172, 170);">0</span><span> done </span><span> </span><span class="token" style="color: rgb(0, 0, 255);">StrCpy</span><span> </span><span class="token" style="color: rgb(54, 172, 170);">\)R1 1
loop:
ReadRegStr \(R2</span><span> </span><span class="token" style="color: rgb(255, 0, 0);">HKCU</span><span> </span><span class="token" style="color: rgb(163, 21, 21);">"Software\MyApp\InstalledFiles"</span><span> </span><span class="token" style="color: rgb(163, 21, 21);">"\)R1”
StrCmp \(R2</span><span> </span><span class="token" style="color: rgb(163, 21, 21);">""</span><span> next </span><span> </span><span class="token" style="color: rgb(0, 0, 255);">IfFileExists</span><span> </span><span class="token" style="color: rgb(163, 21, 21);">"\)R2” 0 next Delete “\(R2"</span><span> </span><span> next</span><span class="token" style="color: rgb(57, 58, 52);">:</span><span> </span><span> </span><span class="token" style="color: rgb(0, 0, 255);">IntOp</span><span> </span><span class="token" style="color: rgb(54, 172, 170);">\)R1 \(R1</span><span> </span><span class="token" style="color: rgb(57, 58, 52);">+</span><span> </span><span class="token" style="color: rgb(54, 172, 170);">1</span><span> </span><span> </span><span class="token" style="color: rgb(0, 0, 255);">IntCmp</span><span> </span><span class="token" style="color: rgb(54, 172, 170);">\)R1 \(R0</span><span> loop done </span><span> done</span><span class="token" style="color: rgb(57, 58, 52);">:</span><span> </span><span> </span><span class="token" style="color: rgb(0, 128, 0); font-style: italic;">; clean up registry</span><span> </span><span> </span><span class="token" style="color: rgb(0, 0, 255);">DeleteRegKey</span><span> </span><span class="token" style="color: rgb(255, 0, 0);">HKCU</span><span> </span><span class="token" style="color: rgb(163, 21, 21);">"Software\MyApp\InstalledFiles"</span><span> </span><span> </span><span class="token" style="color: rgb(0, 0, 255);">DeleteRegValue</span><span> </span><span class="token" style="color: rgb(255, 0, 0);">HKCU</span><span> </span><span class="token" style="color: rgb(163, 21, 21);">"Software\MyApp"</span><span> </span><span class="token" style="color: rgb(163, 21, 21);">"InstallCount"</span><span> </span><span></span><span class="token" style="color: rgb(0, 0, 255);">SectionEnd</span><span> </span></code></div></div></pre> <p>Notes:</p> <ul> <li>Use HKLM for machine-wide installs; HKCU for per-user.</li> <li>Keep InstallCount synchronized during install/uninstall.</li> </ul> <h3>Example 4 — Preserve user files option (interactive or silent)</h3> <p>Provide a flag or UI page to let users keep their files. For silent uninstalls, choose a safe default (preserve).</p> <ul> <li>Add an uninstall page: checkbox "Remove all bundled media files"</li> <li>Store the choice in \)INSTDIR\uninstall-options.txt or registry - Uninstaller reads the flag and proceeds accordingly
Best practices checklist
- Manifest or registry tracking: Always track installed files; never guess.
- Safe defaults: Preserve user content in silent/unattended modes.
- Logs: Write a deletion log to $INSTDIR\uninstall-log.txt for troubleshooting.
- Permissions: Detect and escalate if required (RequestExecutionLevel highest).
- Testing: Test on systems with varied file permissions, read-only files, and files in use.
Troubleshooting common issues
- Files in use: schedule deletion on reboot or notify user.
- Missing manifest/registry entries: skip deletion and log a warning.
- Partial failures: continue and report failures rather than aborting.
Conclusion
Automating uninstalls for media files with NSIS Media Remover is safe and effective when you track installed files, offer an option to preserve user content, and follow robust error-handling and logging practices. Use manifests or registry entries for precise removals, prefer safe defaults for silent uninstalls, and include a simple UI for user choice.
Leave a Reply