In this blog post I will walk you through the solution I implemented by building “RESTful” for “REST” API. Sounds weird right? Yes, this is a challenge I faced at ac client environment! For a business reason team decided to customize the servicenow endpoints. So, as expected dependency in increased along with that technical challenges.
I feel CMDB module is easier in servicenow than others like Request, Request Item, etc . However we need to do multiple query in order to retrieve CMDB information especially for contact.
- Send Request to retrieve parent configuration item.
- Through parent CI query primary and secondary owner information.
Our goal is to achieve
$HostNames = @('server001' , 'server002') foreach($HostName in $HostNames) { Invoke-RestMethod -Uri http://localhost:3000/api/CIContactInformation/$HostName | ConvertTo-Json }
and get output as illustrated below
{ "PrimaryOwnerName": { "Email": "Chendrayan.Venkatesan@contoso.com", "CI Identifier": "CI01234567", "Name": "Chendrayan Venkatesan", "Phome": "+1 xxx-yyy-zzzz" }, "SecondaryOwner": { "CI Identifier": "CI01234567", "Name": "Chendrayan Venkatesan", "Email": "Chendrayan.Venkatesan@contoso.com", "Phone": "+1 xxx-yyy-zzzz" } } { "PrimaryOwnerName": { "Email": null, "CI Identifier": "CI01234568", "Name": null, "Phome": null }, "SecondaryOwner": { "CI Identifier": "CI01234568", "Name": null, "Email": null, "Phone": null } }
Here is the PowerShell script which does the job!
param ( $HostName ) try { if (-not ([System.Management.Automation.PSTypeName]'TrustAllCertsPolicy').Type) { Add-Type -TypeDefinition @" 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; } } "@ } [System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy -ErrorAction SilentlyContinue [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 $Uri = "https://instance:port/domain/service_now/api/now/table/cmdb_ci?sysparm_query=name=$($HostName)&sysparm_limit=1" $Authorization = [Convert]::ToBase64String( [Text.Encoding]::ASCII.GetBytes( ( "{0}:{1}" -f ('UserName' , 'Password') ) ) ) $ProxyAuthorization = [Convert]::ToBase64String( [Text.Encoding]::ASCII.GetBytes( ( "{0}:{1}" -f ('L-User' , 'L-Password') ) ) ) $Headers = @{ apikey = '' apikeySecret = '' "proxy-authorization" = "basic " + $ProxyAuthorization authorization = "basic " + $Authorization "Content-Type" = "application/json" } $CI = Invoke-RestMethod -Method Get -Uri $Uri -Headers $Headers $SnowPassword = 'Password' | ConvertTo-SecureString -AsPlainText -Force $Credentials = New-Object pscredential -ArgumentList ('us_svc_dcsautomation_01' , $SnowPassword) if ($CI.result.u_primary_parent_service.link -ne $null) { $PrimaryParentService = Invoke-RestMethod -Method Get -Uri $CI.result.u_primary_parent_service.link -Credential $Credentials if ($PrimaryParentService.result.owned_by.link -ne $null) { $PrimaryOwner = Invoke-RestMethod -Method Get -Uri $PrimaryParentService.result.owned_by.link -Credential $Credentials } if ($PrimaryParentService.result.u_owned_by_secondary.link -ne $null) { $SecondaryOwner = Invoke-RestMethod -Method Get -Uri $PrimaryParentService.result.u_owned_by_secondary.link -Credential $Credentials } [pscustomobject]@{ PrimaryOwnerName = @{ 'CI Identifier' = $CI.result.u_number Name = $PrimaryOwner.result.name Email = $PrimaryOwner.result.email Phome = $PrimaryOwner.result.mobile_phone } SecondaryOwner = [pscustomobject]@{ 'CI Identifier' = $CI.result.u_number Name = $SecondaryOwner.result.name Email = $SecondaryOwner.result.email Phome = $SecondaryOwner.result.mobile_phone } } | ConvertTo-Json } else { [pscustomobject]@{ PrimaryOwnerName = @{ 'CI Identifier' = $CI.result.u_number Name = $PrimaryOwner.result.name Email = $PrimaryOwner.result.email Phome = $PrimaryOwner.result.mobile_phone } SecondaryOwner = [pscustomobject]@{ 'CI Identifier' = $CI.result.u_number Name = $SecondaryOwner.result.name Email = $SecondaryOwner.result.email Phome = $SecondaryOwner.result.mobile_phone } } | ConvertTo-Json } } catch { $_.Exception }
For my client we need to host the REST API through Layer 7 (Security). That’s the reason code use proxy authorization! Ideally Proxy Authentication is not required. Now, comes the question
“Why are we building RESTful API for available REST?”
I need to fuse this solution with .NET MVC portal and a third party orchestrator. Yes, I can call C# for MVC and use PowerShell for orchestration automation engine. But, it’s not straightforward approach and time consuming. So, I added a route in existing microservice which made a quicker deployment.
Here, is what I did in node!
var express = require('express'), spawn = require('child_process').spawn, child app = express(); app.get("/api/CIContactInformation/:HostName", function (request, response) { child = spawn('powershell.exe', ["C:\\Project\\scripts\\QueryContactInformation.ps1 -HostName " + request.params.HostName]) child.stdout.pipe(response) }) app.listen(3000) console.log("Your application is running on http://localhost:3000")
In short, we query the cmdb table with the given host which yields the parent CI link. Through that we retrieve primary and secondary contact information. In SNOW owner information are stored like a profile link.
Enjoy PowerShell!