> ## Documentation Index
> Fetch the complete documentation index at: https://kb.mspprocess.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Install the desktop agent

> Deploy the Triggr desktop agent as a Windows service, through your RMM or by hand.

After [generating agent credentials](https://kb.mspprocess.com/desktop-agent/generate-credentials.md), run this script on a machine that meets the [requirements](https://kb.mspprocess.com/desktop-agent/overview.md#requirements). It installs the agent as the `TriggrAgentService` Windows service in `C:\Program Files\TriggrAgent`, set to start automatically.

<video controls preload="none" playsInline poster="/images/videos/install-desktop-agent.jpg" src="https://mintcdn.com/triggr/jthEaTOAfk2OUODQ/images/videos/install-desktop-agent.mp4?fit=max&auto=format&n=jthEaTOAfk2OUODQ&q=85&s=42e4de0b0e4b0c1f7342288501b0160a" />

Install the desktop agent: the two variables, running the script, and the agent Online in Studio and Core (1:21).

## Deploy through your RMM

In your RMM, set the `TriggrClientId` and `TriggrClientSecret` environment variables for the target machine to the client ID and secret you generated, then run the script with Windows PowerShell, as administrator. Rerun it to upgrade or reconfigure an agent: it replaces any installed service with the current version.

```powershell TriggrAgentDeploy.ps1 lines theme={null}
# This script uses environment variables for TriggrClientId and TriggrClientSecret.

$ErrorActionPreference = "Stop"
$AgentUrl     = "https://triggr-agent.s3.eu-west-2.amazonaws.com/TriggrAgentService.exe"
$ServiceName  = "TriggrAgentService"
$ExeName      = "TriggrAgentService.exe"
$InstallPath  = "C:\Program Files\TriggrAgent"

# Get variables from Datto RMM environment variables
$ClientId     = $env:TriggrClientId
$ClientSecret = $env:TriggrClientSecret

Write-Host "Starting Triggr Agent Service deployment"
Write-Host "Agent URL: $AgentUrl"
Write-Host "Client ID: $ClientId"
Write-Host "Install Path: $InstallPath"

# Step 1: Check if running as Administrator
Write-Host "Checking administrator privileges..."
if (-NOT ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) {
    Write-Host "ERROR: This script must be run as Administrator"
    exit 2
}
Write-Host "Administrator privileges confirmed"

# Step 2: Create installation directory
Write-Host "Creating installation directory: $InstallPath"
if (!(Test-Path $InstallPath)) {
    New-Item -ItemType Directory -Path $InstallPath -Force | Out-Null
    Write-Host "Installation directory created"
} else {
    Write-Host "Installation directory already exists"
}

# Step 3: Stop and uninstall existing service if it exists
$finalExePath = Join-Path $InstallPath $ExeName
Write-Host "Checking for existing service installation..."
try {
    $existingService = Get-Service -Name $ServiceName -ErrorAction SilentlyContinue
    if ($existingService) {
        Write-Host "Existing service found. Stopping and uninstalling..."
        if ($existingService.Status -eq "Running") {
            Write-Host "Stopping existing service..."
            Stop-Service -Name $ServiceName -Force -ErrorAction SilentlyContinue
            Start-Sleep -Seconds 5
        }
        Write-Host "Uninstalling existing service..."
        & $finalExePath -uninstall | Out-Null
        Start-Sleep -Seconds 3
    } else {
        Write-Host "No existing service found"
    }
} catch {
    Write-Host "WARNING: Error handling existing service: $($_.Exception.Message)"
}

# Step 4: Download the executable directly to final location
Write-Host "Downloading Triggr Agent Service from: $AgentUrl"

# Force modern TLS for WinPS 5.1
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12

try {
    if (Test-Path $finalExePath) {
        Remove-Item $finalExePath -Force
    }
    Invoke-WebRequest -Uri $AgentUrl -OutFile $finalExePath -UseBasicParsing
    Write-Host "Download completed successfully"
    if (!(Test-Path $finalExePath)) {
        Write-Host "ERROR: Downloaded file not found at: $finalExePath"
        exit 3
    }
    $fileSize = (Get-Item $finalExePath).Length
    Write-Host "Downloaded file size: $fileSize bytes"
} catch {
    Write-Host "ERROR: Failed to download agent: $($_.Exception.Message)"
    exit 3
}


# Step 5: Configure credentials
Write-Host "Configuring service credentials..."
try {
    $configArgs = @(
        "-client-id", "`"$ClientId`"",
        "-client-secret", "`"$ClientSecret`""
    )
    Write-Host "Running: $finalExePath $($configArgs -join ' ')"
    $configResult = & $finalExePath $configArgs 2>&1
    if ($LASTEXITCODE -ne 0) {
        Write-Host "ERROR: Failed to configure credentials. Exit code: $LASTEXITCODE. Output: $configResult"
        exit 5
    }
    Write-Host "Credentials configured successfully"
    Write-Host "Configuration output: $configResult"
} catch {
    Write-Host "ERROR: Failed to configure credentials: $($_.Exception.Message)"
    exit 5
}

# Step 6: Install the service
Write-Host "Installing Windows service..."
try {
    $installResult = & $finalExePath -install 2>&1
    if ($LASTEXITCODE -ne 0) {
        Write-Host "ERROR: Failed to install service. Exit code: $LASTEXITCODE. Output: $installResult"
        exit 6
    }
    Write-Host "Service installed successfully"
    Write-Host "Installation output: $installResult"
} catch {
    Write-Host "ERROR: Failed to install service: $($_.Exception.Message)"
    exit 6
}

# Step 7: Wait for service to be ready
Write-Host "Waiting for service to be ready..."
Start-Sleep -Seconds 30

# Step 8: Start the service
Write-Host "Starting Windows service..."
try {
    $startResult = & $finalExePath -start 2>&1
    if ($LASTEXITCODE -ne 0) {
        Write-Host "ERROR: Failed to start service. Exit code: $LASTEXITCODE. Output: $startResult"
        exit 7
    }
    Write-Host "Service started successfully"
    Write-Host "Start output: $startResult"
} catch {
    Write-Host "ERROR: Failed to start service: $($_.Exception.Message)"
    exit 7
}

# Step 9: Verify service is running
Write-Host "Verifying service status..."
Start-Sleep -Seconds 10

try {
    $service = Get-Service -Name $ServiceName -ErrorAction Stop
    Write-Host "Service status: $($service.Status)"
    if ($service.Status -ne "Running") {
        Write-Host "ERROR: Service is not running. Current status: $($service.Status)"
        exit 8
    }
    Write-Host "Service verification successful"
} catch {
    Write-Host "ERROR: Failed to verify service status: $($_.Exception.Message)"
    exit 8
}

# Step 10: Show service information
Write-Host "Retrieving service information..."
try {
    $infoResult = & $finalExePath -info 2>&1
    Write-Host "Service information:"
    Write-Host $infoResult
} catch {
    Write-Host "WARNING: Could not retrieve service information: $($_.Exception.Message)"
}

# Step 11: Cleanup
Write-Host "No cleanup needed - file downloaded directly to final location"

Write-Host "Deployment completed successfully!"
Write-Host "Service Name: $ServiceName"
Write-Host "Installation Path: $InstallPath"
Write-Host "Service Status: Running"
```

## Install without an RMM

Save the script on the machine as `TriggrAgentDeploy.ps1`, open PowerShell as administrator in that folder, and run:

```powershell theme={null}
$env:TriggrClientId = "<client ID>"
$env:TriggrClientSecret = "<secret>"
powershell -ExecutionPolicy Bypass -File .\TriggrAgentDeploy.ps1
```

## Exit codes

Your RMM can report the step that failed from the exit code.

| Code | Meaning |
| - | - |
| `2` | The script is not running as administrator. |
| `3` | The agent download failed. |
| `5` | Configuring the credentials failed. |
| `6` | The Windows service could not be installed. |
| `7` | The Windows service could not be started. |
| `8` | The service is not running after start-up. |

## Check it's connected

Until the agent first signs in, it shows Never Connected. When the script finishes, click **Refresh** under Agent Summary on the client's page in Studio, or under Agent in the client's panel in Core: it shows Online. Then run a workflow with an Execute PowerShell step for that client, and check its output under **On-Prem > Executions** in Studio.

![The Agent section of a client panel in Core: Online, Last seen and Last authenticated 1 min ago, and the Client ID with a Copy button.](https://mintcdn.com/triggr/MwzXHG3UWzFixdSz/images/core/add-your-clients/agent-section.png?fit=max\&auto=format\&n=MwzXHG3UWzFixdSz\&q=85\&s=e2285a85e9e2a6721a75cc38e0b40d57)

## Troubleshooting

> [accordion] The agent never shows Online
>
> On the machine, run `& "C:\Program Files\TriggrAgent\TriggrAgentService.exe" -status`, then read `C:\ProgramData\TriggrAgent\logs\service.log` (or run the same command with `-view-logs`). `authentication failed with status 401`: the client ID or secret is wrong or revoked, so rerun the script with the right values. `failed to send request`: the machine can't reach `api.triggr-app.com` over HTTPS. `Failed to load configuration`: the machine was renamed after the install, so rerun the script.

> [accordion] The script stops at “Configuring service credentials”
>
> `TriggrClientId` and `TriggrClientSecret` aren't set where the script runs: its `Running:` line ends `-client-id "" -client-secret ""`. Stop the script, set both variables and run it again.

> [accordion] Exit code 3: the download failed
>
> The machine can't reach `triggr-agent.s3.eu-west-2.amazonaws.com` over HTTPS, or TLS 1.2 is disabled. Allow the download in your web filter and try again.

> [accordion] Exit code 5: configuring the credentials failed
>
> The agent couldn't save its settings in `C:\ProgramData\TriggrAgent`; the script's output gives the reason. Wrong values don't fail this step; they show up later as an authentication error in the log.

> [accordion] Scripts fail with “Access is denied” or can't find the ActiveDirectory module
>
> The service runs as Local System on that machine. Install it on a domain controller, or change the service's **Log On** account in Services to one with the rights your scripts need, and install the modules they use. Rerunning the script sets it back to Local System.

> [accordion] A script was cut off
>
> The agent stops a script after 10 minutes. Split long jobs into several steps.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.