How to send Invoke-WebRequest with JSON body containing data from File
Asked Answered
S

1

6

QUESTION:
How do I put a file's contents within the JSON body of an Invoke-WebRequest without the unneeded file metadata?

My goal is to send an HTTP request like so:

Invoke-WebRequest -Uri http://localhost:4321/updatefile `
    -ContentType 'application/json' `
    -Method POST `
    -Body $Body

where:

PS C:\Users\User1234> $Body = ConvertTo-Json @(
    @{filename='file1.txt';filecontent=$file1},
    @{filename='file2.txt';filecontent=$file2}
)

PS C:\Users\User1234> $file1 = Get-Content "C:\path\to\file1.txt"
PS C:\Users\User1234> $file2 = Get-Content "C:\path\to\file2.txt"

When I print the variables:

PS C:\Users\User1234> echo $file1
aaaaa
PS C:\Users\User1234> echo $file2
bbbbb

...it prints the contents of the file as I expected.
But printing the file content within the $Body shows a lot more information I don't need:

PS C:\Users\User1234> echo $Body
{
    "filename":  "file1.txt",
    "filecontent":  {
                        "value":  "aaaaa",
                        "PSPath":  "C:\\path\\to\\file1.txt",
                        "PSParentPath":  "C:\\path\\to",
                        "PSChildName":  "file1.txt",
                        "PSDrive":  {
                                        "CurrentLocation":  "Users\\User1234",
                                        "Name":  "C",
                                        "Provider":  "Microsoft.PowerShell.Core\\FileSystem",
                                        "Root":  "C:\\",
                                        "Description":  "OS",
                                        "MaximumSize":  null,
                                        "Credential":  "System.Management.Automation.PSCredential",
                                        "DisplayRoot":  null
                                    },
                        "PSProvider":  {
                                           "ImplementingType":  "Microsoft.PowerShell.Commands.FileSystemProvider",
                                           "HelpFile":  "System.Management.Automation.dll-Help.xml",
                                           "Name":  "FileSystem",
                                           "PSSnapIn":  "Microsoft.PowerShell.Core",
                                           "ModuleName":  "Microsoft.PowerShell.Core",
                                           "Module":  null,
                                           "Description":  "",
                                           "Capabilities":  52,
                                           "Home":  "C:\\Users\\User1234",
                                           "Drives":  "C D Y"
                                       },
                        "ReadCount":  1
                    }
}

I tried setting $file1 and $file2 values using:

$file1 = [IO.File]::ReadAllText("C:\path\to\file1.txt")    
$file2 = [IO.File]::ReadAllText("C:\path\to\file2.txt")

...but the result is the same.

Seraphine answered 7/12, 2018 at 5:18 Comment(1)
R
3

Setup $body first, then convert to json.

$body = @(
    @{
        filename = 'file1.txt'
        filecontent = [io.file]::ReadAllText("1.txt")
    }
)

$body | ConvertTo-Json

OR

$body = @(
    @{
        filename = 'file1.txt'
        filecontent = (get-content 1.txt) -join "`r`n"
    }
)

$body | ConvertTo-Json

output

{
    "filename":  "file1.txt",
    "filecontent":  "1\r\n2\r\n3\r\n"
}

the reason is simple, get-content returns an array, convertto-json does its job but probably not you expected.

Reverberator answered 7/12, 2018 at 5:48 Comment(4)
Your answer is effective, but note that the only reason it works is that using [io.file]::ReadAllText() instead of Get-Content bypasses the problem of Get-Content decorating the output strings with metadata that ConvertTo-Json includes in the serialization - see https://mcmap.net/q/1890324/-using-powershell-to-convert-a-file-39-s-contents-into-a-string-that-can-be-transferred-using-jsonProcrustean
it's also not about the fact that Get-Content returns an array of lines: by using -join "`r`n" you're again bypassing the problem by creating new strings. The preferred way to get the entire file contents is to use Get-Content -Raw 1.txt, but if you use that, the problem of the extra properties resurfaces.Procrustean
For each inner hash table above (the inner collection surrounded by curlies), you need a semicolon separating the items, e.g., a semicolon after filename = 'file1.txt'Biramous
Invoke-WebRequest -Uri 'mywebsite.com/api/ScannedItem' -Method 'POST' -H @{'x-api-key' = 'mykey'; 'Accept' = 'application/json'} -ContentType "application/json" -Body (@{'key1' = 'value1'; 'key2' = 'value2'}|ConvertTo-Json)Alleris

© 2022 - 2024 — McMap. All rights reserved.