Skip to content

Commit 53586a9

Browse files
authored
Merge pull request #123 from Snow-Shell/new-session
v2.0 - New session, different api versions
2 parents a6480a0 + fdb79a1 commit 53586a9

39 files changed

+1354
-1480
lines changed

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
## v2.0
2+
- Although still in the module for backward compatibility, `Set-ServiceNowAuth` is being replaced with `New-ServiceNowSession`. With this comes OAuth support, removal of global variables, and much more folks have asked for. The ability to provide credentials directly to functions has been retained for this release, but will be deprecated in a future release in favor of using `New-ServiceNowSession`.
3+
- Support for different api versions. `Set-ServiceNowAuth` will continue to use v1 of the api, but `New-ServiceNowSession` defaults to the latest. Check out the `-ApiVersion` parameter of `New-ServiceNowSession`.
4+
- `Remove-ServiceNowAuth` has been retained for this release, but as global variables have been removed, there is no longer a need for it; it will always return `$true`. It will be removed in a future release.
5+
- `-PassThru` added to remaining `Update-` and `New-` functions. Depending on your code, this may be a ***breaking change*** if you expected the result to be returned.
6+
- Pipeline support added to many functions
7+
- Standardizing on coding between all functions
8+
19
## v1.8.1
210
- Update links to reference the new GitHub organization this project will be moved to. Module functionality unchanged.
311

