diff --git a/windows-installer/.gitignore b/windows-installer/.gitignore
index 491891551c58508ca04ace937df785a8f00fecd9..40ca37130d71f523e934d82f7640b6897c0a58da 100644
--- a/windows-installer/.gitignore
+++ b/windows-installer/.gitignore
@@ -2,6 +2,7 @@
 *.*
 !staging
 !sfx
+!uninstaller
 !! MAKE SURE FILES ARE IN new-install ARCHIVE FOLDER !.txt
 !BuildInstaller.bat
 !README.txt
diff --git a/windows-installer/BuildInstaller.bat b/windows-installer/BuildInstaller.bat
index 70843d9bab2f4b1b55e477a6ce8b444cf204cf12..cc6ff74b42b7bb902f05818ed093ebb626db90cf 100644
--- a/windows-installer/BuildInstaller.bat
+++ b/windows-installer/BuildInstaller.bat
@@ -1,3 +1,5 @@
+@echo off
+
 set "SCRIPTDIR=%~dp0"
 set "SCRIPTDIR=%SCRIPTDIR:~0,-1%"
 
@@ -7,13 +9,9 @@ IF [%SRB2VERSIONNAME%] == [] set /p SRB2VERSIONNAME=<"%SCRIPTDIR%\VersionFileNam
 
 set SVZIP=
 
