diff --git a/launchers/win32/LauncherDlg.cpp b/launchers/win32/LauncherDlg.cpp
index 07fb57ddcd..d2d149348e 100644
--- a/launchers/win32/LauncherDlg.cpp
+++ b/launchers/win32/LauncherDlg.cpp
@@ -46,6 +46,10 @@ CLauncherDlg::CLauncherDlg(CWnd* pParent)
 	EnableD2DSupport();
 }
 
+CLauncherDlg::~CLauncherDlg() {
+    theApp._manager.closeLog();
+}
+
 void CLauncherDlg::DoDataExchange(CDataExchange* pDX)
 {
 	DDX_Control(pDX, IDC_BUTTON_NEXT, m_btnNext);
@@ -154,25 +158,54 @@ HCURSOR CLauncherDlg::OnQueryDragIcon()
 }
 
 void CLauncherDlg::startProcess() {
-	if (theApp._manager.needsUpdate()) {
-		setDrawDialog(DrawStep::DrawProcessUpdate);
-	} else {
-		setDrawDialog(DrawStep::DrawProcessSetup);
-	}
-	
-	CString installDir;
-	theApp._manager.getAndCreatePaths(LauncherManager::PathType::Interface_Directory, installDir);
-	CString interfaceExe = installDir += "\\interface.exe";
-	if (!theApp._manager.isLoggedIn()) {
-		theApp._manager.downloadContent();
-	} else {
-		theApp._manager.downloadApplication();
-	}
+    if (theApp._manager.needsUpdate()) {
+        theApp._manager.addToLog(_T("Starting Process Update"));
+        setDrawDialog(DrawStep::DrawProcessUpdate);
+    } else {
+        theApp._manager.addToLog(_T("Starting Process Setup"));
+        setDrawDialog(DrawStep::DrawProcessSetup);
+    }
+    theApp._manager.addToLog(_T("Deleting directories before install"));
+
+    CString installDir;
+    theApp._manager.getAndCreatePaths(LauncherManager::PathType::Interface_Directory, installDir);
+    CString downloadDir;
+    theApp._manager.getAndCreatePaths(LauncherManager::PathType::Download_Directory, downloadDir);
+
+    LauncherUtils::deleteDirectoriesOnThread(installDir, downloadDir, [&](int error) {
+        LauncherUtils::DeleteDirError deleteError = (LauncherUtils::DeleteDirError)error;
+        switch(error) { 
+        case LauncherUtils::DeleteDirError::NoErrorDeleting:
+            theApp._manager.addToLog(_T("Install directory deleted."));
+            theApp._manager.addToLog(_T("Downloads directory deleted."));
+            if (!theApp._manager.isLoggedIn()) {
+                theApp._manager.addToLog(_T("Downloading Content"));
+                theApp._manager.downloadContent();
+            } else {
+                theApp._manager.addToLog(_T("Downloading App"));
+                theApp._manager.downloadApplication();
+            }
+            break;
+        case LauncherUtils::DeleteDirError::ErrorDeletingBothDirs:
+            theApp._manager.addToLog(_T("Error deleting directories."));
+            break;
+        case LauncherUtils::DeleteDirError::ErrorDeletingApplicationDir:
+            theApp._manager.addToLog(_T("Error deleting application directory."));
+            break;
+        case LauncherUtils::DeleteDirError::ErrorDeletingDownloadsDir:
+            theApp._manager.addToLog(_T("Error deleting downloads directory."));
+            break;
+        default:
+            break;
+        }
+    });
 }
 
 BOOL CLauncherDlg::getHQInfo(const CString& orgname) {
 	CString hash;
-    LauncherUtils::hMac256(orgname, LAUNCHER_HMAC_SECRET, hash);
+    CString lowerOrgName = orgname;
+    lowerOrgName.MakeLower();
+    LauncherUtils::hMac256(lowerOrgName, LAUNCHER_HMAC_SECRET, hash);
 	return theApp._manager.readOrganizationJSON(hash) == LauncherUtils::ResponseError::NoError;
 }
 
