3

i want to send an event to aws via a cli command in a powershell script. Here is the Json i need to send to the eventbridge:

   [
       {
          "Sensor":"{\"id\":\"880/2021-04-13\",\"attributes\":\"green\",\"Name\":\"SensorGreen\",\"state\":\"SUCCEEDED\"}",
          "Source":"google.com"
       }

    ]

Thats what a tried in powershell:

$json='[{"Sensor":"{\"id\":\"880/2021-04-13\",\"attributes\":\"green\",\"Name\":\"SensorGreen\",\"state\":\"SUCCEEDED\"}","Source":"google.com"}]'|ConvertTo-Json -Compress

aws events put-events --entries $json --region "eu-central-1"  

That does not work. I even tried to write it to a json file and read it and send it from the file but it doesnt work. It somehow leads to too many "\" slashes or no slashes for my "Sensor" where it is necessary. I even tried to create a object and just convert the Sensor object to Json and then the whole object again to have the escaping, but it is not working.

EDIT:

i tried also this as mentioned in the answer:
$RequestObject = [pscustomobject] @(@{
    Sensor = [pscustomobject] @{
        id = "880/2021-04-13"
        attribute = "green"
        Name = "SensorGreen"
        state = "SUCCEEDED"
    }
    Source = "google.com"
})
$RequestObject.Get(0).Sensor=$RequestObject.Get(0).Sensor | ConvertTo-Json -Compress
$Json = $RequestObject | ConvertTo-Json -Compress
aws events put-events --entries $Json --region "eu-central-1"

i included the @() to have an array and converted the sensor object twice to json to include the slashes. but the result is:

Error parsing parameter '--entries': Invalid JSON: Expecting property name enclosed in double quotes: line 1 column 2 (char 1)

if i use the command line interface only with the aws command and put the object directly into the command, then it works.. but the powershell does not.

Khan
  • 1,418
  • 1
  • 25
  • 49

2 Answers2

4
  • You're passing a JSON string to an external program (aws)

  • Irrespective of how you constructed that string - directly as a string, or from an object / hashtable via ConvertTo-Json - as of PowerShell 7.1 - manual escaping of embedded " as \" is required, which, in turn requires escaping the preexisting \ preceding the embedded " as \\.

    • Note: None of this should be necessary, but due to a long-standing bug in PowerShell is - see this answer for details.

    • PowerShell Core 7.2.0-preview.5 now includes experimental feature PSNativeCommandArgumentPassing with an attempted fix, but, unfortunately, it looks like it will lack important accommodations for high-profile CLIs on Windows - see this summary from GitHub issue #15143. However, it would fix calls to aws.exe, the Amazon Web Services CLI.

# The JSON string to be passed as-is.
$json = @'
[
  {
     "Sensor":"{\"id\":\"880/2021-04-13\",\"attributes\":\"green\",\"Name\":\"SensorGreen\",\"state\":\"SUCCEEDED\"}",
     "Source":"google.com"
  }

]
'@

# Up to at least PowerShell 7.1:
# Manually perform the required escaping, to work around PowerShell's
# broken argument-passing to external programs.
# Note:
#  -replace '\\', '\\' *looks* like a no-op, but replaces each '\' with '\\'
$jsonEscaped = $json -replace '\\', '\\' -replace '"', '\"'

# Now pass the *escaped* JSON string to the aws CLI:
aws events put-events --entries $jsonEscaped --region "eu-central-1"  
mklement0
  • 382,024
  • 64
  • 607
  • 775
3

ConvertTo-Json is for converting objects in PowerShell, not a string that you have tried to already write in Json. Your $Json variable produces this.

"[{\"Sensor\":\"{\\\"id\\\":\\\"880/2021-04-13\\\",\\\"attributes\\\":\\\"green\\\",\\\"Name\\\":\\\"SensorGreen\\\",\\\"state\\\":\\\"SUCCEEDED\\\"}\",\"Source\":\"google.com\"}]"

If you want to create the object in PowerShell and convert it to Json, then you can do this.

$RequestObject = [pscustomobject] @{
    Sensor = [pscustomobject] @{
        id = "880/2021-04-13"
        attribute = "green"
        Name = "SensorGreen"
        state = "SUCCEEDED"
    }
    Source = "google.com"
}
$Json = $RequestObject | ConvertTo-Json -Compress
aws events put-events --entries $Json --region "eu-central-1"

