Team:Huntress EDR
Product: ConnectWise Control (ScreenConnect)
Environment: Windows
Summary: Deploy Huntress via ConnectWise Control (ScreenConnect) using PowerShell scripts.
In ConnectWise Control (ScreenConnect), you have the ability to run PowerShell scripts via the GUI.
Should you have the need to install the Huntress Agent via ScreenConnect, you can do so by hardcoding the values in the PowerShell script and copying and pasting it into your browser. See below
Considerations
- While the script is running, the Control page/agent for the Endpoint may appear "frozen." It will return to normal once the script finishes or the timeout period hits, whichever happens first.
- The script runtime and the script result limit are governed by global variables in the AppSetting Web.config. The values you have set may be lower than what's needed for the script to run (see screenshot below).
- Please take note that changing these settings will restart your ConnectWise Control Server.
- Please take note that changing these settings will restart your ConnectWise Control Server.
Copy & Paste Script
Change"__ACCOUNT_KEY__" and "__ORGANIZATION_KEY__" to your Account and Organization keys (in quotes). Copy the entire script and run it from the Control Window.
#!ps #timeout=90000 $AccountKey="__ACCOUNT_KEY__" $OrganizationKey="__ORGANIZATION_KEY__" # Set to "Continue" to enable verbose logging. $DebugPreference = "SilentlyContinue" ############################################################################## ## The following should not need to be adjusted. $reregister = $false $reinstall = $false $acctkey = $AccountKey $orgkey = $OrganizationKey Set-StrictMode -Version Latest $ScriptVersion = "2020 April 3; revision 1" $ScriptType = "PowerShell" if ( ! [string]::IsNullOrEmpty($acctkey) ) { $AccountKey = $acctkey } if ( ! [string]::IsNullOrEmpty($orgkey) ) { $OrganizationKey = $orgkey } $X64 = 64 $X86 = 32 $InstallerName = "HuntressInstaller.exe" $InstallerPath = Join-Path $Env:TMP $InstallerName $DebugLog = Join-Path $Env:TMP HuntressInstaller.log $DownloadURL = "https://update.huntress.io/download/" + $AccountKey + "/" + $InstallerName $HuntressAgentServiceName = "HuntressAgent" $HuntressUpdaterServiceName = "HuntressUpdater" $PowerShellArch = $X86 if ([IntPtr]::size -eq 8) { $PowerShellArch = $X64 } $ScriptFailed = "Script Failed!" $SupportMessage = "Please send the error message to the Huntress Team for help at support@huntress.com" function Get-TimeStamp { return "[{0:yyyy/MM/dd} {0:HH:mm:ss}]" -f (Get-Date) } function LogMessage ($msg) { Add-Content $DebugLog "$(Get-TimeStamp) $msg" Write-Host "$(Get-TimeStamp) $msg" } function Test-Parameters { LogMessage "Verifying received parameters..." if ($reregister -and $reinstall) { $err = "Cannot specify both `-reregister` and `-reinstall` parameters, exiting script!" LogMessage $err exit 1 } if ($AccountKey -eq "__ACCOUNT_KEY__") { $err = "AccountKey not set!" LogMessage $err throw $ScriptFailed + " " + $err exit 1 } elseif ($AccountKey.length -ne 32) { $err = "Invalid AccountKey specified (incorrect length)!" LogMessage $err throw $ScriptFailed + " " + $err exit 1 } if ($OrganizationKey -eq "__ORGANIZATION_KEY__") { $err = "OrganizationKey not specified!" LogMessage $err throw $ScriptFailed + " " + $err exit 1 } elseif ($OrganizationKey.length -lt 1) { $err = "Invalid OrganizationKey specified (length is 0)!" LogMessage $err throw $ScriptFailed + " " + $err exit 1 } } function Confirm-ServiceExists ($service) { if (Get-Service $service -ErrorAction SilentlyContinue) { return $true } return $false } function Confirm-ServiceRunning ($service) { $arrService = Get-Service $service $status = $arrService.Status.ToString() if ($status.ToLower() -eq 'running') { return $true } return $false } function Get-WindowsArchitecture { if ($env:ProgramW6432) { $WindowsArchitecture = $X64 } else { $WindowsArchitecture = $X86 } return $WindowsArchitecture } function verifyInstaller ($file) { $varChain = New-Object -TypeName System.Security.Cryptography.X509Certificates.X509Chain try { $varChain.Build((Get-AuthenticodeSignature -FilePath "$file").SignerCertificate) | out-null } catch [System.Management.Automation.MethodInvocationException] { $err = ( "ERROR: '$file' did not contain a valid digital certificate. " + "Something may have corrupted/modified the file during the download process. " + "If the problem persists please file a support ticket.") LogMessage $err LogMessage $SupportMessage throw $ScriptFailed + " " + $err + " " + $SupportMessage } } function Get-Installer { $msg = "Downloading installer to '$InstallerPath'..." LogMessage $msg $ProtocolsSupported = [enum]::GetValues('Net.SecurityProtocolType') if ( ($ProtocolsSupported -contains 'Tls13') -and ($ProtocolsSupported -contains 'Tls12') ) { # Use only TLS 1.3 or 1.2 LogMessage "Using TLS 1.3 or 1.2..." [Net.ServicePointManager]::SecurityProtocol = ( [Enum]::ToObject([Net.SecurityProtocolType], 12288) -bOR [Enum]::ToObject([Net.SecurityProtocolType], 3072) ) } else { LogMessage "Using TLS 1.2..." try { [Net.ServicePointManager]::SecurityProtocol = [Enum]::ToObject([Net.SecurityProtocolType], 3072) } catch { $msg = $_.Exception.Message $err = "ERROR: Unable to use a secure version of TLS. Please verify Hotfix KB3140245 is installed." LogMessage $msg LogMessage $err throw $ScriptFailed + " " + $msg + " " + $err } } $WebClient = New-Object System.Net.WebClient try { $WebClient.DownloadFile($DownloadURL, $InstallerPath) } catch { $msg = $_.Exception.Message $err = ( "ERROR: Failed to download the Huntress Installer. Please try accessing $DownloadURL " + "from a web browser on the host where the download failed. If the issue persists, please " + "send the error message to the Huntress Team for help at support@huntress.com.") LogMessage $msg LogMessage $err throw $ScriptFailed + " " + $err + " " + $msg } if ( ! (Test-Path $InstallerPath) ) { $err = "ERROR: Failed to download the Huntress Installer from $DownloadURL." LogMessage $err LogMessage $SupportMessage throw $ScriptFailed + " " + $err + " " + $SupportMessage } $msg = "Installer downloaded to '$InstallerPath'..." LogMessage $msg } function Install-Huntress ($OrganizationKey) { LogMessage "Checking for installer '$InstallerPath'..." if ( ! (Test-Path $InstallerPath) ) { $err = "ERROR: The installer was unexpectedly removed from $InstallerPath" $msg = ( "A security product may have quarantined the installer. Please check " + "your logs. If the issue continues to occur, please send the log to the Huntress " + "Team for help at support@huntresslabs.com") LogMessage $err LogMessage $msg throw $ScriptFailed + " " + $err + " " + $SupportMessage } verifyInstaller($InstallerPath) $msg = "Executing installer..." LogMessage $msg $timeout = 30 # Seconds $process = Start-Process $InstallerPath "/ACCT_KEY=`"$AccountKey`" /ORG_KEY=`"$OrganizationKey`" /S" -PassThru try { $process | Wait-Process -Timeout $timeout -ErrorAction Stop } catch { $process | Stop-Process -Force $err = "ERROR: Installer failed to complete in $timeout seconds." LogMessage $err LogMessage $SupportMessage throw $ScriptFailed + " " + $err + " " + $SupportMessage } } function Test-Installation { LogMessage "Verifying installation..." Start-Sleep -Seconds 8 $WindowsArchitecture = Get-WindowsArchitecture if ($WindowsArchitecture -eq $X86) { $HuntressDirPath = Join-Path $Env:ProgramFiles "Huntress" } elseif ($WindowsArchitecture -eq $X64) { $HuntressDirPath = Join-Path $Env:ProgramW6432 "Huntress" } else { $err = "ERROR: Failed to determine the Windows Architecture. Received $WindowsArchitecture." LogMessage $err LogMessage $SupportMessage throw $ScriptFailed + " " + $err + " " + $SupportMessage } $HuntressAgentPath = Join-Path $HuntressDirPath "HuntressAgent.exe" $HuntressUpdaterPath = Join-Path $HuntressDirPath "HuntressUpdater.exe" $WyUpdaterPath = Join-Path $HuntressDirPath "wyUpdate.exe" $HuntressKeyPath = "HKLM:\SOFTWARE\Huntress Labs\Huntress" $AgentIdKeyValueName = "AgentId" $OrganizationKeyValueName = "OrganizationKey" $TagsValueName = "Tags" foreach ( $file in ($HuntressAgentPath, $HuntressUpdaterPath, $WyUpdaterPath) ) { if ( ! (Test-Path $file) ) { $err = "ERROR: $file did not exist." LogMessage $err LogMessage $SupportMessage throw $ScriptFailed + " " + $err + " " + $SupportMessage } LogMessage "'$file' is present." } foreach ( $svc in ($HuntressAgentServiceName, $HuntressUpdaterServiceName) ) { # service installed? if ( ! (Confirm-ServiceExists($svc)) ) { $err = "ERROR: The $svc service is not installed." LogMessage $err LogMessage $SupportMessage throw $ScriptFailed + " " + $err + " " + $SupportMessage } if ( ! (Confirm-ServiceRunning($svc)) ) { $err = "ERROR: The $svc service is not running." LogMessage $err LogMessage $SupportMessage throw $ScriptFailed + " " + $err + " " + $SupportMessage } LogMessage "'$svc' is running." } if ( ($PowerShellArch -eq $X86) -and ($WindowsArchitecture -eq $X64) ) { LogMessage "WARNING: Can't verify registry settings due to 32bit PowerShell on 64bit host." } else { # Ensure the Huntress registry key is present. if ( ! (Test-Path $HuntressKeyPath) ) { $err = "ERROR: The registry key '$HuntressKeyPath' did not exist." LogMessage $err LogMessage $SupportMessage throw $ScriptFailed + " " + $err + " " + $SupportMessage } $HuntressKeyObject = Get-ItemProperty $HuntressKeyPath foreach ( $value in ($AgentIdKeyValueName, $OrganizationKeyValueName, $TagsValueName) ) { If ( ! (Get-Member -inputobject $HuntressKeyObject -name $value -Membertype Properties) ) { $err = "ERROR: The registry value $value did not exist within $HuntressKeyPath." LogMessage $err LogMessage $SupportMessage throw $ScriptFailed + " " + $err + " " + $SupportMessage } } } if ( ($PowerShellArch -eq $X86) -and ($WindowsArchitecture -eq $X64) ) { LogMessage "WARNING: Can't verify agent registration due to 32bit PowerShell on 64bit host." } else { If ($HuntressKeyObject.$AgentIdKeyValueName -eq 0) { $err = ("ERROR: The agent did not register. Check the log (%ProgramFiles%\Huntress\HuntressAgent.log) for errors.") LogMessage $err LogMessage $SupportMessage throw $ScriptFailed + " " + $err + " " + $SupportMessage } LogMessage "Agent registered." } LogMessage "Installation verified!" } function StopHuntressServices { LogMessage "Stopping Huntress services..." Stop-Service -Name "$HuntressAgentServiceName" Stop-Service -Name "$HuntressUpdaterServiceName" } function PrepReregister { LogMessage "Preparing to re-register agent..." StopHuntressServices $HuntressKeyPath = "HKLM:\SOFTWARE\Huntress Labs\Huntress" Remove-Item -Path "$HuntressKeyPath" -Recurse -ErrorAction SilentlyContinue } function main () { LogMessage "Script type: '$ScriptType'" LogMessage "Script version: '$ScriptVersion'" LogMessage "Host name: '$env:computerName'" $os = (get-WMiObject -computername $env:computername -Class win32_operatingSystem).caption.Trim() LogMessage "Host OS: '$os'" LogMessage "Host Architecture: '$(Get-WindowsArchitecture)'" LogMessage "PowerShell Architecture: '$PowerShellArch'" if ($reinstall) { LogMessage "Re-install agent: '$reinstall'" } if ($reregister) { LogMessage "Re-register agent: '$reregister'" } LogMessage "Installer location: '$InstallerPath'" LogMessage "Installer log: '$DebugLog'" $AccountKey = $AccountKey.Trim() $OrganizationKey = $OrganizationKey.Trim() Test-Parameters $masked = $AccountKey.Substring(0,10) + "XXXXXXXXXXXXXXXXXXXXXXX" LogMessage "AccountKey: '$masked'" LogMessage "OrganizationKey: '$OrganizationKey'" if ($reregister) { PrepReregister } elseif ($reinstall) { LogMessage "Re-installing agent..." if ( !(Confirm-ServiceExists($HuntressAgentServiceName)) ) { $err = "The Huntress Agent is NOT installed; nothing to re-install. Exiting." LogMessage "$err" exit 1 } StopHuntressServices } else { LogMessage "Checking for HuntressAgent service..." if ( Confirm-ServiceExists($HuntressAgentServiceName) ) { $err = "The Huntress Agent is already installed. Exiting." LogMessage "$err" exit 0 } } Get-Installer Install-Huntress $OrganizationKey Test-Installation LogMessage "Huntress Agent successfully installed!" } try { main } catch { $ErrorMessage = $_.Exception.Message LogMessage $ErrorMessage exit 1 }
If you need assistance, feel free to reach out to Support here: Contact Us
Comments
0 comments
Please sign in to leave a comment.