-if [%1] == [] (
-	echo.
-) else (
+if NOT [%1] == [] (
 	echo.%~1 | findstr /C:"7z" 1>nul
-	if errorlevel 1 (
-		echo.
-	) else (
+	if NOT errorlevel 1 (
 		if exist "%~1" set "SVZIP=%~1"
 	)
 )
@@ -24,56 +22,55 @@ if ["%SVZIP%"] == [""] (
 	if exist "%ProgramW6432%\7-Zip\7z.exe" set "SVZIP=%ProgramW6432%\7-Zip\7z.exe"
 )
 
+:: Is it in PATH?
+
+if ["%SVZIP%"] == [""] (
+	"7z.exe" --help > NUL 2> NUL
+	if NOT errorlevel 1 (
+		set "SVZIP=7z.exe"
+	)
+)
+
+:: Create the uninstaller
+
+if NOT ["%SVZIP%"] == [""] (
+	del /f /q "%SCRIPTDIR%\Uninstaller.7z" 2> NUL
+	"%SVZIP%" a -t7z "%SCRIPTDIR%\Uninstaller.7z" "%SCRIPTDIR%\uninstaller\*" -m5=LZMA2
+	copy /y /b "%SCRIPTDIR%\sfx\7zsd_LZMA2.sfx" + "%SCRIPTDIR%\sfx\config-uninstaller.txt" + "%SCRIPTDIR%\Uninstaller.7z" "%SCRIPTDIR%\staging\new-install\uninstall.exe"
+	del /f /q "%SCRIPTDIR%\uninstaller.7z"
+)
+
 :: Operate on install archives
 
 type NUL > "%SCRIPTDIR%\staging\new-install\staging.txt"
 
 if exist "%SCRIPTDIR%\Installer.7z" (
-	if ["%SVZIP%"] == [""] (
-		echo.
-	) else (
-		cd "%SCRIPTDIR%\staging"
-		"%SVZIP%" a "%SCRIPTDIR%\Installer.7z" "%SCRIPTDIR%\staging\new-install"
-		"%SVZIP%" a "%SCRIPTDIR%\Installer.7z" "%SCRIPTDIR%\staging\! SRB2 INSTALL INSTRUCTIONS !.txt"
-		cd "%SCRIPTDIR%"
+	if NOT ["%SVZIP%"] == [""] (
+		"%SVZIP%" a "%SCRIPTDIR%\Installer.7z" "%SCRIPTDIR%\staging\*"
 	)
 	copy /y /b "%SCRIPTDIR%\sfx\7zsd_LZMA2.sfx" + "%SCRIPTDIR%\sfx\config-installer.txt" + "%SCRIPTDIR%\Installer.7z" "%SCRIPTDIR%\SRB2-%SRB2VERSIONNAME%-Installer.exe"
 )
 
 if exist "%SCRIPTDIR%\Patch.7z" (
-	if ["%SVZIP%"] == [""] (
-		echo.
-	) else (
-		cd "%SCRIPTDIR%\staging"
-		"%SVZIP%" a "%SCRIPTDIR%\Patch.7z" "%SCRIPTDIR%\staging\new-install\"
-		"%SVZIP%" a "%SCRIPTDIR%\Patch.7z" "%SCRIPTDIR%\staging\! SRB2 INSTALL INSTRUCTIONS !.txt"
-		cd "%SCRIPTDIR%"
+	if NOT ["%SVZIP%"] == [""] (
+		"%SVZIP%" a "%SCRIPTDIR%\Patch.7z" "%SCRIPTDIR%\staging\*"
 	)
 	copy /y /b "%SCRIPTDIR%\sfx\7zsd_LZMA2.sfx" + "%SCRIPTDIR%\sfx\config-patch.txt" + "%SCRIPTDIR%\Patch.7z" "%SCRIPTDIR%\SRB2-%SRB2VERSIONNAME%-Patch.exe"
 )
 
 if exist "%SCRIPTDIR%\Installer_x64.7z" (
-	if ["%SVZIP%"] == [""] (
-		echo.
-	) else (
-		cd "%SCRIPTDIR%\staging"
-		"%SVZIP%" a "%SCRIPTDIR%\Installer_x64.7z" "%SCRIPTDIR%\staging\new-install\"
-		"%SVZIP%" a "%SCRIPTDIR%\Installer_x64.7z" "%SCRIPTDIR%\staging\! SRB2 INSTALL INSTRUCTIONS !.txt"
-		cd "%SCRIPTDIR%"
+	if NOT ["%SVZIP%"] == [""] (
+		"%SVZIP%" a "%SCRIPTDIR%\Installer_x64.7z" "%SCRIPTDIR%\staging\*"
 	)
 	copy /y /b "%SCRIPTDIR%\sfx\7zsd_LZMA2_x64.sfx" + "%SCRIPTDIR%\sfx\config-installer.txt" + "%SCRIPTDIR%\Installer_x64.7z" "%SCRIPTDIR%\SRB2-%SRB2VERSIONNAME%-x64-Installer.exe"
 )
 
 if exist "%SCRIPTDIR%\Patch_x64.7z" (
-	if ["%SVZIP%"] == [""] (
-		echo.
-	) else (
-		cd "%SCRIPTDIR%\staging"
-		"%SVZIP%" a "%SCRIPTDIR%\Patch_x64.7z" "%SCRIPTDIR%\staging\new-install\"
-		"%SVZIP%" a "%SCRIPTDIR%\Patch_x64.7z" "%SCRIPTDIR%\staging\! SRB2 INSTALL INSTRUCTIONS !.txt"
-		cd "%SCRIPTDIR%"
+	if NOT ["%SVZIP%"] == [""] (
+		"%SVZIP%" a "%SCRIPTDIR%\Patch_x64.7z" "%SCRIPTDIR%\staging\*"
 	)
 	copy /y /b "%SCRIPTDIR%\sfx\7zsd_LZMA2_x64.sfx" + "%SCRIPTDIR%\sfx\config-patch.txt" + "%SCRIPTDIR%\Patch_x64.7z" "%SCRIPTDIR%\SRB2-%SRB2VERSIONNAME%-x64-Patch.exe"
 )
 
 del /f /q "%SCRIPTDIR%\staging\new-install\staging.txt"
+del /f /q "%SCRIPTDIR%\staging\new-install\uninstall.exe"
diff --git a/windows-installer/sfx/config-installer.txt b/windows-installer/sfx/config-installer.txt
index 4c83c2b5dd21d1b20c8cf00bed8ff0ccc0dde34f..bdbddea55cf0a7e0c0f5e2f9b40fb8c5d43da974 100644
--- a/windows-installer/sfx/config-installer.txt
+++ b/windows-installer/sfx/config-installer.txt
@@ -17,7 +17,7 @@ Shortcut="Pu,{%%T\\srb2win.exe},{-opengl},{Sonic Robo Blast 2},{Sonic Robo Blast
 Shortcut="Pu,{%%T\\srb2win.exe},{-opengl -win},{Sonic Robo Blast 2},{Sonic Robo Blast 2 (SRB2), a 3D Sonic the Hedgehog fangame.},{SRB2 (OpenGL, Windowed)},{%%T\\},{%%T\\srb2win.exe},{0}"
 Shortcut="Pu,{%%T\\srb2dd.exe},{},{Sonic Robo Blast 2},{Sonic Robo Blast 2 (SRB2), a 3D Sonic the Hedgehog fangame.},{SRB2 (DirectDraw)},{%%T\\},{%%T\\srb2dd.exe},{0}"
 Shortcut="Pu,{%%T\\srb2dd.exe},{-win},{Sonic Robo Blast 2},{Sonic Robo Blast 2 (SRB2), a 3D Sonic the Hedgehog fangame.},{SRB2 (DirectDraw, Windowed)},{%%T\\},{%%T\\srb2dd.exe},{0}"
-Shortcut="Pu,{cmd.exe},{/c \"%%T\\uninstall.bat\"},{Sonic Robo Blast 2},{Sonic Robo Blast 2 (SRB2), a 3D Sonic the Hedgehog fangame.},{Uninstall SRB2},{%%T\\},{shell32.dll},{31}"
+Shortcut="Pu,{%%T\\uninstall.exe},{},{Sonic Robo Blast 2},{Sonic Robo Blast 2 (SRB2), a 3D Sonic the Hedgehog fangame.},{Uninstall SRB2},{%%T\\},{shell32.dll},{31}"
 
 RunProgram="nowait:\"%%T\\new-install\\staging.bat\""
 
diff --git a/windows-installer/sfx/config-patch.txt b/windows-installer/sfx/config-patch.txt
index e78d055cad1cd091ec0f381ff9ef526deffc661e..bde6135dcb501d89579d15cd6f0841a0b3d12c7b 100644
--- a/windows-installer/sfx/config-patch.txt
+++ b/windows-installer/sfx/config-patch.txt
@@ -17,7 +17,7 @@ Shortcut="Pu,{%%T\\srb2win.exe},{-opengl},{Sonic Robo Blast 2},{Sonic Robo Blast
 Shortcut="Pu,{%%T\\srb2win.exe},{-opengl -win},{Sonic Robo Blast 2},{Sonic Robo Blast 2 (SRB2), a 3D Sonic the Hedgehog fangame.},{SRB2 (OpenGL, Windowed)},{%%T\\},{%%T\\srb2win.exe},{0}"
 Shortcut="Pu,{%%T\\srb2dd.exe},{},{Sonic Robo Blast 2},{Sonic Robo Blast 2 (SRB2), a 3D Sonic the Hedgehog fangame.},{SRB2 (DirectDraw)},{%%T\\},{%%T\\srb2dd.exe},{0}"
 Shortcut="Pu,{%%T\\srb2dd.exe},{-win},{Sonic Robo Blast 2},{Sonic Robo Blast 2 (SRB2), a 3D Sonic the Hedgehog fangame.},{SRB2 (DirectDraw, Windowed)},{%%T\\},{%%T\\srb2dd.exe},{0}"
-Shortcut="Pu,{cmd.exe},{/c \"%%T\\uninstall.bat\"},{Sonic Robo Blast 2},{Sonic Robo Blast 2 (SRB2), a 3D Sonic the Hedgehog fangame.},{Uninstall SRB2},{%%T\\},{shell32.dll},{31}"
+Shortcut="Pu,{%%T\\uninstall.exe},{},{Sonic Robo Blast 2},{Sonic Robo Blast 2 (SRB2), a 3D Sonic the Hedgehog fangame.},{Uninstall SRB2},{%%T\\},{shell32.dll},{31}"
 
 RunProgram="nowait:\"%%T\\new-install\\staging.bat\""
 
diff --git a/windows-installer/sfx/config-uninstaller.txt b/windows-installer/sfx/config-uninstaller.txt
new file mode 100644
index 0000000000000000000000000000000000000000..f3de9e2698694f4785427b0549bb8d8b025cae4c
--- /dev/null
+++ b/windows-installer/sfx/config-uninstaller.txt
@@ -0,0 +1,13 @@
+;!@Install@!UTF-8!
+
+GUIFlags="1+2+8"
+GUIMode="2"
+
+Title="Uninstall SRB2"
+BeginPrompt="Are you sure you want to uninstall Sonic Robo Blast 2?\n\nYour game data and mods will be preserved, as well as\nany extra files in your install folder."
+
+InstallPath="%%S"
+
+RunProgram="nowait:\"%%S\\uninstall.bat\" /y"
+
+;!@InstallEnd@!
diff --git a/windows-installer/staging/new-install/staging.bat b/windows-installer/staging/new-install/staging.bat
index d58947b27589c3b5250854e7e8ba4f6b8448aecd..2c3c94915e9c772fb5f255909c3608b93a1aa887 100644
--- a/windows-installer/staging/new-install/staging.bat
+++ b/windows-installer/staging/new-install/staging.bat
@@ -26,12 +26,28 @@ set "STAGINGDIR=!STAGINGDIR:~0,-1!"
 for %%d in ("!STAGINGDIR!") do set "INSTALLDIR=%%~dpd"
 set "INSTALLDIR=!INSTALLDIR:~0,-1!"
 
+:: Find 7z
+
+set SVZIP=
+if ["%SVZIP%"] == [""] (
+	if exist "!ProgramFiles(x86)!\7-Zip\7z.exe" set "SVZIP=!ProgramFiles(x86)!\7-Zip\7z.exe"
+	if exist "!ProgramFiles!\7-Zip\7z.exe" set "SVZIP=!ProgramFiles!\7-Zip\7z.exe"
+	if exist "!ProgramW6432!\7-Zip\7z.exe" set "SVZIP=!ProgramW6432!\7-Zip\7z.exe"
+)
+
+:: Is it in PATH?
+
+if ["%SVZIP%"] == [""] (
+	"7z.exe" --help > NUL 2> NUL
+	if NOT errorlevel 1 (
+		set "SVZIP=7z.exe"
+	)
+)
+
 :: FAILSAFE: Check if staging.txt exists in the directory
 :: If not, exit, so we don't mess up anything by accident.
 
-if exist "!STAGINGDIR!\staging.txt" (
-	echo.
-) else (
+if NOT exist "!STAGINGDIR!\staging.txt" (
 	exit
 )
 
@@ -93,25 +109,19 @@ if errorlevel 1 (
 
 : Are we in Program Files?
 echo.!STAGINGDIR! | findstr /C:"!ProgramFiles!" 1>nul
-if errorlevel 1 (
-	echo.
-) else (
+if NOT errorlevel 1 (
 	goto SetUserDir
 )
 
 :: Are we in Program Files (x86)?
 echo.!STAGINGDIR! | findstr /C:"!ProgramFiles(X86)!" 1>nul
-if errorlevel 1 (
-	echo.
-) else (
+if NOT errorlevel 1 (
 	goto SetUserDir
 )
 
 :: Are we 32-bit and actually in Program Files?
 echo.!STAGINGDIR! | findstr /C:"!ProgramW6432!" 1>nul
-if errorlevel 1 (
-	echo.
-) else (
+if NOT errorlevel 1 (
 	goto SetUserDir
 )
 
@@ -207,6 +217,16 @@ mkdir "!OLDINSTALLDIR!"
 :: install root, then copy that also to old-install
 ::
 
+:: Extract the uninstall-list.txt and uninstall-userdir.txt files from uninstaller.exe
+:: if it exists
+
+if exist "!INSTALLDIR!\uninstall.exe" (
+	if NOT ["!SVZIP!"] == [""] (
+		"!SVZIP!" x "!INSTALLDIR!\uninstall.exe" "uninstall-list.txt" -o"!INSTALLDIR!"
+		"!SVZIP!" x "!INSTALLDIR!\uninstall.exe" "uninstall-userdir.txt" -o"!INSTALLDIR!"
+	)
+)
+
 set OLDINSTALLCHANGED=
 
 if exist "!STAGINGDIR!\old-install-list.txt" (
@@ -223,12 +243,8 @@ set "TESTFILE=!TEMP!\!RANDOM!.txt"
 :: See uninstall.bat for details
 for /F "usebackq tokens=*" %%A in ("!STAGINGDIR!\old-install-list.txt") do (
 	if exist "!INSTALLDIR!\%%A" (
-		if ["%%A"] == [""] (
-			echo.
-		) else (
-			if ["%%A"] == ["%~nx0"] (
-				echo.
-			) else (
+		if NOT ["%%A"] == [""] (
+			if NOT ["%%A"] == ["%~nx0"] (
 				echo %%A> "!TESTFILE!"
 				findstr /r ".*[<>:\"\"/\\|?*%%].*" "!TESTFILE!" >nul
 				if !errorlevel! equ 0 (
@@ -267,12 +283,23 @@ dir /b /a-d "!STAGINGDIR!" >> "!INSTALLDIR!\uninstall-list.txt"
 echo !USERDIR! > "!INSTALLDIR!\uninstall-userdir.txt"
 
 :: Add the install-generated to the uninstall list
+:: NO FOLLOWING SPACES AFTER THE FILENAME!!!
 
-echo uninstall-list.txt >> "!INSTALLDIR!\uninstall-list.txt"
-echo uninstall-userdir.txt >> "!INSTALLDIR!\uninstall-list.txt"
+echo uninstall.bat>> "!INSTALLDIR!\uninstall-list.txt"
+echo uninstall-list.txt>> "!INSTALLDIR!\uninstall-list.txt"
+echo uninstall-userdir.txt>> "!INSTALLDIR!\uninstall-list.txt"
 :: *ahem* Prints as ^! SRB2 Data Folder ^!.lnk
 :: We need to escape the exclamations (^^!) and the carets themselves (^^^^)
-echo ^^^^^^! SRB2 Data Folder ^^^^^^!.lnk >> "!INSTALLDIR!\uninstall-list.txt"
+echo ^^^^^^! SRB2 Data Folder ^^^^^^!.lnk>> "!INSTALLDIR!\uninstall-list.txt"
+
+:: Add the uninstall list files to the uninstall EXE
+
+if NOT ["!SVZIP!"] == [""] (
+	if exist "!INSTALLDIR!\new-install\uninstall.exe" (
+		"!SVZIP!" a "!INSTALLDIR!\new-install\uninstall.exe" "!INSTALLDIR!\uninstall-list.txt" -sdel
+		"!SVZIP!" a "!INSTALLDIR!\new-install\uninstall.exe" "!INSTALLDIR!\uninstall-userdir.txt" -sdel
+	)
+)
 
 :: Start moving files
 
@@ -281,12 +308,8 @@ for %%F in ("!STAGINGDIR!\*") DO (
 		set OLDINSTALLCHANGED=1
 		move "!INSTALLDIR!\%%~nxF" "!OLDINSTALLDIR!\%%~nxF"
 	)
-	if ["%%~nxF"] == ["staging.bat"] (
-		echo.
-	) else (
-		if ["%%~nxF"] == ["staging.txt"] (
-			echo.
-		) else (
+	if NOT ["%%~nxF"] == ["staging.bat"] (
+		if NOT ["%%~nxF"] == ["staging.txt"] (
 			move "!STAGINGDIR!\%%~nxF" "!INSTALLDIR!\%%~nxF"
 		)
 	)
diff --git a/windows-installer/staging/new-install/uninstall.bat b/windows-installer/uninstaller/uninstall.bat
similarity index 82%
rename from windows-installer/staging/new-install/uninstall.bat
rename to windows-installer/uninstaller/uninstall.bat
index 55112bc9917e44222c8f28c617343be8e43eca21..ed7c33391ac3e83316adb0e8271020a998dddc99 100644
--- a/windows-installer/staging/new-install/uninstall.bat
+++ b/windows-installer/uninstaller/uninstall.bat
@@ -11,28 +11,30 @@ set "USERDIR=!USERDIR:~0,-1!"
 
 : ProceedPrompt
 
-set PROCEED=
-set /p PROCEED="Are you sure you want to uninstall SRB2? [yes/no] "
-
-if /I ["!PROCEED:~0,1!"] == ["n"] exit
-if /I ["!PROCEED!"] == ["y"] (
-	echo Type Yes or No
-	echo.
-	goto ProceedPrompt
+if ["%1"] == ["/y"] (
+	set "PROCEED=1"
 ) else (
-	if /I ["!PROCEED!"] == ["yes"] (
-		set PROCEED=1
-	) else (
+	set PROCEED=
+	set /p PROCEED="Are you sure you want to uninstall SRB2? [yes/no] "
+
+	if /I ["!PROCEED:~0,1!"] == ["n"] exit
+	if /I ["!PROCEED!"] == ["y"] (
+		echo Type Yes or No
 		echo.
 		goto ProceedPrompt
+	) else (
+		if /I ["!PROCEED!"] == ["yes"] (
+			set PROCEED=1
+		) else (
+			echo.
+			goto ProceedPrompt
+		)
 	)
 )
 
 :: Failsafe, in case we Ctrl+C and decline "Terminate batch file?"
 
-if ["!PROCEED!"] == ["1"] (
-	echo.
-) else (
+if NOT ["!PROCEED!"] == ["1"] (
 	exit
 )
 
@@ -69,17 +71,14 @@ if errorlevel 1 (
 :: Can %%A be substring'd to get only the filename and extension?
 :: If so, print that to the temp file instead of the whole line
 :: And possibly do the folder check before the invalid char check.
+:: ALSO: Don't honor upward relative paths! (..\)
 ::
 set "TESTFILE=!TEMP!\!RANDOM!.txt"
 
 for /F "usebackq tokens=*" %%A in ("!INSTALLDIR!\uninstall-list.txt") do (
 	if exist "!INSTALLDIR!\%%A" (
-		if ["%%A"] == [""] (
-			echo.
-		) else (
-			if ["%%A"] == ["%~nx0"] (
-				echo.
-			) else (
+		if NOT ["%%A"] == [""] (
+			if NOT ["%%A"] == ["%~nx0"] (
 				echo %%A> "!TESTFILE!"
 				findstr /r ".*[<>:\"\"/\\|?*%%].*" "!TESTFILE!" >nul
 				if !errorlevel! equ 0 (
@@ -113,9 +112,7 @@ rmdir /s /q "!AppData!\Microsoft\Windows\Start Menu\Programs\Sonic Robo Blast 2"
 set USERDIRFILLED=
 set INSTALLDIRFILLED=
 for /F %%i in ('dir /b /a "!USERDIR!\*"') do (
-    if ["%%i"] == ["%~nx0"] (
-		echo.
-	) else (
+    if NOT ["%%i"] == ["%~nx0"] (
 		set USERDIRFILLED=1
 		goto InstallFilledCheck
 	)
@@ -123,9 +120,7 @@ for /F %%i in ('dir /b /a "!USERDIR!\*"') do (
 
 : InstallFilledCheck
 
-if /I ["!USERDIR!"] == ["!INSTALLDIR!"] (
-	echo.
-) else (
+if /I NOT ["!USERDIR!"] == ["!INSTALLDIR!"] (
 	for /F %%i in ('dir /b /a "!INSTALLDIR!\*"') do (
 		if ["%%i"] == ["%~nx0"] (
 			echo.
@@ -161,9 +156,7 @@ if ["!INSTALLDIRFILLED!"] == ["1"] (
 set FINALRESPONSE=
 set /p FINALRESPONSE="!FINALPROMPT! "
 
-if ["!FINALPROMPT!"] == ["Press Enter key to exit."] (
-	echo.
-) else (
+if NOT ["!FINALPROMPT!"] == ["Press Enter key to exit."] (
 	if /I ["!FINALRESPONSE:~0,1!"] == ["y"] (
 		if ["!USERDIRFILLED!"] == ["1"] (
 			"!SystemRoot!\explorer.exe" "!USERDIR!"