Integrate ServiceNow with VSTS RM pipelines using PowerShell

Jul 21, 2018 | Tarun Arora

DevOps VSTS ServiceNow PowerShell

Service Now is deeply routed in enterprises for change management. While development teams mostly live out of Visual Studio Team Services. Both the platforms are great for the purpose they serve, however the disparity starts to create a silo within the organization. Thanks to the solid foundation of API’s in both platforms, integrating the two is fairly easy… Follow along to see how easy it is to integrate service now with VSTS to trigger release pipelines in VSTS on the back of new service tickets in service now.

  • Invoke ServiceNow API using PowerShell
  • Trigger a release pipeline with dynamic parameters
  • Update results in ServiceNow

Service Now API

Now before you can integrate with ServiceNow, you need to know how to get data out of serviceNow. ServiceNow supports a proper REST API. However, you need to be set up to use the REST API, this can be challenging in various enterprises. Simply that or if you are stuck with a ServiceNow instance that’s really old, you’ll find it doesn’t support the REST API.

I’ll show you a little way to cheat, you don’t really need to use the ServiceNow REST API to get data out of ServiceNow… ServiceNow stores everything in either purpose build tables or custom tables, which you can directly navigate to… Let’s see this in action, for example - changes are stored in ‘changes tables’, you can see this reflect in the URL…

ServiceNow Identify Table Name

Now that we know the name of the table, let’s see how easy is to build out a direct URL to it…

https://xxx.service-now.com/change_request.do?sysparm_action=getRecords&sysparm_query=number=CHG00557943&displayvalue=true

Last but not the least, now append &JSON to the URL to get the response back in JSON. You can optionally use csv if you want to get the response back in a comma separated format.

You may find that more up to date instances of ServiceNow would accept &JSONv2 instead of &JSON… More on this available on ServiceNow JSONv2 docs here

https://xxx.service-now.com/change_request.do?sysparm_action=getRecords&sysparm_query=number=CHG00557943&displayvalue=true&JSON

ServiceNow Change Request in JSON

Trigger ServiceNow API using PowerShell

Let’s see now how easy it is to trigger the Service Now API from PowerShell… In the code sample below, we are using basic auth, you can reuse most of the code even if you are using an OAuth token. The credentials are being encoded into base64 and injected into the web request header. The service now url is being dynamically generated and forced to return the result in json by using &JSON in the query string. The response is then simply being parsed and selected fields are being rendered.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
        # Your service now username and password
        $userSn = "your user name"
        $passSn = "your password"

        # Base64 encoding of your credentials 
        $base64AuthInfoSn = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $userSn, $passSn)))
        
        # Create the header for the web request
        $headersSn = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
        $headersSn.Add('Authorization',('Basic {0}' -f $base64AuthInfoSn))
        $headersSn.Add('Accept','application/json')

        # Create & Invoke the service now query URL 
        $groupIdSn = "my assignment group guid"
        $restUrlSn = "u_dtr_list.do?sysparm_action=getRecords&sysparm_query=assignment_group=" + $groupIdSn + "^active=true&displayvalue=true&JSON";
        $uriSn =  "https://xxx.service-now.com/"+ $restUrlSn
        $methodSn = "get"
        $responseSn = Invoke-WebRequest -Headers $headersSn -Method $methodSn -Uri $uriSn

        # Convert response from json
        $responseSn2 = $responseSn.Content | ConvertFrom-Json
        $responseSn2.records | select number, opened_by, short_description

ServiceNow invoke via PowerShell

Let’s continue to build this out further… Our goal is to trigger a release pipeline based on a specific key word… In this case the keyword is ‘Restart’

1
2
3
4
5
6
7
8
9
10
11
12
# loop through the responses
foreach($dtr in $responseSn2.records){

        $alreadyDone = ([Array]::Find($dtrWorkedOn, [Predicate[String]]{ $args[0] -eq $dtr.number }))

            # search for the keyword restart and ignore any already processed items
            if(($dtr.short_description -match "^Restart") -and ($alreadyDone -eq $null)){

                Write-Host "matched"
            }
}

Invoke VSTS RM using PowerShell

Visual Studio Team Services luckily also makes it really easy to consume their API. In the code snippet below we’ll use the VSTS PAT token to invoke the VSTS RM API by injecting the base64 encoded credentials in the request header. The API request will return the list of all the RM definitions in a team project.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# VSTS account name
[string]$vstsAccount = "my vsts account name"

# VSTS credentials
[string]$userVs = "my vsts username"
[string]$tokenVs = "my vsts pat token"

# VSTS Team Project Name
[String]$projectVs = "my vsts team project name"

# VSTS Account RM URI base 
[String]$projecturiVs = "https://$vstsAccount.vsrm.visualstudio.com/"

