Install-Huntress.ps1
# Copyright (c) 2022 Huntress Labs, Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: # * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # * Neither the name of the Huntress Labs nor the names of its contributors may be used to endorse or promote products derived from this software # without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL HUNTRESS LABS BE LIABLE FOR ANY DIRECT, # INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS # OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # Authors: John Ferrell, Dave Kleinatland, Alan Bishop, Cameron Granger # The Huntress installer needs an Account Key and an Organization Key (a user specified name or description) which is used to affiliate an Agent with a # specific Organization within the Huntress Partner's Account. These keys can be hard coded below or passed in when the script is run. # For more details, see our KB article https://support.huntress.io/hc/en-us/articles/4404004936339-Deploying-Huntress-with-PowerShell # Usage (remove brackets [] and substitute <variable> for your value): # powershell -executionpolicy bypass -f ./InstallHuntress.powershellv2.ps1 [-acctkey <account_key>] [-orgkey <organization_key>] [-tags <tags>] [-reregister] [-reinstall] [-uninstall] [-repair] # # example: # powershell -executionpolicy bypass -f ./InstallHuntress.powershellv2.ps1 -acctkey "0b8a694b2eb7b642069" -orgkey "Buzzword Company Name" -tags "production,US West" # Optional command line params, this has to be the first line in the script. #param ( [string]$acctkey, [string]$orgkey, [switch]$reregister, [switch]$uninstall, [switch]$repair #) $acctkey = "" $orgkey = "" $reregister = 0 $uninstall = 0 $repair = 0 ############################################################################## ## Begin user modified variables ############################################################################## # Replace __ACCOUNT_KEY__ with your account secret key (from your Huntress portal's "download agent" section) $AccountKey = "fc0868c385b20178cf2b3e7ad0092365" # Replace __ORGANIZATION_KEY__ with a unique identifier for the organization/client (your choice of naming scheme) #$OrganizationKey = "nzcs" $TagsKey = "" # Set to "Continue" to enable verbose logging. $DebugPreference = "SilentlyContinue" ############################################################################## ## Do not modify anything below this line ############################################################################## # Find poorly written code faster with the most stringent setting. Set-StrictMode -Version Latest # Check for old outdated Windows PowerShell (script works as low as PoSh 2.0) $oldOS = $false if ($PsVersionTable.PsVersion.Major -lt 3){ $oldOS = $true } # These are used by the Huntress support team when troubleshooting. $ScriptVersion = "Version 2, 2022 July 28, revision 3" $ScriptType = "PowerShell" # variables used throughout this script $X64 = 64 $X86 = 32 $InstallerName = "HuntressInstaller.exe" $InstallerPath = Join-Path $Env:TMP $InstallerName $DebugLog = Join-Path $Env:TMP HuntressInstaller.log $HuntressKeyPath = "HKLM:\SOFTWARE\Huntress Labs\Huntress" $HuntressRegKey = "HKLM:\SOFTWARE\Huntress Labs" $timeout = 30 # number of seconds to wait before continuing the install # pick the appropriate file to download based on the OS version if ($oldOS -eq $true) { # For Windows Vista, Server 2008 (PoSh 2) $DownloadURL = "https://update.huntress.io/legacy_download/" + $AccountKey + "/" + $InstallerName } else { # For Windows 7+, Server 2008 R2+ (PoSh 3+) $DownloadURL = "https://update.huntress.io/download/" + $AccountKey + "/" + $InstallerName } # strings used throughout this script $ScriptFailed = "Script Failed!" $SupportMessage = "Please send the error message to support@huntress.com" $HuntressAgentServiceName = "HuntressAgent" $HuntressUpdaterServiceName = "HuntressUpdater" # 32bit PoSh on 64bit Windows is unable to interact with certain assets, so we check for this condition $PowerShellArch = $X86 # 8 byte pointer is 64bit if ([IntPtr]::size -eq 8) { $PowerShellArch = $X64 } # time stamps for logging purposes function Get-TimeStamp { return "[{0:yyyy/MM/dd} {0:HH:mm:ss}]" -f (Get-Date) } # adds time stamp to a message and then writes that to the log file function LogMessage ($msg) { Add-Content $DebugLog "$(Get-TimeStamp) $msg" Write-Host "$(Get-TimeStamp) $msg" } # test that all required parameters were passed, and that they are in the correct format function Test-Parameters { LogMessage "Verifying received parameters..." # If reregister and reinstall were both flagged, just reregister as it is the more robust option if ($reregister -and $reinstall) { $err = "Specified -reregister and -reinstall, defaulting to reregister." LogMessage $err $reinstall = $false } # Ensure we have an account key (either hard coded or from the command line params). if (($AccountKey -eq "__ACCOUNT_KEY__") -and ($args.count -gt 1)) { $err = "AccountKey not set! Suggest using the -acctkey flag followed by your account key." LogMessage $err Write-Host $err -ForegroundColor white -BackgroundColor red throw $ScriptFailed + " " + $err exit 1 } elseif (($AccountKey.length -ne 32) -and ($args.count -gt 1)) { $err = "Invalid AccountKey specified (incorrect length)! Suggest double checking the key was copy/pasted fully" $err = $args.count LogMessage $err Write-Host $err -ForegroundColor white -BackgroundColor red throw $ScriptFailed + " " + $err exit 1 } # Ensure the account key doesn't have any invalid characters if (($AccountKey -match '[^a-zA-Z0-9]') -and ($args.count -gt 1)) { $err = "Invalid AccountKey specified (invalid characters found)! Suggest double checking the key was copy/pasted fully" LogMessage $err Write-Host $err -ForegroundColor white -BackgroundColor red throw $ScriptFailed + " " + $err exit 1 } # Ensure we have an organization key (either hard coded or from the command line params). if (($OrganizationKey -eq "__ORGANIZATION_KEY__") -and ($args.count -gt 1)) { $err = "OrganizationKey not specified! This is a user defined identifier set by you (usually your customer's organization name)" LogMessage $err Write-Host $err -ForegroundColor white -BackgroundColor red throw $ScriptFailed + " " + $err exit 1 } elseif ($OrganizationKey.length -lt 1) { $err = "Invalid OrganizationKey specified (length should be > 0)!" LogMessage $err Write-Host $err -ForegroundColor white -BackgroundColor red throw $ScriptFailed + " " + $err exit 1 } } # check to see if the Huntress service exists (agent or updater) function Confirm-ServiceExists ($service) { if (Get-Service $service -ErrorAction SilentlyContinue) { return $true } return $false } # check to see if the Huntress service is running (agent or updater) function Confirm-ServiceRunning ($service) { $arrService = Get-Service $service $status = $arrService.Status.ToString() if ($status.ToLower() -eq 'running') { return $true } return $false } # Stop the Agent and Updater services function StopHuntressServices { LogMessage "Stopping Huntress services..." if (Confirm-ServiceExists($HuntressAgentServiceName)) { Stop-Service -Name "$HuntressAgentServiceName" } else { LogMessage "$($HuntressAgentServiceName) not found, nothing to stop" } if (Confirm-ServiceExists($HuntressUpdaterServiceName)) { Stop-Service -Name "$HuntressUpdaterServiceName" } else { LogMessage "$($HuntressUpdaterServiceName) not found, nothing to stop" } } # return the architecture type (32 or 64 bit) function Get-WindowsArchitecture { if ($env:ProgramW6432) { $WindowsArchitecture = $X64 } else { $WindowsArchitecture = $X86 } return $WindowsArchitecture } # Ensure the installer was not modified during download by validating the file signature. 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. " + "Suggest trying again, contact support@huntress.com if it fails >2 times") LogMessage $err LogMessage $SupportMessage Write-Host $err -ForegroundColor white -BackgroundColor red throw $ScriptFailed + " " + $err + " " + $SupportMessage } } # download the Huntress installer function Get-Installer { $msg = "Downloading installer to '$InstallerPath'..." LogMessage $msg # Ensure a secure TLS version is used. $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 { # In certain .NET 4.0 patch levels, SecurityProtocolType does not have a TLS 1.2 entry. # Rather than check for 'Tls12', we force-set TLS 1.2 and catch the error if it's truly unsupported. [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 } } # Attempt to download the correct installer for the given OS, throw error if it fails $WebClient = New-Object System.Net.WebClient try { $WebClient.DownloadFile($DownloadURL, $InstallerPath) } catch { $msg = $_.Exception.Message $err = "ERROR: Failed to download the Huntress Installer. Try accessing $($DownloadURL) from the host where the download failed. Contact support@huntress.io if the problem persists" LogMessage $msg LogMessage "$($err) Please contact support@huntress.io if the problem persists" throw $ScriptFailed + " " + $err + " " + $msg } # Ensure the file downloaded correctly, if not, throw error if ( ! (Test-Path $InstallerPath) ) { $err = "ERROR: Failed to download the Huntress Installer from $DownloadURL. Suggest testing the URL in a browser." LogMessage $err LogMessage $SupportMessage throw $ScriptFailed + " " + $err + " " + $SupportMessage } $msg = "Installer downloaded to '$InstallerPath'..." LogMessage $msg } # check if the agent downloaded, is a valid install file, if those match up then run the installer function Install-Huntress ($OrganizationKey) { # check that the installer downloaded and wasn't quarantined 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 Write-Host $err + $msg -ForegroundColor white -BackgroundColor red throw $ScriptFailed + " " + $err + " " + $SupportMessage } # verify the installer's integrity verifyInstaller($InstallerPath) # execute the installer, stopping if it gets hung (security product interference) $msg = "Executing installer..." LogMessage $msg # if $Tags value exists install using the provided tags, otherwise no tags #if ($Tags) { # $process = Start-Process $InstallerPath "/ACCT_KEY=`"$AccountKey`" /ORG_KEY=`"$OrganizationKey`" /TAGS=`"$TagsKey`" /S" -PassThru #} else { $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. Possible interference from a security product?" Write-Host $err -ForegroundColor white -BackgroundColor red LogMessage $err LogMessage $SupportMessage throw $ScriptFailed + " " + $err + " " + $SupportMessage } } # Test that the Huntress agent was able to install, register, and start service correctly function Test-Installation { LogMessage "Verifying installation..." # Give the agent a few seconds to start and register. Start-Sleep -Seconds 8 # Get the file locations of some of the Huntress executables $HuntressDirectory = getAgentPath $WyUpdaterPath = Join-Path $HuntressDirectory "wyUpdate.exe" $HuntressAgentPath = Join-Path $HuntressDirectory "HuntressAgent.exe" $HuntressUpdaterPath = Join-Path $HuntressDirectory "HuntressUpdater.exe" # Get the registry location, and store some strings for use in registry $AgentIdKeyValueName = "AgentId" $OrganizationKeyValueName = "OrganizationKey" $TagsValueName = "Tags" # Ensure the critical files were created. foreach ( $file in ($HuntressAgentPath, $HuntressUpdaterPath, $WyUpdaterPath) ) { if ( ! (Test-Path $file) ) { $err = "ERROR: $file did not exist. Check your AV/security software quarantine" LogMessage $err LogMessage $SupportMessage throw $ScriptFailed + " " + $err + " " + $SupportMessage } LogMessage "'$file' is present." } # Ensure the services are installed and running. foreach ( $svc in ($HuntressAgentServiceName, $HuntressUpdaterServiceName) ) { # service installed? if ( ! (Confirm-ServiceExists($svc)) ) { $err = "ERROR: The $svc service is not installed. You may need to reinstall." LogMessage $err LogMessage $SupportMessage throw $ScriptFailed + " " + $err + " " + $SupportMessage } # service running? if ( ! (Confirm-ServiceRunning($svc)) ) { $err = "ERROR: The $svc service is not running. You may need to manually start it for more info." LogMessage $err LogMessage $SupportMessage throw $ScriptFailed + " " + $err + " " + $SupportMessage } LogMessage "'$svc' is running." } # look for a condition that prevents checking registry keys, if not then check for registry keys if ( ($PowerShellArch -eq $X86) -and ($WindowsArchitecture -eq $X64) ) { LogMessage "WARNING: Can't verify registry settings due to 32bit PowerShell on 64bit host. Please run PowerShell in 64 bit mode" } else { # Ensure the Huntress registry key is present. if ( ! (Test-Path $HuntressKeyPath) ) { $err = "ERROR: The registry key '$HuntressKeyPath' did not exist. You may need to reinstall with the -reregister flag" LogMessage $err LogMessage $SupportMessage throw $ScriptFailed + " " + $err + " " + $SupportMessage } # Ensure the Huntress registry values are present. $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. You may need to reinstall with the -reregister flag" LogMessage $err LogMessage $SupportMessage throw $ScriptFailed + " " + $err + " " + $SupportMessage } } } # Verify the agent registered (if not blocked by 32/64 bit incompatibilities). 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!" } # prepare to reregister by stopping the Huntress service and deleting all the registry keys function PrepReregister { LogMessage "Preparing to re-register agent..." StopHuntressServices $HuntressKeyPath = "HKLM:\SOFTWARE\Huntress Labs\Huntress" Remove-Item -Path "$HuntressKeyPath" -Recurse -ErrorAction SilentlyContinue } # looks at the Huntress log to return true if the agent is orphaned, false if the agent is active AB function isOrphan { # find the Huntress log file or state that it can't be found if (Test-Path 'C:\Program Files\Huntress\HuntressAgent.log') { $Path = 'C:\Program Files\Huntress\HuntressAgent.log' } elseif (Test-Path 'C:\Program Files (x86)\Huntress\HuntressAgent.log') { $Path = 'C:\Program Files (x86)\Huntress\HuntressAgent.log' } else { LogMessage "Unable to locate log file, thus unable to check if orphaned" return $false } # if the log was found, look through the last 10 lines for the orphaned agent error code if ($Path -match 'HuntressAgent.log') { $linesFromLog = Get-Content $Path | Select -last 10 ForEach ($line in $linesFromLog) { if ($line -like "*bad status code: 401*") { return $true } } } return $false } # Check if the script is being run with admin access AB function testAdministrator { $user = [Security.Principal.WindowsIdentity]::GetCurrent(); (New-Object Security.Principal.WindowsPrincipal $user).IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator) } # Ensure the disk has enough space for the install files + agent, then write results to the log AB function checkFreeDiskSpace { # Using an older disk query to be backwards compatible with PoSh 2, catch WMI errors and check repository try { $freeSpace = (Get-WmiObject -query "Select * from Win32_LogicalDisk where DeviceID='c:'" | Select FreeSpace).FreeSpace } catch { LogMessage "WMI issues discovered (free space query), attempting to fix the repository" winmgt -verifyrepository $drives = get-psdrive foreach ($drive in $drives) { if ($drive.Name -eq "C") { $freeSpace = $drive.Free } } } $freeSpaceNice = $freeSpace.ToString('N0') $estimatedSpaceNeeded = 45123456 if ($freeSpace -lt $estimatedSpaceNeeded) { $err = "Low disk space detected, you may have troubles completing this install. Only $($freeSpaceNice) bytes remaining (need about $($estimatedSpaceNeeded.ToString('N0'))." Write-Host $err -ForegroundColor white -BackgroundColor red LogMessage $err } else { LogMessage "Free disk space: $($freeSpaceNice)" } } # determine the path in which Huntress is installed AB function getAgentPath { # Ensure we resolve the correct Huntress directory regardless of operating system or process architecture. if (Get-WindowsArchitecture -eq $X64) { return (Join-Path $Env:ProgramW6432 "Huntress") } else { return (Join-Path $Env:ProgramFiles "Huntress") } } # attempt to run a process and log the results AB function runProcess ($process, $flags, $name){ try { Start-Process $process $flags | Wait-Process -Timeout $timeout -ErrorAction Stop LogMessage "$($name) finished" } catch { Stop-Process $process -Force $err = "ERROR: $($name) failed to complete in $timeout seconds." Write-Host $err -ForegroundColor white -BackgroundColor red LogMessage $err exit 0 } } # Fully uninstall the agent AB function uninstallHuntress { $agentPath = getAgentPath $updaterPath = Join-Path $agentPath "HuntressUpdater.exe" $exeAgentPath = Join-Path $agentPath "HuntressAgent.exe" $uninstallerPath = Join-Path $agentPath "Uninstall.exe" # attempt to use the built in uninstaller, if not found use the uninstallers built into the Agent and Updater if (Test-Path $agentPath) { Write-Host "Uninstalling, please wait :) " # run uninstaller.exe, if not found run the Agent's built in uninstaller and the Updater's built in uninstaller if (Test-Path $uninstallerPath) { runProcess "$($uninstallerPath)" "/S" "Uninstall.exe" -wait Start-Sleep 15 } elseif (Test-Path $exeAgentPath) { runProcess "$($exeAgentPath)" "/S" "Huntress Agent uninstaller" -wait Start-Sleep 15 } elseif (Test-Path $updaterPath) { runProcess "$($updaterPath)" "/S" "Updater uninstaller" -wait Start-Sleep 15 } else { LogMessage "Agent path found but no uninstallers found. Attempting to manually uninstall" } } else { $err = "Note: unable to find Huntress install folder. Attempting to manually uninstall." Write-Host $err -ForegroundColor white -BackgroundColor red LogMessage $err } # look for the Huntress directory, if found then delete if (Test-Path $agentPath) { Remove-Item -LiteralPath $agentPath -Force -Recurse -ErrorAction SilentlyContinue LogMessage "Manual cleanup of Huntress folder: success" } else { LogMessage "Manual cleanup of Huntress folder: folder not found" } # look for the registry keys, if exist then delete if (Test-Path $HuntressRegKey) { Get-Item -path $HuntressRegKey | Remove-Item -recurse LogMessage "Manually deleted Huntress registry keys" } else { LogMessage "No registry keys found, uninstallation complete" } } # grab the currently installed agent version AB function getAgentVersion { $exeAgentPath = Join-Path (getAgentPath) "HuntressAgent.exe" $agentVersion = (Get-Item $exeAgentPath).VersionInfo.FileVersion LogMessage "Agent version $($agentVersion) found" return $agentVersion } # ensure all the Huntress services are running AB function repairAgent { Start-Service HuntressAgent Start-Service HuntressUpdater } function main () { if ($reinstallSetting -eq 'Y') { $reinstall = $True LogMessage "Reinstall" } else { $reinstall = $False LogMessage "New Install" } write-host $reinstallSetting # gather info on the host for logging purposes LogMessage "Script type.: '$ScriptType'" LogMessage "Script version: '$ScriptVersion'" LogMessage "Host name: '$env:computerName'" try { $os = (get-WMiObject -computername $env:computername -Class win32_operatingSystem).caption.Trim() } catch { LogMessage "WMI issues discovered (computer name query), attempting to fix the repository" winmgt -verifyrepository $os = (get-itemproperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion" -Name ProductName).ProductName } LogMessage "Host OS: '$os'" LogMessage "Host Architecture: '$(Get-WindowsArchitecture)'" if ($oldOS) { LogMessage "Warning! Older version of PowerShell detected" } checkFreeDiskSpace LogMessage "PowerShell Architecture: '$PowerShellArch'" LogMessage "Installer location: '$InstallerPath'" LogMessage "Installer log: '$DebugLog'" LogMessage "Administrator access: $(testAdministrator)" # if run with the uninstall flag, exit so we don't reinstall the agent after if ($uninstall) { LogMessage "Uninstalling Huntress agent" uninstallHuntress exit 0 } # if the agent is orphaned, switch to the full uninstall/reinstall (reregister flag) if ( !($reregister)) { if (isOrphan) { $err = 'Huntress Agent is orphaned, unable to use the provided flag. Switching to uninstall/reinstall (reregister flag)' Write-Host $err -ForegroundColor white -BackgroundColor red LogMessage "$err" $reregister = $true } } # if run with no flags and no account key, assume repair if (!$repair -and !$reregister -and !$uninstall -and !$reinstall -and ($AccountKey -eq "__ACCOUNT_KEY__")) { LogMessage "No flags or account key found! Defaulting to the -repair flag." $repair = $true } # if run with the repair flag, check if installed (install if not), if ver < 0.13.16 apply the fix if ($repair) { if (Test-Path(getAgentPath)){ repairAgent LogMessage "Repair complete!" exit 0 } else { LogMessage "Agent not found! Attempting to install" $reregister = $true } } # trim keys for blanks before use $AccountKey = $AccountKey.Trim() $OrganizationKey = $OrganizationKey.Trim() # check that all the parameters that were passed are valid Test-Parameters # Hide most of the account key in the logs, keeping the front and tail end for troubleshooting if ($AccountKey -ne "__Account_Key__") { $masked = $AccountKey.Substring(0,4) + "************************" + $AccountKey.SubString(28,4) LogMessage "AccountKey: '$masked'" LogMessage "OrganizationKey: '$OrganizationKey'" } # reregister > reinstall > uninstall > install (in decreasing order of impact) # reregister = reinstall + delete registry keys # reinstall = install + stop Huntress service if ($reregister) { LogMessage "Re-register agent: '$reregister'" if ( !(Confirm-ServiceExists($HuntressAgentServiceName))) { LogMessage "Run with the -reregister flag but the service wasn't found. Attempting to install...." } PrepReregister } elseif ($reinstall) { LogMessage "Re-install agent: '$reinstall'" if ( !(Confirm-ServiceExists($HuntressAgentServiceName)) ) { $err = "Script was run w/ reinstall flag but there's nothing to reinstall. Attempting to clean remnants, then install the agent fresh." LogMessage "$err" uninstallHuntress exit 0 } StopHuntressServices } else { LogMessage "Checking for HuntressAgent service..." if ( Confirm-ServiceExists($HuntressAgentServiceName) ) { $err = "The Huntress Agent is already installed. Exiting with no changes. Suggest using -reregister or -reinstall flags" LogMessage "$err" Write-Host 'Huntress Agent is already installed. Suggest using the -reregister or -reinstall flags' -ForegroundColor white -BackgroundColor red exit 0 } } Get-Installer Install-Huntress $OrganizationKey Test-Installation LogMessage "Huntress Agent successfully installed!" } try { main } catch { $ErrorMessage = $_.Exception.Message LogMessage $ErrorMessage exit 1 } |