Pete Hinchley: Remove a User's Device Profile and Directory Number from Cisco Unified Communications Manager using PowerShell

Here is some code I wrote this week to remove a user's device profile and directory number from Cisco Unified Communications Manager (UCM) via the AXL API using PowerShell. There are a few parts to the solution:

  1. A name-based wildcard search is initiated to retrieve all device profiles. I do this, because it isn't possible to directly retrieve a specific device profile via a user's login id. To keep the result set small, I only retrieve the name and associated login id for each device profile.
  2. The result set is iterated over until a matching login id is found.
  3. The complete device profile of the matched record is retrieved (using the matched profile name).
  4. The directory number is obtained from the retrieved device profile.
  5. The device profile is deleted.
  6. The line associated with the directory number is deleted.

To use the code, set the login variable to the login id of the user to be deleted, the username and password variables to those of an account with administrator privileges within Cisco UCM, and the api variable to the AXL API endpoint that is used within your environment.

I am sure this is a fairly niche task, but I hope someone may find the code useful.

# the login id of the user to delete.
$login = 'jbloggs'

# creds for connecting to the api.
$username = 'admin'
$password = 'password'

# api endpoint.
$api = 'https://10.1.1.1:8443/axl/'

# build authorization header.
$cred = [system.text.utf8encoding]::utf8.getbytes($username + ':' + $password)
$auth = 'BASIC ' + [system.convert]::tobase64string($cred)

add-type @"
  using System.Net;
  using System.Security.Cryptography.X509Certificates;
  public class TrustAllCertsPolicy : ICertificatePolicy {
    public bool CheckValidationResult(
      ServicePoint srvPoint,
      X509Certificate certificate,
      WebRequest request,
      int certificateProblem
    ) { return true; }
  }
"@

# used to bypass certificate validity check.
[System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy

# soap template.
$template = @'
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns="http://www.cisco.com/AXL/API/11.5">
    <soapenv:Header/>
    <soapenv:Body>
      {0}
    </soapenv:Body>
</soapenv:Envelope>
'@

# first, we will check if the user has a device profile.
# we can't search by login id, so we will retrieve all users (using a name wildcard search).
# to keep the result set small, we will only return the name and login id fields.
# we will then iterate through the results looking for a matching login id.
$snippet = '<ns:listDeviceProfile><searchCriteria><name>%</name></searchCriteria><returnedTags><name /><loginUserId /></returnedTags></ns:listDeviceProfile>'

# build request body from template + snippet.
$body = $template -f $snippet

try {
  $result = invoke-restmethod -contentType 'text/xml' -headers @{ Authorization = $auth; SOAPAction = 'CUCM:DB ver=11.5 listDeviceProfile' } -uri $api -method post -body $body
  if ($result.Envelope.Body.listDeviceProfileResponse.return.length -eq 0) {
    write-host 'The user does not have a device profile in Call Manager.'; exit
  }
} catch { write-warning 'Error searching for the device profile in Call Manager.'; exit }

$name = $null
$result.Envelope.Body.listDeviceProfileResponse.return.deviceProfile | %{
  # break if we find a user with a matching login id.
  if ($_.loginUserId.'#text' -eq $login) { $name = $_.name; break }
}

if ($name -eq $null) { write-host 'The user does not have a device profile in Call Manager.'; exit }

# having found a user with a matching login id, we will retrieve the user's full device profile.
$snippet = '<ns:getDeviceProfile><name>{0}</name></ns:getDeviceProfile>' -f $name
$body = $template -f $snippet

try {
  $result = invoke-restmethod -contentType 'text/xml' -headers @{ Authorization = $auth; SOAPAction = 'CUCM:DB ver=11.5 getDeviceProfile' } -uri $api -method post -body $body
} catch { write-warning "Error retrieving the user's device profile in Call Manager."; exit }

# we will now extract the user's directory number from the device profile.
$pattern = $result.Envelope.Body.getDeviceProfileResponse.return.deviceProfile.lines.FirstChild.dirn.pattern
if (! $pattern) { write-host 'The user does not have a directory number in Call Manager.'; exit }

# now we can remove the user's device profile.
$snippet = '<ns:removeDeviceProfile><name>{0}</name></ns:removeDeviceProfile>' -f $name
$body = $template -f $snippet

try {
  $result = invoke-restmethod -contentType 'text/xml' -headers @{ Authorization = $auth; SOAPAction = 'CUCM:DB ver=11.5 removeDeviceProfile' } -uri $api -method post -body $body
} catch { write-warning 'The device profile could not be removed from Call Manager.'; exit }

# and finally, we can remove the user's directory number.
# note: you may need to modify the route partition name for your environment.
$snippet = '<ns:removeLine><pattern>{0}</pattern><routePartitionName>-SYSTEM</routePartitionName></ns:removeLine>' -f $pattern
$body = $template -f $snippet

try {
  $result = invoke-restmethod -contentType 'text/xml' -headers @{ Authorization = $auth; SOAPAction = 'CUCM:DB ver=11.5 removeLine' } -uri $api -method post -body $body
} catch { write-warning 'The directory number could not be removed from Call Manager.'; exit }