Powershell ConvertTo-JSON returning "nested" object - json

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)

Related

Powershell: Using Invoke-WebRequest, How To Use Variable Within JSON?

Using Powershell, I'm trying to PUT data into an API, but I'm having trouble using a variable within the JSON:
This code below does not generate an error from the API, but it PUTS the singer as, literally, "$var_currentsinger" and doesn't use the intended variable
$currentsinger = "Michael Jackson"
$headers.Add("Content-Type", "application/json")
$response = Invoke-WebRequest -Uri https://stackoverflow.com -Method PUT -Headers $headers -Body '{
"album": {
"name": "Moonlight Sonata",
"custom_fields": [{
"singer": "$currentsinger",
"songwriter": "Etta James"
}]
}
}'
This version below does not work, I assume because there are no quotes around the singer name. The API returns a value that the data is invalid
$currentsinger = "Michael Jackson"
$headers.Add("Content-Type", "application/json")
$response = Invoke-WebRequest -Uri https://stackoverflow.com -Method PUT -Headers $headers -Body '{
"album": {
"name": "Moonlight Sonata",
"custom_fields": [{
"singer": $currentsinger,
"songwriter": "Etta James"
}]
}
}'
The only thing I have tried is double quotes and triple quotes around the variable, but I either get the $currentsinger variable within the JSON and have it submit the variable value and not the variable name.
JSON requires double-quotes, so one example way to handle is by escaping the quotes or with a double-quoted here-string:
# here-string
$json = #"
"singer": $currentsinger,
"songwriter": "Etta James"
"#
# escaped
$json = "
`"singer`": $currentsinger,
`"songwriter`": `"Etta James`"
"

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

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

Invoke RestMethod issues parsing JSON: Value not convertible to Int

I have to use PowerShell to manage a Websense server via API. I am using Invoke-RestMethod and I am using a json format to make the changes. The comand to the server is as follows:
Invoke-RestMethod -Uri $uriCreate -Method Post -Headers $headers -Body ($jsonCat | ConvertTo-Json) -ContentType "application/json"
My variables are as follows:
$uriCreate = https://<ipaddress>:<port>/api/web/v1/categories
$headers = #{ Authorization = <credentials> }
$jsonCat = [ordered]#{
"Transaction ID" = $transID
Categories = #(
[ordered]#{
"Category Name" = $catName
"Category Description" = $catDesc
"Parent" = $catID
}
)
}
When I attempt to create the category via Powershell I get the following error returned:
Invoke-RestMethod : {
"Error" : [ "Could not parse JSON: Value is not convertible to Int." ]
}
Any idea what I am doing wrong?

Powershell Invoke-Webrequest w/ JSON Body - Can not deserialize...?

I need to perform an Invoke-Webrequest with a specifically formatted body to add devices to a product. Here is what it looks like in json (example straight from the vendor's documentation):
$body_json = '{"datasource": [{
"parentId": "123456789000",
"name": "(name)",
"id": "(value)",
"typeId": 0,
"childEnabled": false,
"childCount": 0,
"childType": 0,
"ipAddress": "(ipAddress)",
"zoneId": 0,
"url": "(url)",
"enabled": false,
"idmId": 123456789000,
"parameters": [{
"key": "(key)",
"value": "(value)"
}]
}]}'
When I try to submit this in its json representation though, I get the following error:
Invoke-WebRequest : Can not deserialize instance of
com.vendor.etc.DataSourceDetail out of START_ARRAY token at [Source:
java.io.StringReader#22c614; line: 1, column: 1] At
C:\powershell_script_location\ps.ps1:114 char 9
+ $request = Invoke-WebRequest $url -Method Post -Headers $headers -Body $body_json - ...
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation:
(System.Net.HttpWebRequest:HttpWebRequest) [Invoke-WebRequest],
WebException + FullyQualifiedErrorId :
WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeWebRequestCommand
The issue is with the format of the "parameters", parameter because the request submits fine when omitting the "parameters", but then the
devices that I'm adding are missing important parameter details.
Is there something wrong with Invoke-WebRequest, JavaScriptSerializer,
the vendor's code, or is this a user error? Let me know if any clarification is needed.
Unfortunately I don't know what a com.vendor.etc.DataSourceDetail instance looks like, as I am using an API and I don't have access to it directly.
Use Invoke-RestMethod instead of Invoke-WebRequest.
If you have the body as a string use:
Invoke-RestMethod -Uri http://your-url.com -Method POST -Body $body_json -ContentType "application/json"
If the body must be constructed from data/parameters, it might be easier to build a hashtable and convert it to json via ConvertTo-Json:
$body_json = #{
datasource = #(
#{
parentId = 123456789000
name = "name"
id = "value"
typeId = 0
childEnabled = $false
childCount = 0
childType = 0
ipAddress = "ipAddress"
zoneId = 0
url = "url"
enabled = $false
idmId = 123456789000
parameters = #( #{
key = "key"
value = "value"
})
})} | ConvertTo-Json -Depth 4
Invoke-RestMethod -Method 'Post' -Uri http://your-url.com -Body $body_json -ContentType "application/json"
Body Undefined
I couldn't understand why the req.body on the server was undefined (NodeJS Azure Function). It turns out I had a header that was an empty string.
It's not clear whether is was invoke-restmethod or azure-functions-core-tools that has a bug.
FWIW.

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
}
}
}
]