Skip to content

Instantly share code, notes, and snippets.

@RylandDeGregory
Created November 11, 2023 14:12
Show Gist options
  • Save RylandDeGregory/ab21955d990a5f6ff649c29d34cca858 to your computer and use it in GitHub Desktop.
Save RylandDeGregory/ab21955d990a5f6ff649c29d34cca858 to your computer and use it in GitHub Desktop.
Azure Cosmos DB (NoSQL API) REST operations using PowerShell.
function New-MasterKeyAuthorizationSignature {
<#
.SYNOPSIS
Generate Cosmos DB Master Key Authentication header for use with the NoSQL REST API.
.EXAMPLE
$AuthKeyParams = @{
Method = Post
ResourceId = "dbs/$DatabaseId/colls/$CollectionId"
Date = [DateTime]::UtcNow.ToString('r')
MasterKey = $MasterKey
}
$AuthorizationKey = New-MasterKeyAuthorizationSignature @AuthKeyParams
#>
[OutputType([string])]
[CmdletBinding()]
param (
[Parameter(Mandatory)]
[ValidateSet(
'Get',
'Post',
'Put',
'Patch',
'Delete'
)]
[string] $Method,
[Parameter(Mandatory)]
[string] $ResourceId,
[Parameter()]
[string] $ResourceType = 'docs',
[Parameter(Mandatory)]
[string] $Date,
[Parameter(Mandatory)]
[string] $MasterKey
)
$KeyType = 'master'
$TokenVersion = '1.0'
$SigningString = "$($Method.ToLower())`n$($ResourceType.ToLower())`n$ResourceId`n$($Date.ToString().ToLower())`n`n"
$HmacSha = [System.Security.Cryptography.HMACSHA256]@{ Key = [Convert]::FromBase64String($MasterKey) }
$Signature = [Convert]::ToBase64String($HmacSha.ComputeHash([Text.Encoding]::UTF8.GetBytes($SigningString)))
$AuthorizationString = [System.Web.HttpUtility]::UrlEncode('type=' + $KeyType + '&ver=' + $TokenVersion + '&sig=' + $Signature)
$HmacSha.Dispose()
return $AuthorizationString
}
function New-Sha256HashedString {
<#
.SYNOPSIS
Generate the SHA256 hash of a string
.EXAMPLE
New-Sha256HashedString -String 'Hello'
#>
[OutputType([string])]
[CmdletBinding()]
param (
[Parameter(Mandatory)]
[string] $String
)
$Sha256 = [System.Security.Cryptography.HashAlgorithm]::Create('SHA256')
$HashedBytes = $Sha256.ComputeHash([Text.Encoding]::UTF8.GetBytes($String))
$HashedString = [BitConverter]::ToString($HashedBytes) -replace '-', ''
$Sha256.Dispose()
return $HashedString.ToLower()
}
function New-CosmosDocument {
<#
.SYNOPSIS
Create a new Cosmos DB NoSQL API document using the REST API. Uses Master Key Authentication.
.LINK
New-MasterKeyAuthorizationSignature
.EXAMPLE
$NewDocParams = @{
Endpoint = 'https://xxxxx.documents.azure.com:443/'
MasterKey = $MasterKey
ResourceId = "dbs/$DatabaseId/colls/$CollectionId"
PartitionKey = $PartitionKey
PartitionKeyValue = $PartitionKeyValue
Document = @{property1 = 'value1'; property2 = @('value1', 'value2')} ## Any valid PSObject
}
New-CosmosDocument @NewDocParams
#>
[CmdletBinding()]
param (
[Parameter(Mandatory)]
[string] $Endpoint,
[Parameter(Mandatory)]
[string] $MasterKey,
[Parameter(Mandatory)]
[string] $ResourceId,
[Parameter()]
[string] $ResourceType = 'docs',
[Parameter(Mandatory)]
[string] $PartitionKey,
[Parameter(Mandatory)]
[string] $PartitionKeyValue,
[Parameter(Mandatory)]
[psobject] $Document,
# Whether to treat the insert operation as an update
# if the Document ID already exists in the Collection
[Parameter()]
[boolean] $IsUpsert = $true
)
# Calculate current date for use in Authorization header
$Date = [DateTime]::UtcNow.ToString('r')
# Compute Authorization header value and define headers dictionary
$AuthorizationKey = New-MasterKeyAuthorizationSignature -Method Post -ResourceId $ResourceId -Date $Date -MasterKey $MasterKey
$Headers = @{
'accept' = 'application/json'
'authorization' = $AuthorizationKey
'cache-control' = 'no-cache'
'content-type' = 'application/json'
'x-ms-date' = $Date
'x-ms-documentdb-partitionkey' = "[`"$PartitionKeyValue`"]"
'x-ms-version' = '2018-12-31'
}
if ($IsUpsert) {
$Headers += @{'x-ms-documentdb-is-upsert' = $true}
}
# Add Partition Key
Add-Member -InputObject $Document -MemberType NoteProperty -Name $PartitionKey -Value $PartitionKeyValue
# Add Document ID
if ($Document.id) { $Document.PSObject.Properties.Remove('id') }
$DocumentId = New-Sha256HashedString -String ($Document | ConvertTo-Json -Depth 15) # Use any deterministic value
Add-Member -InputObject $Document -MemberType NoteProperty -Name 'id' -Value $DocumentId
# Send request to NoSQL REST API
try {
$Response = Invoke-RestMethod -Uri "$Endpoint$ResourceId/$ResourceType" -Headers $Headers -Method Post -Body ($Document | ConvertTo-Json -Depth 15)
@{
id = $Response.id
$PartitionKey = $Response.$PartitionKey
etag = $Response.'_etag'
timestamp = $Response.'_ts'
}
} catch {
Write-Error "StatusCode: $($_.Exception.Response.StatusCode.value__) | ExceptionMessage: $($_.Exception.Message) | $_"
}
}
function Get-CosmosDocument {
<#
.SYNOPSIS
Retrieve a Cosmos DB NoSQL API document by ID using the REST API. Uses Master Key Authentication.
.LINK
New-MasterKeyAuthorizationSignature
.EXAMPLE
$GetDocParams = @{
Endpoint = 'https://xxxxx.documents.azure.com:443/'
MasterKey = $MasterKey
ResourceId = "dbs/$DatabaseId/colls/$CollectionId"
DocumentId = $DocumentId
PartitionKeyValue = $PartitionKeyValue
}
Get-CosmosDocument @GetDocParams
#>
[CmdletBinding()]
param (
[Parameter(Mandatory)]
[string] $Endpoint,
[Parameter(Mandatory)]
[string] $MasterKey,
[Parameter(Mandatory)]
[string] $ResourceId,
[Parameter(Mandatory)]
[string] $DocumentId,
[Parameter()]
[string] $ResourceType = 'docs',
[Parameter(Mandatory)]
[string] $PartitionKeyValue
)
# Calculate current date for use in Authorization header
$Date = [DateTime]::UtcNow.ToString('r')
# Compute Authorization header value and define headers dictionary
$AuthorizationKey = New-MasterKeyAuthorizationSignature -Method Get -ResourceId "$ResourceId/$ResourceType/$DocumentId" -Date $Date -MasterKey $MasterKey
$Headers = @{
'accept' = 'application/json'
'authorization' = $AuthorizationKey
'cache-control' = 'no-cache'
'content-type' = 'application/json'
'x-ms-date' = $Date
'x-ms-documentdb-partitionkey' = "[`"$PartitionKeyValue`"]"
'x-ms-version' = '2018-12-31'
}
# Send request to NoSQL REST API
try {
Invoke-RestMethod -Uri "$Endpoint$ResourceId/$ResourceType/$DocumentId" -Headers $Headers -Method Get
} catch {
Write-Error "StatusCode: $($_.Exception.Response.StatusCode.value__) | ExceptionMessage: $($_.Exception.Message) | $_"
}
}
function Remove-CosmosDocument {
<#
.SYNOPSIS
Remove a Cosmos DB NoSQL API document using the REST API. Uses Master Key Authentication.
.LINK
New-CFCosmosMasterKeyAuthorizationSignature
.EXAMPLE
$RemoveDocParams = @{
Endpoint = 'https://xxxxx.documents.azure.com:443/'
MasterKey = $MasterKey
ResourceId = "dbs/$DatabaseId/colls/$CollectionId"
PartitionKeyValue = $PartitionKeyValue
DocumentId = $DocumentId
}
Remove-CosmosDocument @RemoveDocParams
#>
[CmdletBinding()]
param (
[Parameter(Mandatory)]
[string] $Endpoint,
[Parameter(Mandatory)]
[string] $MasterKey,
[Parameter(Mandatory)]
[string] $ResourceId,
[Parameter()]
[string] $ResourceType = 'docs',
[Parameter(Mandatory)]
[string] $PartitionKeyValue,
[Parameter(Mandatory)]
[string] $DocumentId
)
# Calculate current date for use in Authorization header
$Date = [DateTime]::UtcNow.ToString('r')
# Compute Authorization header value and define headers dictionary
$AuthorizationKey = New-MasterKeyAuthorizationSignature -Method Delete -ResourceId "$ResourceId/$ResourceType/$DocumentId" -Date $Date -MasterKey $MasterKey
$Headers = @{
'accept' = 'application/json'
'authorization' = $AuthorizationKey
'cache-control' = 'no-cache'
'content-type' = 'application/json'
'x-ms-date' = $Date
'x-ms-documentdb-partitionkey' = "[`"$PartitionKeyValue`"]"
'x-ms-version' = '2018-12-31'
}
# Send request to NoSQL REST API
try {
Invoke-RestMethod -Uri "$Endpoint$ResourceId/$ResourceType/$DocumentId" -Headers $Headers -Method Delete
} catch {
Write-Error "StatusCode: $($_.Exception.Response.StatusCode.value__) | ExceptionMessage: $($_.Exception.Message) | $_"
}
}
function Search-CosmosDocuments {
<#
.SYNOPSIS
Retrieve one or more Cosmos DB NoSQL API documents by query using the REST API. Uses Master Key Authentication.
.LINK
New-MasterKeyAuthorizationSignature
.EXAMPLE
$Query = @{
query = 'SELECT * FROM c WHERE c[@PartitionKey] = @PartitionKeyValue'
parameters = @(
@{
name = '@PartitionKey'
value = $PartitionKey
}
@{
name = '@PartitionKeyValue'
value = $PartitionKeyValue
}
)
}
$QueryDocParams = @{
Endpoint = 'https://xxxxx.documents.azure.com:443/'
MasterKey = $MasterKey
ResourceId = "dbs/$DatabaseId/colls/$CollectionId"
Query = $Query
}
Search-CosmosDocuments @QueryDocParams
#>
[CmdletBinding()]
param (
[Parameter(Mandatory)]
[string] $Endpoint,
[Parameter(Mandatory)]
[string] $MasterKey,
[Parameter(Mandatory)]
[string] $ResourceId,
[Parameter()]
[string] $ResourceType = 'docs',
[Parameter(Mandatory)]
[psobject] $Query
)
# Calculate current date for use in Authorization header
$Date = [DateTime]::UtcNow.ToString('r')
# Compute Authorization header value and define headers dictionary
$AuthorizationKey = New-MasterKeyAuthorizationSignature -Method Post -ResourceId $ResourceId -Date $Date -MasterKey $MasterKey
$Headers = @{
'accept' = 'application/json'
'authorization' = $AuthorizationKey
'cache-control' = 'no-cache'
'content-type' = 'application/query+json'
'x-ms-date' = $Date
'x-ms-documentdb-isquery' = 'True'
'x-ms-documentdb-query-enablecrosspartition' = 'True'
'x-ms-version' = '2018-12-31'
}
# Send request to NoSQL REST API
try {
Invoke-RestMethod -Uri "$Endpoint$ResourceId/$ResourceType" -Headers $Headers -Method Post -Body ($Query | ConvertTo-Json)
} catch {
Write-Error "StatusCode: $($_.Exception.Response.StatusCode.value__) | ExceptionMessage: $($_.Exception.Message) | $_"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment