【问题标题】:Azure Storage Rest-API via Powershell to list container contentAzure Storage Rest-API 通过 Powershell 列出容器内容
【发布时间】:2020-03-09 14:56:44
【问题描述】:

我尝试以“liveworkerstorage”为例列出我们存储帐户的内容。 我创建了一个 auth 标头,并且可以在容器上创建一个文件,但是当我只想通过 Powershell 列出内容时,我收到一条错误消息,告诉我:

Invoke-RestMethod : AuthenticationFailedServer failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.
RequestId:781ec136-101e-0012-0620-f6ebe4000000
Time:2020-03-09T14:40:50.3148026ZThe MAC signature found in the HTTP request '16lBcDgjTWNtqInwWSghnHT0ae7yc5OS/05B72fVS4E=' is not the same as any computed signature. Server used following string to sign: 'GET
x-ms-blob-type:BlockBlob
x-ms-date:Mon, 09 Mar 2020 15:40:52 GMT
x-ms-version:2014-02-14
/liveworkerstorage/curltestdonotdelete/
restype:container'.
In C:\temp\Powershell\StoragePing\StoragePimg3.ps1:40 Zeichen:1
+ Invoke-RestMethod -method $method -Uri $Url -Headers $headers
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebException
    + FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand

这是我的代码... 您可以看到,在我创建 PUT 方法的地方有注释掉的值并且有效。

$method = "GET"
#$method = "PUT"
$headerDate = '2014-02-14'
$headers = @{"x-ms-version" = "$headerDate" }
$StorageAccountName = "xxXXxx"
$StorageContainerName = "xxXXxx"
$StorageAccountKey = "xxXXxxXX"
#$Url = "https://$StorageAccountName.blob.core.cloudapi.de/$StorageContainerName/Test.txt"
$Url = "https://$StorageAccountName.blob.core.cloudapi.de/$StorageContainerName/?restype=container"
#$body = "Hello world"
$xmsdate = (get-date -format r).ToString()
$headers.Add("x-ms-date", $xmsdate)
$bytes = ([System.Text.Encoding]::UTF8.GetBytes($body))
$contentLength = $bytes.length
$headers.Add("Content-Length", "$contentLength")
$headers.Add("x-ms-blob-type", "BlockBlob")

$signatureString = "$method$([char]10)$([char]10)$([char]10)$contentLength$([char]10)$([char]10)$([char]10)$([char]10)$([char]10)$([char]10)$([char]10)$([char]10)$([char]10)"
#Add CanonicalizedHeaders
$signatureString += "x-ms-blob-type:" + $headers["x-ms-blob-type"] + "$([char]10)"
$signatureString += "x-ms-date:" + $headers["x-ms-date"] + "$([char]10)"
$signatureString += "x-ms-version:" + $headers["x-ms-version"] + "$([char]10)"


#Add CanonicalizedResource
$uri = New-Object System.Uri -ArgumentList $url
$signatureString += "/" + $StorageAccountName + $uri.AbsolutePath                   

$dataToMac = [System.Text.Encoding]::UTF8.GetBytes($signatureString)

$accountKeyBytes = [System.Convert]::FromBase64String($StorageAccountKey)

$hmac = new-object System.Security.Cryptography.HMACSHA256((, $accountKeyBytes))
$signature = [System.Convert]::ToBase64String($hmac.ComputeHash($dataToMac))

$headers.Add("Authorization", "SharedKey " + $StorageAccountName + ":" + $signature);
write-host -fore green $signatureString
#Invoke-RestMethod -Uri $Url -Method $method -headers $headers -Body $body
Invoke-RestMethod -method $method -Uri $Url -Headers $headers

提前谢谢你

最好的问候


我有一个更新。到目前为止感谢您的回答!!还是不行……

我更改了获取查询的代码。

但它告诉我容器不存在。怎么可能只列出存储的根部分?

我找到了这个

$root?restype=container

所以这是我的代码和执行时收到的错误消息...

#[CmdletBinding()]
#Param(
  #[Parameter(Mandatory=$true,Position=1)] [string] $StorageAccountName,
  #[Parameter(Mandatory=$True,Position=2)] [string] $FilesystemName,
  #[Parameter(Mandatory=$True,Position=2)] [string] $AccessKey
#)
$StorageAccountName = "XXX"
#$StorageAccountName = "XXX"
#$FilesystemName = "XXX"
$FilesystemName = "XXX"
#$AccessKey = "XXX"
$AccessKey = "XXX"


$date = [System.DateTime]::UtcNow.ToString("R") 

$n = "`n"
$method = "GET"

$stringToSign = "$method$n" #VERB
$stringToSign += "$n" # Content-Encoding + "\n" +  
$stringToSign += "$n" # Content-Language + "\n" +  
$stringToSign += "$n" # Content-Length + "\n" +  
$stringToSign += "$n" # Content-MD5 + "\n" +  
$stringToSign += "$n" # Content-Type + "\n" +  
$stringToSign += "$n" # Date + "\n" +  
$stringToSign += "$n" # If-Modified-Since + "\n" +  
$stringToSign += "$n" # If-Match + "\n" +  
$stringToSign += "$n" # If-None-Match + "\n" +  
$stringToSign += "$n" # If-Unmodified-Since + "\n" +  
$stringToSign += "$n" # Range + "\n" + 
$stringToSign +=    
                    <# SECTION: CanonicalizedHeaders + "\n" #>
                    "x-ms-date:$date" + $n + 
                    "x-ms-version:2018-11-09" + $n # 
                    <# SECTION: CanonicalizedHeaders + "\n" #>

$stringToSign +=    
                    <# SECTION: CanonicalizedResource + "\n" #>
                    "/$StorageAccountName/$FilesystemName" + $n + 
                    "recursive:true" + $n +
                    "resource:filesystem"# 
                    <# SECTION: CanonicalizedResource + "\n" #>

$sharedKey = [System.Convert]::FromBase64String($AccessKey)

$hasher = New-Object System.Security.Cryptography.HMACSHA256
$hasher.Key = $sharedKey

$signedSignature = [System.Convert]::ToBase64String($hasher.ComputeHash([System.Text.Encoding]::UTF8.GetBytes($stringToSign)))

$authHeader = "SharedKey ${StorageAccountName}:$signedSignature"

$headers = @{"x-ms-date"=$date} 
$headers.Add("x-ms-version","2018-11-09")
$headers.Add("Authorization",$authHeader)

$URI = "https://$StorageAccountName.blob.core.cloudapi.de/" + $FilesystemName + "?recursive=true&resource=filesystem"

$result = Invoke-RestMethod -method GET -Uri $URI -Headers $headers

错误信息:

Invoke-RestMethod : ContainerNotFoundThe specified container does not exist.
RequestId:c652069a-301e-0027-5ae1-f645b1000000
Time:2020-03-10T13:41:22.8270890Z
In C:\temp\Powershell\StoragePing\StoragePingfromweb.ps1:60 Zeichen:11
+ $result = Invoke-RestMethod -method GET -Uri $URI -Headers $headers
+           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebException
    + FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand

到目前为止,谢谢!

【问题讨论】:

  • 我不是 100% 确定,但我认为 REST API 需要一个不记名令牌。有什么特别的理由不使用docs.microsoft.com/en-us/powershell/module/azure.storage/… 吗?
  • 您是否有理由编写代码以直接使用 REST API 而不是使用 Azure 存储 PowerShell Cmdlet?
  • 我们想在 azure webapp 上运行这个脚本。无法使用 Azure AZ 或其他东西。
  • 既然如此,那为什么不用SDK呢?

标签: azure powershell rest api storage


【解决方案1】:

如果通过 Azure 生成 sas 令牌会更简单,但这是我发现使用 sas 令牌时有效的方法...(无需发送标头)

以下是帮助我整理的参考资料: https://blog.zuehlke.cloud/2019/10/access-azure-blob-storage-with-rest-and-sas/

# The sas token used below is the one generated by Azure in the Storage Account settings and censored
# and not one generated and signed using other methods (eg. the method you consistently see on help sites)
# To Note, in order to utilize the sas token with filters, you need to change the preceeding '?' with '&'
# Apologies for the variable names, I just yanked them from a larger test script
# The biggest difference when using a filter for these REST operations WITH A SAS KEY seems to be the need 
# to define "&restype=container" whereas the same operation anonymously has no need for "&restype=container"
#
$sasTokenS1 = "?sv=<DATE>&ss=bfqt&srt=sco&sp=rwdlacupx&se=<DATEandTIME>&spr=https&sig=<Signature already in address format>" #included only for comparison
$sasTokenS1v2 = "&sv=<DATE>&ss=bfqt&srt=sco&sp=rwdlacupx&se=<DATEandTIME>&spr=https&sig=<Signature already in address format>"
$storageAccountS1 = "storageaccountname"  #Standard StorageV2 (general purpose v2), paired with $sasTokenS1
$containerName2 = "containername"
$filter1 = "?comp=list" #the filter to list/read
$method1 = "GET" #the REST method, must be all CAPS
#
# With a sas token
$blobUri = "https://$storageAccountS1.blob.core.windows.net/$containerName2/$filter1&restype=container$sasTokenS1v2"
# Anonymous
$blobUri = "https://$storageAccountS1.blob.core.windows.net/$containerName2/$filter1"
#
#
Invoke-RestMethod -Method $method1 -Uri $blobUri

【讨论】:

    【解决方案2】:

    我在您的代码中看到的一个问题是您错误地计算了canonicalizedResource 字符串。根据文档here,您需要在其中包含查询字符串参数。

    所以基本上这行代码:

    $signatureString += "/" + $StorageAccountName + $uri.AbsolutePath
    

    应该是:

    $signatureString += "/" + $StorageAccountName + $uri.AbsolutePath + $([char]10) + "restype:container"
    

    还有一些其他的cmets:

    • 由于您要列出 Blob,因此您真的不需要 x-ms-blob-type 标头。
    • 列出 blob 容器是一个 GET 操作,因此您真的不需要 Content-Length 标头。

    【讨论】:

      猜你喜欢
      • 2015-10-15
      • 2015-09-26
      • 2019-03-27
      • 2017-06-24
      • 2017-06-16
      • 2020-06-25
      • 1970-01-01
      • 2020-06-12
      相关资源
      最近更新 更多