Create CW RMM Agent Deployment GPO
Summary
The task will generate a ConnectWise RMM Agent Deployment Group Policy Object (GPO) on the domain controller where it is run. It is recommended to execute the script on the Primary Domain Controller.
The established GPO will execute a PowerShell script on the terminal device at startup or after the computer reboots. This script will attempt to install the ConnectWise RMM Agent on the Windows computers within the domain that do not currently have the CW RMM agent installed.
The results of the script execution will be stored on the endpoint in either the Install-RMMAgent-log.txt
or Install-RMMAgent-Error.txt
files. These files can be found in the C:/ProgramData/_automation/script/Install-RMMAgent
directory.
GPO
Scope: The GPO will be linked with the domain.
Details:
Settings:
Delegation:
Sample Run
User Parameters
Name | Example | Required | Description |
---|---|---|---|
Token | 7f67c643-bf18-4c2b-be9d-f7a355e1f68a | True | The ConnectWise RMM Agent Installer token corresponding to the client/site of the Domain Controller where the script is run. |
Installer Token Generation
- Go to Devices > Computers. Once the page loads, you will see a Manage option in the Action Bar, at the top-left of the page.
- Click Manage to open the Menu Item. In the Menu, click Download Agent.
- A new window will launch from where you can generate the agent installer token.
- In the Download Agent window, select your site from the list of sites provided in the dropdown. You can also type to search for your site and select it.
- After selecting the site, the
Agent Token
will be displayed. You can copy the token by clicking on theCopy token to clipboard
button.
Create Script
Create a new Script Editor
style script in the system to implement this task.
Name: Create CW RMM Agent Deployment GPO
Description: The task will generate a ConnectWise RMM Agent Deployment Group Policy Object (GPO) on the domain controller where it is run. It is recommended to execute the script on the Primary Domain Controller.
Category: Setup
Parameters
Click the Add Parameter
button.
The Add New Script Parameter
box will appear.
In the box, fill in the following details and select Save
to create the Token
parameter.
- Parameter Name:
Token
- Required Field:
True
- Parameter Type:
Text String
- Default Value:
False
Script
Start by adding a row. You can do this by clicking the Add Row
button at the bottom of the script page.
Row 1 Function: PowerShell Script
Select the PowerShell Script
function.
Paste in the following PowerShell script, set the expected time of script execution to 300
seconds, and click the Save
button.
$Token = '@Token@'
#region Strapper
Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass -Force -Erroraction SilentlyContinue
[Net.ServicePointManager]::SecurityProtocol = [Enum]::ToObject([Net.SecurityProtocolType], 3072)
Get-PackageProvider -Name NuGet -ForceBootstrap | Out-Null
Set-PSRepository -Name PSGallery -InstallationPolicy Trusted
try {
Update-Module -Name Strapper -ErrorAction Stop
} catch {
Install-Module -Name Strapper -Repository PSGallery -SkipPublisherCheck -Force
Get-Module -Name Strapper -ListAvailable | Where-Object { $_.Version -ne (Get-InstalledModule -Name Strapper).Version } | ForEach-Object { Uninstall-Module -Name Strapper -MaximumVersion $_.Version }
}
Import-Module -Name Strapper 3>&1 2>&1 1>$null
Set-StrapperEnvironment
#endregion
#Working Directory
$ProjectName = 'Install-RMMAgentGPO'
$WorkingDirectory = "C:\ProgramData\_automation\script\$ProjectName"
$StrapperSession.LogPath = "$WorkingDirectory\$ProjectName-log.txt"
$StrapperSession.ErrorPath = "$WorkingDirectory\$ProjectName-Error.txt"
if ( !(Test-Path $WorkingDirectory) ) {
try {
New-Item -Path $WorkingDirectory -ItemType Directory -Force -Erroraction Stop| Out-Null
} catch {
Write-Log -Level Error -Text "Failed to Create $WorkingDirectory. Reason: $($Error[0].Excpection.Message)"
}
}
if (-not ( ( ( Get-Acl $WorkingDirectory ).Access | Where-Object { $_.IdentityReference -Match 'EveryOne' } ).FileSystemRights -Match 'FullControl' ) ) {
$ACl = Get-ACL $WorkingDirectory
$AccessRule = New-Object System.Security.AccessControl.FileSystemAccessRule('Everyone', 'FullControl', 'ContainerInherit, ObjectInherit', 'none', 'Allow')
$Acl.AddAccessRule($AccessRule)
Set-Acl $WorkingDirectory $Acl
}
#End Region
#Process
Function New-ScriptFile {
param (
[Parameter(Mandatory = $True)]
[ValidatePattern('^[a-f0-9]{8}(-[a-f0-9]{4}){3}-[a-f0-9]{12}$')]
[String]$Token
)
$ScriptText = @"
if ( Get-Service -Name 'ITSPlatform','ITSPlatformManager' -ErrorAction SilentlyContinue ) {
return
}
#region Strapper
Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass -Force -Erroraction SilentlyContinue
[Net.ServicePointManager]::SecurityProtocol = [Enum]::ToObject([Net.SecurityProtocolType], 3072)
Get-PackageProvider -Name NuGet -ForceBootstrap | Out-Null
Set-PSRepository -Name PSGallery -InstallationPolicy Trusted
try {
Update-Module -Name Strapper -ErrorAction Stop
} catch {
Install-Module -Name Strapper -Repository PSGallery -SkipPublisherCheck -Force
Get-Module -Name Strapper -ListAvailable | Where-Object { `$_.Version -ne (Get-InstalledModule -Name Strapper).Version } | ForEach-Object { Uninstall-Module -Name Strapper -MaximumVersion `$_.Version }
}
Import-Module -Name Strapper 3>&1 2>&1 1>`$null
Set-StrapperEnvironment
#endregion
`$ProjectName = 'Install-RMMAgent'
`$WorkingDirectory = "C:\ProgramData\_automation\script\`$ProjectName"
`$StrapperSession.LogPath = "`$WorkingDirectory\`$ProjectName-log.txt"
`$StrapperSession.ErrorPath = "`$WorkingDirectory\`$ProjectName-Error.txt"
`$Installer = "`$WorkingDirectory\Agent_TKN$($Token).msi"
if ( !(Test-Path `$WorkingDirectory) ) {
try {
New-Item -Path `$WorkingDirectory -ItemType Directory -Force -Erroraction Stop| Out-Null
} catch {
Write-Log -Level Error -Text "Failed to Create `$WorkingDirectory. Reason: `$(`$Error[0].Excpection.Message)"
}
}
if (-not ( ( ( Get-Acl `$WorkingDirectory ).Access | Where-Object { `$_.IdentityReference -Match 'EveryOne' } ).FileSystemRights -Match 'FullControl' ) ) {
`$ACl = Get-ACL `$WorkingDirectory
`$AccessRule = New-Object System.Security.AccessControl.FileSystemAccessRule('Everyone', 'FullControl', 'ContainerInherit, ObjectInherit', 'none', 'Allow')
`$Acl.AddAccessRule(`$AccessRule)
Set-Acl `$WorkingDirectory `$Acl
}
`$DesktopURL = "https://prod.setup.itsupport247.net/windows/DPMA/32/Agent_TKN$($Token)/MSI/setup"
`$ServerURL = "https://prod.setup.itsupport247.net/windows/MSMA/32/Agent_TKN$($Token)/MSI/setup"
`$url = if ( ( Get-Ciminstance -Class Win32_OperatingSystem ).Caption -match 'Server' ) { `$ServerURL } else { `$DesktopURL }
try {
`$webClient = [System.Net.WebClient]::new()
`$WebClient.DownloadFile(`$url, `$installer)
Unblock-File -Path `$Installer -Confirm:`$false -ErrorAction SilentlyContinue
} catch {
Write-Log -Level Error -Text "Failed to download the installer. Reason: `$(`$Error[0].exception.Message)"
}
`$ExitCode = (Start-Process 'C:\Windows\System32\msiexec.exe' -ArgumentList "/i ""`$(`$installer)"" /qn" -Wait -PassThru).ExitCode
do {
try {`$connection = test-connection 8.8.8.8 -Erroraction Stop} catch {`$connection = 'down'}
} until (`$connection -ne 'Down' )
Start-Sleep -Seconds 30
`$serviceRestartTimeout = 1
do {
Write-Log -Level Information -Text 'Waiting for the ITPSPlatform Service to appear.'
Start-Sleep -Seconds 1
`$serviceRestartTimeout++
} until ( ( Get-Service -Name 'ITSPlatform','ITSPlatformManager' -ErrorAction SilentlyContinue ) -or `$serviceRestartTimeout -gt 120 )
if ( Get-Service -Name 'ITSPlatform','ITSPlatformManager' -ErrorAction SilentlyContinue ) {
Write-Log -Level Information -Text 'Successfully installed CW RMM agent.'
Start-Sleep -Seconds 30
foreach ( `$service in ( ( Get-Service -Name 'ITSPlatform','ITSPlatformManager' | Where-Object { `$_.Status -ne 'Running' } ).Name) ) {
Restart-Service -Name `$service -Force -Confirm:`$false -ErrorAction SilentlyContinue
}
} else {
Write-Log -Level Error -Text "CW RMM Agent Installation Failed with exit code `$ExitCode."
}
"@
$Utf8NoBomEncoding = New-Object System.Text.UTF8Encoding $False
[System.IO.File]::WriteAllLines("$($WorkingDirectory)\$($ProjectName).ps1", $ScriptText, $Utf8NoBomEncoding)
}
Import-Module GroupPolicy
$ExistingGPO = Get-GPO -name 'Deploy-CWRMMAgent' 2>$Null
$domain = Get-ADDomain
$forest = $domain.forest
If ( !$ExistingGPO ) {
New-ScriptFile -Token $Token
$Name = 'Deploy-CWRMMAgent'
$GPO = New-GPO -Name $name -Comment 'GPO to Deploy CW RMM Agent'
Start-Sleep -s 5
$guid = $gpo.id.ToString().ToUpper()
Write-Log -Level Information -Text "Group Policy Created: $guid"
$Target = $forest.Split('.')
$GPO | New-GPLink -Target "dc=$($Target[0]),dc=$($Target[1])" -LinkEnabled Yes
mkdir "C:\Windows\SYSVOL\sysvol\$forest\Policies\{$guid}\Machine\Scripts\Startup" -Force | Out-Null
Copy-Item "$($WorkingDirectory)\$($ProjectName).ps1" "C:\Windows\SYSVOL\sysvol\$forest\Policies\{$guid}\Machine\Scripts\Startup" -Force
$pshellscript = @"
[Startup]
0CmdLine=$($projectName).ps1
0Parameters=
"@
$psfilename = "C:\Windows\SYSVOL\sysvol\$forest\Policies\{$guid}\Machine\Scripts\psscripts.ini"
$pshellscript | Out-File $psfilename -Encoding unicode
$psfile = Get-Item $psfilename -Force
$psfile.attributes = 'Hidden'
$gptini = @'
[General]
Version=2
displayName=New Group Policy Object
'@
$gptinifilename = "C:\Windows\SYSVOL\sysvol\$forest\Policies\{$guid}\GPT.ini"
$gptini | Out-File $gptinifilename -Encoding utf8
$gPCMachineExtensionNames = '[{42B5FAAE-6536-11D2-AE5A-0000F87571E3}{40B6664F-4972-11D1-A7CA-0000F87571E3}]'
$adgpo = ([adsisearcher]"(&(objectCategory=groupPolicyContainer)(name={$guid}))").FindAll().Item(0)
$gpoentry = $adgpo.GetDirectoryEntry()
$gpoentry.Properties['gPCMachineExtensionNames'].Value = $gPCMachineExtensionNames
$gpoentry.Properties['versionNumber'].Value = '2'
$gpoentry.CommitChanges()
} else {
Write-Log -Level Information -Text 'CW RMM Agent Deployment Group Policy Object exists'
Write-Log -Level Information -Text $ExistingGPO
$Guid = $ExistingGPO.ID.ToString().ToUpper()
$oldscript = Get-Content -Path "C:\Windows\SYSVOL\sysvol\$forest\Policies\{$Guid}\Machine\Scripts\Startup\$ProjectName.ps1" -ErrorAction SilentlyContinue
if ($oldscript -match $token) {
Write-Log -Level Information -Text 'Token matches'
return
} else {
Write-Log -Level Information -Text 'token doesnt match, applying new token'
New-ScriptFile -Token $Token
Copy-Item "$($WorkingDirectory)\$($ProjectName).ps1" "C:\Windows\SYSVOL\sysvol\$forest\Policies\{$guid}\Machine\Scripts\Startup" -Force
}
}
Row 2 Function: Script Log
Insert a new row by clicking the Add Row
button.
Select the Script Log
function.
Paste this line in the Script Log Message
box and click the Save
button.
PowerShell Output: %Output%
Row 3 Function: PowerShell Script
Insert a new row by clicking the Add Row
button.
Select the PowerShell Script
function.
Paste in the following PowerShell script, set the expected time of script execution to 300
seconds, and click the Save
button.
Get-Content -Path "C:\ProgramData\_automation\script\Install-RMMAgentGPO\Install-RMMAgentGPO-Log.txt" -ErrorAction SilentlyContinue
Get-Content -Path "C:/ProgramData/_automation/script/Install-RMMAgentGPO/Install-RMMAgentGPO-Log.txt" -ErrorAction SilentlyContinue


#### Row 4 Function: Script Log
Insert a new row by clicking the `Add Row` button.

Select the `Script Log` function.


Paste this line in the `Script Log Message` box and click the `Save` button.
`Script Logs: %Output%`


Click the `Save` button to save the Task.

## Completed Script

## Output
- Script Log
