From 4fdf7bc4d1ed6dfe222789f2fffe5a4de00b4cff Mon Sep 17 00:00:00 2001 From: uhlwoogi Date: Tue, 14 Apr 2026 13:20:09 +0000 Subject: [PATCH] Add TacticalRMM and RustDesk deployment scripts Co-Authored-By: Claude Sonnet 4.6 --- 1-Install-TacticalRMM-and-RustDesk.ps1 | 166 +++++++++++++++++++++++++ 2-Install-RustDesk-Standalone.ps1 | 101 +++++++++++++++ 3-Uninstall-RustDesk.ps1 | 109 ++++++++++++++++ 3 files changed, 376 insertions(+) create mode 100644 1-Install-TacticalRMM-and-RustDesk.ps1 create mode 100644 2-Install-RustDesk-Standalone.ps1 create mode 100644 3-Uninstall-RustDesk.ps1 diff --git a/1-Install-TacticalRMM-and-RustDesk.ps1 b/1-Install-TacticalRMM-and-RustDesk.ps1 new file mode 100644 index 0000000..90728a9 --- /dev/null +++ b/1-Install-TacticalRMM-and-RustDesk.ps1 @@ -0,0 +1,166 @@ +# author: https://github.com/bradhawkins85 +# modified: added RustDesk (ScoutIT-RemoteSupport) silent install with service verification and ID output +$ErrorActionPreference = 'SilentlyContinue' + +$innosetup = 'tacticalagent-v2.10.0-windows-amd64.exe' +$api = '"https://apirmm.scoutitsystems.com"' +$clientid = '1' +$siteid = '1' +$agenttype = '"workstation"' +$power = 0 +$rdp = 0 +$ping = 0 +$auth = '"f77cac29dc421abacbfc1882c2700b655f7a4bcf6500aaec040208dc2a5bdbff"' +$downloadlink = 'https://agents.tacticalrmm.com/api/v2/agents/?version=2.10.0&arch=amd64&token=f3c1cbee-7d48-4f2a-8f0a-7cc33bb42802&plat=windows&api=apirmm.scoutitsystems.com' +$apilink = $downloadlink.split('/') + +# ── RustDesk / ScoutIT Remote Support config ────────────────────────────────── +$rustdeskMsi = 'estudio-scoutit-remotesupport.msi' +$rustdeskDl = 'https://files.scoutitsystems.com/public/api/raw?hash=VOG5D5aP2ih-2KAaDT0h4Q' +$rustdeskInstallDir = 'C:\Program Files\ScoutIT-RemoteSupport' +$rustdeskService = 'ScoutIT-RemoteSupport' + +[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 + +# ── Helper: Install RustDesk ────────────────────────────────────────────────── +function Install-RustDesk { + $msiPath = "$env:TMP\$rustdeskMsi" + + # Download + Write-Host "Downloading ScoutIT Remote Support client..." + Try { + Invoke-WebRequest -Uri $rustdeskDl -OutFile $msiPath + } + Catch { + Write-Warning "RustDesk download failed: $($_.Exception.Message)" + return + } + + # Silent MSI install + Write-Host "Installing ScoutIT Remote Support client silently..." + Try { + Start-Process -FilePath "msiexec.exe" ` + -ArgumentList "/i `"$msiPath`" /qn /norestart CREATEDESKTOPSHORTCUTS=`"N`" INSTALLPRINTER=`"N`"" ` + -Wait + Start-Sleep -Seconds 10 + } + Catch { + Write-Warning "RustDesk MSI install failed: $($_.Exception.Message)" + return + } + Finally { + if (Test-Path $msiPath) { Remove-Item -Path $msiPath -Force } + } + + # Locate the installed exe + $rustdeskExe = "$rustdeskInstallDir\$($rustdeskMsi -replace '\.msi$', '.exe')" + if (-not (Test-Path $rustdeskExe)) { + Write-Host "Searching for RustDesk exe in Program Files..." + $found = Get-ChildItem 'C:\Program Files' -Recurse -Filter '*.exe' -ErrorAction SilentlyContinue | + Where-Object { $_.Name -match 'rustdesk|scoutit|remotesupport' } | + Select-Object -First 1 + if ($found) { + $rustdeskExe = $found.FullName + Write-Host "Found exe at: $rustdeskExe" + } else { + Write-Warning "Could not locate RustDesk exe. Skipping service and ID steps." + return + } + } + + $exeDir = Split-Path $rustdeskExe + + # Install service if not present + $svc = Get-Service -Name $rustdeskService -ErrorAction SilentlyContinue + if ($null -eq $svc) { + Write-Host "Registering ScoutIT Remote Support service..." + Start-Process -FilePath $rustdeskExe -ArgumentList '--install-service' -Wait + Start-Sleep -Seconds 20 + $svc = Get-Service -Name $rustdeskService -ErrorAction SilentlyContinue + } + + # Ensure service is running + if ($null -ne $svc) { + $attempts = 0 + while ($svc.Status -ne 'Running' -and $attempts -lt 5) { + Write-Host "Starting ScoutIT Remote Support service (attempt $($attempts + 1))..." + Start-Service -Name $rustdeskService -ErrorAction SilentlyContinue + Start-Sleep -Seconds 5 + $svc.Refresh() + $attempts++ + } + if ($svc.Status -eq 'Running') { + Write-Host "ScoutIT Remote Support service is running." + } else { + Write-Warning "ScoutIT Remote Support service did not reach Running state." + } + } else { + Write-Warning "Service '$rustdeskService' not found after install." + } + + # Get and output the RustDesk ID (visible in RMM job logs) + Push-Location $exeDir + $rustdeskId = & $rustdeskExe --get-id 2>&1 + Pop-Location + + Write-Output "................................................." + Write-Output "ScoutIT Remote Support ID: $rustdeskId" + Write-Output "................................................." +} + +# ── Tactical RMM ───────────────────────────────────────────────────────────── +$serviceName = 'tacticalrmm' +If (Get-Service $serviceName -ErrorAction SilentlyContinue) { + Write-Host "Tactical RMM Is Already Installed" +} Else { + $OutPath = $env:TMP + $output = $innosetup + $installArgs = @('-m install --api ', "$api", '--client-id', $clientid, '--site-id', $siteid, '--agent-type', "$agenttype", '--auth', "$auth") + if ($power) { $installArgs += "--power" } + if ($rdp) { $installArgs += "--rdp" } + if ($ping) { $installArgs += "--ping" } + + Try { + $DefenderStatus = Get-MpComputerStatus | Select-Object AntivirusEnabled + if ($DefenderStatus -match "True") { + Add-MpPreference -ExclusionPath 'C:\Program Files\TacticalAgent\*' + Add-MpPreference -ExclusionPath 'C:\Program Files\Mesh Agent\*' + Add-MpPreference -ExclusionPath 'C:\ProgramData\TacticalRMM\*' + } + } + Catch { # pass + } + + $X = 0 + do { + Write-Output "Waiting for network" + Start-Sleep -s 5 + $X += 1 + } until (($connectresult = Test-NetConnection $apilink[2] -Port 443 | Where-Object { $_.TcpTestSucceeded }) -or $X -eq 3) + + if ($connectresult.TcpTestSucceeded -eq $true) { + Try { + Invoke-WebRequest -Uri $downloadlink -OutFile "$OutPath\$output" + Start-Process -FilePath "$OutPath\$output" -ArgumentList '/VERYSILENT /SUPPRESSMSGBOXES' -Wait + Write-Host "Extracting..." + Start-Sleep -s 5 + Start-Process -FilePath "C:\Program Files\TacticalAgent\tacticalrmm.exe" -ArgumentList $installArgs -Wait + + # ── Install RustDesk after Tactical RMM ── + Install-RustDesk + + exit 0 + } + Catch { + $ErrorMessage = $_.Exception.Message + $FailedItem = $_.Exception.ItemName + Write-Error -Message "$ErrorMessage $FailedItem" + exit 1 + } + Finally { + if (Test-Path "$OutPath\$output") { Remove-Item -Path "$OutPath\$output" -Force } + } + } else { + Write-Output "Unable to connect to server" + } +} diff --git a/2-Install-RustDesk-Standalone.ps1 b/2-Install-RustDesk-Standalone.ps1 new file mode 100644 index 0000000..814b883 --- /dev/null +++ b/2-Install-RustDesk-Standalone.ps1 @@ -0,0 +1,101 @@ +# ScoutIT Remote Support (RustDesk) - Standalone Install Script +$ErrorActionPreference = 'SilentlyContinue' + +# ── Config ──────────────────────────────────────────────────────────────────── +$rustdeskMsi = 'estudio-scoutit-remotesupport.msi' +$rustdeskDl = 'https://files.scoutitsystems.com/public/api/raw?hash=VOG5D5aP2ih-2KAaDT0h4Q' +$rustdeskInstallDir = 'C:\Program Files\ScoutIT-RemoteSupport' +$rustdeskService = 'ScoutIT-RemoteSupport' + +[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 + +# ── Check if already installed ──────────────────────────────────────────────── +$svcCheck = Get-Service -Name $rustdeskService -ErrorAction SilentlyContinue +if ($null -ne $svcCheck) { + Write-Host "ScoutIT Remote Support is already installed. Exiting." + exit 0 +} + +# ── Download ────────────────────────────────────────────────────────────────── +$msiPath = "$env:TMP\$rustdeskMsi" +Write-Host "Downloading ScoutIT Remote Support client..." +Try { + Invoke-WebRequest -Uri $rustdeskDl -OutFile $msiPath +} +Catch { + Write-Error "Download failed: $($_.Exception.Message)" + exit 1 +} + +# ── Silent MSI install ──────────────────────────────────────────────────────── +Write-Host "Installing ScoutIT Remote Support client silently..." +Try { + Start-Process -FilePath "msiexec.exe" ` + -ArgumentList "/i `"$msiPath`" /qn /norestart CREATEDESKTOPSHORTCUTS=`"N`" INSTALLPRINTER=`"N`"" ` + -Wait + Start-Sleep -Seconds 10 +} +Catch { + Write-Error "MSI install failed: $($_.Exception.Message)" + exit 1 +} +Finally { + if (Test-Path $msiPath) { Remove-Item -Path $msiPath -Force } +} + +# ── Locate the installed exe ────────────────────────────────────────────────── +$rustdeskExe = "$rustdeskInstallDir\$($rustdeskMsi -replace '\.msi$', '.exe')" +if (-not (Test-Path $rustdeskExe)) { + Write-Host "Searching for RustDesk exe in Program Files..." + $found = Get-ChildItem 'C:\Program Files' -Recurse -Filter '*.exe' -ErrorAction SilentlyContinue | + Where-Object { $_.Name -match 'rustdesk|scoutit|remotesupport' } | + Select-Object -First 1 + if ($found) { + $rustdeskExe = $found.FullName + Write-Host "Found exe at: $rustdeskExe" + } else { + Write-Error "Could not locate RustDesk exe after install." + exit 1 + } +} + +$exeDir = Split-Path $rustdeskExe + +# ── Install service if not present ──────────────────────────────────────────── +$svc = Get-Service -Name $rustdeskService -ErrorAction SilentlyContinue +if ($null -eq $svc) { + Write-Host "Registering ScoutIT Remote Support service..." + Start-Process -FilePath $rustdeskExe -ArgumentList '--install-service' -Wait + Start-Sleep -Seconds 20 + $svc = Get-Service -Name $rustdeskService -ErrorAction SilentlyContinue +} + +# ── Ensure service is running ───────────────────────────────────────────────── +if ($null -ne $svc) { + $attempts = 0 + while ($svc.Status -ne 'Running' -and $attempts -lt 5) { + Write-Host "Starting ScoutIT Remote Support service (attempt $($attempts + 1))..." + Start-Service -Name $rustdeskService -ErrorAction SilentlyContinue + Start-Sleep -Seconds 5 + $svc.Refresh() + $attempts++ + } + if ($svc.Status -eq 'Running') { + Write-Host "ScoutIT Remote Support service is running." + } else { + Write-Warning "Service did not reach Running state after $attempts attempts." + } +} else { + Write-Warning "Service '$rustdeskService' not found after install." +} + +# ── Output RustDesk ID ──────────────────────────────────────────────────────── +Push-Location $exeDir +$rustdeskId = & $rustdeskExe --get-id 2>&1 +Pop-Location + +Write-Output "................................................." +Write-Output "ScoutIT Remote Support ID: $rustdeskId" +Write-Output "................................................." + +exit 0 diff --git a/3-Uninstall-RustDesk.ps1 b/3-Uninstall-RustDesk.ps1 new file mode 100644 index 0000000..0813364 --- /dev/null +++ b/3-Uninstall-RustDesk.ps1 @@ -0,0 +1,109 @@ +# ScoutIT Remote Support (RustDesk) - Uninstall Script +$ErrorActionPreference = 'SilentlyContinue' + +# ── Config ──────────────────────────────────────────────────────────────────── +$rustdeskInstallDir = 'C:\Program Files\ScoutIT-RemoteSupport' +$rustdeskService = 'ScoutIT-RemoteSupport' +$rustdeskMsiName = 'estudio-scoutit-remotesupport' # used to find uninstall key in registry + +[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 + +Write-Host "Starting ScoutIT Remote Support uninstall..." + +# ── Stop and unregister the service ────────────────────────────────────────── +$svc = Get-Service -Name $rustdeskService -ErrorAction SilentlyContinue +if ($null -ne $svc) { + Write-Host "Stopping ScoutIT Remote Support service..." + Stop-Service -Name $rustdeskService -Force -ErrorAction SilentlyContinue + Start-Sleep -Seconds 3 + + # Attempt graceful service uninstall via exe first + $rustdeskExe = Get-ChildItem $rustdeskInstallDir -Filter '*.exe' -ErrorAction SilentlyContinue | + Select-Object -First 1 + if ($rustdeskExe) { + Write-Host "Unregistering service via exe..." + Start-Process -FilePath $rustdeskExe.FullName -ArgumentList '--uninstall-service' -Wait + Start-Sleep -Seconds 5 + } +} else { + Write-Host "Service '$rustdeskService' not found - may already be removed." +} + +# ── MSI uninstall via registry ProductCode ─────────────────────────────────── +Write-Host "Looking for MSI uninstall entry in registry..." +$uninstallKeys = @( + 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*', + 'HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*' +) + +$productCode = $null +foreach ($key in $uninstallKeys) { + $match = Get-ItemProperty $key -ErrorAction SilentlyContinue | + Where-Object { $_.DisplayName -match 'scoutit|remotesupport|rustdesk' -or + $_.Publisher -match 'scoutit|rustdesk' } | + Select-Object -First 1 + if ($match) { + $productCode = $match.PSChildName + Write-Host "Found uninstall entry: $($match.DisplayName) [$productCode]" + break + } +} + +if ($productCode) { + Write-Host "Running MSI uninstall..." + Start-Process -FilePath "msiexec.exe" ` + -ArgumentList "/x `"$productCode`" /qn /norestart" ` + -Wait + Start-Sleep -Seconds 10 + Write-Host "MSI uninstall complete." +} else { + Write-Warning "No MSI uninstall entry found in registry. Falling back to manual removal." +} + +# ── Kill any remaining processes ───────────────────────────────────────────── +Write-Host "Killing any remaining RustDesk processes..." +Get-Process | Where-Object { $_.Path -match 'ScoutIT-RemoteSupport|rustdesk|scoutit' } | + Stop-Process -Force -ErrorAction SilentlyContinue +Start-Sleep -Seconds 2 + +# ── Remove install directory ────────────────────────────────────────────────── +if (Test-Path $rustdeskInstallDir) { + Write-Host "Removing install directory: $rustdeskInstallDir" + Remove-Item -Path $rustdeskInstallDir -Recurse -Force -ErrorAction SilentlyContinue + if (Test-Path $rustdeskInstallDir) { + Write-Warning "Directory still exists - may have locked files. You may need to reboot and re-run." + } else { + Write-Host "Install directory removed." + } +} else { + Write-Host "Install directory not found - already removed." +} + +# ── Remove leftover AppData / config ───────────────────────────────────────── +$appDataPaths = @( + "$env:APPDATA\ScoutIT-RemoteSupport", + "$env:APPDATA\RustDesk", + "$env:ProgramData\ScoutIT-RemoteSupport", + "$env:ProgramData\RustDesk" +) +foreach ($path in $appDataPaths) { + if (Test-Path $path) { + Write-Host "Removing: $path" + Remove-Item -Path $path -Recurse -Force -ErrorAction SilentlyContinue + } +} + +# ── Confirm ─────────────────────────────────────────────────────────────────── +$svcFinal = Get-Service -Name $rustdeskService -ErrorAction SilentlyContinue +$dirFinal = Test-Path $rustdeskInstallDir + +Write-Output "................................................." +if ($null -eq $svcFinal -and -not $dirFinal) { + Write-Output "ScoutIT Remote Support successfully uninstalled." +} else { + if ($null -ne $svcFinal) { Write-Warning "Service '$rustdeskService' still present." } + if ($dirFinal) { Write-Warning "Install directory still present - reboot may be required." } +} +Write-Output "................................................." + +exit 0