The Now Platform® Washington DC release is live. Watch now!

Help
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

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

ericroberts
Giga 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

 

9 REPLIES 9

Dustdreams27
Kilo Contributor

Thanks for sharing this Eric! You saved me a ton of time with your solution. Our powershell scripts look incredibly similar. I was trying to create a new Incident, grab the SysID and post again for file upload and everything was working, except the attached file on the incident would be corrupted and no data available. I didn't know about the -InFile parameter and was trying to pass in a file attachment through the $Body variable. Thanks again for sharing, the -Infile method worked perfectly!

Wonderful...I'm glad it helped you.  I figured it'd be worth the time spent documenting it if it helped even one person...so I'm glad there was at least one :).  And it'll now be here for me in a year or so when I need it again and have lost the code locally.

ER

Hi Dustdreams,

 

I'm getting 400 bad request from service-now following the same process of getting sys id and then creating post uri as in the above document. It would be great if you can Please help me with your URI and Invoke-webrequest command arguments masking the values with duplicate ones.

Dustdreams27
Kilo Contributor

Hey Eric, since you work with ServiceNow and Powershell I was wondering if you ever happen to run into this issue? 

 

https://community.servicenow.com/community?id=community_question&sys_id=d2974c82db5157c84816f3231f961914

 

To summarize, I cannot seem to close out a Task, while populating the Closed_By and Closed_At fields. The actual state reflects "Closed Complete", but the closed time (Closed_At) is blank, even when I attempt to force populate the field.

 

Dustin