Join the #BuildWithBuildAgent Challenge! Get recognized, earn exclusive swag, and inspire the ServiceNow Community with what you can build using Build Agent.  Join the Challenge.

SOLUTION - How to attach a file to a record using Windows PowerShell (Invoke-WebRequest)

ericroberts
Tera Contributor

**I started this thread as a question...but figured it out along the way.  I guess I should make this an article...but I have already put everything here and don't want to lose my code again...so sorry if this is in bad form.

GOAL: Attach a file to an existing (or new) incident using Windows PowerShell.

Start with adding a new record in this case to the incident table.

Add (POST) New Record Using PowerShell:

##############################################
#####            NEW RECORD              #####
##############################################

# Eg. User name="admin", Password="admin" for this code sample.
$user = "admin"
$pass = "admin"

# Build auth header
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $user, $pass)))

# Set proper headers
$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add('Authorization',('Basic {0}' -f $base64AuthInfo))
$headers.Add('Accept','application/json')
$headers.Add('Content-Type','application/json')

# Specify endpoint uri
$uri = "https://dev53556.service-now.com/api/now/table/incident"

# Specify HTTP method
$method = "post"

# Specify request body
#{request.body ? "$body = \"" :""}}{\"short_description\":\"Added using PowerShell...\",\"caller_id\":\"a8f98bb0eb32010045e1a5115206fe3a\"}"
# Could't get above line to work...seems like this example from the REST API Explorer is buggy...lots of posts on it not working...ended up using the approach below

$body = @{
'short_description' = 'Added using PowerShell'
'caller_id' = 'a8f98bb0eb32010045e1a5115206fe3a'
}

$bodyJson = $body | ConvertTo-Json

# Send HTTP request
$response = Invoke-WebRequest -Headers $headers -Method $method -Uri $uri -Body $bodyJson

# Print response
$response.RawContent

# Other methods
$response2 = $response.Content | ConvertFrom-Json

# Now you can select specific fields as PowerShell Objects. Example:
$response2.result | Select category, state, impact

#Example of adding specific field to a string
$response2.result | % {Write-host "SysID: $($_.sys_id)"}


**Remember for later that you can get the sys_id of the newly created record from the response2.result var/object.

The next thing I did was to update an existing record:

Update (PATCH) Existing Record Using PowerShell:

##############################################
#####         PATCH RECORD               #####
##############################################

# Eg. User name="admin", Password="admin" for this code sample.
$dateNow = Get-Date

$user = "admin"
$pass = "admin"

# Build auth header
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $user, $pass)))

# Set proper headers
$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add('Authorization',('Basic {0}' -f $base64AuthInfo))
$headers.Add('Accept','application/json')
$headers.Add('Content-Type','application/json')

# Specify endpoint uri
$uri = "https://dev53556.service-now.com/api/now/table/incident/935ca5d74f2023002bd2224f9310c783"

# Specify HTTP method
$method = "patch"

$body = @{
'short_description' = ' <<== Last Modified -- using $method via PowerShell'
'caller_id' = 'f298d2d2c611227b0106c6be7f154bc8'
}

$bodyJson = $body | ConvertTo-Json

# Send HTTP request
$response = Invoke-WebRequest -Headers $headers -Method $method -Uri $uri -Body $bodyJson

# Print response
$response.RawContent

**If needed you can paste in that response2 code from the 'add new record' example to get at specific fields in the updated record.

And finally now I want to add an attachment to an existing incident record.  Note that in this example the URI path changes somewhat from the other two operations.  Ensure that you add the right table name ("table_name=") and then the sys id ("table_sys_id") for the record you want to attach files to.  Note that "table_sys_id" is not the sys id for the table...but the sys id for the record you want to attach the file to.

Upload (POST) File Attachment to Existing Record Using PowerShell:

##############################################
#####         FILE UPLOAD                #####
##############################################

# Eg. User name="admin", Password="admin" for this code sample.
$user = "admin"
$pass = "admin"

# Build auth header
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $user, $pass)))

# Set proper headers
$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add('Authorization',('Basic {0}' -f $base64AuthInfo))
$headers.Add('Accept','application/json')
$headers.Add('Content-Type','application/json')
# $headers.Add('Content-Type','text/plain')  ??didn't seem to need this

# Specify endpoint uri
$uri = "https://dev53556.service-now.com/api/now/attachment/file?table_name=incident&table_sys_id=935ca5d74f2023002bd2224f9310c783&file_name=MySampleDoc.txt"

# Specifiy file to attach
$fileToAttach = "c:\Users\ericroberts\sample.txt"

# Specify HTTP method (POST, PATCH, PUT)
$method = "POST"

# Send HTTP request
$response = Invoke-WebRequest -Headers $headers -Method $method -Uri $uri -InFile $fileToAttach

# Print response
$response.RawContent

 

Last thing is adding a file attachment or attachments to a new record.  Using the add new record method allows you to get the response variable where you can get the sys_id of the newly created record.  From that you can then attach an associated file to that new record.  In the final example I made variables out of the constants like instance, table name, etc.

Add New Record And Immediately Attach a File To It:

##############################################
#####  ADD NEW RECORD THEN ATTACH FILE   #####
##############################################

# Eg. User name="admin", Password="admin" for this code sample.
$user = "admin"
$pass = "admin"

# Build auth header
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $user, $pass)))

# Set proper headers
$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add('Authorization',('Basic {0}' -f $base64AuthInfo))
$headers.Add('Accept','application/json')
$headers.Add('Content-Type','application/json')

#Define instance and table names
$instanceName = "dev53556"
$tableName = "incident"

# Specify endpoint URI for creating new record
$newRecordURI = "https://$($instanceName).service-now.com/api/now/table/$($tableName)"

# Specify HTTP method
$method = "POST"

$body = @{
'short_description' = 'New Incident Record that will get a file attachment.'
'caller_id' = 'a8f98bb0eb32010045e1a5115206fe3a'
}

$bodyJson = $body | ConvertTo-Json

# Send HTTP request
$response = Invoke-WebRequest -Headers $headers -Method $method -Uri $newRecordURI -Body $bodyJson

# Take response and get at the fields just created:
$response2 = $response.Content | ConvertFrom-Json

#Capture the sysID of the newly created record
$newRecordSysID = $response2.result.sys_id

##############################################
#####         FILE UPLOAD                #####
##############################################

# Specify endpoint URI for attaching a file

$recordSysID = $newRecordSysID
$fileName = "190685.docx"

$uriForFileAttach = "https://$($instanceName).service-now.com/api/now/attachment/file?table_name=$($tableName)&table_sys_id=$($recordSysID)&file_name=$($fileName)"

# Specifiy file to attach
$fileToAttach = "c:\Users\ericroberts\$($fileName)"

# Specify HTTP method (POST, PATCH, PUT)
$method = "POST"

# Send HTTP request
$response = Invoke-WebRequest -Headers $headers -Method $method -Uri $uriForFileAttach -InFile $fileToAttach

Hope this helps someone some day.

Thanks,

ER

 

10 REPLIES 10

bgmoreira
Tera Expert

Hi

I used your example "Upload (POST) File Attachment to Existing Record Using PowerShell" but a recived this response :

Invoke-WebRequest : O servidor remoto retornou um erro: (401) Não Autorizado.

 

I put all possibles roles in my integration user. Do you have any tips?

 

Tahnk you !!!