What This Covers
The ConnectWiseAutomateAgent module handles more than agent installation. It exposes functions for health checks, configuration management, proxy settings, branding, and uninstallation – all scriptable, all composable with standard PowerShell tooling.
This post walks through practical examples: onboarding, compliance reporting, DR testing, version audits, multi-tenant deployment, proxy changes, migrations, network testing, health monitoring, and department branding. Each one is a pattern you can adapt to your environment.
New Hire Provisioning
Scenario: Your client onboards new employees weekly. Each workstation needs an RMM (Remote Monitoring and Management) agent installed, configured, and reporting to the correct location.
The manual version: HR notifies IT, IT provisions the machine, IT manually installs the agent, and the agent eventually shows up in Automate.
Scripted version:
# Integrated onboarding script
param(
[string]$EmployeeName,
[string]$Department
)
# Determine LocationID based on department
$locationMap = @{
'Sales' = 100
'Engineering' = 101
'Support' = 102
'Management' = 103
}
$locationID = $locationMap[$Department]
# Provision new computer (your existing process)
$computer = New-ADComputer -Name "WKS-$EmployeeName" -Path "OU=$Department,DC=company,DC=com" -PassThru
# Wait for computer to come online
do {
Start-Sleep -Seconds 30
} until (Test-Connection -ComputerName $computer.Name -Count 1 -Quiet)
# Install RMM agent
Invoke-Command -ComputerName $computer.Name -ScriptBlock {
Install-Module ConnectWiseAutomateAgent -Force
Install-CWAA -Server 'https://automate.msp.com' `
-InstallerToken $using:token `
-LocationID $using:locationID `
-Hide `
-Rename "Company IT Services"
}
# Verify
Start-Sleep 30
$agentInfo = Invoke-Command -ComputerName $computer.Name -ScriptBlock {
Get-CWAAInfo
}
# Update ticket/notification
Send-MailMessage -To "[email protected]" `
-Subject "New Hire Setup Complete: $EmployeeName" `
-Body "Computer: $($computer.Name)`nAgent ID: $($agentInfo.ID)`nLocation: $Department"
Result: Fully automated provisioning from AD computer creation to RMM monitoring in minutes.
Compliance Reporting
Scenario: Monthly compliance reports require knowing which machines have RMM agents and which don’t.
Scripted version:
# Monthly compliance check
$allComputers = Get-ADComputer -Filter * -SearchBase "DC=company,DC=com"
$complianceReport = @()
foreach ($computer in $allComputers) {
try {
$agentInfo = Invoke-Command -ComputerName $computer.Name -ScriptBlock {
Get-CWAAInfo
} -ErrorAction Stop
$complianceReport += [PSCustomObject]@{
ComputerName = $computer.Name
HasAgent = $true
AgentID = $agentInfo.ID
LastContact = $agentInfo.LastSuccessfulContact
Version = $agentInfo.Version
Compliant = $true
}
}
catch {
$complianceReport += [PSCustomObject]@{
ComputerName = $computer.Name
HasAgent = $false
AgentID = 'N/A'
LastContact = 'N/A'
Version = 'N/A'
Compliant = $false
}
}
}
# Generate report
$complianceReport | Export-Csv "Compliance-$(Get-Date -Format 'yyyy-MM').csv" -NoTypeInformation
# Email non-compliant systems
$nonCompliant = $complianceReport | Where-Object { -not $_.Compliant }
if ($nonCompliant) {
$body = $nonCompliant | ConvertTo-Html | Out-String
Send-MailMessage -To "compliance@company.com" `
-Subject "RMM Compliance Alert: $($nonCompliant.Count) systems need attention" `
-Body $body `
-BodyAsHtml
}
Result: Automated monthly compliance reporting with alerts for non-compliant systems.
Disaster Recovery Testing
Scenario: Quarterly DR tests require removing and reinstalling agents to verify you can recover from a complete loss.
Scripted version:
# DR Test: Backup, remove, and restore agent configurations
param([string[]]$TestComputers)
foreach ($computer in $TestComputers) {
Write-Host "Testing DR for $computer..." -ForegroundColor Cyan
Invoke-Command -ComputerName $computer -ScriptBlock {
# Backup current configuration
$backup = New-CWAABackup
$backup | Export-Clixml "C:\Temp\AgentBackup-$(Get-Date -Format 'yyyyMMdd').xml"
# Simulate disaster - remove agent
Uninstall-CWAA -Force
# Wait
Start-Sleep 10
# Restore from backup
$restoredSettings = Import-Clixml "C:\Temp\AgentBackup-$(Get-Date -Format 'yyyyMMdd').xml"
Install-CWAA -Server $restoredSettings.Server `
-LocationID $restoredSettings.LocationID `
-InstallerToken $using:token
# Verify
$newInfo = Get-CWAAInfo
if ($newInfo.ID -and $newInfo.LocationID -eq $restoredSettings.LocationID) {
Write-Host "DR Test PASSED for $env:COMPUTERNAME" -ForegroundColor Green
}
else {
Write-Host "DR Test FAILED for $env:COMPUTERNAME" -ForegroundColor Red
}
}
}
Result: Automated DR testing with verification that agents can be restored to correct configurations.
Agent Version Audit and Update
Scenario: A vulnerability is found in agent version 11.1.2345. You need to find and update all affected agents.
Scripted version:
# Find and update vulnerable agents
$vulnerableVersion = '11.1.2345'
$computers = Get-ADComputer -Filter * | Select-Object -ExpandProperty Name
$affectedSystems = $computers | ForEach-Object -Parallel {
try {
$info = Invoke-Command -ComputerName $_ -ScriptBlock {
Get-CWAAInfo
} -ErrorAction Stop
if ($info.Version -eq $using:vulnerableVersion) {
[PSCustomObject]@{
Computer = $_
CurrentVersion = $info.Version
NeedsUpdate = $true
}
}
}
catch {
# Skip offline/inaccessible machines
}
} -ThrottleLimit 20
# Report affected systems
Write-Host "Found $($affectedSystems.Count) systems with vulnerable version" -ForegroundColor Yellow
$affectedSystems | Export-Csv "VulnerableAgents.csv" -NoTypeInformation
# Update all affected systems
$affectedSystems | ForEach-Object -Parallel {
Invoke-Command -ComputerName $_.Computer -ScriptBlock {
Import-Module ConnectWiseAutomateAgent
Update-CWAA
}
} -ThrottleLimit 10
Write-Host "Updates deployed to $($affectedSystems.Count) systems" -ForegroundColor Green
Result: Rapid identification and patching of vulnerable agents across entire infrastructure.
Multi-Tenant Client Segregation
Scenario: You’re an MSP managing 50+ clients. Each client’s agents need to land in the correct location with the right display name.
Scripted version:
# Client configuration database
$clientConfig = @(
@{ ClientName = 'Acme Corp'; LocationID = 100; Server = 'https://automate.msp.com'; Token = 'token1'; DisplayName = 'Acme IT Services' }
@{ ClientName = 'Globex Inc'; LocationID = 200; Server = 'https://automate.msp.com'; Token = 'token2'; DisplayName = 'Globex Monitoring' }
@{ ClientName = 'Initech LLC'; LocationID = 300; Server = 'https://automate.msp.com'; Token = 'token3'; DisplayName = 'Initech IT Support' }
)
# Deploy based on client
function Deploy-ClientAgent {
param(
[string]$ComputerName,
[string]$ClientName
)
$config = $clientConfig | Where-Object { $_.ClientName -eq $ClientName } | Select-Object -First 1
if (-not $config) {
Write-Error "Client $ClientName not found in configuration"
return
}
Invoke-Command -ComputerName $ComputerName -ScriptBlock {
Install-CWAA -Server $using:config.Server `
-InstallerToken $using:config.Token `
-LocationID $using:config.LocationID `
-Rename $using:config.DisplayName `
-Hide
}
Write-Host "Deployed agent for $ClientName to $ComputerName" -ForegroundColor Green
}
# Usage
Deploy-ClientAgent -ComputerName "ACME-WKS001" -ClientName "Acme Corp"
Result: Standardized, error-free agent deployment with proper client segregation and branding.
Proxy Configuration Management
Scenario: A client changes their proxy server. You need to update all 300 agents.
Scripted version:
# Update proxy on all agents
param(
[string]$NewProxyURL = "http://newproxy.client.com:8080",
[string]$ClientLocationID = 100
)
# Get all computers for this client
$computers = Invoke-RestMethod -Uri "https://automate.msp.com/api/computers?locationId=$ClientLocationID"
# Update proxy on each
$results = $computers | ForEach-Object -Parallel {
$computer = $_.ComputerName
try {
Invoke-Command -ComputerName $computer -ScriptBlock {
Import-Module ConnectWiseAutomateAgent
Set-CWAAProxy -ProxyServerURL $using:NewProxyURL
Restart-CWAA
}
[PSCustomObject]@{
Computer = $computer
Status = 'Updated'
}
}
catch {
[PSCustomObject]@{
Computer = $computer
Status = "Failed: $($_.Exception.Message)"
}
}
} -ThrottleLimit 25
# Report
$results | Export-Csv "ProxyUpdate-Results.csv" -NoTypeInformation
Write-Host "Updated proxy on $(($results | Where-Object Status -eq 'Updated').Count) computers" -ForegroundColor Green
Result: Instant proxy configuration change across entire client infrastructure.
Pre-Migration Agent Removal
Scenario: You’re migrating a client to a different RMM. You need clean agent removal from 400 endpoints, with verification that nothing is left behind.
Scripted version:
# Mass agent removal with verification
$computers = Get-ADComputer -Filter * -SearchBase "OU=Client,DC=domain,DC=com"
$removalResults = $computers | ForEach-Object -Parallel {
$computer = $_.Name
try {
Invoke-Command -ComputerName $computer -ScriptBlock {
Import-Module ConnectWiseAutomateAgent
Uninstall-CWAA -Force
# Verify removal
Start-Sleep 10
$service = Get-Service LTService -ErrorAction SilentlyContinue
if ($service) {
throw "Service still present after uninstall"
}
# Verify registry cleaned
$reg = Get-ItemProperty "HKLM:\SOFTWARE\LabTech\Service" -ErrorAction SilentlyContinue
if ($reg) {
throw "Registry keys still present"
}
}
[PSCustomObject]@{
Computer = $computer
Status = 'Removed'
Message = 'Agent fully removed and verified'
}
}
catch {
[PSCustomObject]@{
Computer = $computer
Status = 'Failed'
Message = $_.Exception.Message
}
}
} -ThrottleLimit 15
# Report
$removalResults | Export-Csv "AgentRemoval-$(Get-Date -Format 'yyyyMMdd').csv" -NoTypeInformation
$successful = ($removalResults | Where-Object Status -eq 'Removed').Count
Write-Host "Successfully removed agents from $successful / $($computers.Count) computers" -ForegroundColor Green
Result: Clean, verified removal of agents from entire client infrastructure.
Network Segmentation Testing
Scenario: You’re testing firewall rules for a new office and need to verify RMM connectivity from the test subnet before deploying agents.
Scripted version:
# Network connectivity verification script
param(
[string[]]$TestComputers,
[string]$Server = "https://automate.msp.com"
)
$testResults = foreach ($computer in $TestComputers) {
Invoke-Command -ComputerName $computer -ScriptBlock {
Import-Module ConnectWiseAutomateAgent
# Test all required ports (output is string-based, not objects)
$portOutput = Test-CWAAPort -Server $using:Server
$failedPorts = $portOutput | Where-Object { $_ -match 'Connection failed' }
[PSCustomObject]@{
Computer = $env:COMPUTERNAME
Subnet = (Get-NetIPAddress -AddressFamily IPv4 | Where-Object { $_.InterfaceAlias -notmatch 'Loopback' } | Select-Object -First 1).IPAddress
PortTestOutput = ($portOutput -join "`n")
AllPortsOpen = ($failedPorts.Count -eq 0)
}
}
}
# Report
$testResults | Format-Table -AutoSize
$failures = $testResults | Where-Object { -not $_.AllPortsOpen }
if ($failures) {
Write-Host "`nFirewall issues detected on $($failures.Count) computers:" -ForegroundColor Red
$failures | Format-Table Computer, Subnet, PortTestOutput
}
else {
Write-Host "All network connectivity tests passed!" -ForegroundColor Green
}
Result: Automated firewall rule verification before agent deployment.
Fleet Health Monitoring
Scenario: You want a daily sweep of all agents that catches issues and attempts basic remediation, with a report of what it found.
If you’re looking for per-endpoint self-healing that runs as a scheduled task on each machine, see Self-Healing Agents. That post covers Repair-CWAA, escalation logic, and the health check task in detail.
This pattern is different – it’s a centralized sweep you run from a management server against your whole fleet.
Scripted version:
# Daily agent health check with auto-remediation
# Run as scheduled task at 6 AM daily
$computers = Get-ADComputer -Filter * | Select-Object -ExpandProperty Name
$issues = @()
foreach ($computer in $computers) {
try {
$health = Invoke-Command -ComputerName $computer -ScriptBlock {
Import-Module ConnectWiseAutomateAgent
$info = Get-CWAAInfo
$services = Get-Service LTService, LTSvcMon
# Check for issues
$problems = @()
# Issue 1: Services stopped
if ($services.Status -contains 'Stopped') {
Restart-CWAA
$problems += "Services were stopped - restarted"
}
# Issue 2: Old last contact (> 1 hour)
$lastContact = [datetime]$info.LastSuccessfulContact
if ((Get-Date) - $lastContact -gt [timespan]::FromHours(1)) {
Invoke-CWAACommand -Command "Send Status"
$problems += "Stale last contact - forced status update"
}
# Issue 3: Critical errors in logs
$errors = Get-CWAAError | Select-Object -Last 100 | Where-Object { $_ -match "CRITICAL|FATAL" }
if ($errors) {
$problems += "Critical errors in log: $($errors.Count) entries"
}
if ($problems.Count -gt 0) {
[PSCustomObject]@{
Computer = $env:COMPUTERNAME
Issues = $problems -join '; '
Remediated = $true
}
}
}
if ($health) {
$issues += $health
}
}
catch {
$issues += [PSCustomObject]@{
Computer = $computer
Issues = "Unable to connect: $($_.Exception.Message)"
Remediated = $false
}
}
}
# Send daily report
if ($issues.Count -gt 0) {
$htmlReport = $issues | ConvertTo-Html -Title "Daily Agent Health Report" | Out-String
Send-MailMessage -To "[email protected]" `
-From "[email protected]" `
-Subject "Daily Agent Health Report: $($issues.Count) issues found" `
-Body $htmlReport `
-BodyAsHtml `
-SmtpServer "smtp.msp.com"
$issues | Export-Csv "HealthReport-$(Get-Date -Format 'yyyyMMdd').csv" -NoTypeInformation
}
Result: Proactive monitoring and auto-remediation of common agent issues before they become tickets.
Department-Based Agent Branding
Scenario: A large enterprise wants different agent display names per department for charge-back reporting.
Scripted version:
# Department-based agent naming
$departmentMap = @{
'OU=Sales' = 'Sales Department IT'
'OU=Engineering' = 'Engineering Services'
'OU=HR' = 'Human Resources IT'
'OU=Finance' = 'Finance Department IT'
}
$computers = Get-ADComputer -Filter * -Properties DistinguishedName
foreach ($computer in $computers) {
# Determine department from DN
$department = $departmentMap.Keys | Where-Object { $computer.DistinguishedName -match $_ } | Select-Object -First 1
$displayName = $departmentMap[$department]
if ($displayName) {
Invoke-Command -ComputerName $computer.Name -ScriptBlock {
Import-Module ConnectWiseAutomateAgent
Rename-CWAAAddRemove -Name $using:displayName
}
Write-Host "Updated $($computer.Name) to '$displayName'" -ForegroundColor Green
}
}
Result: Automated agent branding based on organizational structure for accurate charge-back.
Patterns Worth Noting
A few things show up across most of these examples:
- Parallel execution –
ForEach-Object -Parallelkeeps things fast when you’re hitting hundreds of machines - Error handling – every script accounts for machines being offline or unreachable
- Reporting – CSV exports and email notifications so you have a record of what happened
- Verification – confirm the action worked, don’t assume it did
- Composability – module functions combine naturally with AD, email, and your existing tooling
Here’s a starter template if you want to build your own:
# Template for custom use cases
param([string[]]$Computers)
$results = $Computers | ForEach-Object -Parallel {
try {
Invoke-Command -ComputerName $_ -ScriptBlock {
Import-Module ConnectWiseAutomateAgent
# Your logic here
# - Get-CWAAInfo
# - Set-CWAAProxy
# - Restart-CWAA
# - etc.
}
# Success
[PSCustomObject]@{
Computer = $_
Status = 'Success'
}
}
catch {
# Failure
[PSCustomObject]@{
Computer = $_
Status = 'Failed'
Error = $_.Exception.Message
}
}
} -ThrottleLimit 20
# Report results
$results | Export-Csv "Results.csv" -NoTypeInformation
Getting started:
Install-Module ConnectWiseAutomateAgent
Full function reference and examples: GitHub Repository
Comments