ADO: upload an attachment to Azure DevOps via HTTP REST request - json

We're using ADO Server 2019 and as part of a larger project I need to upload some emails to the ADO environment to attach to work items. I've already figured out that you first need to upload the attachment, pass over the attachment ID to the work item patch request and add the relationship from the work item end however what I can't for the life of me figure out is where to pick the actual email or any item up to upload.
The example that's given within the MS docs shows you how to post an upload but it uploads nothing, it just creates a blank page.
POST https://{instance}/fabrikam/_apis/wit/attachments?fileName=textAsFileAttachment.txt&api-version=5.0
A body for the request needs to be built to define where the attachment is from what I can gather however there isn't any kind of documentation around this for simply posting it via HTTP.
We're using Blue Prism so using C# is an option but not ideal.
Thanks in advance.

Please follow the steps below:
1.Upload a text file
POST https://{instance}/fabrikam/_apis/wit/attachments?fileName=textAsFileAttachment.txt&api-version=5.0
Request Body: "User text content to upload"
2.You will get a response like:
{
"id": "6b2266bf-a155-4582-a475-ca4da68193ef",
"url": "https://fabrikam:8080/tfs/_apis/wit/attachments/6b2266bf-a155-4582-a475-ca4da68193ef?fileName=textAsFileAttachment.txt"
}
Copy this url from the response.
3.Add an attachment to work items:
POST https://{instance}/fabrikam/_apis/wit/attachments?fileName=textAsFileAttachment.txt&api-version=5.0
Request body:
[
{
"op": "add",
"path": "/relations/-",
"value": {
"rel": "AttachedFile",
"url": "https://fabrikam:8080/tfs/_apis/wit/attachments/6b2266bf-a155-4582-a475-ca4da68193ef?fileName=textAsFileAttachment.txt",
"attributes": {
"comment": "Spec for the work"
}
}
}
]
Replace the url of the request body.

You have to pass a file content if you create a new attachment. Upload a binary file
POST
https://dev.azure.com/fabrikam/_apis/wit/attachments?fileName=imageAsFileAttachment.png&api-version=6.1-preview.3
"[BINARY FILE CONTENT]"
Here is an example through Powershell:
$user = ""
$token = "<personal access token>"
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $user,$token)))
$org = "org_name"
$teamProject = "teamproject"
$wiId = "work item Id"
$folderPath = "c:/temp"
$fileName = "some_file.zip"
$createAttachmetUrlTemplate = "https://dev.azure.com/$org/$teamProject/_apis/wit/attachments?fileName={fileName}&api-version=5.0"
$updateWIUrlTemplate = "https://dev.azure.com/$org/_apis/wit/workitems/{id}?api-version=5.0"
$wiBodyTemplate = "[{`"op`": `"add`",`"path`": `"/relations/-`",`"value`": {`"rel`": `"AttachedFile`",`"url`": `"{attUrl}`", `"attributes`": {`"comment`": `"Spec for the work`"}}}]"
function InvokePostRequest ($PostUrl, $body)
{
return Invoke-RestMethod -Uri $PostUrl -Method Post -ContentType "application/json" -Headers #{Authorization=("Basic {0}" -f $base64AuthInfo)} -Body $body
}
function InvokePatchRequest ($PatchUrl, $body)
{
return Invoke-RestMethod -Uri $PatchUrl -Method Patch -ContentType "application/json-patch+json" -Headers #{Authorization=("Basic {0}" -f $base64AuthInfo)} -Body $body
}
$bytes = [System.IO.File]::ReadAllBytes("$folderPath/$fileName")
$createAttachmetUrl = $createAttachmetUrlTemplate -replace "{filename}", $fileName
$resAtt = InvokePostRequest $createAttachmetUrl $bytes
$updateWIUrl = $updateWIUrlTemplate -replace "{id}", $wiId
$wiBody = $wiBodyTemplate -replace "{attUrl}", $resAtt.url
InvokePatchRequest $updateWIUrl $wiBody

Related

Json Array in Powershell from Podto Powershell

I have the following Json in the body of a Postman. what would be equivalent code in Powershell to send rest API via invoke-webrequest or via invoke-restmethod?
Postman Body:
{
"extra_vars": {
"servername": "apicall1234",
"servers": "server01,server02,server06,server-12345"
}
}
You can pass a request body via the -Body parameter on either of the web cmdlets. As with Postman (or any other HTTP client), you'll need to provide an address and a method/verb.
$uri = 'https://<url goes here>/path'
$reqBody = '{ "extra_vars": { "servername": "apicall1234", "servers": "server01,server02,server06,server-12345" } }'
Invoke-WebRequest -Uri $uri -Body $reqBody -Method Post

How to put a hyperlink in a MS Teams message sent from a Powershell script in a TeamCity build project?

I'm using TeamCity to build my project.
In one of my build steps, I put a Powershell script, which uses Webhook to send a message to a MS Teams channel.
$url = "https://..."
$body = #{
title = "MtTitle";
text = "Visit: $url";
} | ConvertTo-Json
$postBody = [Text.Encoding]::UTF8.GetByres($body)
Invoke-WebRequest -Method Post -Uri "https://mycorp.webhook.office.com/..." -Body $postBody -ContentType "application/json" -UseBasicParsing
As a result of the script above, a message is sent to the Teams channel as expected, but the URL (the string after Visit:) is shown as a plain text.
How is it possible to make it a clickable hyperlink?
Should I use a MessageCard as shown in the link below?
Get Build Job URL in TeamCity Build Step
You can create a link in teams like that:
[HereText](hereLink)
Code would look somthing like that:
$url = "https://..."
$urlText = "some"
$body = #{
title = "MtTitle";
text = "Visit [$urlText]($url)";
} | ConvertTo-Json
Invoke-WebRequest -Method Post -Uri "https://mycorp.webhook.office.com/..." -Body $postBody -ContentType "application/json" -UseBasicParsing

