Skip to content

Commit 97caff7

Browse files
authored
Major update (#240)
1 parent 6d8ec7b commit 97caff7

19 files changed

+743
-844
lines changed

ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,10 @@ function Invoke-ServiceNowRestMethod {
4343
[hashtable] $Values,
4444

4545
[parameter()]
46-
[System.Collections.ArrayList] $Filter,
46+
[object[]] $Filter,
4747

4848
[parameter()]
49-
[System.Collections.ArrayList] $Sort = @('opened_at', 'desc'),
49+
[object[]] $Sort = @('opened_at', 'desc'),
5050

5151
# sysparm_query param in the format of a ServiceNow encoded query string (see http://wiki.servicenow.com/index.php?title=Encoded_Query_Strings)
5252
[Parameter()]
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
<#
2+
.SYNOPSIS
3+
Lookup table and id info
4+
.DESCRIPTION
5+
Lookup table and id info from module config.
6+
Get sys_id if needed.
7+
#>
8+
function Invoke-TableIdLookup {
9+
10+
[OutputType([Array])]
11+
[CmdletBinding()]
12+
13+
Param (
14+
[Parameter(ParameterSetName = 'Table', Mandatory)]
15+
[Parameter(ParameterSetName = 'TableID', Mandatory)]
16+
[Parameter(ParameterSetName = 'TableIdSysId', Mandatory)]
17+
[AllowEmptyString()]
18+
[AllowNull()]
19+
[Alias('T')]
20+
[string] $Table,
21+
22+
[Parameter(ParameterSetName = 'ID', Mandatory)]
23+
[Parameter(ParameterSetName = 'TableID', Mandatory)]
24+
[Parameter(ParameterSetName = 'IdSysId', Mandatory)]
25+
[Parameter(ParameterSetName = 'TableIdSysId', Mandatory)]
26+
[AllowEmptyString()]
27+
[AllowNull()]
28+
[Alias('I')]
29+
[string] $ID,
30+
31+
[Parameter(ParameterSetName = 'IdSysId', Mandatory)]
32+
[Parameter(ParameterSetName = 'TableIdSysId', Mandatory)]
33+
[Alias('AS')]
34+
[switch] $AsSysId,
35+
36+
[Parameter(ParameterSetName = 'IdSysId')]
37+
[Parameter(ParameterSetName = 'TableIdSysId')]
38+
[Alias('C')]
39+
[hashtable] $Connection,
40+
41+
[Parameter(ParameterSetName = 'IdSysId')]
42+
[Parameter(ParameterSetName = 'TableIdSysId')]
43+
[Alias('S')]
44+
[hashtable] $ServiceNowSession
45+
46+
)
47+
48+
$thisTable = $thisID = $null
49+
50+
if ( $Table ) {
51+
$thisTable = $script:ServiceNowTable | Where-Object { $_.Name.ToLower() -eq $Table.ToLower() -or $_.ClassName.ToLower() -eq $Table.ToLower() }
52+
if ( -not $thisTable ) {
53+
# we aren't aware of this table, create default config
54+
$thisTable = @{
55+
Name = $Table
56+
ClassName = $null
57+
Type = $null
58+
NumberPrefix = $null
59+
DescriptionField = $null
60+
}
61+
}
62+
}
63+
64+
if ( $ID ) {
65+
if ( $ID -match '^[a-zA-Z0-9]{32}$' ) {
66+
if ( -not $thisTable ) {
67+
throw 'Providing sys_id for -ID requires a value for -Table. Alternatively, provide an ID with a prefix, eg. INC1234567, and the table will be automatically determined.'
68+
}
69+
70+
$thisID = $ID
71+
}
72+
else {
73+
if ( -not $thisTable ) {
74+
# get table name from prefix if only Id was provided
75+
$idPrefix = ($ID | Select-String -Pattern '^([a-zA-Z]+)([0-9]+$)').Matches.Groups[1].Value.ToLower()
76+
77+
$thisTable = $script:ServiceNowTable | Where-Object { $_.NumberPrefix -and $idPrefix -eq $_.NumberPrefix }
78+
if ( -not $thisTable ) {
79+
throw ('The prefix for Id ''{0}'' was not found and the appropriate table cannot be determined. Known prefixes are {1}. Please provide a value for -Table.' -f $ID, ($ServiceNowTable.NumberPrefix.Where( { $_ }) -join ', '))
80+
}
81+
}
82+
83+
if ( $AsSysId ) {
84+
$getParams = @{
85+
Table = $thisTable.Name
86+
Filter = @('number', '-eq', $ID)
87+
Property = 'sys_class_name', 'sys_id', 'number'
88+
Connection = $Connection
89+
ServiceNowSession = $ServiceNowSession
90+
}
91+
92+
$thisRecord = Invoke-ServiceNowRestMethod @getParams
93+
94+
if ( -not $thisRecord ) {
95+
throw ('Table: {0}, ID: {1} not found' -f $thisTable.Name, $ID)
96+
}
97+
else {
98+
$thisID = $thisRecord.sys_id
99+
}
100+
}
101+
else {
102+
$thisID = $ID
103+
}
104+
}
105+
}
106+
107+
$thisTable, $thisID
108+
}

ServiceNow/Public/Add-ServiceNowAttachment.ps1

Lines changed: 29 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,11 @@ Function Add-ServiceNowAttachment {
4242
4343
Upload one or more files by record sys_id
4444
45+
.EXAMPLE
46+
Get-ServiceNowRecord inc0000010 | Add-ServiceNowAttachment -File '.\File01.txt'
47+
48+
Use Get-ServiceNowRecord for record details, one or more, to add an attachment to
49+
4550
.EXAMPLE
4651
New-ServiceNowIncident @params -PassThru | Add-ServiceNowAttachment -File file01.txt
4752
@@ -69,26 +74,23 @@ Function Add-ServiceNowAttachment {
6974
[CmdletBinding(SupportsShouldProcess)]
7075

7176
Param(
72-
[Parameter(ValueFromPipelineByPropertyName)]
77+
[Parameter(ParameterSetName = 'Table', Mandatory)]
78+
[Parameter(ParameterSetName = 'TableId', Mandatory, ValueFromPipelineByPropertyName)]
7379
[Alias('sys_class_name')]
7480
[string] $Table,
7581

76-
[Parameter(Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)]
77-
[ValidateScript( {
78-
if ($_ -match '^[a-zA-Z0-9]{32}$' -or $_ -match '^([a-zA-Z]+)[0-9]+$') {
79-
$true
80-
} else {
81-
throw 'Id must be either a 32 character alphanumeric, ServiceNow sysid, or prefix/id, ServiceNow number.'
82-
}
83-
})]
82+
# validation not needed as Invoke-TableIdLookup will handle it with -AsSysId
83+
[Parameter(ParameterSetName = 'Id', Mandatory, ValueFromPipeline, Position = 0)]
84+
[Parameter(ParameterSetName = 'TableId', Mandatory, ValueFromPipelineByPropertyName)]
8485
[Alias('sys_id', 'SysId', 'number')]
8586
[string] $ID,
8687

8788
[Parameter(Mandatory)]
8889
[ValidateScript( {
8990
if ( Test-Path $_ ) {
9091
$true
91-
} else {
92+
}
93+
else {
9294
throw 'One or more files do not exist'
9395
}
9496
})]
@@ -111,62 +113,24 @@ Function Add-ServiceNowAttachment {
111113

112114
begin {
113115
$auth = Get-ServiceNowAuth -C $Connection -S $ServiceNowSession
114-
$invokeRestMethodSplat = $auth
115-
$invokeRestMethodSplat.UseBasicParsing = $true
116-
$invokeRestMethodSplat.Method = 'POST'
116+
$params = $auth
117+
$params.UseBasicParsing = $true
118+
$params.Method = 'POST'
117119
}
118120

119121
process {
120122

121-
if ( $Table ) {
122-
$thisTableName = $ServiceNowTable.Where{ $_.ClassName -eq $Table } | Select-Object -ExpandProperty Name
123-
if ( -not $thisTableName ) {
124-
$thisTableName = $Table
125-
}
126-
}
127-
128-
if ( $ID -match '^[a-zA-Z0-9]{32}$' ) {
129-
if ( -not $thisTableName ) {
130-
Write-Error 'Providing sys_id for -Id requires a value for -Table. Alternatively, provide an -Id with a prefix, eg. INC1234567, and the table will be automatically determined.'
131-
Continue
132-
}
133-
134-
$thisSysId = $ID
135-
136-
} else {
137-
if ( -not $thisTableName ) {
138-
$thisTable = $ServiceNowTable.Where{ $_.NumberPrefix -and $ID.ToLower().StartsWith($_.NumberPrefix) }
139-
if ( $thisTable ) {
140-
$thisTableName = $thisTable.Name
141-
} else {
142-
Write-Error ('The prefix for Id ''{0}'' was not found and the appropriate table cannot be determined. Known prefixes are {1}. Please provide a value for -Table.' -f $ID, ($ServiceNowTable.NumberPrefix.Where( { $_ }) -join ', '))
143-
Continue
144-
}
145-
}
146-
147-
$getParams = @{
148-
Table = $thisTableName
149-
Id = $ID
150-
Property = 'sys_id'
151-
Connection = $Connection
152-
ServiceNowSession = $ServiceNowSession
153-
}
154-
155-
$tableRecord = Get-ServiceNowRecord @getParams
156-
157-
if ( -not $tableRecord ) {
158-
Write-Error "Record not found for Id '$ID'"
159-
continue
160-
}
161-
162-
$thisSysId = $tableRecord.sys_id
163-
}
164-
123+
$thisTable, $thisID = Invoke-TableIdLookup -T $Table -I $ID -AsSysId -C $Connection -S $ServiceNowSession
165124

166125
foreach ($thisFile in $File) {
167126

168127
$thisFileObject = Get-ChildItem $thisFile
169128

129+
if ( $thisFileObject.Size -eq 0 ) {
130+
Write-Warning ('{0} is a 0 byte file and will not be uploaded' -f $thisFileObject.FullName)
131+
Continue
132+
}
133+
170134
If ( -not $PSBoundParameters.ContainsKey('ContentType') ) {
171135
# Thanks to https://github.com/samuelneff/MimeTypeMap/blob/master/MimeTypeMap.cs from which
172136
# MimeTypeMap.json was adapted
@@ -182,22 +146,23 @@ Function Add-ServiceNowAttachment {
182146
}
183147

184148
# POST: https://instance.service-now.com/api/now/attachment/file?table_name=incident&table_sys_id=d71f7935c0a8016700802b64c67c11c6&file_name=Issue_screenshot
185-
$invokeRestMethodSplat.Uri = '{0}/attachment/file?table_name={1}&table_sys_id={2}&file_name={3}' -f $auth.Uri, $thisTableName, $thisSysId, $thisFileObject.Name
186-
$invokeRestMethodSplat.ContentType = $ContentType
187-
$invokeRestMethodSplat.InFile = $thisFileObject.FullName
149+
$params.Uri = '{0}/attachment/file?table_name={1}&table_sys_id={2}&file_name={3}' -f $auth.Uri, $thisTable.Name, $thisID, $thisFileObject.Name
150+
$params.ContentType = $ContentType
151+
$params.InFile = $thisFileObject.FullName
188152

189-
If ($PSCmdlet.ShouldProcess(('{0} {1}' -f $thisTableName, $thisSysId), ('Add attachment {0}' -f $thisFileObject.FullName))) {
153+
If ($PSCmdlet.ShouldProcess(('{0} {1}' -f $thisTable.Name, $ID), ('Add attachment {0}' -f $thisFileObject.FullName))) {
190154

191-
Write-Verbose ($invokeRestMethodSplat | ConvertTo-Json)
155+
Write-Verbose ($params | ConvertTo-Json)
192156

193-
$response = Invoke-WebRequest @invokeRestMethodSplat
157+
$response = Invoke-WebRequest @params
194158

195159
if ( $response.Content ) {
196160
if ( $PassThru ) {
197161
$content = $response.content | ConvertFrom-Json
198162
$content.result
199163
}
200-
} else {
164+
}
165+
else {
201166
# invoke-webrequest didn't throw an error, but we didn't get content back either
202167
throw ('"{0} : {1}' -f $response.StatusCode, $response | Out-String )
203168
}

ServiceNow/Public/Export-ServiceNowAttachment.ps1

Lines changed: 31 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
<#
22
.SYNOPSIS
3-
Save a ServiceNow attachment identified by its sys_id property and saved as the filename specified.
3+
Export an attachment
44
55
.DESCRIPTION
6-
Save a ServiceNow attachment identified by its sys_id property and saved as the filename specified.
6+
Export an attachment identified by its attachment table sys_id.
7+
The contents will be saved to a file by default, but can also be outputted directly.
78
8-
.PARAMETER SysID
9-
The ServiceNow sys_id of the file
9+
.PARAMETER ID
10+
The attachment table sys_id of the file
1011
1112
.PARAMETER FileName
1213
File name the file is saved as. Do not include the path.
@@ -24,27 +25,30 @@ Adds the SysID to the file name. Intended for use when a ticket has multiple fi
2425
Instead of writing to a file, return the attachment contents
2526
2627
.EXAMPLE
27-
Export-ServiceNowAttachment -SysID $SysID -FileName 'mynewfile.txt'
28+
Export-ServiceNowAttachment -ID $SysID -FileName 'mynewfile.txt'
2829
2930
Save the attachment with the specified sys_id with a name of 'mynewfile.txt'
3031
3132
.EXAMPLE
32-
Get-ServiceNowAttachment -Id INC1234567 | Export-ServiceNowAttachment
33+
Get-ServiceNowAttachment -ID INC1234567 | Export-ServiceNowAttachment
3334
34-
Save all attachments from the ticket. Filenames will be assigned from the attachment name.
35+
Save all attachments from the ticket.
36+
Filenames will be assigned from the attachment name.
3537
3638
.EXAMPLE
37-
Get-ServiceNowAttachment -Id INC1234567 | Export-ServiceNowAttachment -AppendNameWithSysID
39+
Get-ServiceNowAttachment -ID INC1234567 | Export-ServiceNowAttachment -AppendNameWithSysID
3840
39-
Save all attachments from the ticket. Filenames will be assigned from the attachment name and appended with the sys_id.
41+
Save all attachments from the ticket.
42+
Filenames will be assigned from the attachment name and appended with the sys_id.
4043
4144
.EXAMPLE
42-
Get-ServiceNowAttachment -Id INC1234567 | Export-ServiceNowAttachment -Destination $path -AllowOverwrite
45+
Get-ServiceNowAttachment -ID INC1234567 | Export-ServiceNowAttachment -Destination $path -AllowOverwrite
4346
4447
Save all attachments from the ticket to the destination allowing for overwriting the destination file.
4548
4649
.EXAMPLE
47-
Export-ServiceNowAttachment -SysId $SysId -AsValue
50+
Export-ServiceNowAttachment -ID $ID -AsValue
51+
4852
Return the contents of the attachment instead of writing to a file
4953
5054
#>
@@ -55,8 +59,16 @@ Function Export-ServiceNowAttachment {
5559
Param(
5660

5761
[Parameter(Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)]
58-
[Alias('sys_id')]
59-
[string] $SysId,
62+
[ValidateScript( {
63+
if ( $_ -match '^[a-zA-Z0-9]{32}$' ) {
64+
$true
65+
}
66+
else {
67+
throw '-ID must be a sys_id 32 character alphanumeric'
68+
}
69+
})]
70+
[Alias('sys_id', 'SysID')]
71+
[string] $ID,
6072

6173
[Parameter(ParameterSetName = 'ToFile', ValueFromPipelineByPropertyName)]
6274
[Alias('file_name')]
@@ -95,25 +107,25 @@ Function Export-ServiceNowAttachment {
95107

96108
$params = $authParams.Clone()
97109

98-
$params.Uri += '/attachment/' + $SysId + '/file'
110+
$params.Uri += '/attachment/' + $ID + '/file'
99111

112+
# if not to file, attachment contents to output
100113
if ( $PSCmdlet.ParameterSetName -eq 'ToFile' ) {
101114
$thisFileName = $FileName
102-
If ( $AppendNameWithSysId.IsPresent ) {
103-
$thisFileName = "{0}_{1}{2}" -f [io.path]::GetFileNameWithoutExtension($thisFileName), $SysId, [io.path]::GetExtension($thisFileName)
115+
If ( $AppendNameWithSysId ) {
116+
$thisFileName = "{0}_{1}{2}" -f [io.path]::GetFileNameWithoutExtension($thisFileName), $ID, [io.path]::GetExtension($thisFileName)
104117
}
105118
$outFile = Join-Path $Destination $thisFileName
106119

107-
If ((Test-Path $outFile) -and -not $AllowOverwrite.IsPresent) {
120+
If ((Test-Path $outFile) -and -not $AllowOverwrite ) {
108121
throw ('The file ''{0}'' already exists. Please choose a different name, use the -AppendNameWithSysID switch parameter, or use the -AllowOverwrite switch parameter to overwrite the file.' -f $OutFile)
109122
}
110123

111124
$params.OutFile = $outFile
112125
}
113126

114-
If ($PSCmdlet.ShouldProcess($outFile, "Save attachment")) {
127+
If ($PSCmdlet.ShouldProcess($ID, "Export attachment")) {
115128
Invoke-RestMethod @params
116129
}
117130
}
118-
end {}
119131
}

0 commit comments

Comments
 (0)