@@ -181,33 +214,44 @@ afx_msg void CLauncherDlg::OnTroubleClicked() {
 }
 
 afx_msg void CLauncherDlg::OnNextClicked() {
-	if (_drawStep != DrawStep::DrawChoose) {
-		CString token;
-		CString username, password, orgname;
-		m_orgname.GetWindowTextW(orgname);
-		m_username.GetWindowTextW(username);
-		m_password.GetWindowTextW(password);
-		LauncherUtils::ResponseError error;
-		if (orgname.GetLength() > 0 && username.GetLength() > 0 && password.GetLength() > 0) {
-			if (getHQInfo(orgname)) {
-				error = theApp._manager.getAccessTokenForCredentials(username, password);
-				if (error == LauncherUtils::ResponseError::NoError) {
-					setDrawDialog(DrawStep::DrawChoose);
-				} else if (error == LauncherUtils::ResponseError::BadCredentials) {
-					setDrawDialog(DrawStep::DrawLoginErrorCred);
-				} else {
-					MessageBox(L"Error Reading or retreaving response.", L"Network Error", MB_OK | MB_ICONERROR);
-				}
-			} else {
-				setDrawDialog(DrawStep::DrawLoginErrorOrg);
-			}
-		}
-	} else {
-		CString displayName;
-		m_username.GetWindowTextW(displayName);
-		theApp._manager.setDisplayName(displayName);
-		startProcess();
-	}
+    if (_drawStep != DrawStep::DrawChoose) {
+        CString token;
+        CString username, password, orgname;
+        m_orgname.GetWindowTextW(orgname);
+        m_username.GetWindowTextW(username);
+        m_password.GetWindowTextW(password);
+
+        username = LauncherUtils::urlEncodeString(username);
+        password = LauncherUtils::urlEncodeString(password);
+        LauncherUtils::ResponseError error;
+        if (orgname.GetLength() > 0 && username.GetLength() > 0 && password.GetLength() > 0) {
+            theApp._manager.addToLog(_T("Trying to get organization data"));
+            if (getHQInfo(orgname)) {
+                theApp._manager.addToLog(_T("Organization data received."));
+                theApp._manager.addToLog(_T("Trying to log in with credentials"));
+                error = theApp._manager.getAccessTokenForCredentials(username, password);
+                if (error == LauncherUtils::ResponseError::NoError) {
+                    theApp._manager.addToLog(_T("Logged in correctly."));
+                    setDrawDialog(DrawStep::DrawChoose);
+                } else if (error == LauncherUtils::ResponseError::BadCredentials) {
+                    theApp._manager.addToLog(_T("Bad credentials. Try again"));
+                    setDrawDialog(DrawStep::DrawLoginErrorCred);
+                } else {
+                    theApp._manager.addToLog(_T("Error Reading or retrieving response."));
+                    MessageBox(L"Error Reading or retrieving response.", L"Network Error", MB_OK | MB_ICONERROR);
+                }
+            } else {
+                theApp._manager.addToLog(_T("Organization name does not exist."));
+                setDrawDialog(DrawStep::DrawLoginErrorOrg);
+            }
+        }
+    } else {
+        CString displayName;
+        m_username.GetWindowTextW(displayName);
+        theApp._manager.setDisplayName(displayName);
+        theApp._manager.addToLog(_T("Setting display name: " + displayName));
+        startProcess();
+    }
 }
 
 void CLauncherDlg::drawBackground(CHwndRenderTarget* pRenderTarget) {
@@ -534,11 +578,13 @@ void CLauncherDlg::OnTimer(UINT_PTR nIDEvent) {
 	}
 	if (_showSplash) {
 		if (_splashStep == 0){
-			if (theApp._manager.needsUninstall()) {
-				setDrawDialog(DrawStep::DrawProcessUninstall);
-			} else {
-				setDrawDialog(DrawStep::DrawLogo);
-			}			
+            if (theApp._manager.needsUninstall()) {
+                theApp._manager.addToLog(_T("Waiting to uninstall"));
+                setDrawDialog(DrawStep::DrawProcessUninstall);
+            } else {
+                theApp._manager.addToLog(_T("Start splash screen"));
+                setDrawDialog(DrawStep::DrawLogo);
+            }			
 		} else if (_splashStep > 100) {
 			_showSplash = false;
 			if (theApp._manager.shouldShutDown()) {
@@ -551,6 +597,7 @@ void CLauncherDlg::OnTimer(UINT_PTR nIDEvent) {
 				theApp._manager.uninstallApplication();
 				exit(0);
 			} else {
+                theApp._manager.addToLog(_T("Starting login"));
 				setDrawDialog(DrawStep::DrawLoginLogin);
 			}
 		}
diff --git a/launchers/win32/LauncherDlg.h b/launchers/win32/LauncherDlg.h
index 55bc97f205..d743dd31d2 100644
--- a/launchers/win32/LauncherDlg.h
+++ b/launchers/win32/LauncherDlg.h
@@ -38,6 +38,7 @@ public:
 	};
 
 	CLauncherDlg(CWnd* pParent = nullptr);
+    ~CLauncherDlg();
 	virtual BOOL PreTranslateMessage(MSG* pMsg);
 
 	void setDrawDialog(DrawStep step, BOOL isUpdate = FALSE);
diff --git a/launchers/win32/LauncherManager.cpp b/launchers/win32/LauncherManager.cpp
index 94a659a4d7..3dc7ddedcc 100644
--- a/launchers/win32/LauncherManager.cpp
+++ b/launchers/win32/LauncherManager.cpp
@@ -9,6 +9,7 @@
 //
 
 #include "stdafx.h"
+#include <time.h>
 #include <fstream>
 
 #include "LauncherManager.h"
@@ -24,19 +25,57 @@ LauncherManager::~LauncherManager()
 }
 
 void LauncherManager::init() {
-	getMostRecentBuild(_latestApplicationURL, _latestVersion);
-	CString currentVersion;
-	if (isApplicationInstalled(currentVersion, _domainURL, _contentURL, _loggedIn) && _loggedIn) {
-		if (_latestVersion.Compare(currentVersion) == 0) {
-			launchApplication();
-			_shouldShutdown = TRUE;
-		} else {
-			_shouldUpdate = TRUE;
-		}
-	}
+    initLog();
+    addToLog(_T("Getting most recent build"));
+    getMostRecentBuild(_latestApplicationURL, _latestVersion);
+    addToLog(_T("Latest version: ") + _latestVersion);
+    CString currentVersion;
+    if (isApplicationInstalled(currentVersion, _domainURL, _contentURL, _loggedIn) && _loggedIn) {
+        addToLog(_T("Installed version: ") + currentVersion);
+        if (_latestVersion.Compare(currentVersion) == 0) {
+            addToLog(_T("Already running most recent build. Launching interface.exe"));
+            launchApplication();
+            _shouldShutdown = TRUE;
+        } else {
+            addToLog(_T("New build found. Updating"));
+            _shouldUpdate = TRUE;
+        }
+    }
+}
+
+BOOL LauncherManager::initLog() {
+    CString logPath;
+    auto result = getAndCreatePaths(PathType::Launcher_Directory, logPath);
+    if (result) {
+        logPath += _T("log.txt");
+        return result = _logFile.Open(logPath, CFile::modeCreate | CFile::modeReadWrite);
+    }
+    return FALSE;
+}
+
+BOOL LauncherManager::addToLog(const CString& line) {
+    if (_logFile.m_hFile != CStdioFile::hFileNull) {
+        char buff[100];
+        time_t now = time(0);
+        tm ltm;
+        localtime_s(&ltm, &now);
+
+        strftime(buff, 100, "%Y-%m-%d %H:%M:%S", &ltm);
+        CString timeStr = CString(buff);
+        _logFile.WriteString(timeStr + _T("  ") + line + _T("\n"));
+        return TRUE;
+    }
+    return FALSE;
+}
+
+void LauncherManager::closeLog() {
+    if (_logFile.m_hFile != CStdioFile::hFileNull) {
+        _logFile.Close();
+    }
 }
 
 BOOL LauncherManager::installLauncher() {
+    addToLog(_T("Installing Launcher."));
 	CString appPath;
 	BOOL result = getAndCreatePaths(PathType::Running_Path, appPath);
 	if (!result) {
@@ -60,6 +99,7 @@ BOOL LauncherManager::installLauncher() {
 			CopyFile(appPath, instalationPath, FALSE);
 		}
 	} else if (_shouldUninstall) {
+        addToLog(_T("Launching uninstall mode."));
 		CString tempPath;
 		if (getAndCreatePaths(PathType::Temp_Directory, tempPath)) {
 			tempPath += _T("\\HQ_uninstaller_tmp.exe");
@@ -73,6 +113,7 @@ BOOL LauncherManager::installLauncher() {
 
 BOOL LauncherManager::createShortcuts() {
 	CString desktopLnkPath;
+    addToLog(_T("Creating shortcuts."));
 	getAndCreatePaths(PathType::Desktop_Directory, desktopLnkPath);
 	desktopLnkPath += _T("\\HQ Launcher.lnk");
 	CString installDir;
@@ -100,6 +141,7 @@ BOOL LauncherManager::createShortcuts() {
 
 BOOL LauncherManager::deleteShortcuts() {
 	CString desktopLnkPath;
+    addToLog(_T("Deleting shortcuts."));
 	getAndCreatePaths(PathType::Desktop_Directory, desktopLnkPath);
 	desktopLnkPath += _T("\\HQ Launcher.lnk");
 	BOOL success = LauncherUtils::deleteFileOrDirectory(desktopLnkPath);
@@ -353,13 +395,17 @@ BOOL LauncherManager::uninstallApplication() {
 
 void LauncherManager::onZipExtracted(ZipType type, int size) {
 	if (type == ZipType::ZipContent) {
+        addToLog(_T("Downloading application."));
 		downloadApplication();
 	} else if (type == ZipType::ZipApplication) {
 		createShortcuts();
 		CString versionPath;
 		getAndCreatePaths(LauncherManager::PathType::Launcher_Directory, versionPath);
-		createConfigJSON();
+        addToLog(_T("Creating config.json"));
+        createConfigJSON();
+        addToLog(_T("Launching application."));
 		launchApplication(_tokensJSON);
+        addToLog(_T("Creating registry keys."));
 		createApplicationRegistryKeys(size);
 		_shouldShutdown = TRUE;
 	}
@@ -377,8 +423,10 @@ BOOL LauncherManager::extractApplication() {
 
 void LauncherManager::onFileDownloaded(DownloadType type) {
 	if (type == DownloadType::DownloadContent) {
+        addToLog(_T("Installing content."));
 		installContent();
 	} else if (type == DownloadType::DownloadApplication) {
+            addToLog(_T("Installing application."));
 		extractApplication();
 	}
 }
@@ -412,6 +460,7 @@ BOOL LauncherManager::downloadFile(DownloadType type, const CString& url, CStrin
 }
 
 BOOL LauncherManager::downloadContent() {
+    addToLog(_T("Downloading content."));
 	CString contentURL = getContentURL();
 	return downloadFile(DownloadType::DownloadContent, contentURL, _contentZipPath);
 }
diff --git a/launchers/win32/LauncherManager.h b/launchers/win32/LauncherManager.h
index 3ad21694f6..4bc09b49ca 100644
--- a/launchers/win32/LauncherManager.h
+++ b/launchers/win32/LauncherManager.h
@@ -53,6 +53,9 @@ public:
 	LauncherManager();
 	~LauncherManager();
 	void init();
+    BOOL initLog();
+    BOOL addToLog(const CString& line);
+    void closeLog();
 	BOOL getAndCreatePaths(PathType type, CString& outPath);
 	BOOL getInstalledVersion(const CString& path, CString& version);
 	BOOL isApplicationInstalled(CString& version, CString& domain,
@@ -105,5 +108,6 @@ private:
 	BOOL _shouldUpdate{ FALSE };
 	BOOL _shouldUninstall{ FALSE };
 	BOOL _shouldShutdown{ FALSE };
+    CStdioFile _logFile;
 };
 
diff --git a/launchers/win32/LauncherUtils.cpp b/launchers/win32/LauncherUtils.cpp
index 8a75747e9b..22724ac499 100644
--- a/launchers/win32/LauncherUtils.cpp
+++ b/launchers/win32/LauncherUtils.cpp
@@ -17,6 +17,24 @@
 
 #include "LauncherUtils.h"
 
+CString LauncherUtils::urlEncodeString(const CString& url) {
+    std::map<CString, CString> specialCharsMap = { { _T("$"), _T("%24") }, { _T(" "), _T("%20") }, { _T("#"), _T("%23") },
+                                                   { _T("@"), _T("%40") }, { _T("`"), _T("%60") }, { _T("&"), _T("%26") },
+                                                   { _T("/"), _T("%2F") }, { _T(":"), _T("%3A") }, { _T(";"), _T("%3B") },
+                                                   { _T("<"), _T("%3C") }, { _T(">"), _T("%3E") }, { _T("="), _T("%3D") },
+                                                   { _T("?"), _T("%3F") }, { _T("["), _T("%5B") }, { _T("\\"), _T("%5C") },
+                                                   { _T("]"), _T("%5D") }, { _T("^"), _T("%5E") }, { _T("{"), _T("%7B") },
+                                                   { _T("|"), _T("%7C") }, { _T("}"), _T("%7D") }, { _T("~"), _T("%7E") },
+                                                   { _T("�"), _T("%22") }, { _T("�"), _T("%27") }, { _T("+"), _T("%2B") },
+                                                   { _T(","), _T("%2C") } };
+    CString stringOut = url;
+    stringOut.Replace(_T("%"), _T("%25"));
+    for (auto& itr = specialCharsMap.begin(); itr != specialCharsMap.end(); itr++) {
+        stringOut.Replace(itr->first, itr->second);
+    }
+    return stringOut;
+}
+
 BOOL LauncherUtils::IsProcessRunning(const wchar_t *processName) {
 	bool exists = false;
 	PROCESSENTRY32 entry;
@@ -374,6 +392,19 @@ DWORD WINAPI LauncherUtils::downloadThread(LPVOID lpParameter)
 	return 0;
 }
 
+DWORD WINAPI LauncherUtils::deleteDirectoriesThread(LPVOID lpParameter) {
+    DeleteThreadData& data = *((DeleteThreadData*)lpParameter);
+    DeleteDirError error = DeleteDirError::NoErrorDeleting;
+    if (!LauncherUtils::deleteFileOrDirectory(data._applicationDir)) {
+        error = DeleteDirError::ErrorDeletingApplicationDir;
+    }
+    if (!LauncherUtils::deleteFileOrDirectory(data._downloadsDir)) {
+        error = error == NoError ? DeleteDirError::ErrorDeletingDownloadsDir : DeleteDirError::ErrorDeletingBothDirs;
+    }
+    data.callback(error);
+    return 0;
+}
+
 BOOL LauncherUtils::unzipFileOnThread(int type, const std::string& zipFile, const std::string& path, std::function<void(int, int)> callback) {
 	DWORD myThreadID;
 	UnzipThreadData* unzipThreadData = new UnzipThreadData();
@@ -402,4 +433,20 @@ BOOL LauncherUtils::downloadFileOnThread(int type, const CString& url, const CSt
 		return TRUE;
 	}
 	return FALSE;
-}
\ No newline at end of file
+}
+
+BOOL LauncherUtils::deleteDirectoriesOnThread(const CString& applicationDir,
+                                              const CString& downloadsDir,
+                                              std::function<void(int)> callback) {
+    DWORD myThreadID;
+    DeleteThreadData* deleteThreadData = new DeleteThreadData();
+    deleteThreadData->_applicationDir = applicationDir;
+    deleteThreadData->_downloadsDir = downloadsDir;
+    deleteThreadData->setCallback(callback);
+    HANDLE myHandle = CreateThread(0, 0, deleteDirectoriesThread, deleteThreadData, 0, &myThreadID);
+    if (myHandle) {
+        CloseHandle(myHandle);
+        return TRUE;
+    }
+    return FALSE;
+}
diff --git a/launchers/win32/LauncherUtils.h b/launchers/win32/LauncherUtils.h
index 3e9f18d892..47a8fc56c8 100644
--- a/launchers/win32/LauncherUtils.h
+++ b/launchers/win32/LauncherUtils.h
@@ -30,6 +30,13 @@ public:
 		NoError
 	};
 
+    enum DeleteDirError {
+        NoErrorDeleting = 0,
+        ErrorDeletingApplicationDir,
+        ErrorDeletingDownloadsDir,
+        ErrorDeletingBothDirs
+    };
+
 	struct DownloadThreadData {
 		int _type;
 		CString _url;
@@ -52,6 +59,13 @@ public:
 		}
 	};
 
+    struct DeleteThreadData {
+        CString _applicationDir;
+        CString _downloadsDir;
+        std::function<void(int)> callback;
+        void setCallback(std::function<void(int)> fn) { callback = std::bind(fn, std::placeholders::_1); }
+    };
+
 	static BOOL parseJSON(const CString& jsonTxt, Json::Value& jsonObject);
 	static ResponseError makeHTTPCall(const CString& callerName, const CString& mainUrl,
 		const CString& dirUrl, const CString& contentType,
@@ -69,9 +83,14 @@ public:
 	static BOOL deleteRegistryKey(const CString& registryPath);
 	static BOOL unzipFileOnThread(int type, const std::string& zipFile, const std::string& path, std::function<void(int, int)> callback);
 	static BOOL downloadFileOnThread(int type, const CString& url, const CString& file, std::function<void(int)> callback);
+    static BOOL deleteDirectoriesOnThread(const CString& applicationDir,
+                                              const CString& downloadsDir,
+                                              std::function<void(int)> callback);
+    static CString urlEncodeString(const CString& url);
 
 private:
 	// Threads
 	static DWORD WINAPI unzipThread(LPVOID lpParameter);
 	static DWORD WINAPI downloadThread(LPVOID lpParameter);
+    static DWORD WINAPI deleteDirectoriesThread(LPVOID lpParameter);
 };
\ No newline at end of file