Powershell Script to create user and add to servicedesk suddenly not working

last year I created a PS script, that took care of automatically creating users and adding them to our servicedesk, we use a special user creation account for this, the credentials are locally saved in a text file. It all worked fine, however the script doesn't seem to work anymore, did the JIRA API change?
I get following error message: Invoke-Rest-Method: The remote server returned an error (401) Unauthorized at response = Invoke-Rest-Method -Uri...etc
I checked and our user creation account still has all the permissions to create users, I can manually create them and the log shows that the user also logs in normally through the script.
Hopefully somebody can help with my problem!
Here's the code:
$jiraCredentials = Get-Content -Raw -Path "C:\PowerShellScripts\New-AdUser\credentials.json" |ConvertFrom-Json
$bytes = [System.Text.Encoding]::ASCII.GetBytes("${$jiraCredentials.username}:${$jiraCredentials.password}")
$base64 = [System.Convert]::ToBase64String($bytes)
$basicAuthValue = "Basic $base64"
$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.add("Authorization", $basicAuthValue)
$headers.add("X-Experimentalapi", "opt-in")
$headers.add("Content-Type", "application/json")
#$headers.add("X-Atlassian-Token", "nocheck")
$JSON = #"
{
"fullName": "$emailAddressClean",
"email": "$emailAddressClean"
}
"#
$response = Invoke-RestMethod -Uri https://jira.dilax.com/rest/servicedeskapi/customer -Method POST -Body $JSON -ContentType "application/json" -Headers $headers
#add customer to servicedesk
$JSON2 = #"
{
"usernames":[
"$emailAddressClean"
]
}
"#
$response2 = Invoke-RestMethod -Uri https://jira.dilax.com/rest/servicedeskapi/servicedesk/9/customer -Method POST -Body $JSON2 -ContentType "application/json" -Headers $headers
managed to fix it because the log in credentials didn't get transmitted correctly:
$jiraCredentials = Get-Content -Raw -Path "C:\PowerShellScripts\New-AdUser\credentials.json" |ConvertFrom-Json
$user = $jiraCredentials.username
$pass = $jiraCredentials.password
$pair = "${user}:${pass}"
$bytes = [System.Text.Encoding]::ASCII.GetBytes($pair)
$base64 = [System.Convert]::ToBase64String($bytes)
$basicAuthValue = "Basic $base64"

Powershell ConvertTo-JSON returning "nested" object