Readme.md

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,16 @@ This PowerShell module provides a series of cmdlets for interacting with the [Se
66

77
**IMPORTANT:** Neither this module nor its creator are in any way affiliated with ServiceNow.
88

9+
## Version 2
10+
11+
Building on the great work the community has done thus far, a lot of new updates with this release.
12+
- Although still in the module for backward compatibility, `Set-ServiceNowAuth` is being replaced with `New-ServiceNowSession`. With this comes OAuth support, removal of global variables, and much more folks have asked for. The ability to provide credentials directly to functions has been retained for this release, but will be deprecated in a future release in favor of using `New-ServiceNowSession`.
13+
- Support for different api versions. `Set-ServiceNowAuth` will continue to use v1 of the api, but `New-ServiceNowSession` defaults to the latest. Check out the `-ApiVersion` parameter of `New-ServiceNowSession`.
14+
- `Remove-ServiceNowAuth` has been retained for this release, but as global variables have been removed, there is no longer a need for it; it will always return `$true`. It will be removed in a future release.
15+
- `-PassThru` added to remaining `Update-` and `New-` functions. Depending on your code, this may be a ***breaking change*** if you expected the result to be returned.
16+
- Pipeline support added to many functions
17+
- Standardizing on coding between all functions
18+
919
## Version 1
1020

1121
The module has been renamed from PSServiceNow to ServiceNow for version 1. This change moves us away from the reserved "PS" prefix. Since the name change is a major change for the user base and the project was never incremented to v1 we've taken the opportunity to label it such.
@@ -108,12 +118,11 @@ The `Connection` parameter accepts a hashtable object that requires a username,
108118
* Get-ServiceNowUserGroup
109119
* New-ServiceNowChangeRequest
110120
* New-ServiceNowIncident
121+
* New-ServiceNowSession
111122
* New-ServiceNowQuery
112123
* New-ServiceNowTableEntry
113124
* Remove-ServiceNowAttachment
114-
* Remove-ServiceNowAuth
115125
* Remove-ServiceNowTableEntry
116-
* Set-ServiceNowAuth
117126
* Test-ServiceNowAuthIsSet
118127
* Update-ServiceNowChangeRequest
119128
* Update-ServiceNowIncident
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
function Get-ServiceNowAuth {
2+
<#
3+
.SYNOPSIS
4+
.DESCRIPTION
5+
.INPUTS
6+
None
7+
.OUTPUTS
8+
Hashtable
9+
#>
10+
11+
[OutputType([Hashtable])]
12+
[CmdletBinding()]
13+
Param (
14+
[Parameter()]
15+
[PSCredential] $Credential,
16+
17+
[Parameter()]
18+
[string] $ServiceNowURL,
19+
20+
[Parameter()]
21+
[hashtable] $Connection,
22+
23+
[Parameter()]
24+
[hashtable] $ServiceNowSession = $script:ServiceNowSession
25+
)
26+
27+
$hashOut = @{}
28+
29+
# Get credential and ServiceNow REST URL
30+
if ( $ServiceNowSession.Count -gt 0 ) {
31+
$hashOut.Uri = $ServiceNowSession.BaseUri
32+
if ( $ServiceNowSession.AccessToken ) {
33+
$hashOut.Headers = @{
34+
'Authorization' = 'Bearer {0}' -f $ServiceNowSession.AccessToken
35+
}
36+
} else {
37+
$hashOut.Credential = $ServiceNowSession.Credential
38+
}
39+
} elseif ( $Credential -and $ServiceNowURL ) {
40+
Write-Warning -Message 'This authentication path, providing URL and credential directly, will be deprecated in a future release. Please use New-ServiceNowSession.'
41+
$hashOut.Uri = 'https://{0}/api/now/v1' -f $ServiceNowURL
42+
$hashOut.Credential = $Credential
43+
} elseif ( $Connection ) {
44+
$SecurePassword = ConvertTo-SecureString $Connection.Password -AsPlainText -Force
45+
$Credential = New-Object System.Management.Automation.PSCredential ($Connection.Username, $SecurePassword)
46+
$hashOut.Credential = $Credential
47+
$hashOut.Uri = 'https://{0}/api/now/v1' -f $Connection.ServiceNowUri
48+
} else {
49+
throw "Exception: You must do one of the following to authenticate: `n 1. Call the New-ServiceNowSession cmdlet `n 2. Pass in an Azure Automation connection object `n 3. Pass in an endpoint and credential"
50+
}
51+
52+
$hashOut
53+
}
Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
function Invoke-ServiceNowRestMethod {
2+
<#
3+
.SYNOPSIS
4+
Retrieves records for the specified table
5+
.DESCRIPTION
6+
The Get-ServiceNowTable function retrieves records for the specified table
7+
.INPUTS
8+
None
9+
.OUTPUTS
10+
System.Management.Automation.PSCustomObject
11+
.LINK
12+
Service-Now Kingston REST Table API: https://docs.servicenow.com/bundle/kingston-application-development/page/integrate/inbound-rest/concept/c_TableAPI.html
13+
Service-Now Table API FAQ: https://hi.service-now.com/kb_view.do?sysparm_article=KB0534905
14+
#>
15+
16+
[OutputType([System.Management.Automation.PSCustomObject])]
17+
[CmdletBinding(SupportsPaging)]
18+
Param (
19+
[parameter()]
20+
[ValidateSet('Get', 'Post', 'Patch', 'Delete')]
21+
[string] $Method = 'Get',
22+
23+
# Name of the table we're querying (e.g. incidents)
24+
[parameter(Mandatory, ParameterSetName = 'Table')]
25+
[ValidateNotNullOrEmpty()]
26+
[string] $Table,
27+
28+
[parameter(ParameterSetName = 'Table')]
29+
[ValidateNotNullOrEmpty()]
30+
[string] $SysId,
31+
32+
[parameter(ParameterSetName = 'Uri')]
33+
[ValidateNotNullOrEmpty()]
34+
[string] $UriLeaf,
35+
36+
# [parameter()]
37+
# [hashtable] $Header,
38+
39+
[parameter()]
40+
[hashtable] $Values,
41+
42+
# sysparm_query param in the format of a ServiceNow encoded query string (see http://wiki.servicenow.com/index.php?title=Encoded_Query_Strings)
43+
[Parameter()]
44+
[string] $Query,
45+
46+
# Maximum number of records to return
47+
[Parameter()]
48+
[int] $Limit,
49+
50+
# Fields to return
51+
[Parameter()]
52+
[Alias('Fields')]
53+
[string[]] $Properties,
54+
55+
# Whether or not to show human readable display values instead of machine values
56+
[Parameter()]
57+
[ValidateSet('true', 'false', 'all')]
58+
[string] $DisplayValues = 'true',
59+
60+
[Parameter()]
61+
[PSCredential] $Credential,
62+
63+
[Parameter()]
64+
[string] $ServiceNowUrl,
65+
66+
[Parameter()]
67+
[hashtable] $Connection,
68+
69+
[Parameter()]
70+
[hashtable] $ServiceNowSession = $script:ServiceNowSession
71+
)
72+
73+
$getAuth = @{
74+
Credential = $Credential
75+
ServiceNowUrl = $ServiceNowUrl
76+
Connection = $Connection
77+
ServiceNowSession = $ServiceNowSession
78+
}
79+
$params = Get-ServiceNowAuth @getAuth
80+
81+
$params.Method = $Method
82+
$params.ContentType = 'application/json'
83+
84+
if ( $Table ) {
85+
$params.Uri += "/table/$Table"
86+
if ( $SysId ) {
87+
$params.Uri += "/$SysId"
88+
}
89+
} else {
90+
$params.Uri += $UriLeaf
91+
}
92+
93+
if ( $Method -eq 'Get') {
94+
$Body = @{
95+
'sysparm_display_value' = $DisplayValues
96+
}
97+
98+
# Handle paging parameters
99+
# If -Limit was provided, write a warning message, but prioritize it over -First.
100+
# The value of -First defaults to [uint64]::MaxValue if not specified.
101+
# If no paging information was provided, default to the legacy behavior, which was to return 10 records.
102+
103+
if ($PSBoundParameters.ContainsKey('Limit')) {
104+
Write-Warning "The -Limit parameter is deprecated, and may be removed in a future release. Use the -First parameter instead."
105+
$Body['sysparm_limit'] = $Limit
106+
} elseif ($PSCmdlet.PagingParameters.First -ne [uint64]::MaxValue) {
107+
$Body['sysparm_limit'] = $PSCmdlet.PagingParameters.First
108+
} else {
109+
$Body['sysparm_limit'] = 10
110+
}
111+
112+
if ($PSCmdlet.PagingParameters.Skip) {
113+
$Body['sysparm_offset'] = $PSCmdlet.PagingParameters.Skip
114+
}
115+
116+
if ($PSCmdlet.PagingParameters.IncludeTotalCount) {
117+
# Accuracy is a double between 0.0 and 1.0 representing an estimated percentage accuracy.
118+
# 0.0 means we have no idea and 1.0 means the number is exact.
119+
120+
# ServiceNow does return this information in the X-Total-Count response header,
121+
# but we're currently using Invoke-RestMethod to perform the API call, and Invoke-RestMethod
122+
# does not provide the response headers, so we can't capture this info.
123+
124+
# To properly support this parameter, we'd need to fall back on Invoke-WebRequest, read the
125+
# X-Total-Count header of the response, and update this parameter after performing the API
126+
# call.
127+
128+
# Reference:
129+
# https://developer.servicenow.com/app.do#!/rest_api_doc?v=jakarta&id=r_TableAPI-GET
130+
131+
[double] $accuracy = 0.0
132+
$PSCmdlet.PagingParameters.NewTotalCount($PSCmdlet.PagingParameters.First, $accuracy)
133+
}
134+
135+
# Populate the query
136+
if ($Query) {
137+
$Body.sysparm_query = $Query
138+
}
139+
140+
if ($Properties) {
141+
$Body.sysparm_fields = ($Properties -join ',').ToLower()
142+
}
143+
}
144+
145+
if ( $Values ) {
146+
$Body = $Values | ConvertTo-Json
147+
148+
#Convert to UTF8 array to support special chars such as the danish "�","�","�"
149+
$body = [System.Text.Encoding]::UTf8.GetBytes($Body)
150+
}
151+
152+
if ( $Body ) {
153+
$params.Body = $Body
154+
}
155+
156+
Write-Verbose ($params | ConvertTo-Json)
157+
158+
$response = Invoke-RestMethod @params
159+
160+
switch ($Method) {
161+
'Get' {
162+
if ( $response.result ) {
163+
164+
$result = $response | Select-Object -ExpandProperty result
165+
$ConvertToDateField = @('closed_at', 'expected_start', 'follow_up', 'opened_at', 'sys_created_on', 'sys_updated_on', 'work_end', 'work_start')
166+
ForEach ($SNResult in $Result) {
167+
ForEach ($Property in $ConvertToDateField) {
168+
If (-not [string]::IsNullOrEmpty($SNResult.$Property)) {
169+
Try {
170+
# Extract the default Date/Time formatting from the local computer's "Culture" settings, and then create the format to use when parsing the date/time from Service-Now
171+
$CultureDateTimeFormat = (Get-Culture).DateTimeFormat
172+
$DateFormat = $CultureDateTimeFormat.ShortDatePattern
173+
$TimeFormat = $CultureDateTimeFormat.LongTimePattern
174+
$DateTimeFormat = "$DateFormat $TimeFormat"
175+
$SNResult.$Property = [DateTime]::ParseExact($($SNResult.$Property), $DateTimeFormat, [System.Globalization.DateTimeFormatInfo]::InvariantInfo, [System.Globalization.DateTimeStyles]::None)
176+
} Catch {
177+
Try {
178+
# Universal Format
179+
$DateTimeFormat = 'yyyy-MM-dd HH:mm:ss'
180+
$SNResult.$Property = [DateTime]::ParseExact($($SNResult.$Property), $DateTimeFormat, [System.Globalization.DateTimeFormatInfo]::InvariantInfo, [System.Globalization.DateTimeStyles]::None)
181+
} Catch {
182+
# If the local culture and universal formats both fail keep the property as a string (Do nothing)
183+
$null = 'Silencing a PSSA alert with this line'
184+
}
185+
}
186+
}
187+
}
188+
}
189+
} else {
190+
$response
191+
}
192+
}
193+
194+
{ $_ -in 'Post', 'Patch' } {
195+
$result = $response | Select-Object -ExpandProperty result
196+
}
197+
198+
'Delete' {
199+
# nothing to do
200+
}
201+
202+
Default {
203+
# we should never get here given the list of methods is set
204+
}
205+
}
206+
207+
$result
208+
# Invoke-RestMethod -Uri $Uri -Credential $Credential -Body $Body -ContentType "application/json" | Select-Object -ExpandProperty Result
209+
}

ServiceNow/Private/Test-ServiceNowURL.ps1

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,31 +9,27 @@ Function Test-ServiceNowURL {
99
.EXAMPLE
1010
Test-ServiceNowURL -Url tenant.domain.com
1111
12-
This example can have text
13-
1412
.OUTPUTS
1513
System.Boolean
16-
1714
#>
1815

1916
[OutputType([System.Boolean])]
2017
[CmdletBinding()]
2118
param (
2219
# Pipeline variable
23-
[Parameter(Mandatory = $true)]
20+
[Parameter(Mandatory, ValueFromPipeline)]
2421
[ValidateNotNullOrEmpty()]
25-
[string]$Url
22+
[string] $Url
2623
)
2724

28-
begin {}
29-
process {
25+
begin {}
26+
process {
3027
Write-Verbose "Testing url: $Url"
31-
if ($Url -match '^\w+\..*\.\w+') {
28+
if ($Url -match '^\w+\..*\.\w+') {
3229
$true
33-
}
34-
else {
30+
} else {
3531
Throw "The expected URL format is tenant.domain.com"
3632
}
3733
}
38-
end {}
34+
end {}
3935
}

0 commit comments

Comments
 (0)