Microsoft.Azure.Cosmos.Samples/Usage/PowerShellRestApi/PowerShellScripts/MigrateToAnalyticalStore.ps1 (131 lines of code) (raw):
#Requires -Version 7
#Requires -Module Az.CosmosDB
# Note: Analytical migration is in preview, so this script will only work if your Cosmos DB account is opted into the preview.
# This script requires PowerShell 7.0.0 or higher.
param(
[Parameter(Mandatory = $True, Position = 0, ValueFromPipeline = $false)]
[System.String]
$SubscriptionId,
[Parameter(Mandatory = $True, Position = 1, ValueFromPipeline = $false)]
[System.String]
$ResourceGroupName,
[Parameter(Mandatory = $True, Position = 2, ValueFromPipeline = $false)]
[System.String]
$AccountName,
[Parameter(Mandatory = $True, Position = 3, ValueFromPipeline = $false)]
[System.String]
$DatabaseName,
[Parameter(Mandatory = $True, Position = 4, ValueFromPipeline = $false)]
[System.String]
$ContainerName,
[Parameter(Mandatory = $False, Position = 5, ValueFromPipeline = $false)]
[int]
$NewAnalyticalTTL = -1,
# The progress on the backend is updated every 60 seconds.
# PollingIntervalInSeconds is how often we want to fetch this value from the backend (any less than 60 is redundant).
[Parameter(Mandatory = $False, Position = 6, ValueFromPipeline = $false)]
[int]
$PollingIntervalInSeconds = 60
)
Add-Type -AssemblyName System.Web
# First, check if EnableAnalyticalStorage is true. If not, enable it.
Write-Host "Checking if EnableAnalyticalStorage is true..."
$result = Connect-AzAccount
$result = Select-AzSubscription -Subscription $SubscriptionId
$AccountInfo = Get-AzCosmosDBAccount -ResourceGroupName $ResourceGroupName -Name $AccountName
if (!$AccountInfo.EnableAnalyticalStorage) {
Write-Host "Setting EnableAnalyticalStorage capability to true..."
$result = Update-AzCosmosDBAccount -ResourceGroupName $ResourceGroupName -Name $AccountName -EnableAnalyticalStorage 1
}
Write-Host "EnableAnalyticalStorage capability is true."
# Get the account key and endpoint.
$result = Get-AzCosmosDBAccountKey -ResourceGroupName $ResourceGroupName -Name $AccountName
$MasterKey = $result["PrimaryMasterKey"]
$result = Get-AzCosmosDBAccount -ResourceGroupName $ResourceGroupName -Name $AccountName
$Endpoint = $result.DocumentEndpoint
$containerResourceLink = "dbs/" + $DatabaseName + "/colls/" + $ContainerName
$requestUri = "$Endpoint$containerResourceLink"
Function New-MasterKeyAuthorizationSignature {
[CmdletBinding()]
param (
[string] $Verb,
[string] $ResourceId,
[string] $ResourceType,
[string] $Date,
[string] $MasterKey,
[String] $KeyType,
[String] $TokenVersion
)
$keyBytes = [System.Convert]::FromBase64String($MasterKey)
$sigCleartext = @($Verb.ToLower() + "`n" + $ResourceType.ToLower() + "`n" + $ResourceId + "`n" + $Date.ToString().ToLower() + "`n" + "" + "`n")
$bytesSigClear = [Text.Encoding]::UTF8.GetBytes($sigCleartext)
$hmacsha = new-object -TypeName System.Security.Cryptography.HMACSHA256 -ArgumentList (, $keyBytes)
$hash = $hmacsha.ComputeHash($bytesSigClear)
$signature = [System.Convert]::ToBase64String($hash)
$key = [System.Web.HttpUtility]::UrlEncode('type=' + $KeyType + '&ver=' + $TokenVersion + '&sig=' + $signature)
return $key
}
Function Get-Header {
[CmdletBinding()]
param (
[string] $Verb,
[string] $MasterKey,
[string] $DatabaseName,
[string] $ContainerName
)
$date = Get-Date
$utcDate = $date.ToUniversalTime()
$xDate = $utcDate.ToString('r', [System.Globalization.CultureInfo]::InvariantCulture)
$KeyType = "master"
$TokenVersion = "1.0"
$containerResourceType = "colls"
$containerResourceId = "dbs/" + $DatabaseName + "/colls/" + $ContainerName
$userAgent = "PowerShell-MigrateToAnalyticalStore"
$authKey = New-MasterKeyAuthorizationSignature -Verb $Verb -ResourceId $containerResourceId -ResourceType $containerResourceType -Date $xDate -MasterKey $MasterKey -KeyType $KeyType -TokenVersion $TokenVersion -ErrorAction Stop
$header = @{
"authorization" = "$authKey";
"x-ms-version" = "2018-12-31";
"Cache-Control" = "no-cache";
"x-ms-date" = "$xDate";
"Accept" = "application/json";
"User-Agent" = "$userAgent";
}
return $header
}
# Step 1: Collection read to get the existing indexing policy.
$verbMethod = "GET"
$header = Get-Header -Verb $verbMethod -MasterKey $MasterKey -DatabaseName $DatabaseName -ContainerName $ContainerName
$header.add("x-ms-cosmos-populate-analytical-migration-progress", "true")
$responseHeaders = $null
$result = Invoke-RestMethod -Uri $requestUri -Headers $header -Method $verbMethod -ContentType "application/json" -ResponseHeadersVariable responseHeaders
if(!$result.analyticalStorageTtl) {
$result | Add-Member -MemberType NoteProperty -Name "analyticalStorageTtl" -Value $NewAnalyticalTTL -Force
$body = $result | ConvertTo-Json -Depth 20
# Step 2: Collection replace to trigger analytical migration.
$verbMethod = "PUT"
$header = Get-Header -Verb $verbMethod -MasterKey $MasterKey -DatabaseName $DatabaseName -ContainerName $ContainerName
$result = Invoke-RestMethod -Uri $requestUri -Headers $header -Method $verbMethod -ContentType "application/json" -Body $body
Write-Host "Analytical migration has been triggered and is pending."
}
else {
$Progress = $responseHeaders["x-ms-cosmos-analytical-migration-progress"]
if($Progress -eq "100") {
Write-Host "Migration is already complete."
return
}
}
# Step 3: Wait for analytical migration progress to reach 100%.
Write-Host "Polling for progress..."
while ($true) {
$verbMethod = "GET"
$header = Get-Header -Verb $verbMethod -MasterKey $MasterKey -DatabaseName $DatabaseName -ContainerName $ContainerName
$header.add("x-ms-cosmos-populate-analytical-migration-progress", "true")
$result = Invoke-RestMethod -Uri $requestUri -Headers $header -Method $verbMethod -ContentType "application/json" -ResponseHeadersVariable responseHeaders
$Progress = $responseHeaders["x-ms-cosmos-analytical-migration-progress"]
Write-Host "$(Get-Date) - Progress = $Progress%"
if ($Progress -eq "100") {
Write-Host "Migration complete."
return
}
Start-Sleep -s $PollingIntervalInSeconds
}