{"id":7219,"date":"2023-07-23T20:44:30","date_gmt":"2023-07-23T19:44:30","guid":{"rendered":"https:\/\/rakhesh.com\/?p=7219"},"modified":"2023-07-24T23:17:19","modified_gmt":"2023-07-24T22:17:19","slug":"connecting-azure-function-powershell-to-cosmos-db","status":"publish","type":"post","link":"https:\/\/rakhesh.com\/azure\/connecting-azure-function-powershell-to-cosmos-db\/","title":{"rendered":"Connecting Azure Function (PowerShell) to Cosmos DB"},"content":{"rendered":"

There are numerous blog posts on this but I couldn’t quite figure out how to do this. I guess it’s a Sunday, my brain isn’t working… \ud83d\ude0a<\/p>\n

Also, this blog post is more like notes for myself as I am pretty much creating it as I figure this stuff. Usually I take notes in Bear<\/a>\u00a0 and then write a blog post, this time I am skipping that to save me some double work. Instead, I am creating a test version of the items below so I get a hang of what needs doing; and then I’ll recreate it for real later. This also means, I will be going with defaults for most of the settings as the aim is to get the two talking to each other as quickly as possible.<\/em><\/p>\n

Cosmos DB<\/h3>\n

First off, creating a Cosmos DB account. I want a NoSQL one, this is just for storing a bunch of JSON files. I don’t need high performance etc. currently, so it’s mostly going to be default settings. Serverless.<\/p>\n

\"\"<\/p>\n

\"\"<\/p>\n

This is a helpful document<\/a> to understand the elements of Cosmos DB.<\/p>\n

\"Diagram<\/p>\n

The database account contains a database, which in turn contains one or more containers, which contain the items.<\/p>\n

\"Diagram<\/p>\n

(Both images are from the article I linked to above). Note that what a “database”, “container”, or “item” actually refers to depends on what type of Cosmos DB is in use.
\n<\/em><\/p>\n

Once it is created, I will create a container.<\/p>\n

\"\"<\/p>\n

After clicking “Add Container” I am presented with the following screen. I fill it thus:<\/p>\n\n\n\n
I have to give a Database id – the name of the database, basically. I will call it “rakcosmosdb”. Within the Cosmos DB account I can have more than one database<\/em>.<\/p>\n

I have to give a Container id. I will call this “appRegistrations-Prod”. This contain will contain a bunch of App Registrations, and will be used by my production instance – hence I name it that way.<\/p>\n

Finally, for the partition key I will choose “objectId”. I know this is a property that exists in the App Registration. It is unique. And using this Cosmos can distribute the data efficiently.<\/td>\n

\"\"<\/p>\n

 <\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n

The result is the following.<\/p>\n

\"\"<\/p>\n

Azure Function<\/h3>\n

Next, I’ll create the Azure Function App. Again, this is just a basic setup, going with the defaults.<\/p>\n

\"\"<\/p>\n

Go through the rest of the screens and create the Function App.<\/p>\n

I found this overview document<\/a> that I am going to follow now.<\/p>\n

First off, it’s for Function runtime versions 2.x and above; and using extension bundle 4.x. Looks like I am on 4.x runtime, so that’s good.<\/p>\n

\"\"<\/p>\n

Now for extension bundles<\/a>.<\/p>\n

Something to note<\/a>, only Cosmos DB for NoSQL is supported via extensions in Azure Functions. Cosmos DB for Table too is supported via Table bindings<\/a>; for the rest one must use other ways. Let’s go with version 4.x of the extension. I need to add the following code to host.json<\/code>.<\/p>\n

{\r\n  \"version\": \"2.0\",\r\n  \"extensionBundle\": {\r\n    \"id\": \"Microsoft.Azure.Functions.ExtensionBundle.Preview\",\r\n    \"version\": \"[4.0.0, 5.0.0)\"\r\n  }\r\n}<\/pre>\n

The host.json<\/code> can be found under the App Files section. Here’s the default as of now:<\/p>\n

{\r\n  \"version\": \"2.0\",\r\n  \"managedDependency\": {\r\n    \"Enabled\": true\r\n  },\r\n  \"extensionBundle\": {\r\n    \"id\": \"Microsoft.Azure.Functions.ExtensionBundle\",\r\n    \"version\": \"[3.*, 4.0.0)\"\r\n  }\r\n}<\/pre>\n

I must replace the highlighted section.<\/p>\n

{\r\n  \"version\": \"2.0\",\r\n  \"managedDependency\": {\r\n    \"Enabled\": true\r\n  },\r\n  \"extensionBundle\": {\r\n    \"id\": \"Microsoft.Azure.Functions.ExtensionBundle.Preview\",\r\n    \"version\": \"[4.0.0, 5.0.0)\"\r\n  }\r\n}<\/pre>\n

Next, I think I have to add the following<\/a> too to host.json<\/code>:<\/p>\n

{\r\n    \"version\": \"2.0\",\r\n    \"extensions\": {\r\n        \"cosmosDB\": {\r\n            \"connectionMode\": \"Gateway\",\r\n            \"userAgentSuffix\": \"MyDesiredUserAgentStamp\"\r\n        }\r\n    }\r\n}<\/pre>\n

I am not sure to be honest, let’s add and see. Here’s the final result:<\/p>\n

{\r\n  \"version\": \"2.0\",\r\n  \"managedDependency\": {\r\n    \"Enabled\": true\r\n  },\r\n  \"extensionBundle\": {\r\n    \"id\": \"Microsoft.Azure.Functions.ExtensionBundle.Preview\",\r\n    \"version\": \"[4.0.0, 5.0.0)\"\r\n  },\r\n  \"extensions\": {\r\n    \"cosmosDB\": {\r\n      \"connectionMode\": \"Gateway\",\r\n      \"userAgentSuffix\": \"rakfunction12334\"\r\n    }\r\n  }\r\n}<\/pre>\n

I set the userAgentSuffix<\/code> to something that identifies the Function App. Could have just used the Function App name.<\/p>\n

Now I will create an HTTP triggered function, just to test things out. Going with the default settings for now. After creating, I went to the Integration section and tried adding an output binding.<\/p>\n

\"\"<\/p>\n

Click on “Add output above. Select Cosmos DB:<\/p>\n

\"\"<\/p>\n

Click “New” to create a new connection:<\/p>\n

\"\"<\/p>\n

It shows my Cosmos DB already. I select that and click OK.<\/p>\n

\"\"<\/p>\n

Here’s what the screen looks like now:<\/p>\n

\"\"<\/p>\n

I will leave the document parameter name as is. From when I created the Cosmos DB account, I know my database name is “rakcosmosdb”. And the collection name is “appRegistrations-Prod”. Fill these and click OK.<\/p>\n

\"\"<\/p>\n

What the creation of a new connection has done is that it’s created the following in the Configuration section.<\/p>\n

\"\"<\/p>\n

This contains the connection string to the Cosmos DB.<\/p>\n

And in the Function itself, I now have the following in function.json<\/code>.<\/p>\n

{\r\n  \"bindings\": [\r\n    {\r\n      \"authLevel\": \"FUNCTION\",\r\n      \"type\": \"httpTrigger\",\r\n      \"direction\": \"in\",\r\n      \"name\": \"Request\",\r\n      \"methods\": [\r\n        \"get\",\r\n        \"post\"\r\n      ]\r\n    },\r\n    {\r\n      \"type\": \"http\",\r\n      \"direction\": \"out\",\r\n      \"name\": \"Response\"\r\n    },\r\n    {\r\n      \"name\": \"outputDocument\",\r\n      \"direction\": \"out\",\r\n      \"type\": \"cosmosDB\",\r\n      \"connectionStringSetting\": \"rakcosmosdb01224_DOCUMENTDB\",\r\n      \"databaseName\": \"rakcosmosdb\",\r\n      \"collectionName\": \"appRegistrations-Prod\"\r\n    }\r\n  ]\r\n}<\/pre>\n

Here’s what run.ps1<\/code> currently looks like:<\/p>\n

using namespace System.Net\r\n\r\n# Input bindings are passed in via param block.\r\nparam($Request, $TriggerMetadata)\r\n\r\n# Write to the Azure Functions log stream.\r\nWrite-Host \"PowerShell HTTP trigger function processed a request.\"\r\n\r\n# Interact with query parameters or the body of the request.\r\n$name = $Request.Query.Name\r\nif (-not $name) {\r\n    $name = $Request.Body.Name\r\n}\r\n\r\n$body = \"This HTTP triggered function executed successfully. Pass a name in the query string or in the request body for a personalized response.\"\r\n\r\nif ($name) {\r\n    $body = \"Hello, $name. This HTTP triggered function executed successfully.\"\r\n}\r\n\r\n# Associate values to output bindings by calling 'Push-OutputBinding'.\r\nPush-OutputBinding -Name Response -Value ([HttpResponseContext]@{\r\n    StatusCode = [HttpStatusCode]::OK\r\n    Body = $body\r\n})\r\n<\/pre>\n

Let me add something to write to the DB too.<\/p>\n

using namespace System.Net\r\n\r\n# Input bindings are passed in via param block.\r\nparam($Request, $TriggerMetadata)\r\n\r\n# Write to the Azure Functions log stream.\r\nWrite-Host \"PowerShell HTTP trigger function processed a request.\"\r\n\r\n# Interact with query parameters or the body of the request.\r\n$name = $Request.Query.Name\r\nif (-not $name) {\r\n    $name = $Request.Body.Name\r\n}\r\n\r\n$body = \"This HTTP triggered function executed successfully. Pass a name in the query string or in the request body for a personalized response.\"\r\n\r\nif ($name) {\r\n    $body = \"Hello, $name. This HTTP triggered function executed successfully.\"\r\n}\r\n\r\n$objectId = Get-Random -Minimum 60 -Maximum 300\r\nWrite-Host \"Writing $objectId to the DB\"\r\nPush-OutputBinding -Name outputDocument -Value\u202f@{ \r\n\u202f\u202f\u202f\u202fobjectId\u202f= $objectId\r\n\u202f\u202f\u202f\u202fname\u202f=\u202f\"Rakhesh\" \r\n} \r\n\r\n# Associate values to output bindings by calling 'Push-OutputBinding'.\r\nPush-OutputBinding -Name Response -Value ([HttpResponseContext]@{\r\n    StatusCode = [HttpStatusCode]::OK\r\n    Body = $body\r\n})\r\n<\/pre>\n

Then I clicked the Test\/Run button to see what happens.<\/p>\n

Hmm, not good.<\/p>\n

\"\"<\/p>\n

This stumped me for a while. Initially, I didn’t find anything additional in the “Monitor” section either; but after about 2-3 minutes<\/em> I found errors there too. And those had more details:<\/p>\n

\"\"<\/p>\n

This is “CosmosDB”, not “cosmosDB”. The latter is what was added to host.json<\/code> and function.json<\/code>. Where is it picking that from?<\/p>\n

Googling a bit, I came across this post<\/a>. Sounds like I have to use a Managed Identity? The bundle install page did say <\/a>v4.x introduces the ability to connect with a Managed Identity, but I figured that’s just an optional thing… especially since the portal itself created the connection string for me. But I guess not. I think once I use the 4.x version I must use a Managed Identity<\/a>.<\/p>\n

Ok, step 1<\/a> enable the identity for the Function App.<\/p>\n

\"\"<\/p>\n

Step 2<\/strong> grant it permissions<\/a>.<\/p>\n

\"\"<\/p>\n

What the heck, I need to create a role using the Cosmos DB built-in RBAC system? Can’t do that via the portal<\/a>! \ud83d\ude21<\/p>\n

So, open Cloud Shell. Switch to PowerShell.<\/p>\n

I know the id of my Function App Managed Identity from the portal as it’s shown on the screen.<\/p>\n

\"\"<\/p>\n

But just in case I didn’t want to lookup via the portal, I can use the following to find it:<\/p>\n

> Get-AzADServicePrincipal -DisplayName \"rakcosmostest12334\"\r\n\r\nDisplayName        Id                                   AppId\r\n-----------        --                                   -----\r\nrakcosmostest12334 8509455c-b382-4926-8e5d-f3ce934fbd37 2fe04331-f008-42f1-9c5c-e26796b9ea84<\/pre>\n

I found the following snippet in the RBAC document<\/a>:<\/p>\n

$resourceGroupName = \"<myResourceGroup>\"\r\n$accountName = \"<myCosmosAccount>\"\r\n$readOnlyRoleDefinitionId = \"<roleDefinitionId>\" # as fetched above\r\n# For Service Principals make sure to use the Object ID as found in the Enterprise applications section of the Azure Active Directory portal blade.\r\n$principalId = \"<aadPrincipalId>\"\r\nNew-AzCosmosDBSqlRoleAssignment -AccountName $accountName `\r\n    -ResourceGroupName $resourceGroupName `\r\n    -RoleDefinitionId $readOnlyRoleDefinitionId `\r\n    -Scope \"\/\" `\r\n    -PrincipalId $principalId<\/pre>\n

Before I fill that I need to get the role definition Id. I know I want the Cosmos DB Built-in Data Contributor<\/a> role.<\/p>\n

> Get-AzCosmosDBSqlRoleDefinition -AccountName rakcosmosdb01224 -ResourceGroupName cosmosdbtest\r\n\r\nId                         : \/subscriptions\/71e7c041-1d56-44bb-a7d3-08b475bd5e44\/resourceGroups\/cosmosdbtest\/providers\/Microsoft.DocumentDB\/databaseAccounts\/rakcosmosdb01224\/s\r\n                             qlRoleDefinitions\/00000000-0000-0000-0000-000000000001\r\nRoleName                   : Cosmos DB Built-in Data Reader\r\nType                       : BuiltInRole\r\nAssignableScopes           : {\/subscriptions\/71e7c041-1d56-44bb-a7d3-08b475bd5e44\/resourceGroups\/cosmosdbtest\/providers\/Microsoft.DocumentDB\/databaseAccounts\/rakcosmosdb01224}\r\nPermissions.DataActions    : {Microsoft.DocumentDB\/databaseAccounts\/readMetadata, Microsoft.DocumentDB\/databaseAccounts\/sqlDatabases\/containers\/executeQuery, \r\n                             Microsoft.DocumentDB\/databaseAccounts\/sqlDatabases\/containers\/readChangeFeed, \r\n                             Microsoft.DocumentDB\/databaseAccounts\/sqlDatabases\/containers\/items\/read}\r\nPermissions.NotDataActions : \r\n\r\nId                         : \/subscriptions\/71e7c041-1d56-44bb-a7d3-08b475bd5e44\/resourceGroups\/cosmosdbtest\/providers\/Microsoft.DocumentDB\/databaseAccounts\/rakcosmosdb01224\/s\r\n                             qlRoleDefinitions\/00000000-0000-0000-0000-000000000002\r\nRoleName                   : Cosmos DB Built-in Data Contributor\r\nType                       : BuiltInRole\r\nAssignableScopes           : {\/subscriptions\/71e7c041-1d56-44bb-a7d3-08b475bd5e44\/resourceGroups\/cosmosdbtest\/providers\/Microsoft.DocumentDB\/databaseAccounts\/rakcosmosdb01224}\r\nPermissions.DataActions    : {Microsoft.DocumentDB\/databaseAccounts\/readMetadata, Microsoft.DocumentDB\/databaseAccounts\/sqlDatabases\/containers\/*, \r\n                             Microsoft.DocumentDB\/databaseAccounts\/sqlDatabases\/containers\/items\/*}\r\nPermissions.NotDataActions :<\/pre>\n

Now I have:<\/p>\n

$resourceGroupName = \"cosmosdbtest\"\r\n$accountName = \"rakcosmosdb01224\"\r\n$readOnlyRoleDefinitionId = \"\/subscriptions\/71e7c041-1d56-44bb-a7d3-08b475bd5e44\/resourceGroups\/cosmosdbtest\/providers\/Microsoft.DocumentDB\/databaseAccounts\/rakcosmosdb01224\/sqlRoleDefinitions\/00000000-0000-0000-0000-000000000002\" # as fetched above\r\n# For Service Principals make sure to use the Object ID as found in the Enterprise applications section of the Azure Active Directory portal blade.\r\n$principalId = \"8509455c-b382-4926-8e5d-f3ce934fbd37\"\r\nNew-AzCosmosDBSqlRoleAssignment -AccountName $accountName `\r\n    -ResourceGroupName $resourceGroupName `\r\n    -RoleDefinitionId $readOnlyRoleDefinitionId `\r\n    -Scope \"\/\" `\r\n    -PrincipalId $principalId<\/pre>\n

Copy paste that into the Cloud Shell, wait up to a minute (coz it just hung for me), and boom its in place!<\/p>\n

\"\"<\/p>\n

And finally, step 3<\/strong>, add these to the app settings<\/a>. I replaced the existing connection string that was automatically created, with this:<\/p>\n

\"\"<\/p>\n

The “rakcosmosdb01224_DOCUMENTDB” part is my connection string in function.json<\/code>. To that I added two underscores, and the word “credential”. And changed the value to “managedidentity”.<\/p>\n

I think that’s all I need, coz according to the doc<\/a> the other two are optional if I am using the system managed identity.<\/p>\n

Did that work? Now I got a different error, but that’s a good thing I think:<\/p>\n

\"\"<\/p>\n

I know what to do for this. It’s the missing module. In the App Files section I must edit requirements.psd1<\/code> and uncomment the line for the Az module.<\/p>\n

# This file enables modules to be automatically managed by the Functions service.\r\n# See https:\/\/aka.ms\/functionsmanageddependency for additional information.\r\n#\r\n@{\r\n    # For latest supported version, go to 'https:\/\/www.powershellgallery.com\/packages\/Az'. \r\n    # To use the Az module in your function app, please uncomment the line below.\r\n    'Az' = '10.*'\r\n}\r\n<\/pre>\n

Restart the Function App after that, and let’s try again.<\/p>\n

\"\"<\/p>\n

Waiting… \ud83e\udd43<\/p>\n

Still waiting… \ud83e\udd43\ud83d\ude34<\/p>\n

\ud83e\udd71<\/p>\n

\"\"<\/p>\n

Sighs.<\/p>\n

Let’s try again.<\/p>\n

This is the part I hate with Function Apps and modules. The first few times are a torture while it downloads.<\/p>\n

I did the Test\/Run again and it’s again downloading.<\/p>\n

Finally it succeeded. But it kept erroring upon pushing. Same error:<\/p>\n

\"\"<\/p>\n

I remember this being a PITA when I was figuring out Managed Identities and Event Hubs<\/a> in the past. I tried to read up on the extenstion itself and found this blog post introducing it<\/a>. So I need a second setting: rakcosmosdb01224_DOCUMENTDB__accountEndpoint<\/code> with value https:\/\/rakcosmosdb01224.documents.azure.com:443\/<\/code>.<\/p>\n

Silly me, of course it needs to know the details of the Cosmos DB account. Previously this was in the connection string I deleted.<\/p>\n

Added these. Saved.<\/p>\n

\"\"<\/p>\n

Try again!<\/p>\n

\"\"<\/p>\n

\ud83e\udd2c<\/p>\n

Still no luck, after that completes. What the heck.<\/p>\n

Ooh, one more thing from the blog post<\/a>.<\/p>\n

\"\"<\/p>\n

Huh. Ok, so I rename that in function.json<\/code>.<\/p>\n

\"\"<\/p>\n

Almost missed above, “Anything named Collection is now Container<\/em>“. This one’s my bad, it is there in the docs I was following too<\/a>. (And I realized, further below in the docs<\/a>, outside of the example given, they do use “connection” instead of “connectionStringSetting”).<\/p>\n

{\r\n  \"bindings\": [\r\n    {\r\n      \"authLevel\": \"FUNCTION\",\r\n      \"type\": \"httpTrigger\",\r\n      \"direction\": \"in\",\r\n      \"name\": \"Request\",\r\n      \"methods\": [\r\n        \"get\",\r\n        \"post\"\r\n      ]\r\n    },\r\n    {\r\n      \"type\": \"http\",\r\n      \"direction\": \"out\",\r\n      \"name\": \"Response\"\r\n    },\r\n    {\r\n      \"name\": \"outputDocument\",\r\n      \"direction\": \"out\",\r\n      \"type\": \"cosmosDB\",\r\n      \"connection\": \"rakcosmosdb01224_DOCUMENTDB\",\r\n      \"databaseName\": \"rakcosmosdb\",\r\n      \"containerName\": \"appRegistrations-Prod\"\r\n    }\r\n  ]\r\n}<\/pre>\n

Screenshot of the v4.x settings:<\/p>\n

\"\"<\/p>\n

And… test!<\/p>\n

Still I get the error.<\/p>\n

Here’s a thought, maybe it’s not happy with the connection string name? Let me change it from “rakcosmosdb01224_DOCUMENTDB” to “rakcosmosdb01224” both in function.json<\/code> and the two configuration settings.<\/p>\n

\"\"<\/p>\n

Nope, no luck.<\/p>\n

And then I noticed a weird thing. Even though I had updated function.json<\/code>, when I went to a different page and came back the changes had reverted. Huh. It wasn’t a one-time – I tried it couple of times with the same result.<\/p>\n

So I removed the following from the file (this is in the incorrect bit):<\/p>\n

    {\r\n      \"name\": \"outputDocument\",\r\n      \"direction\": \"out\",\r\n      \"type\": \"cosmosDB\",\r\n      \"connectionStringSetting\": \"rakcosmosdb01224\",\r\n      \"databaseName\": \"rakcosmosdb\",\r\n      \"collectionName\": \"appRegistrations-Prod\"\r\n    }<\/pre>\n

Saved it. Went to the Integration section. Ensured it’s removed, and then I added it back correctly.<\/p>\n

    {\r\n      \"name\": \"outputDocument\",\r\n      \"direction\": \"out\",\r\n      \"type\": \"cosmosDB\",\r\n      \"connection\": \"rakcosmosdb01224\",\r\n      \"databaseName\": \"rakcosmosdb\",\r\n      \"containerName\": \"appRegistrations-Prod\"\r\n    }<\/pre>\n

Oddly, this time when I ran the Function it didn’t complain… but looks like everything I added to function.json<\/code> disappeared. What the heck. When I ran the Function again it complained that [Error] ERROR: The specified name ‘outputDocument’ cannot be resolved to a valid output binding of this function.<\/em><\/p>\n

I don’t know what’s going on here. I repeated the steps, and again it kept disappearing.<\/p>\n

At this point I am just going to delete the Function and recreate it. Not the Function App, just the Function. Here’s the code as a backup:<\/p>\n

using namespace System.Net\r\n\r\n# Input bindings are passed in via param block.\r\nparam($Request, $TriggerMetadata)\r\n\r\n# Write to the Azure Functions log stream.\r\nWrite-Host \"PowerShell HTTP trigger function processed a request.\"\r\n\r\n# Interact with query parameters or the body of the request.\r\n$name = $Request.Query.Name\r\nif (-not $name) {\r\n    $name = $Request.Body.Name\r\n}\r\n\r\n$body = \"This HTTP triggered function executed successfully. Pass a name in the query string or in the request body for a personalized response.\"\r\n\r\nif ($name) {\r\n    $body = \"Hello, $name. This HTTP triggered function executed successfully.\"\r\n}\r\n\r\n$objectId = Get-Random -Minimum 60 -Maximum 300\r\nWrite-Host \"Writing $objectId to the DB\"\r\nPush-OutputBinding -Name outputDocument -ErrorAction Stop -Value\u202f@{ \r\n    objectId\u202f= $objectId\r\n    name\u202f=\u202f\"Rakhesh\" \r\n} \r\n\r\n# Associate values to output bindings by calling 'Push-OutputBinding'.\r\nPush-OutputBinding -Name Response -Value ([HttpResponseContext]@{\r\n    StatusCode = [HttpStatusCode]::OK\r\n    Body = $body\r\n})<\/pre>\n

Ok, new Function created. Copy pasted the stuff. But nope, now it complains it cannot find the output binding! Coz it has disappeared.<\/p>\n

If I re-add it, restart the Function App, the part I added stays. Yet, doing a Test\/Run seems to nuke it.<\/p>\n

At this point I went into a stupid cycle of copy pasting it again, trying to restart the Function App a few times etc… until I think I finally made it stick. I have no idea what I did. It was just stupid persistence and frustration I think.<\/p>\n

On the plus side, now that it sticks, while the console continues to give an error the message different.<\/p>\n

Response status code does not indicate success: BadRequest (400); Substatus: 0; ActivityId: fb0616b6-9c09-4be9-bb3f-0b6c034c4ae9; Reason: (Message: {“Errors”:[“One of the specified inputs is invalid”]} ActivityId: fb0616b6-9c09-4be9-bb3f-0b6c034c4ae9, Request URI: \/apps\/0b12014b-f854-44a4-8f6f-c5cedc3481fe\/services\/4919abae-b1f5-4b75-9186-772877134ddd\/partitions\/78009af3-c91e-4793-b1f9-77ad07aa126b\/replicas\/133345776092212266p\/, RequestStats: RequestStartTime: 2023-07-23T19:08:18.6420113Z, RequestEndTime: 2023-07-23T19:08:18.6435872Z, Number of regions attempted…<\/p><\/blockquote>\n

A quick Google pointed me to the answer<\/a>: I should be adding an Id property, of type string.<\/p>\n

Push-OutputBinding -Name outputDocument -ErrorAction Stop -Value\u202f@{\r\n    id = \"$objectId\"\r\n    objectId\u202f= $objectId\r\n    name\u202f=\u202f\"Rakhesh\" \r\n}<\/pre>\n

Did that, and finally finally finally it works!<\/p>\n

\"\"<\/p>\n

Phew.<\/p>\n

To Summarize?<\/h3>\n

I’ve lost the plot of things I did here. \ud83d\ude03 So here’s a summary for next time:<\/p>\n