@@ -30,7 +30,7 @@ Function Get-DocumentsUrl([string]$Container, [string]$Collection, [string]$Reco
3030 $encodedRecordId = [uri ]::EscapeDataString($RecordId )
3131
3232 return @ {
33- ApiUrl = " $collectionsUrl /$DOCS_TYPE /$encodedRecordId " ;
33+ ApiUrl = " $collectionsUrl /$DOCS_TYPE /$encodedRecordId " ;
3434 ResourceUrl = " $collectionsUrl /$DOCS_TYPE /$RecordId " ;
3535 }
3636}
@@ -61,20 +61,36 @@ Function Set-CacheValue([string]$key, $value, [hashtable]$cache, [int]$expiratio
6161}
6262
6363Function Get-Base64Masterkey ([string ]$ResourceGroup , [string ]$Database , [string ]$SubscriptionId ) {
64- $cacheKey = " $SubscriptionId /$ResourceGroup /$Database "
64+ $readonly = $env: COSMOS_DB_FLAG_ENABLE_READONLY_KEYS -eq 1
65+
66+ $cacheKey = " $SubscriptionId /$ResourceGroup /$Database /$readonly "
6567 $cacheResult = Get-CacheValue - Key $cacheKey - Cache $MASTER_KEY_CACHE
6668 if ($cacheResult ) {
6769 return $cacheResult
6870 }
6971
70- if ($SubscriptionId ) {
71- $masterKey = az cosmosdb keys list -- name $Database -- query primaryMasterKey -- output tsv -- resource- group $ResourceGroup -- subscription $SubscriptionId
72+ $masterKey = Get-Base64MasterkeyWithoutCaching - ResourceGroup $ResourceGroup - Database $Database - SubscriptionId $SubscriptionId - Readonly $readonly
73+
74+ Set-CacheValue - Key $cacheKey - Value $masterKey - Cache $MASTER_KEY_CACHE - ExpirationHours 6
75+
76+ $masterKey
77+ }
78+
79+ # This is just to support testing caching with Get-Base64Masterkey and isn't meant to be used directly
80+ Function Get-Base64MasterkeyWithoutCaching ([string ]$ResourceGroup , [string ]$Database , [string ]$SubscriptionId , [bool ]$Readonly ) {
81+ $query = if ($readonly ) {
82+ " primaryReadonlyMasterKey"
7283 }
7384 else {
74- $masterKey = az cosmosdb keys list -- name $Database -- query primaryMasterKey -- output tsv -- resource - group $ResourceGroup
85+ " primaryMasterKey"
7586 }
7687
77- Set-CacheValue - Key $cacheKey - Value $masterKey - Cache $MASTER_KEY_CACHE - ExpirationHours 6
88+ if ($SubscriptionId ) {
89+ $masterKey = az cosmosdb keys list -- name $Database -- query $query -- output tsv -- resource- group $ResourceGroup -- subscription $SubscriptionId
90+ }
91+ else {
92+ $masterKey = az cosmosdb keys list -- name $Database -- query $query -- output tsv -- resource- group $ResourceGroup
93+ }
7894
7995 $masterKey
8096}
@@ -140,9 +156,9 @@ Function Get-CommonHeaders([string]$now, [string]$encodedAuthString, [string]$co
140156 $headers [" x-ms-documentdb-partitionkey" ] = " [`" $PartitionKey `" ]"
141157 }
142158
143- if ($Etag ) {
144- $headers [" If-Match" ] = $Etag
145- }
159+ if ($Etag ) {
160+ $headers [" If-Match" ] = $Etag
161+ }
146162
147163 $headers
148164}
@@ -172,15 +188,16 @@ Function Get-ExceptionResponseOrThrow($err) {
172188
173189 if ($err.Exception.Response ) {
174190 $msg = @ {
175- StatusCode = $err.Exception.Response.StatusCode ;
191+ StatusCode = $err.Exception.Response.StatusCode ;
176192 RawResponse = $err.Exception.Response ;
177193 }
178194
179195 if ($PSVersionTable.PSEdition -eq " Core" ) {
180196 # In PS Core, the body is eaten and put into this message
181197 # See: https://stackoverflow.com/questions/18771424/how-to-get-powershell-invoke-restmethod-to-return-body-of-http-500-code-response
182198 $msg.Content = $err.ErrorDetails.Message
183- } else {
199+ }
200+ else {
184201 # In Desktop we can re-read the content stream
185202 $result = $err.Exception.Response.GetResponseStream ()
186203 $reader = New-Object System.IO.StreamReader($result )
@@ -191,7 +208,8 @@ Function Get-ExceptionResponseOrThrow($err) {
191208 }
192209
193210 return [PSCustomObject ]$msg
194- } else {
211+ }
212+ else {
195213 throw $err.Exception
196214 }
197215}
@@ -802,7 +820,8 @@ Function Update-CosmosDbRecord {
802820
803821 if ($EnforceOptimisticConcurrency ) {
804822 $headers = Get-CommonHeaders - now $now - encodedAuthString $encodedAuthString - PartitionKey $requestPartitionKey - Etag $Object._etag
805- } else {
823+ }
824+ else {
806825 $headers = Get-CommonHeaders - now $now - encodedAuthString $encodedAuthString - PartitionKey $requestPartitionKey
807826 }
808827
@@ -911,11 +930,12 @@ Function Get-CosmosDbRecordContent([parameter(ValueFromPipeline)]$RecordResponse
911930 process {
912931 $code = [int ]$RecordResponse.StatusCode
913932 $content =
914- if ($RecordResponse.Content ) {
915- $RecordResponse.Content | ConvertFrom-Json
916- } else {
917- $null
918- }
933+ if ($RecordResponse.Content ) {
934+ $RecordResponse.Content | ConvertFrom-Json
935+ }
936+ else {
937+ $null
938+ }
919939
920940 if ($code -lt 300 ) {
921941 if ($RecordResponse.Content ) {
@@ -925,6 +945,12 @@ Function Get-CosmosDbRecordContent([parameter(ValueFromPipeline)]$RecordResponse
925945 $null
926946 }
927947 }
948+ elseif ($code -eq 401 ) {
949+ if ($env: COSMOS_DB_FLAG_ENABLE_READONLY_KEYS -eq 1 ) {
950+ throw " Unauthorized (used a readonly key)"
951+ }
952+ throw " Unauthorized"
953+ }
928954 elseif ($code -eq 404 ) {
929955 if ($content.Message -like " *Owner resource does not exist*" ) {
930956 throw " Database does not exist"
@@ -935,6 +961,7 @@ Function Get-CosmosDbRecordContent([parameter(ValueFromPipeline)]$RecordResponse
935961 elseif ($code -eq 429 ) {
936962 throw " Request rate limited"
937963 }
964+
938965 else {
939966 $message = $content.Message
940967 throw " Request failed with status code $code with message`n`n $message "
@@ -961,6 +988,14 @@ Function Use-CosmosDbInternalFlag
961988 }
962989}
963990
991+ Function Use-CosmosDbReadonlyKeys
992+ (
993+ [switch ]$Disable
994+ ) {
995+ $env: COSMOS_DB_FLAG_ENABLE_READONLY_KEYS = if ($Disable ) { 0 } else { 1 }
996+ }
997+
998+
964999Export-ModuleMember - Function " Get-CosmosDbRecord"
9651000Export-ModuleMember - Function " Get-AllCosmosDbRecords"
9661001
@@ -974,4 +1009,6 @@ Export-ModuleMember -Function "Remove-CosmosDbRecord"
9741009
9751010Export-ModuleMember - Function " Get-CosmosDbRecordContent"
9761011
977- Export-ModuleMember - Function " Use-CosmosDbInternalFlag"
1012+ Export-ModuleMember - Function " Use-CosmosDbReadonlyKeys"
1013+
1014+ Export-ModuleMember - Function " Use-CosmosDbInternalFlag"
0 commit comments