# inspired by:
# https://stackoverflow.com/questions/53653473/generating-an-sas-token-in-java-to-download-a-file-in-an-azure-data-storage-cont?rq=1
# https://docs.microsoft.com/en-us/rest/api/storageservices/create-account-sas#constructing-the-signature-string
function Create-SASToken( [string] $Account, [string] $AccessKey, [string] $Version, [DateTime] $Now, [DateTime] $Expires, [string] $Permissions='r', $ResourceTypes='o', [string] $Services='b' )
{
[Reflection.Assembly]::LoadWithPartialName("System.Web") | Out-Null
[string] $nowIso = (Get-Date (Get-Date $Now).ToUniversalTime() -Format "u").Replace( ' ', 'T' )
[string] $expiresIso = (Get-Date (Get-Date $Expires).ToUniversalTime() -Format "u").Replace( ' ', 'T' )
$stringToSign = $Account + "`n" `
+ $Permissions + "`n" `
+ $Services + "`n" `
+ $ResourceTypes + "`n" `
+ $nowIso + "`n" `
+ $expiresIso + "`n" `
+ "`n" `
+ "https" + "`n" `
+ $Version + "`n"
$hmac = New-Object System.Security.Cryptography.HMACSHA256
$hmac.key = [Convert]::FromBase64String( $AccessKey )
$signature = $hmac.ComputeHash( [Text.Encoding]::UTF8.GetBytes( $stringToSign ) )
$signature = [Convert]::ToBase64String( $signature )
$sasToken = "sv=$Version" `
+ "&ss=$Services" `
+ "&srt=$ResourceTypes" `
+ "&sp=$Permissions" `
+ "&se=" + [System.Web.HttpUtility]::UrlEncode( $expiresIso ) `
+ "&st=" + [System.Web.HttpUtility]::UrlEncode( $nowIso ) `
+ "&spr=https" `
+ "&sig=" + [System.Web.HttpUtility]::UrlEncode( $signature )
Write-Debug "now: $nowIso"
Write-Debug "expires: $expiresIso"
Write-Debug "stringToSign: $stringToSign"
Write-Debug "sasToken: $sasToken"
$signature, $sasToken
}
function Invoke-BlobRequest( [Uri] $Uri, [DateTime] $Now, [string] $Version, [string] $Method='GET', [string] $FilePath='' )
{
$requestParams = @{}
$requestParams.Add( 'Uri', $Uri )
$requestParams.Add( 'Method', $Method )
if ( $FilePath )
{
$requestParams.Add( 'Infile', $FilePath )
}
$requestParams.Add( 'Headers', @{ `
'x-ms-blob-type' = 'BlockBlob'; `
'x-ms-date' = "$(Get-Date (Get-Date $Now).ToUniversalTime() -Format 'R')"; `
'x-ms-version' = $Version `
} `
)
Write-Debug ".... Invoke-WebRequest: $Uri"
$requestParams.Keys | % {
if ( $_ -eq 'Headers' )
{
$item = $_
$requestParams.Item($_).Keys | % {
Write-Debug "...... Headers $_ : $($requestParams.Item($item).Item($_))"
}
} else {
Write-Debug "...... $_ $($requestParams.Item($_))"
}
}
# run the web service request
$response = Invoke-WebRequest @requestParams
$response
}
# ---------- ---------- ----------
# Main
# ---------- ---------- ----------
$ownerAccount = '<storage account>'
$ownerAccessKey = '<storage account access key>'
$requesterAccount = '<requester account>'
$version = '2019-10-10'
# consider badly synchronized server time and start 3 minutes in the past
$now = (Get-Date).ToUniversalTime().AddMinutes(-3)
# set the SAS token lifetime to 1 day
$expires = $now.AddDays(1).ToUniversalTime()
# consider the following values when creating SAS tokens
# Permission: (r)ead, (w)rite, (d)elete, (l)ist
# ResourceTypes: (o)bject, (c)ontainer, (s)ervice
# Services: (b)lob, (q)ueue, (t)able, (f)ile
Write-Host "`n"
Write-Host "# ++++++++++++++++++++++++++++++"
Write-Host "# Get Access Token"
Write-Host "# ++++++++++++++++++++++++++++++"
# step 1: create signature and SAS token for any operation (read, write, delete, list) on any resources (container, object) of the blob service
$signature, $sasToken = Create-SASToken -Account $ownerAccount -AccessKey $accessKey -Version $version -Now $now -Expires $expires `
-Permissions 'rwdl' -ResourceTypes 'oc' -Services 'b'
Write-Host "Signature: $signature"
Write-Host "SAS Token: $sasToken"
Write-Host "`n"
Write-Host "# ++++++++++++++++++++++++++++++"
Write-Host "# List Blobs in Container"
Write-Host "# ++++++++++++++++++++++++++++++"
<#
# step 1: create signature and SAS token for list operation on container resources of the blob service
$signature, $sasToken = Create-SASToken -Account $ownerAccount -AccessKey $accessKey -Version $version -Now $now -Expires $expires `
-Permissions 'l' -ResourceTypes 'c' -Services 'b'
Write-Host "Signature: $signature"
Write-Host "SAS Token: $sasToken"
#>
# step 2: send web service request
$container = 'yade'
$uri = "https://$($ownerAccount).blob.core.windows.net/$($container)?restype=container&comp=list"
$response = Invoke-BlobRequest -Uri ($uri + '&' + $sasToken) -Now $now -Version $version -Method 'GET'
Write-Host "Status Code: $($response.StatusCode)"
Write-Host $response.Content
Write-Host "`n"
Write-Host "# ++++++++++++++++++++++++++++++"
Write-Host "# Get Blob from Container"
Write-Host "# ++++++++++++++++++++++++++++++"
<#
# step 1: create signature and SAS token for read operation on object resources of the blob service
$signature, $sasToken = Create-SASToken -Account $ownerAccount -AccessKey $accessKey -Version $version -Now $now -Expires $expires `
-Permissions 'r' -ResourceTypes 'o' -Services 'b'
Write-Host "Signature: $signature"
Write-Host "SAS Token: $sasToken"
#>
# step 2: send web service request
$container = 'yade'
$blob = 'test.txt'
$uri = "https://$($ownerAccount).blob.core.windows.net/$($container)/$($blob)"
$response = Invoke-BlobRequest -Uri ($uri + '?' + $sasToken) -Now $now -Version $version -Method 'GET'
Write-Host "Status Code: $($response.StatusCode)"
Write-Host $response.Content
Write-Host "`n"
Write-Host "# ++++++++++++++++++++++++++++++"
Write-Host "# Write Blob to Container"
Write-Host "# ++++++++++++++++++++++++++++++"
<#
# step 1: create signature and SAS token for write operation on object resources of the blob service
$signature, $sasToken = Create-SASToken -Account $ownerAccount -AccessKey $accessKey -Version $version -Now $now -Expires $expires `
-Permissions 'w' -ResourceTypes 'o' -Services 'b'
Write-Host "Signature: $signature"
Write-Host "SAS Token: $sasToken"
#>
# step 2: send web service request
$container = 'yade'
$filePath = "/tmp/some_blob.txt"
$blob = (Get-Item $filePath).Name
$uri = "https://$($ownerAccount).blob.core.windows.net/$($container)/$($blob)"
$response = Invoke-BlobRequest -Uri ($uri + '?' + $sasToken) -Now $now -Version $version -Method 'PUT' -FilePath $filePath
Write-Host "Status Code: $($response.StatusCode)"
Write-Host $response.Content
|