@echo off REM ==================================================================== REM ConnectWise RMM Migration Worker REM Uninstalls old RMM and installs new tenant RMM REM ==================================================================== SET "New_Tenant_Agent_URL=%~1" SET TEMP_DIR=C:\Temp REM Create temp directory if it doesn't exist if not exist "%TEMP_DIR%" mkdir "%TEMP_DIR%" REM Create timestamped log filename using PowerShell (Windows 11 compatible) for /f "tokens=1-6 delims=/: " %%a in ('powershell -Command "Get-Date -Format 'yyyyMMdd_HHmmss'"') do set timestamp=%%a SET LOG_FILE=%TEMP_DIR%\RMM_Migration_%timestamp%.log echo ================================================ > "%LOG_FILE%" echo ConnectWise RMM Migration Worker Log >> "%LOG_FILE%" echo Started: %date% %time% >> "%LOG_FILE%" echo ================================================ >> "%LOG_FILE%" echo. >> "%LOG_FILE%" echo New Tenant URL: %New_Tenant_Agent_URL% >> "%LOG_FILE%" echo. >> "%LOG_FILE%" REM Wait 60 seconds for RMM processes to stop echo Waiting 60 seconds for RMM processes to stop... >> "%LOG_FILE%" timeout /t 60 /nobreak >nul REM Extract installer name for /f "usebackq delims=" %%a in (`powershell -Command "$url = '%New_Tenant_Agent_URL%'; $parts = $url -split '/'; $parts[-3]"`) do set INSTALLER_NAME=%%a if "%INSTALLER_NAME%"=="" ( echo ERROR: Could not extract installer name >> "%LOG_FILE%" exit /b 1 ) echo Installer Name: %INSTALLER_NAME%.msi >> "%LOG_FILE%" SET INSTALLER_PATH=%TEMP_DIR%\%INSTALLER_NAME%.msi SET DOWNLOAD_URL=%New_Tenant_Agent_URL% echo ================================================ >> "%LOG_FILE%" echo Step 1: Uninstalling old ConnectWise RMM agent >> "%LOG_FILE%" echo ================================================ >> "%LOG_FILE%" REM Get product code FIRST before any uninstall attempts (PowerShell - works Windows 7 through 11) for /f "delims=" %%a in ('powershell -Command "$p = Get-WmiObject -Class Win32_Product -Filter \"Name='ITSPlatform'\" -ErrorAction SilentlyContinue; if ($p) { $p.IdentifyingNumber }"') do set PRODUCTCODE=%%a if defined PRODUCTCODE ( echo Found product code: %PRODUCTCODE% >> "%LOG_FILE%" echo Uninstalling via msiexec... >> "%LOG_FILE%" msiexec /x %PRODUCTCODE% /qn /norestart /L*v "%TEMP_DIR%\RMM_Uninstall.log" echo msiexec uninstall exit code: %errorLevel% >> "%LOG_FILE%" timeout /t 30 /nobreak >nul ) else ( echo Product code not found via WMIC >> "%LOG_FILE%" ) REM Try PowerShell uninstall as backup (works Windows 7 through 11) echo Attempting PowerShell uninstall... >> "%LOG_FILE%" powershell -Command "$p = Get-WmiObject -Class Win32_Product -Filter \"Name='ITSPlatform'\" -ErrorAction SilentlyContinue; if ($p) { $p.Uninstall() }" >> "%LOG_FILE%" 2>&1 timeout /t 10 /nobreak >nul REM Force uninstall any remaining ITSPlatform installations (PowerShell) echo Forcing removal of any remaining installations... >> "%LOG_FILE%" for /f "delims=" %%a in ('powershell -Command "$products = Get-WmiObject -Class Win32_Product -Filter \"Name='ITSPlatform'\" -ErrorAction SilentlyContinue; if ($products) { $products.IdentifyingNumber }"') do ( echo Found remaining installation: %%a >> "%LOG_FILE%" msiexec /x %%a /qn /norestart >> "%LOG_FILE%" 2>&1 timeout /t 15 /nobreak >nul ) timeout /t 10 /nobreak >nul REM Check if ITSPlatform still exists using PowerShell powershell -Command "$p = Get-WmiObject -Class Win32_Product -Filter \"Name='ITSPlatform'\" -ErrorAction SilentlyContinue; if ($p) { exit 0 } else { exit 1 }" >nul 2>&1 if %errorLevel% equ 0 ( echo WARNING: Old RMM agent may still be present >> "%LOG_FILE%" timeout /t 20 /nobreak >nul ) else ( echo Old RMM agent successfully removed >> "%LOG_FILE%" ) echo ================================================ >> "%LOG_FILE%" echo Step 2: Additional Cleanup >> "%LOG_FILE%" echo ================================================ >> "%LOG_FILE%" REM Kill any remaining ITSPlatform processes echo Stopping any remaining ITSPlatform processes... >> "%LOG_FILE%" taskkill /f /im platform-agent-core.exe >nul 2>&1 taskkill /f /im platform-agent-manager.exe >nul 2>&1 taskkill /f /im platform-installation-manager.exe >nul 2>&1 taskkill /f /im ITSPlatform.exe >nul 2>&1 taskkill /f /im AdvancedMonitoringAgent.exe >nul 2>&1 REM Stop any remaining services echo Stopping any remaining services... >> "%LOG_FILE%" sc stop ITSPlatform >nul 2>&1 sc stop ITSPlatformManager >nul 2>&1 sc stop AdvancedMonitoringAgent >nul 2>&1 REM Delete any remaining services echo Deleting any remaining services... >> "%LOG_FILE%" sc delete ITSPlatform >nul 2>&1 sc delete ITSPlatformManager >nul 2>&1 sc delete AdvancedMonitoringAgent >nul 2>&1 REM Wait for cleanup timeout /t 15 /nobreak >nul REM Restart Windows Installer service echo Restarting Windows Installer service... >> "%LOG_FILE%" net stop msiserver >> "%LOG_FILE%" 2>&1 timeout /t 10 /nobreak >nul net start msiserver >> "%LOG_FILE%" 2>&1 timeout /t 10 /nobreak >nul echo Cleanup completed >> "%LOG_FILE%" echo Waiting for system to stabilize... >> "%LOG_FILE%" timeout /t 60 /nobreak >nul echo ================================================ >> "%LOG_FILE%" echo Step 3: Downloading new RMM installer >> "%LOG_FILE%" echo ================================================ >> "%LOG_FILE%" if exist "%INSTALLER_PATH%" del /f /q "%INSTALLER_PATH%" echo Downloading from: %DOWNLOAD_URL% >> "%LOG_FILE%" powershell -Command "& {[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; (New-Object System.Net.WebClient).DownloadFile('%DOWNLOAD_URL%', '%INSTALLER_PATH%')}" >> "%LOG_FILE%" 2>&1 if %errorLevel% neq 0 ( echo PowerShell download failed, trying bitsadmin... >> "%LOG_FILE%" bitsadmin /transfer "RMMDownload" /priority high "%DOWNLOAD_URL%" "%INSTALLER_PATH%" >> "%LOG_FILE%" 2>&1 ) if not exist "%INSTALLER_PATH%" ( echo ERROR: Installer download failed >> "%LOG_FILE%" exit /b 1 ) for %%A in ("%INSTALLER_PATH%") do set FILE_SIZE=%%~zA echo Download completed - Size: %FILE_SIZE% bytes >> "%LOG_FILE%" REM Calculate retry time (10 minutes from now) BEFORE attempting install for /f "tokens=1-3 delims=:." %%a in ("%time%") do ( set /a hour=%%a set /a minute=%%b + 10 ) if %minute% geq 60 ( set /a minute=%minute% - 60 set /a hour=%hour% + 1 ) if %hour% geq 24 set /a hour=%hour% - 24 if %hour% lss 10 set hour=0%hour% if %minute% lss 10 set minute=0%minute% set retrytime=%hour%:%minute% REM Pre-create retry task in case installation hangs or fails echo Creating safety retry task for %retrytime%... >> "%LOG_FILE%" schtasks /delete /tn "RMM_Migration_Retry" /f >nul 2>&1 schtasks /create /tn "RMM_Migration_Retry" /tr "msiexec /i \"%INSTALLER_PATH%\" /qn /norestart /L*v \"%TEMP_DIR%\RMM_Install_Retry.log\"" /sc once /st %retrytime% /ru SYSTEM /rl HIGHEST /f >nul 2>&1 echo ================================================ >> "%LOG_FILE%" echo Step 4: Installing new RMM agent >> "%LOG_FILE%" echo ================================================ >> "%LOG_FILE%" echo If installation fails, retry will run at %retrytime% >> "%LOG_FILE%" msiexec /i "%INSTALLER_PATH%" /qn /norestart /L*v "%TEMP_DIR%\RMM_Install.log" SET INSTALL_EXITCODE=%errorLevel% REM Check for success codes (0 = success, 3010 = success with reboot required) if %INSTALL_EXITCODE% equ 0 ( echo Installation completed successfully >> "%LOG_FILE%" echo Deleting retry task (no longer needed) >> "%LOG_FILE%" schtasks /delete /tn "RMM_Migration_Retry" /f >nul 2>&1 goto :install_complete ) if %INSTALL_EXITCODE% equ 3010 ( echo Installation successful - Reboot required >> "%LOG_FILE%" echo Deleting retry task (no longer needed) >> "%LOG_FILE%" schtasks /delete /tn "RMM_Migration_Retry" /f >nul 2>&1 goto :install_complete ) REM If we get here, installation failed echo Installation failed - Exit code: %INSTALL_EXITCODE% >> "%LOG_FILE%" echo Retry task will execute at %retrytime% >> "%LOG_FILE%" echo Check retry log: %TEMP_DIR%\RMM_Install_Retry.log >> "%LOG_FILE%" :install_complete timeout /t 60 /nobreak >nul echo ================================================ >> "%LOG_FILE%" echo Step 5: Verifying installation >> "%LOG_FILE%" echo ================================================ >> "%LOG_FILE%" REM Verify ITSPlatform installation using PowerShell powershell -Command "$p = Get-WmiObject -Class Win32_Product -Filter \"Name='ITSPlatform'\" -ErrorAction SilentlyContinue; if ($p) { Write-Host \"Name: $($p.Name), Version: $($p.Version)\" }" >> "%LOG_FILE%" 2>&1 REM Check for ScreenConnect/ConnectWise Control backup using PowerShell powershell -Command "$sc = Get-WmiObject -Class Win32_Product | Where-Object { $_.Name -like '*ScreenConnect*' }; if ($sc) { exit 0 } else { exit 1 }" >nul 2>&1 if %errorLevel% equ 0 ( echo ScreenConnect backup present >> "%LOG_FILE%" ) else ( powershell -Command "$cw = Get-WmiObject -Class Win32_Product | Where-Object { $_.Name -like '*ConnectWise Control*' }; if ($cw) { exit 0 } else { exit 1 }" >nul 2>&1 if %errorLevel% equ 0 ( echo ConnectWise Control backup present >> "%LOG_FILE%" ) else ( echo WARNING: No ScreenConnect backup detected >> "%LOG_FILE%" ) ) echo ================================================ >> "%LOG_FILE%" echo Migration completed: %date% %time% >> "%LOG_FILE%" echo ================================================ >> "%LOG_FILE%" schtasks /delete /tn "RMM_Migration" /f >nul 2>&1 exit /b %INSTALL_EXITCODE%