~/2022/10/12/autotask-powershell-enable-client-portal-for-all-users.md
PowerShell: Autotask – Enable Client Portal for All Users
--- author: Tom Lasswell date: updated: read: 1 min in: [ps, scripts] tags: [autotask, powershell] ---
$ grep -n '^#' post.md
This is a quick one, it’s been forever since I’ve posted here. After moving back to Autotask, there’s still a ton of things to automate. One of the things that was bugging me was the fact you can’t set the client portal to default. Well, here’s a script you can run periodically to enable all the users to have the simple version of the client portal.
Requirements
- PowerShell 3.0 or later (the script uses
Invoke-RestMethod). - An Autotask REST API user with permission to read companies and contacts and to create client portal users.
- The Autotask REST API base URL for your zone, the API integration code, and the API username and secret, supplied as environment variables (see Parameters).
- Network access to the Autotask REST API.
Parameters
The script has no param block. It reads its settings from these environment variables, which must be set in the session before it runs.
| Name | Type | Required | Description |
|---|---|---|---|
at_uri | Environment variable (string) | Yes | Base URL of your Autotask REST API zone, without /v1.0. |
at_integrationcode | Environment variable (string) | Yes | API integration code (sent as the ApiIntegrationcode header). |
at_username | Environment variable (string) | Yes | Autotask API user name. |
at_secret | Environment variable (string) | Yes | Secret for the Autotask API user. |
Two values in the script are specific to the author's Autotask instance and must be adjusted before you run it: the companyCategoryID filter and Select-Object -Skip 3. See Notes.
Usage
Set the environment variables for the current session, then run the script. It lists the contacts it enables as it goes.
$env:at_uri = "<autotask-rest-url>"
$env:at_integrationcode = "<integration-code>"
$env:at_username = "<api-username>"
$env:at_secret = "<api-secret>"
.\Enable-AutotaskClientPortal.ps1
Script
<#
.SYNOPSIS
Enables the simple client portal for every active Autotask contact that does not have it yet.
.DESCRIPTION
Queries Autotask companies (filtered by company category), then the active
contacts of each company, and compares them with the existing client portal
users. For every contact without a client portal user it creates one, with
the contact's e-mail address as the user name and a random 10-character
password. Settings are read from environment variables, not parameters.
.PARAMETER at_uri
Environment variable. Base URL of your Autotask REST API zone, without /v1.0.
.PARAMETER at_integrationcode
Environment variable. API integration code (sent as the ApiIntegrationcode header).
.PARAMETER at_username
Environment variable. Autotask API user name.
.PARAMETER at_secret
Environment variable. Secret for the Autotask API user.
.EXAMPLE
$env:at_uri = "<autotask-rest-url>"
$env:at_integrationcode = "<integration-code>"
$env:at_username = "<api-username>"
$env:at_secret = "<api-secret>"
.\Enable-AutotaskClientPortal.ps1
.NOTES
Author : Thomas Lasswell (https://www.techcolumnist.com)
Version : 1.0 (2022-10-12)
Requires: PowerShell 3.0 or later, Autotask REST API user
Adjust : Select-Object -Skip 3 skips the first three companies returned and
companyCategoryID 101 is a category ID from the author's Autotask
instance. Change or remove both before running.
Limit : Only companies with 500 or fewer contacts are handled.
#>
function New-SecurePassword {
$Password = "!?@#$%^&*0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz".ToCharArray()
($Password | Get-Random -Count 10) -join ''
}
$at_uri = $($env:at_uri)
$at_integrationcode = $($env:at_integrationcode)
$at_username = $($env:at_username)
$at_secret = $($env:at_secret)
# Autotask headers.
$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add("ApiIntegrationcode", "$at_integrationcode")
$headers.Add("Content-Type", 'application/json')
$headers.Add("UserName", "$at_username")
$headers.Add("Secret", "$at_secret")
# Get the companies to process.
$companies = $(Invoke-RestMethod -Uri $($at_uri + '/v1.0/Companies/query?search={"IncludeFields": ["id", "companyName","companyNumber","isActive"],"filter":[{"op":"eq","field":"companyCategoryID","value":"101"}]}') -Headers $headers -Method Get).items
foreach ($company in $companies | Select-Object -Skip 3) {
# Get the active contacts of the company.
$contacts = $(Invoke-RestMethod -Uri $($at_uri + '/v1.0/Contacts/query?search={"IncludeFields": ["id", "firstName","lastName","isActive","emailAddress"],"filter":[{"op":"and","items":[{"op":"eq","field":"companyID","value":"' + $($company.id) + '"},{"op":"eq","field":"isActive","value":"true"}]}]}') -Headers $headers -Method Get).items
$query = $null
$x = 0
$y = 0
$clientportal = @()
# Get the existing client portal users, 100 contacts per query.
do {
foreach ($contact in $contacts) {
if ($query) {
$query += ',{"op":"eq","field":"contactID","value":"' + $($contact.id) + '"}'
}
if (!$query) {
$query = '{"op":"eq","field":"contactID","value":"' + $($contact.id) + '"}'
}
$y++
$x++
if ($x -eq $contacts.Count) {
$y = 100
}
if ($y -eq 100) {
$postbody = '{"filter":[{"op":"or","items":[' + $query + ']}]}'
$clientportal += $(Invoke-RestMethod -Uri $($at_uri + '/v1.0/ClientPortalUsers/query') -Body $postbody -Headers $headers -Method Post).items
$query = $null
$y = 0
}
}
}
while ($x -lt $contacts.Count)
# Create client portal users for the contacts that are missing one.
if ($clientportal.Count -ne $contacts.Count) {
Write-Host "Contacts: $($contacts.Count)"
Write-Host "Enabled: $($clientportal.Count)"
$missing = $null
$missing = $contacts.id | Where-Object { $_ -notin $clientportal.contactId }
foreach ($miss in $missing) {
$contact = $null
$contact = $contacts | Where-Object { $miss -eq $_.id }
Write-Host "$($contact.emailAddress)"
$json = [PSObject]@{
contactID = $($contact.id)
userName = "$($contact.emailAddress)"
securityLevel = 1
password = "$(New-SecurePassword)"
numberFormat = 22
dateFormat = 1
timeFormat = 1
isClientPortalActive = $true
}
$json = $json | ConvertTo-Json
Start-Sleep -Milliseconds 10
Invoke-RestMethod -Uri $($at_uri + '/v1.0/ClientPortalUsers') -Method POST -Body $json -Headers $headers
}
}
}
Notes
- There are a few places you might want to update. I use a filter for a specific customer category, so where your
$companiesvariable is, you may want to change or remove this part of the query:{"op":"eq","field":"companyCategoryID","value":"101"} - Category
101and theSelect-Object -Skip 3(which skips the first three companies returned) are specific to my Autotask instance. Adjust or remove both for yours. - The script currently only handles companies with 500 or fewer contacts. I’ll update it with a loop to get all the contacts as well.