I'm trying to make a POST request to my server. Everything was fine until I decided to convert my object to JSON. Here's my code:
$postParams = #{
Login = "JonSnow66";
Password = "LetItSnow";
Email = "Jon.Snow#wall.com";
Name = "Jon Snow";
Desc = "I know nothing";
BirthDate = "1572 2 16";
Img = Get-Content -Path ./PH_img.txt | Out-String;
Type = "Admin";
}
Invoke-WebRequest -Uri http://localhost:3000/api/add/user -Method POST -Body (ConvertTo-Json $postParams -Compress)
Instead of returning regular JSON object like:
{
"Login": "JonSnow66"
...
}
It returns:
{{
"Login": "JonSnow66",
"BirthDate": "1572 2 16",
"Desc": "I know nothing",
"Name": "Jon Snow",
"Type": "Admin",
"Password": "LetItSnow",
"Img": "/9j/4<BASE64>/Z\r\n",
"Email": "Jon.Snow#wall.com"
}: ""}
I'm just a powershell beginner.
I think you need to specify ContentType on Invoke-WebRequest to be 'application/json'. If you don't specify a content type and are performing a Post then I think the cmdlet assumes you are submitting a form by default, and that might explain the extra { } characters you are seeing in the result.
Here's the modified code:
Invoke-WebRequest -Uri 'http://localhost:3000/api/add/user' -Method POST -ContentType 'application/json' -Body (ConvertTo-Json $postParams -Compress)

Correct json to add a parent link to a TFS work item

I am trying to add a parent link to a TFS work item using powershell and json. We have an internal TFS server (ie, not team services).
I get answers to my queries, so my connection to TFS is working, but when I try to update I get the following error:
"You must pass a valid patch document in the body of the request."
I am a json noob and got my json skeleton from this MSDN page
Here is my json:
[
{
"op": "add",
"path": "/relations/-",
"value":
{
"rel": "System.LinkTypes.Hierarchy-Reverse",
"url": "https://tfs.myCompany.org/tfs/DefaultCollection/_apis/wit/workitems/259355",
"attributes":
{
{ "isLocked": false }
}
}
}
]
I tested with square brackets in a few places based on some other json samples I found but they didn't help so I returned to the syntax from the MSDN page above.
And this is the powershell script I am using.
param(
[System.String]$TaskId=288346
)
$username = "myUserInfo"
$password = "myPassword"
$securePassword = $password | ConvertTo-SecureString -AsPlainText -Force
$credential = New-Object System.Management.Automation.PSCredential($username, $securePassword)
$taskItemURL ="https://tfs.myCompanynet.org/tfs/DefaultCollection/_apis/wit/workitems/$TaskId"
$taskItemRequest = $taskItemUrl+'?$expand=relations'
$taskItemJson = Invoke-RestMethod -uri "$taskItemRequest" -Method get -
Credential $credential
if($taskItemJson.relations)
{
write-host "relation exists: " $taskItemJson.relations[0].url
}
else
{
write-host "relation does not exist. Creating it."
$jsonTemplate = Get-Content E:\scripts\JsonTemplate.txt # | ConvertTo-Json
$result = Invoke-RestMethod -uri $taskItemURL"?api-version=1.0" -Method patch -UseDefaultCredentials -ContentType application/json-patch+json -body $jsonTemplate
}
As you can see I have commented out the convertTo-json because I was getting this error:
ConvertTo-Json : The converted JSON string is in bad format.
I wasn't sure if I was getting that error because it is already json.
I also tested skipping the get-content and using the -inFile parameter but it resulted in the same error above.
$result = Invoke-RestMethod -uri $taskItemURL"?api-version=1.0" -Method patch -Credential $credential -ContentType application/json-patch+json -InFile E:\scripts\JsonTemplate.txt
Any ideas on what is wrong with my json?
Thanks!
Aargh! I was so close. I chanced a guess that the double curly brackets under attribrutes were wrong even though the documentation looks like it should be so. When I removed those it worked beautifully.
Now my json looks like this:
[
{
"op": "add",
"path": "/relations/-",
"value":
{
"rel": "System.LinkTypes.Hierarchy-Reverse",
"url": "https://tfs.myCompany.org/tfs/DefaultCollection/_apis/wit/workitems/259355",
"attributes":
{
"isLocked": false
}
}
}
]