Your Json will look like this if you print your variable out.

{"Sensor":{"id":"880/2021-04-13","attribute":"green","Name":"SensorGreen","state":"SUCCEEDED"},"Source":"google.com"}

Which I think is like the Json that the command is expecting. Not entirely sure why you need the strings escaping or the array. Here it is uncompressed.

{
    "Sensor":  {
                   "id":  "880/2021-04-13",
                   "attribute":  "green",
                   "Name":  "SensorGreen",
                   "state":  "SUCCEEDED"
               },
    "Source":  "google.com"
}

Just noticed the powershell-2.0 tag. If you are using it, then you should do this instead to create your Json.

$Sensor = New-Object psobject -Property @{
    id = "880/2021-04-13"
    attribute = "green"
    Name = "SensorGreen"
    state = "SUCCEEDED"
}
$RequestObject = New-Object psobject -Property @{
    Sensor = $Sensor
    Source = "google.com"
}
$Json = $RequestObject | ConvertTo-Json -Compress

EDIT

If you absolutely must escape the strings in that way and have a single item array, then you should just pass the Json that you have written in your answer without any further conversion.

$json='[{"Sensor":"{\"id\":\"880/2021-04-13\",\"attributes\":\"green\",\"Name\":\"SensorGreen\",\"state\":\"SUCCEEDED\"}","Source":"google.com"}]'

If you want to make PowerShell do that for you then you would need to perform some string replacement on the Sensor object first.

PowerShell 2.0

$Sensor = New-Object psobject -Property @{
    id = "880/2021-04-13"
    attribute = "green"
    Name = "SensorGreen"
    state = "SUCCEEDED"
} 
$SensorJson = $Sensor | ConvertTo-Json -Compress
$SensorJson.Replace("`"","\`"")
$RequestObject = New-Object psobject -Property @{
    Sensor = $SensorJson
    Source = "google.com"
}
$Json = $RequestObject | ConvertTo-Json -Compress

PowerShell 3.0+

$Sensor = [pscustomobject] @{
    id = "880/2021-04-13"
    attribute = "green"
    Name = "SensorGreen"
    state = "SUCCEEDED"
}
$SensorJson = $Sensor | ConvertTo-Json -Compress
$SensorJson.Replace("`"","\`"")
$RequestObject = [pscustomobject] @{
    Sensor = $SensorJson
    Source = "google.com"
}
$Json = $RequestObject | ConvertTo-Json -Compress

Then your AWS command

# Add the array around the compressed Json string.
aws events put-events --entries "[$Json]" --region "eu-central-1"

"[$Json]" prints

[{"Sensor":"{\"id\":\"880/2021-04-13\",\"attribute\":\"green\",\"Name\":\"SensorGreen\",\"state\":\"SUCCEEDED\"}","Source":"google.com"}]
Ash
  • 3,030
  • 3
  • 15
  • 33
  • yes nice. But i need the Sensor object to include escaping because the endpoint iam calling, expects the Sensor object to be like this: "Sensor":"{\"id\":\"880/2021-04-13\",\"attributes\":\"green\",\"Name\":\"SensorGreen\",\"state\":\"SUCCEEDED\"}" – Khan May 15 '21 at 19:59
  • if i add $RequestObject.Sensor=$RequestObject.Sensor|ConvertTo-Json -Compress as the 2nd last statement. I can put the backslashes to the Sensor object. Then i have what i wanted, but using the cli, it gives me the Error: Error parsing parameter '--entries': Invalid JSON: Expecting property name enclosed in double quotes: line 1 column 2 (char 1) – Khan May 15 '21 at 20:07
  • and the array is still missing. At the end its an array with one object. – Khan May 15 '21 at 20:09
  • That seems to be a strange schema to me, and on checking, it doesn't seem to be what is reflected [here in the docs for your command](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/events/put-events.html). Maybe I am mistaken, I do not use AWS. – Ash May 15 '21 at 20:14
  • its a custom thing so the call iam making is processed again where it has to be like that. I updated my answer so you can see what i get as result – Khan May 15 '21 at 20:15
  • I have updated my answer if you want to create it in PowerShell from objects. – Ash May 15 '21 at 20:23