# Base64-encodes the Personal Access Token (PAT) appropriately
$base64AuthInfoVs = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $userVs,$tokenVs)))
$headersVs = @{Authorization=("Basic {0}" -f $base64AuthInfoVs)}

$urlVs= $projecturiVs + $projectVs + '/_apis/release/definitions?api-version=4.1-preview.3'

Write-Host "$urlVs"
$responseVs = ""
$methodVs = "get"

# Invoke the rest api with headers
$responseVs= Invoke-RestMethod -Uri $urlVs  -ContentType "application/json" -headers $headersVs -Method $methodVs  

# Write the response from VSTS
Write-Host "Reponse: " $responseVs

The response ..

`https://.vsrm.visualstudio.com//_apis/release/definitions?api-version=4.1-preview.3

Response: @{count=4; value=System.Object[]} `

In case you didn’t know, VSTS now supports triggering release’s with dynamic parameters. In simple terms you can inject parameter values at the time of triggering the release. While this feature has always been available in builds, this is a recent addition to release pipelines… Very useful to enable the scenario we are implementing!

Let’s build this out further, our goal is to trigger a specific release definition with dynamic parameters. The VSTS API has returned us the list of all release definitions in the team project. In the code snippet below, we’ll loop through the list to find the release definition called ‘restart’. Create a new release with with a dynamic variable, the value of which we’ve picked up from the service now ticket…

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# Loop through the list of release definitions and find the one with the name 'Restart'
foreach($releasedefVs in $responseVs.value){

    if($releasedefVs.name -match "ReStart"){

        # Extract and store the release identifier in a variable 
        $releasedefVs
        $releasedefVs.name
        $releasedefVs.id
        $releasedefVs._links

        # Create a release parameter
        $createReleaseParams = @{
            "definitionId"=$releasedefVs.id;
            "variables"=@{
                "ENV"=@{
                    "value"="$svNowValue"; # A value extracted from service now ticket
                }
            }
        }

        # Create a release base URL using the RM API
        $createReleaseUrl= $projecturiVs + $projectVs + '/_apis/release/releases?api-version=4.1-preview.6'
        $createReleaseUrl

        $method = "Post"
        $release = ""

        # Invoke the release API with the release parameter
        $release= Invoke-RestMethod -Uri $createReleaseUrl  -ContentType "application/json" -Body ($createReleaseParams|ConvertTo-Json) -headers $headersVs -Method $method  

        $release

        # Spit out the release status 
        $release.status

    }
}

In the spirit of two way communication, we can publish an update back to the service now ticket to indicate that the release action has been performed on the ticket. To do this we’ll use the service now API with

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# Create a URL for service now update action
$updateRestUrl = "u_dtr_list.do?JSON&sysparm_query=number="+$dtr.number+"&sysparm_action=update";
$updateUri =  "https://xxx.service-now.com/"+ $updateRestUrl
$updateMethod = "Post"

# Send HTTP request to update comments in the ticket
$updateParams = @{
                    "short_description"="=> $dtr.short_description";
                    "comments"="$found Restart has been Triggered";
                }

# Invoke the api with headers to update the ticket with comments
$updateResponse = Invoke-WebRequest -Headers $headersSn -Method $updateMethod -Body ($updateParams|ConvertTo-Json) -Uri $updateUri

# Print response
$updateResponse.RawContent

Voila! Job done… To summarize what we have achieved in this blogpost,

  • Hacking the service now URL and adding &JSON in query string to return json response
  • Use PowerShell to invoke the service now API
    • Filter tickets to get a specific ticket
    • Extract and store a key value from the service ticket
  • Use PoweShell to invoke the VSTS API
    • Filter the release definitions to find a specific release definition
    • Create a release for the release definition with dynamic parameter using a key value extract from the service ticket
    • Update service now to comments field in the ticket to reflect the work carried out

Obviously this script can be adapted to run as a scheduled job within a VSTS build pipeline, that can use chaining to trigger the release pipeline with dynamic parameters. In the next blogpost, i’ll walk you through how easy it is to convert this into an Azure function so this operation can run in the cloud as a scheduled job…

Mean while, check out my previous blogpost on how to integrate service now into VSTS release management to auto approve release using a release gate

I hope you enjoyed this post, be sure to share it, subscribe to the blog for updates on the cool DevOps hacks!

Tarun

About author
Author Image
Tarun Arora
Tarun Arora is obsessed with high-quality working software, DevOps, Continuous Delivery and Agile. His core strengths are Azure, VSTS, PowerShell, SQL and WPF. He is a Microsoft MVP in Visual Studio Development Tools and the author of 'DevOps & ALM with TFS 2015'.
Comments