Gathering ServiceNow CMDB Server Data

Process to True Up a ServiceNow CMDB

A version of this blog was first published in my Linkedin profile blog.

We use ServiceNow to maintain a CMDB of all our deployed servers. I have mixed feelings about ServiceNow, but the ServiceNow Discovery capability works well. ServiceNow provides a REST API that can be used to programmatically pull data. As of PowerShell 3 PowerShell provides the Invoke-RestMethod to interact with REST API services. In order to make use of the ServiceNow REST interface, you need an ID that has the correct permissions. It also helps if you have a ServiceNow role that lets you browse your ServiceNow instance tables.
A basic understanding of ServiceNow server classes is also helpful. In my case I’m interested in Windows and Linux server classes.
My goal was to pull data on server configuration items (CI). This information will then be used in the true up process for the server inventory in the CMDB. This was to run daily as a scheduled PowerShell job. This is the first step in building a true up process for the CMDB.

Required PowerShell Modules:

  • ServiceNow: A smart dude named Sam Martin has created a module and published it on github that performs most of the REST API heavy lifting for you . The page linked to above provides all the info you need to download and make use of this module. Pay particular attention to the ServiceNow Role requirements.

Create the ServiceNow Query:

A review of the applicable ServiceNow tables and some Google searches led to the data I need. The following ServiceNow tables have what I was looking for for this project.

Server CI DataServiceNow Table Name
This table contains the status of the server CI. The ServiceNow tenant I am working with uses a status of “Installed” for active CI and “Retired” for server CI that have been decommissioned. Server CI are not deleted from the CMDBcmdb_ci
This table has discovered information for Windows server class CI.cmdb_ci_win_server
This table has discovered information for Linux server class CI.cmdb_ci_linux_server
During my Google searches I found that the ServiveNow REST API allows use of cmdb_ci_server to get Windows and Linux server data using one call.cmdb_ci_server

I stored a ServiceNow credential with the right ServiceNow roles using the Export-CliXml cmdlet and import using Import-CliXml for use in the script.

Lesson learned:

Keep in mind that the only user that can import a credential in this way is the user that performed the export.

$ServiceNowCredential = Import-CliXml -Path "${env:\userprofile}\snow_export.Cred"

Lesson learned:

The ServiceNow module’s Set-ServiceNowAuth cmdlet returns True if the credential works, a nice touch. Even if this returns True it doesn’t mean the identity used can pull the CI data.

$cred_is_good = $false
$cred_is_good = Set-ServiceNowAuth -Url $tenantURL -Credentials $ServiceNowCredential
if($cred_is_good -eq $true){
   Write-EventLog -LogName "Application" -Source "CustomScripts" -EventId 1000 -EntryType Information -"ServiceNow cred 
   is good}else{
   Write-EventLog -LogName "Application" -Source "CustomScripts" -EventId 1000 -EntryType Error -"ServiceNow cred 
   is not good. Exiting";Exit  }

The ServiceNow module from Sam Martin provides the Get-ServiceNowConfigurationItem function.
It takes an input parameter for the properties of the CI you want.

#For the CI query
$comonProps = 'ip_address', 'name', 'last_discovered', 'first_discovered', 'sys_id', 'os', 'fqdn',`
'cpu_core_count', 'cpu_core_thread', 'cpu_count','cpu_type', 'manufacturer', 'model_id', 'location',`
'serial_number','sys_class_name'
$table = 'cmdb_ci_server'
$CMDBServers = Get-ServiceNowConfigurationItem -First 10000 -table $table -Properties $comonProps

Manufacturer and Model ID require a little more processing to arrive at a human readable value. Adding new properties to the returned object to hold that data.

$CMDBServers | Add-Member -MemberType NoteProperty -name 'model' -Value ' '
$CMDBServers | Add-Member -MemberType NoteProperty -name 'maker' -Value ' '
$CMDBServers | Add-Member -MemberType NoteProperty -name 'site' -Value ' '

Now loop through the server objects and get the attribute values for the report.

foreach ($svr in $CMDBServers) {
 $svr.model = $svr.model_id.display_value
 $svr.maker = $svr.manufacturer.display_value
 $svr.site = $svr.location.display_value
# Don't need the original Properties now so remove them
 $svr.PSObject.Properties.Remove('model_id')
 $svr.PSObject.Properties.Remove('manufacturer')
 $svr.PSObject.Properties.Remove('location')
 }

$CMDBServers is almost ready to export. When reviewing the data I noticed I was getting some duplicate servers when sorting by server name. Turned out some of the deployed Windows servers were running Hyper-V and so had two entries in the CI table. One as a Windows class and another as a Hyper-V class. I decided to report that data as is but to include a new property that indicates duplicate entries exist.

# Assume CMDB has multiple records with same value for the Name field.
$dupCount = $CMDBServers.Name | group | select Count, Name | sort Count -d
# Field for holding count of records that have same Name value
$CMDBServers | Add-Member -MemberType NoteProperty -Name 'recordCount' -Value 1

# This just places the duplicate count in the NoteProperty for each server CI. If there are no duplicate the record count will be 1.
foreach ($srv in $CMDBServers)
 {
 foreach ($svr in $dupCount) {
    If ($svr.Name -eq $srv.Name) {
	$srv.recordCount = $svr.Count
     }	
  }
} 

Now it’s just a matter of exporting $CMDBServers to an excel workbook.

The ServiceNow module makes getting data from the CMDB a breeze.

Lesson Learned: ServiceNow requires use of TLS 1.2

ServiceNow recently updated their web services layer to require use of TLS 1.2. After some Google searches I found that I needed to force PowerShell to use TLS 1.2. Adding this to the script before attempting to connect to ServiceNow solved the problem for me.

[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12