Skip to content

Commit cb403ee

Browse files
authored
New change task, add GraphQL support, custom variable format update (#196)
1 parent f86c553 commit cb403ee

File tree

7 files changed

+334
-68
lines changed

7 files changed

+334
-68
lines changed

RELEASE.md

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
- Add docker image with each new build and [publish to dockerhub](https://hub.docker.com/repository/docker/gdbarron/servicenow-module). Add the below environment variables to `Get-ServiceNowAuth` for use with docker image, but could be used outside of it as well.
2-
- SNOW_SERVER: the ServiceNow instance, eg. instance.service-now.com
3-
- SNOW_TOKEN: pre-generated oauth token. Provide this or SNOW_USER/SNOW_PASS.
4-
- SNOW_USER: username to connect to SNOW_SERVER
5-
- SNOW_PASS: password for SNOW_USER
1+
- Add `New-ServiceNowChangeTask`, [#103](https://github.com/Snow-Shell/servicenow-powershell/issues/103)
2+
- Add GraphQL support including `New-ServiceNowSession -GraphQL` and `Invoke-ServiceNowGraphQL`, the latter is a WIP
3+
- Update custom variable format with `Get-ServiceNowRecord -IncludeCustomVariable`. The new format adds each custom variable as an object property as opposed to an array of hashtables. Old: `$response.CustomVariable.where{$_.name -eq 'mycustvar'}.value`, New: `$response.CustomVariable.mycustvar.value`. Access the new format with `-IncludeCustomVariable -New`

ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -109,9 +109,6 @@ function Invoke-ServiceNowRestMethod {
109109
if ($PSCmdlet.PagingParameters.First -ne [uint64]::MaxValue) {
110110
$Body['sysparm_limit'] = $PSCmdlet.PagingParameters.First
111111
}
112-
# else {
113-
# $Body['sysparm_limit'] = 10
114-
# }
115112

116113
if ($PSCmdlet.PagingParameters.Skip) {
117114
$Body['sysparm_offset'] = $PSCmdlet.PagingParameters.Skip
@@ -126,12 +123,6 @@ function Invoke-ServiceNowRestMethod {
126123
}
127124
}
128125

129-
# Populate the query
130-
# else {
131-
# $body['sysparm_query'] = (New-ServiceNowQuery -Filter $Filter -Sort $Sort)
132-
# }
133-
134-
135126
if ( $Values ) {
136127
$Body = $Values | ConvertTo-Json
137128

@@ -197,7 +188,7 @@ function Invoke-ServiceNowRestMethod {
197188
}
198189

199190
# if option to get all records was provided, loop and get them all
200-
if ( $PSCmdlet.PagingParameters.IncludeTotalCount.IsPresent ) {
191+
if ( $PSCmdlet.PagingParameters.IncludeTotalCount ) {
201192

202193
$retrieveRecordCount = $totalRecordCount - $PSCmdlet.PagingParameters.Skip
203194
if ( $retrieveRecordCount -ne 0 ) {

ServiceNow/Public/Get-ServiceNowRecord.ps1

Lines changed: 61 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,11 @@
4848
Some records may have associated custom variables, some may not.
4949
For instance, an RITM may have custom variables, but the associated tasks may not.
5050
A property named 'CustomVariable' will be added to the return object.
51+
When used with -New, you can now get the value with $return.CustomVariable.CustomVarName.Value.
52+
53+
.PARAMETER New
54+
Used with -IncludeCustomVariable for the new format.
55+
Each property is now added by name with a value of .value.
5156
5257
.PARAMETER AsValue
5358
Return the underlying value instead of pscustomobject.
@@ -107,7 +112,7 @@
107112
Get all change requests, paging 100 at a time.
108113
109114
.EXAMPLE
110-
Get-ServiceNowRecord -Table 'change request' -IncludeCustomVariable -First 5
115+
Get-ServiceNowRecord -Table 'change request' -IncludeCustomVariable -New -First 5
111116
Get the first 5 change requests and retrieve custom variable info
112117
113118
.EXAMPLE
@@ -146,8 +151,7 @@ function Get-ServiceNowRecord {
146151
[ValidateScript( {
147152
if ($_ -match '^[a-zA-Z0-9]{32}$' -or $_ -match '^([a-zA-Z]+)[0-9]+$') {
148153
$true
149-
}
150-
else {
154+
} else {
151155
throw 'Id must be either a 32 character alphanumeric, ServiceNow sysid, or prefix/id, ServiceNow number.'
152156
}
153157
})]
@@ -158,8 +162,7 @@ function Get-ServiceNowRecord {
158162
[ValidateScript( {
159163
if ($_ -match '^[a-zA-Z0-9]{32}$' -or $_ -match '^([a-zA-Z]+)[0-9]+$') {
160164
$true
161-
}
162-
else {
165+
} else {
163166
throw 'ParentId must be either a 32 character alphanumeric, ServiceNow sysid, or prefix/id, ServiceNow number.'
164167
}
165168
})]
@@ -187,6 +190,9 @@ function Get-ServiceNowRecord {
187190
[Parameter()]
188191
[switch] $IncludeCustomVariable,
189192

193+
[Parameter()]
194+
[switch] $New,
195+
190196
[Parameter()]
191197
[switch] $AsValue,
192198

@@ -235,8 +241,7 @@ function Get-ServiceNowRecord {
235241
}
236242

237243
$idFilter = @('sys_id', '-eq', $ID)
238-
}
239-
else {
244+
} else {
240245
if ( -not $thisTable ) {
241246
# get table name from prefix if only Id was provided
242247
$idPrefix = ($ID | Select-String -Pattern '^([a-zA-Z]+)([0-9]+$)').Matches.Groups[1].Value.ToLower()
@@ -251,8 +256,7 @@ function Get-ServiceNowRecord {
251256

252257
if ( $invokeParams.Filter ) {
253258
$invokeParams.Filter = $invokeParams.Filter, 'and', $idFilter
254-
}
255-
else {
259+
} else {
256260
$invokeParams.Filter = $idFilter
257261
}
258262

@@ -264,15 +268,13 @@ function Get-ServiceNowRecord {
264268
if ( $ParentID ) {
265269
if ( $ParentID -match '^[a-zA-Z0-9]{32}$' ) {
266270
$parentIdFilter = @('parent.sys_id', '-eq', $ParentID)
267-
}
268-
else {
271+
} else {
269272
$parentIdFilter = @('parent.number', '-eq', $ParentID)
270273
}
271274

272275
if ( $invokeParams.Filter ) {
273276
$invokeParams.Filter = $invokeParams.Filter, 'and', $parentIdFilter
274-
}
275-
else {
277+
} else {
276278
$invokeParams.Filter = $parentIdFilter
277279
}
278280
}
@@ -286,8 +288,7 @@ function Get-ServiceNowRecord {
286288

287289
if ( $invokeParams.Filter ) {
288290
$invokeParams.Filter = $invokeParams.Filter, 'and', @($thisTable.DescriptionField, '-like', $Description)
289-
}
290-
else {
291+
} else {
291292
$invokeParams.Filter = @($thisTable.DescriptionField, '-like', $Description)
292293
}
293294
}
@@ -313,10 +314,6 @@ function Get-ServiceNowRecord {
313314

314315
if ( $IncludeCustomVariable ) {
315316

316-
# suppress warning when getting total count
317-
$existingWarning = $WarningPreference
318-
$WarningPreference = 'SilentlyContinue'
319-
320317
# for each record, get the variable names and then get the variable values
321318
foreach ($record in $result) {
322319

@@ -325,54 +322,70 @@ function Get-ServiceNowRecord {
325322
Filter = @('request_item', '-eq', $record.sys_id), 'and', @('sc_item_option.item_option_new.type', '-in', '1,2,3,4,5,6,7,8,9,10,16,18,21,22,26')
326323
Property = 'sc_item_option.item_option_new.name', 'sc_item_option.value', 'sc_item_option.item_option_new.type', 'sc_item_option.item_option_new.question_text'
327324
IncludeTotalCount = $true
325+
ServiceNowSession = $ServiceNowSession
328326
}
329327

330-
$customVarsOut = Get-ServiceNowRecord @customVarParams
331-
332-
$record | Add-Member @{
333-
'CustomVariable' = $customVarsOut | Select-Object -Property `
334-
@{
335-
'n' = 'Name'
336-
'e' = { $_.'sc_item_option.item_option_new.name' }
337-
},
338-
@{
339-
'n' = 'Value'
340-
'e' = { $_.'sc_item_option.value' }
341-
},
342-
@{
343-
'n' = 'DisplayName'
344-
'e' = { $_.'sc_item_option.item_option_new.question_text' }
345-
},
346-
@{
347-
'n' = 'Type'
348-
'e' = { $_.'sc_item_option.item_option_new.type' }
328+
# suppress warning when getting total count
329+
$customVarsOut = Get-ServiceNowRecord @customVarParams -WarningAction SilentlyContinue
330+
331+
if ( $New ) {
332+
333+
$record | Add-Member @{
334+
'CustomVariable' = [pscustomobject]@{}
335+
}
336+
foreach ($var in $customVarsOut) {
337+
$record.CustomVariable | Add-Member @{
338+
$var.'sc_item_option.item_option_new.name' = @{
339+
Value = $var.'sc_item_option.value'
340+
DisplayName = $var.'sc_item_option.item_option_new.question_text'
341+
Type = $var.'sc_item_option.item_option_new.type'
342+
}
343+
}
344+
}
345+
} else {
346+
347+
Write-Warning 'The format for custom variables will soon change. Start using -New with -IncludeCustomVariable to preview.'
348+
349+
$record | Add-Member @{
350+
'CustomVariable' = $customVarsOut | Select-Object -Property `
351+
@{
352+
'n' = 'Name'
353+
'e' = { $_.'sc_item_option.item_option_new.name' }
354+
},
355+
@{
356+
'n' = 'Value'
357+
'e' = { $_.'sc_item_option.value' }
358+
},
359+
@{
360+
'n' = 'DisplayName'
361+
'e' = { $_.'sc_item_option.item_option_new.question_text' }
362+
},
363+
@{
364+
'n' = 'Type'
365+
'e' = { $_.'sc_item_option.item_option_new.type' }
366+
}
349367
}
350368
}
351369

370+
352371
if ( $addedSysIdProp ) {
353372
$record | Select-Object -Property * -ExcludeProperty sys_id
354-
}
355-
else {
373+
} else {
356374
$record
357375
}
358376
}
359377

360-
$WarningPreference = $existingWarning
361-
362-
}
363-
else {
378+
} else {
364379

365380
# format the results
366381
if ( $Property ) {
367382
if ( $Property.Count -eq 1 -and $AsValue ) {
368383
$propName = $result | Get-Member | Where-Object { $_.MemberType -eq 'NoteProperty' } | Select-Object -exp Name
369384
$result | Select-Object -ExpandProperty $propName
370-
}
371-
else {
385+
} else {
372386
$result
373387
}
374-
}
375-
else {
388+
} else {
376389
if ($thisTable.Type) {
377390
$result | ForEach-Object { $_.PSObject.TypeNames.Insert(0, $thisTable.Type) }
378391
}
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
<#
2+
.SYNOPSIS
3+
Retrieve or update data via GraphQL - still a work in progress :)
4+
5+
.DESCRIPTION
6+
Retrieve or update data via GraphQL.
7+
Ensure you create a new session with -GraphQL.
8+
9+
.PARAMETER Operation
10+
Allowed values are 'query' or 'mutation'.
11+
The default is query.
12+
13+
.PARAMETER Application
14+
Application namespace for your API
15+
16+
.PARAMETER Schema
17+
Schema namespace for your API
18+
19+
.PARAMETER Query
20+
Inner query string. Operation, application, and schema will be added automatically.
21+
22+
.PARAMETER Variable
23+
Currently only supported with -Raw.
24+
Ensure the query includes the operation, application, and schema.
25+
26+
.PARAMETER Raw
27+
Provide the server response as is instead of parsing out the application, schema, and service names.
28+
29+
.PARAMETER Connection
30+
Azure Automation Connection object containing username, password, and URL for the ServiceNow instance
31+
32+
.PARAMETER ServiceNowSession
33+
ServiceNow session created by New-ServiceNowSession. Will default to script-level variable $ServiceNowSession.
34+
35+
.EXAMPLE
36+
Invoke-ServiceNowGraphQL -Application myapp -Schema incident -Query 'findById (id: "INC0010001") {sys_id {value} description {value}}'
37+
38+
Perform a query
39+
40+
.OUTPUTS
41+
PSCustomObject
42+
43+
.LINK
44+
https://docs.servicenow.com/bundle/sandiego-application-development/page/integrate/graphql/concept/scripted-graph-ql.html
45+
#>
46+
function Invoke-ServiceNowGraphQL {
47+
48+
[OutputType([System.Management.Automation.PSCustomObject])]
49+
[CmdletBinding()]
50+
51+
Param (
52+
[Parameter()]
53+
[ValidateSet('query', 'mutation')]
54+
[string] $Operation = 'query',
55+
56+
[Parameter(Mandatory)]
57+
[string] $Application,
58+
59+
[Parameter(Mandatory)]
60+
[string] $Schema,
61+
62+
[Parameter(Mandatory)]
63+
[string] $Query,
64+
65+
[Parameter()]
66+
[string] $Variable,
67+
68+
[Parameter()]
69+
[switch] $Raw,
70+
71+
[Parameter()]
72+
[hashtable] $Connection,
73+
74+
[Parameter()]
75+
[hashtable] $ServiceNowSession = $script:ServiceNowSession
76+
)
77+
78+
begin {
79+
80+
Write-Warning 'This function is in beta and subject to change. Please please feedback/enhancements at https://github.com/Snow-Shell/servicenow-powershell/issues.'
81+
82+
if ( $Raw ) {
83+
$fullQuery = $Query
84+
} else {
85+
$fullQuery = ('{0} {{ {1} {{ {2} {{ {3} }}}}}}' -f $Operation, $Application, $Schema, $Query)
86+
}
87+
88+
$params = Get-ServiceNowAuth -C $Connection -S $ServiceNowSession
89+
90+
$params.Method = 'Post'
91+
$params.ContentType = 'application/json'
92+
$params.UseBasicParsing = $true
93+
94+
$body = @{
95+
'query' = $fullQuery
96+
}
97+
98+
if ( $Variable ) {
99+
$body.variables = $Variable
100+
}
101+
102+
$params.Body = $body | ConvertTo-Json -Compress
103+
}
104+
105+
process {
106+
Write-Verbose ($params | ConvertTo-Json)
107+
$result = Invoke-RestMethod @params
108+
109+
if ( $Raw ) {
110+
$result
111+
} else {
112+
$serviceName = $Query -replace '^(\w*).*', '$1'
113+
if ( $result.data.$Application.$Schema.$serviceName ) {
114+
$result.data.$Application.$Schema.$serviceName
115+
}
116+
}
117+
}
118+
}

0 commit comments

Comments
 (0)