Private/Invoke-ServiceNowRestMethod.ps1
function Invoke-ServiceNowRestMethod { <# .SYNOPSIS Retrieves records for the specified table .DESCRIPTION The Get-ServiceNowTable function retrieves records for the specified table .INPUTS None .OUTPUTS System.Management.Automation.PSCustomObject .LINK Service-Now Kingston REST Table API: https://docs.servicenow.com/bundle/kingston-application-development/page/integrate/inbound-rest/concept/c_TableAPI.html Service-Now Table API FAQ: https://hi.service-now.com/kb_view.do?sysparm_article=KB0534905 #> [OutputType([System.Management.Automation.PSCustomObject])] [CmdletBinding(SupportsPaging)] Param ( [parameter()] [ValidateSet('Get', 'Post', 'Patch', 'Delete')] [string] $Method = 'Get', # Name of the table we're querying (e.g. incidents) [parameter(Mandatory, ParameterSetName = 'Table')] [ValidateNotNullOrEmpty()] [string] $Table, [parameter(ParameterSetName = 'Table')] [ValidateNotNullOrEmpty()] [string] $SysId, [parameter(ParameterSetName = 'Uri')] [ValidateNotNullOrEmpty()] [string] $UriLeaf, # [parameter()] # [hashtable] $Header, [parameter()] [hashtable] $Values, # sysparm_query param in the format of a ServiceNow encoded query string (see http://wiki.servicenow.com/index.php?title=Encoded_Query_Strings) [Parameter()] [string] $Query, # Maximum number of records to return [Parameter()] [int] $Limit, # Fields to return [Parameter()] [Alias('Fields')] [string[]] $Properties, # Whether or not to show human readable display values instead of machine values [Parameter()] [ValidateSet('true', 'false', 'all')] [string] $DisplayValues = 'true', [Parameter()] [PSCredential] $Credential, [Parameter()] [string] $ServiceNowUrl, [Parameter()] [hashtable] $Connection, [Parameter()] [hashtable] $ServiceNowSession = $script:ServiceNowSession ) $getAuth = @{ Credential = $Credential ServiceNowUrl = $ServiceNowUrl Connection = $Connection ServiceNowSession = $ServiceNowSession } $params = Get-ServiceNowAuth @getAuth $params.Method = $Method $params.ContentType = 'application/json' if ( $Table ) { $params.Uri += "/table/$Table" if ( $SysId ) { $params.Uri += "/$SysId" } } else { $params.Uri += $UriLeaf } if ( $Method -eq 'Get') { $Body = @{ 'sysparm_display_value' = $DisplayValues } # Handle paging parameters # If -Limit was provided, write a warning message, but prioritize it over -First. # The value of -First defaults to [uint64]::MaxValue if not specified. # If no paging information was provided, default to the legacy behavior, which was to return 10 records. if ($PSBoundParameters.ContainsKey('Limit')) { Write-Warning "The -Limit parameter is deprecated, and may be removed in a future release. Use the -First parameter instead." $Body['sysparm_limit'] = $Limit } elseif ($PSCmdlet.PagingParameters.First -ne [uint64]::MaxValue) { $Body['sysparm_limit'] = $PSCmdlet.PagingParameters.First } else { $Body['sysparm_limit'] = 10 } if ($PSCmdlet.PagingParameters.Skip) { $Body['sysparm_offset'] = $PSCmdlet.PagingParameters.Skip } if ($PSCmdlet.PagingParameters.IncludeTotalCount) { # Accuracy is a double between 0.0 and 1.0 representing an estimated percentage accuracy. # 0.0 means we have no idea and 1.0 means the number is exact. # ServiceNow does return this information in the X-Total-Count response header, # but we're currently using Invoke-RestMethod to perform the API call, and Invoke-RestMethod # does not provide the response headers, so we can't capture this info. # To properly support this parameter, we'd need to fall back on Invoke-WebRequest, read the # X-Total-Count header of the response, and update this parameter after performing the API # call. # Reference: # https://developer.servicenow.com/app.do#!/rest_api_doc?v=jakarta&id=r_TableAPI-GET [double] $accuracy = 0.0 $PSCmdlet.PagingParameters.NewTotalCount($PSCmdlet.PagingParameters.First, $accuracy) } # Populate the query if ($Query) { $Body.sysparm_query = $Query } if ($Properties) { $Body.sysparm_fields = ($Properties -join ',').ToLower() } } if ( $Values ) { $Body = $Values | ConvertTo-Json #Convert to UTF8 array to support special chars such as the danish "�","�","�" $body = [System.Text.Encoding]::UTf8.GetBytes($Body) } if ( $Body ) { $params.Body = $Body } Write-Verbose ($params | ConvertTo-Json) $response = Invoke-RestMethod @params switch ($Method) { 'Get' { if ( $response.result ) { $result = $response | Select-Object -ExpandProperty result $ConvertToDateField = @('closed_at', 'expected_start', 'follow_up', 'opened_at', 'sys_created_on', 'sys_updated_on', 'work_end', 'work_start') ForEach ($SNResult in $Result) { ForEach ($Property in $ConvertToDateField) { If (-not [string]::IsNullOrEmpty($SNResult.$Property)) { Try { # 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 $CultureDateTimeFormat = (Get-Culture).DateTimeFormat $DateFormat = $CultureDateTimeFormat.ShortDatePattern $TimeFormat = $CultureDateTimeFormat.LongTimePattern $DateTimeFormat = "$DateFormat $TimeFormat" $SNResult.$Property = [DateTime]::ParseExact($($SNResult.$Property), $DateTimeFormat, [System.Globalization.DateTimeFormatInfo]::InvariantInfo, [System.Globalization.DateTimeStyles]::None) } Catch { Try { # Universal Format $DateTimeFormat = 'yyyy-MM-dd HH:mm:ss' $SNResult.$Property = [DateTime]::ParseExact($($SNResult.$Property), $DateTimeFormat, [System.Globalization.DateTimeFormatInfo]::InvariantInfo, [System.Globalization.DateTimeStyles]::None) } Catch { # If the local culture and universal formats both fail keep the property as a string (Do nothing) $null = 'Silencing a PSSA alert with this line' } } } } } } else { $response } } { $_ -in 'Post', 'Patch' } { $result = $response | Select-Object -ExpandProperty result } 'Delete' { # nothing to do } Default { # we should never get here given the list of methods is set } } $result # Invoke-RestMethod -Uri $Uri -Credential $Credential -Body $Body -ContentType "application/json" | Select-Object -ExpandProperty Result } |