Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
4667 lines (4554 sloc) 181 KB
#region Constants
$Script:UTF8ByteOrderMark=[System.Text.Encoding]::Default.GetString([System.Text.Encoding]::UTF8.GetPreamble())
#Permissions - QUERY: 'r',ADD: 'a',UPDATE: 'u',DELETE: 'd'
$Script:AclTemplate=@"
<SignedIdentifier>
<Id>{0}</Id>
<AccessPolicy>
<Start>{2}</Start>
<Expiry>{3}</Expiry>
<Permission>{1}</Permission>
</AccessPolicy>
</SignedIdentifier>
"@
$Script:AclRequestTemplate=@"
<?xml version="1.0" encoding="utf-8"?>
<SignedIdentifiers>
{0}
</SignedIdentifiers>
"@
#endregion
#region Helpers
Function EncodeStorageRequest
{
[CmdletBinding()]
param
(
[Parameter(Mandatory = $true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
[String[]]$StringToSign,
[Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)]
[String]$SigningKey
)
PROCESS
{
foreach ($item in $StringToSign)
{
$KeyBytes = [System.Convert]::FromBase64String($SigningKey)
$HMAC = New-Object System.Security.Cryptography.HMACSHA256
$HMAC.Key = $KeyBytes
$UnsignedBytes = [System.Text.Encoding]::UTF8.GetBytes($item)
$KeyHash = $HMAC.ComputeHash($UnsignedBytes)
$SignedString=[System.Convert]::ToBase64String($KeyHash)
Write-Output $SignedString
}
}
}
Function GetTokenStringToSign
{
[CmdletBinding()]
param
(
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)]
[ValidateSet('GET','PUT','DELETE','POST','OPTIONS','MERGE')]
[string]
$Verb="GET",
[Parameter(Mandatory=$true,ValueFromPipelineByPropertyName = $true)]
[System.Uri]
$Resource,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)]
[long]
$ContentLength,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)]
[String]
$Date,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)]
[String]
$ContentLanguage,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)]
[String]
$ContentEncoding,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)]
[String]
$IfModifiedSince,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)]
[String]
$IfUnmodifiedSince,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)]
[String]
$IfMatch,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)]
[String]
$IfNoneMatch,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)]
[String]
$ContentType,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)]
[String]
$ContentMD5,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)]
[long]
$RangeStart,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)]
[long]
$RangeEnd,
[Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)]
[System.Collections.IDictionary]
$Headers
)
PROCESS
{
$ResourceBase=($Resource.Host.Split('.') | Select-Object -First 1).TrimEnd("`0")
$ResourcePath=$Resource.LocalPath.TrimStart('/').TrimEnd("`0")
$LengthString=[String]::Empty
$Range=[String]::Empty
if($ContentLength -gt 0)
{
$LengthString="$ContentLength"
}
if($RangeEnd -gt 0)
{
$Range="bytes=$($RangeStart)-$($RangeEnd-1)"
}
$SigningPieces=@(
$Verb,$ContentEncoding,
$ContentLanguage,$LengthString,
$ContentMD5,$ContentType,$Date,$IfModifiedSince,$IfMatch,$IfNoneMatch,$IfUnmodifiedSince,$Range
)
foreach ($item in $Headers.Keys)
{
$SigningPieces+="$($item):$($Headers[$item])"
}
$SigningPieces+="/$ResourceBase/$($ResourcePath.Replace(' ','%20'))"
if ([String]::IsNullOrEmpty($Resource.Query) -eq $false)
{
$QueryResources=@{}
$QueryParams=$Resource.Query.Substring(1).Split('&')
foreach ($QueryParam in $QueryParams)
{
$ItemPieces=$QueryParam.Split('=')
$ItemKey = ($ItemPieces|Select-Object -First 1).TrimEnd("`0")
$ItemValue = ($ItemPieces|Select-Object -Last 1).TrimEnd("`0")
if($QueryResources.ContainsKey($ItemKey))
{
$QueryResources[$ItemKey] = "$($QueryResources[$ItemKey]),$ItemValue"
}
else
{
$QueryResources.Add($ItemKey, $ItemValue)
}
}
$Sorted=$QueryResources.Keys|Sort-Object
foreach ($QueryKey in $Sorted)
{
$SigningPieces += "$($QueryKey):$($QueryResources[$QueryKey])"
}
}
$StringToSign = [String]::Join("`n",$SigningPieces)
Write-Output $StringToSign
}
}
Function GetTableTokenStringToSign
{
[CmdletBinding()]
param
(
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)]
[ValidateSet('GET','PUT','DELETE','POST','OPTIONS','MERGE')]
[string]
$Verb="GET",
[Parameter(Mandatory=$true,ValueFromPipelineByPropertyName = $true)]
[System.Uri]
$Resource,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)]
[String]
$ContentMD5,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)]
[String]
$ContentType,
[String]
$Date
)
$ResourceBase=($Resource.Host.Split('.') | Select-Object -First 1).TrimEnd("`0")
$ResourcePath=$Resource.LocalPath.TrimStart('/').TrimEnd("`0")
$SigningPieces=@($Verb,$ContentMD5,$ContentType,$Date)
#Get the canonicalized resource...
$CanonicalizedResource="/$ResourceBase/$ResourcePath"
if([String]::IsNullOrEmpty($Resource.Query) -eq $false)
{
foreach ($item in $Resource.Query.TrimStart('?').ToLower().Split('&')) {
if($item.StartsWith('comp='))
{
$CanonicalizedResource+="?$item"
break
}
}
}
$SigningPieces+=$CanonicalizedResource
$StringToSign = [String]::Join("`n",$SigningPieces)
Write-Output $StringToSign
}
Function InvokeAzureStorageRequest
{
[CmdletBinding()]
param
(
[Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)]
[Uri]$Uri,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName=$true)]
[Microsoft.PowerShell.Commands.WebRequestMethod]
$Method = "GET",
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName=$true)]
[System.Object]
$Body,
[Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)]
[System.Collections.IDictionary]
$Headers,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName=$true)]
[Switch]
$ReturnHeaders,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName=$true)]
[String]
$ContentType='application/octet-stream',
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName=$true)]
[String]
$ExpandProperty
)
PROCESS
{
$WebParams=@{
Method=$Method;
Uri=$Uri;
Headers=$Headers;
UseBasicParsing=$true;
ErrorAction='Stop'
}
if($Body -ne $null)
{
$WebParams.Add('Body',$Body)
}
if([string]::IsNullOrEmpty($ContentType) -eq $false)
{
$WebParams.Add('ContentType',$ContentType)
}
$Response=Invoke-WebRequest @WebParams
if($Response -ne $null)
{
if($ReturnHeaders.IsPresent -and $Response.Headers -ne $null)
{
Write-Output $Response.Headers
}
$ResponseType="application/xml"
if($Response.Headers -ne $null -and (-not [String]::IsNullOrEmpty($Response.Headers['Content-Type'])))
{
$ResponseType=$Response.Headers['Content-Type']
}
if ([String]::IsNullOrEmpty($Response.Content) -eq $false)
{
$ResultString=$Response.Content
if($ResultString.StartsWith($Script:UTF8ByteOrderMark,[System.StringComparison]::Ordinal))
{
#Really UTF-8 BOM???
$ResultString=$ResultString.Remove(0,$Script:UTF8ByteOrderMark.Length)
}
if(-not [String]::IsNullOrEmpty($ExpandProperty))
{
if($ResponseType -like 'application*xml*')
{
$Result=$(([Xml]$ResultString)|Select-Object -ExpandProperty $ExpandProperty)
}
elseif($ResponseType -like 'application/json*')
{
$Result=$(($ResultString|ConvertFrom-Json)|Select-Object -ExpandProperty $ExpandProperty)
}
Write-Output $Result
}
else
{
if($ResponseType -like 'application*xml*')
{
[Xml]$Result=$ResultString
}
elseif($ResponseType -like 'application/json*')
{
$Result=$ResultString|ConvertFrom-Json
}
Write-Output $Result
}
}
}
}
}
Function GetStorageUri
{
[CmdletBinding()]
param
(
[Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)]
[string]$AccountName,
[Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)]
[string]$StorageServiceFQDN,
[Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)]
[bool]$IsInsecure
)
if($IsInsecure)
{
$Scheme='http'
}
else
{
$Scheme='https'
}
$ResultUri=New-Object System.Uri("$($Scheme)://$AccountName.$StorageServiceFQDN")
Write-Output $ResultUri
}
<#
.SYNOPSIS
Retreives a large file over HTTP
#>
Function DownloadBlob
{
[CmdletBinding()]
param
(
[Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
[System.Uri]$Uri,
[Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true)]
[System.Collections.IDictionary]$Headers,
[Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
[System.String]
$Destination,
[Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true)]
[int]
$BufferSize = 4096000
)
$ResponseStream = [System.IO.Stream]::Null
$OutputStream = [System.IO.Stream]::Null
$Activity="Downloading $(Split-Path -Path $Destination -Leaf)"
$WebRequest = [System.Net.WebRequest]::Create($Uri)
if ($Headers -ne $null -and $Headers.Count -gt 0)
{
foreach ($HeaderName in $Headers.Keys)
{
$WebRequest.Headers.Add($HeaderName, $Headers[$HeaderName])
}
}
$Stopwatch=New-Object System.Diagnostics.Stopwatch
try
{
#Get a content length for progress....
Write-Progress -Activity $Activity -Status "Contacting $($Uri.AbsoluteUri)" -PercentComplete 0
Write-Verbose "$Activity - Contacting $($Uri.AbsoluteUri)"
$WebResponse = $WebRequest.GetResponse()
$TotalSize=$WebResponse.ContentLength
$ContentType=$WebResponse.ContentType
$Stopwatch.Start()
Write-Progress -Activity $Activity -Status "Status:$($WebResponse.StatusCode) $ContentType Response of $($TotalSize/1MB) MB" -PercentComplete 0
Write-Verbose "$Activity - Status:$($WebResponse.StatusCode) $ContentType Response of $($TotalSize/1MB) MB"
$ResponseStream = $WebResponse.GetResponseStream()
$OutputStream = [System.IO.File]::OpenWrite($Destination)
$ReadBuffer = New-Object Byte[]($BufferSize)
$BytesWritten=0
$BytesRead = $ResponseStream.Read($ReadBuffer, 0, $BufferSize)
$BytesWritten+=$BytesRead
$Activity="$Activity $($TotalSize/1MB)mb"
while ($BytesRead -gt 0)
{
$OutputStream.Write($ReadBuffer, 0, $BytesRead)
$BytesRead = $ResponseStream.Read($ReadBuffer, 0, $BufferSize)
$BytesWritten+=$BytesRead
$Speed=[Math]::Round(($BytesWritten/1MB)/$Stopwatch.Elapsed.TotalSeconds,2)
Write-Progress -Activity $Activity -Status "Response $ContentType $(Split-Path -Path $Destination -Leaf) $([Math]::Round($BytesWritten/1MB)) MB written - ($Speed mb/s)" `
-PercentComplete $(($BytesWritten/$TotalSize) * 100)
}
}
catch [System.Net.WebException], [System.Exception]
{
throw $_
}
finally
{
$Stopwatch.Stop()
if ($OutputStream -ne $null)
{
$OutputStream.Dispose()
}
if ($ResponseStream -ne $null)
{
$ResponseStream.Dispose()
}
Write-Progress -Activity $Activity -Completed
}
}
<#
.SYNOPSIS
Retreives an MD5 hash for either a file or arbitrary bytes
#>
Function GetMd5Hash
{
[CmdletBinding()]
param
(
[Parameter(Mandatory=$true,ValueFromPipeline=$true,ParameterSetName='file')]
[System.IO.FileInfo[]]$InputObject,
[Parameter(Mandatory=$true,ValueFromPipeline=$true,ParameterSetName='content')]
[System.Byte[]]$Content
)
BEGIN
{
$Hasher= New-Object System.Security.Cryptography.MD5CryptoServiceProvider
}
PROCESS
{
if($PSCmdlet.ParameterSetName -eq 'file')
{
foreach ($item in $InputObject)
{
Write-Verbose "[GetMd5Hash] Calculating MD5 Hash for $($item.FullName)"
$Md5Hash=@()
$HashResult=Get-FileHash -Path $item.FullName -Algorithm MD5|Select-Object -ExpandProperty Hash
for ($i = 0; $i -lt $HashResult.Length; $i+=2)
{
$Md5Hash+=$([Byte]::Parse($HashResult.Substring($i,2) -f "0:x",[System.Globalization.NumberStyles]::HexNumber))
}
Write-Output $([System.Convert]::ToBase64String($Md5Hash))
}
}
else
{
Write-Verbose "[GetMd5Hash] Calculating MD5 Hash for Bytes Length $($Content.Length)"
$Md5Hash=$Hasher.ComputeHash($Content)
Write-Output $([System.Convert]::ToBase64String($Md5Hash))
}
}
END
{
$Hasher.Dispose()
}
}
#endregion
<#
.SYNOPSIS
Generates a new Shared Key Signature
.PARAMETER Verb
The HTTP Verb for the request
.PARAMETER Resource
The resource to be accessed
.PARAMETER ContentLength
The Content-Length header value
.PARAMETER ContentEncoding
The Content-Encoding header value
.PARAMETER ContentType
The Content-Type header value
.PARAMETER ContentMD5
The Content-MD5 header value
.PARAMETER RangeStart
The Range header start value
.PARAMETER RangeEnd
The Range header end value
.PARAMETER Headers
The Request Header collection (usually 'including the canonical x-ms-date and x-ms-version')
.PARAMETER AccessKey
The storage service access key
.PARAMETER ServiceType
The storage service type to be accessed
#>
Function New-SharedKeySignature
{
[CmdletBinding()]
param
(
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName=$true)]
[ValidateSet('GET','PUT','DELETE','POST','OPTIONS','MERGE')]
[string]
$Verb="GET",
[Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)]
[System.Uri]
$Resource,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName=$true)]
[long]
$ContentLength,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName=$true)]
[String]
$ContentLanguage,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName=$true)]
[String]
$ContentEncoding,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)]
[String]
$IfModifiedSince,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)]
[String]
$IfUnmodifiedSince,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)]
[String]
$IfMatch,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)]
[String]
$IfNoneMatch,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName=$true)]
[String]
$ContentType,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName=$true)]
[String]
$Date,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName=$true)]
[String]
$ContentMD5,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName=$true)]
[int]
$RangeStart,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName=$true)]
[int]
$RangeEnd,
[Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)]
[string]
$AccessKey,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName=$true)]
[System.Collections.IDictionary]
$Headers,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName=$true)]
[ValidateSet('Blob','Table','Queue','File')]
[String]
$ServiceType='BLOB'
)
BEGIN
{
Write-Verbose "[New-SharedKeySignature] Encoding Signature for service:$ServiceType - $Resource"
$CopiedHeaders=[ordered]@{}
foreach ($HeaderName in $Headers.Keys)
{
if($HeaderName -eq 'Date')
{
if([String]::IsNullOrEmpty($Date))
{
$Date=$Headers['Date']
}
}
elseif($HeaderName -eq 'x-ms-date')
{
if([String]::IsNullOrEmpty($Date))
{
$Date=$Headers['x-ms-date']
$CopiedHeaders.Add($HeaderName,$Headers[$HeaderName])
}
}
elseif($HeaderName -eq 'Content-MD5')
{
if([String]::IsNullOrEmpty($ContentMD5))
{
$ContentMD5=$Headers['Content-MD5']
}
}
elseif($HeaderName -eq 'Content-Type')
{
if([String]::IsNullOrEmpty($ContentType))
{
$ContentType=$Headers['Content-Type']
}
}
elseif($HeaderName -eq 'Content-Encoding')
{
if([String]::IsNullOrEmpty($ContentType))
{
$ContentEncoding=$Headers['Content-Encoding']
}
}
else
{
$CopiedHeaders.Add($HeaderName,$Headers[$HeaderName])
}
}
$SigningElements=@{
Verb=$Verb;
Resource=$Resource;
ContentMD5=$ContentMD5;
ContentType=$ContentType;
}
if($ServiceType -ne'Table')
{
$SigningElements.Add('ContentLanguage',$ContentLanguage)
$SigningElements.Add('ContentEncoding',$ContentEncoding)
$SigningElements.Add('RangeStart',$RangeStart)
$SigningElements.Add('RangeEnd',$RangeEnd)
$SigningElements.Add('ContentLength',$ContentLength)
$SigningElements.Add('Headers',$CopiedHeaders)
}
else
{
$SigningElements.Add('Date',$Date)
}
}
PROCESS
{
if($ServiceType -eq 'Table')
{
$StringToSign = GetTableTokenStringToSign @SigningElements
}
else
{
$StringToSign = GetTokenStringToSign @SigningElements
}
Write-Verbose "[New-SharedKeySignature] String to Sign:`n$StringToSign"
$SharedAccessSignature=EncodeStorageRequest -StringToSign $StringToSign -SigningKey $AccessKey
Write-Output $SharedAccessSignature
}
}
#region Table
<#
.SYNOPSIS
Returns properties for the table service on the storage account
.PARAMETER StorageAccountName
The storage account name
.PARAMETER StorageAccountDomain
The FQDN for the storage account service
.PARAMETER AccessKey
The storage service access key
.PARAMETER UseHttp
Use Insecure requests
.PARAMETER ApiVersion
The version of the storage service API
#>
Function Get-AzureTableServiceProperties
{
[CmdletBinding()]
param
(
[Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)]
[String]$StorageAccountName,
[Parameter(Mandatory=$false,ValueFromPipelineByPropertyName=$true)]
[String]$StorageAccountDomain="table.core.windows.net",
[Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)]
[String]$AccessKey,
[Parameter(Mandatory=$false,ValueFromPipelineByPropertyName=$true)]
[Switch]$UseHttp,
[Parameter(Mandatory=$false,ValueFromPipelineByPropertyName=$true)]
[String]$ApiVersion="2016-05-31",
[Parameter(Mandatory=$false,ValueFromPipelineByPropertyName=$true)]
[String]$ODataServiceVersion='3.0;Netfx'
)
BEGIN
{
$TableHeaders=[ordered]@{
'x-ms-version'=$ApiVersion
'DataServiceVersion'=$ODataServiceVersion
'Accept-Charset'='UTF-8'
'Date'=[DateTime]::UtcNow.ToString('R');
}
$TableUri=GetStorageUri -AccountName $StorageAccountName -StorageServiceFQDN $StorageAccountDomain -IsInsecure $UseHttp.IsPresent
$TableUriBld=New-Object System.UriBuilder($TableUri)
$TableUriBld.Path='/'
$TableUriBld.Query="restype=service&comp=properties"
$TokenParams=@{
Resource=$TableUriBld.Uri;
Verb='GET';
Headers=$TableHeaders;
ServiceType='Table';
AccessKey=$AccessKey;
}
$RequestParams=@{
Uri=$TableUriBld.Uri;
Method='GET';
Headers=$TableHeaders;
ExpandProperty="StorageServiceProperties";
}
}
PROCESS
{
$TableSignature=New-SharedKeySignature @TokenParams
$RequestParams.Headers.Add('Authorization',"SharedKey $($StorageAccountName):$($TableSignature)")
$TableResult=InvokeAzureStorageRequest @RequestParams
Write-Output $TableResult
}
}
<#
.SYNOPSIS
Retrieves the list of tables within the storage account
.PARAMETER StorageAccountName
The storage account name
.PARAMETER StorageAccountDomain
The FQDN for the storage account service
.PARAMETER AccessKey
The storage service access key
.PARAMETER UseHttp
Use Insecure requests
.PARAMETER ApiVersion
The version of the storage service API
#>
Function Get-AzureTableServiceTables
{
[CmdletBinding()]
param
(
[Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)]
[String]$StorageAccountName,
[Parameter(Mandatory=$false,ValueFromPipelineByPropertyName=$true)]
[String]$StorageAccountDomain="table.core.windows.net",
[Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)]
[String]$AccessKey,
[Parameter(Mandatory=$false,ValueFromPipelineByPropertyName=$true)]
[Switch]$UseHttp,
[Parameter(Mandatory=$false,ValueFromPipelineByPropertyName=$true)]
[String]$ApiVersion="2016-05-31",
[Parameter(Mandatory=$false,ValueFromPipelineByPropertyName=$true)]
[String]$ODataServiceVersion='3.0;Netfx',
[ValidateSet('application/json;odata=nometadata','application/json;odata=minimalmetadata','application/json;odata=fullmetadata')]
[Parameter(Mandatory=$false,ValueFromPipelineByPropertyName=$true)]
[String]$ContentType='application/json;odata=nometadata'
)
BEGIN
{
$TableHeaders=[ordered]@{
'x-ms-version'=$ApiVersion
'DataServiceVersion'=$ODataServiceVersion
'Accept-Charset'='UTF-8'
'Accept'=$ContentType;
'Date'=[DateTime]::UtcNow.ToString('R');
}
$TableUri=GetStorageUri -AccountName $StorageAccountName -StorageServiceFQDN $StorageAccountDomain -IsInsecure $UseHttp.IsPresent
$TableUriBld=New-Object System.UriBuilder($TableUri)
$TableUriBld.Path='tables'
$TokenParams=@{
Resource=$TableUriBld.Uri;
Verb='GET';
Headers=$TableHeaders;
ContentType=$ContentType;
ServiceType='Table';
AccessKey=$AccessKey;
}
$RequestParams=@{
Uri=$TableUriBld.Uri;
Method='GET';
Headers=$TableHeaders;
ExpandProperty='value';
ContentType=$ContentType;
}
}
PROCESS
{
$TableSignature=New-SharedKeySignature @TokenParams
$RequestParams.Headers.Add('Authorization',"SharedKey $($StorageAccountName):$($TableSignature)")
$Response=InvokeAzureStorageRequest @RequestParams
Write-Output $Response
}
}
<#
.SYNOPSIS
Returns statistics for the table service on the storage account
.PARAMETER StorageAccountName
The storage account name
.PARAMETER StorageAccountDomain
The FQDN for the storage account service
.PARAMETER AccessKey
The storage service access key
.PARAMETER UseHttp
Use Insecure requests
.PARAMETER ApiVersion
The version of the storage service API
#>
Function Get-AzureTableServiceStats
{
[CmdletBinding()]
param
(
[Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)]
[String]$StorageAccountName,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)]
[String]$StorageAccountDomain = "table.core.windows.net",
[Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)]
[String]$AccessKey,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName=$true)]
[Switch]$UseHttp,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)]
[String]$ApiVersion = "2016-05-31",
[Parameter(Mandatory=$false,ValueFromPipelineByPropertyName=$true)]
[String]$ODataServiceVersion='3.0;Netfx'
)
$TableUri=GetStorageUri -AccountName "$StorageAccountName" -StorageServiceFQDN $StorageAccountDomain -IsInsecure $UseHttp.IsPresent
$TableUriBld=New-Object System.UriBuilder($TableUri)
$TableUriBld.Query = "restype=service&comp=stats"
$TableHeaders=[ordered]@{
'x-ms-version'=$ApiVersion
'DataServiceVersion'=$ODataServiceVersion
'Accept-Charset'='UTF-8'
'Date'=[DateTime]::UtcNow.ToString('R');
}
$TokenParams=@{
Resource=$TableUriBld.Uri;
Verb='GET';
Headers=$TableHeaders;
ServiceType='Table';
AccessKey=$AccessKey;
}
$TableSignature=New-SharedKeySignature @TokenParams
$TableHeaders.Add('Authorization',"SharedKey $($StorageAccountName):$($TableSignature)")
$TableUriBld.Host="$StorageAccountName-secondary.$StorageAccountDomain"
$RequestParams=@{
Uri=$TableUriBld.Uri;
Method='GET';
Headers=$TableHeaders;
ExpandProperty='StorageServiceStats'
}
$TableStats=InvokeAzureStorageRequest @RequestParams
Write-Output $TableStats
}
<#
.SYNOPSIS
Returns ACL(s) for the table
.PARAMETER StorageAccountName
The storage account name
.PARAMETER TableName
The name of the table
.PARAMETER StorageAccountDomain
The FQDN for the storage account service
.PARAMETER AccessKey
The storage service access key
.PARAMETER UseHttp
Use Insecure requests
.PARAMETER ApiVersion
The storage API version
.PARAMETER ODataServiceVersion
The OData service version
#>
Function Get-AzureTableACL
{
[CmdletBinding()]
param
(
[Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)]
[String]$StorageAccountName,
[Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)]
[String]$TableName,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)]
[String]$StorageAccountDomain = "table.core.windows.net",
[Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)]
[String]$AccessKey,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName=$true)]
[Switch]$UseHttp,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)]
[String]$ApiVersion = "2016-05-31",
[Parameter(Mandatory=$false,ValueFromPipelineByPropertyName=$true)]
[String]$ODataServiceVersion='3.0;Netfx'
)
$TableUri=GetStorageUri -AccountName "$StorageAccountName" -StorageServiceFQDN $StorageAccountDomain -IsInsecure $UseHttp.IsPresent
$TableUriBld=New-Object System.UriBuilder($TableUri)
$TableUriBld.Path=$TableName
$TableUriBld.Query = "comp=acl"
$TableHeaders=[ordered]@{
'x-ms-version'=$ApiVersion
'DataServiceVersion'=$ODataServiceVersion
'Accept-Charset'='UTF-8'
'Date'=[DateTime]::UtcNow.ToString('R');
}
$TokenParams=@{
Resource=$TableUriBld.Uri;
Verb='GET';
Headers=$TableHeaders;
ServiceType='Table';
AccessKey=$AccessKey;
}
$TableSignature=New-SharedKeySignature @TokenParams
$TableHeaders.Add('Authorization',"SharedKey $($StorageAccountName):$TableSignature")
$RequestParams=@{
Uri=$TableUriBld.Uri;
Method='GET';
Headers=$TableHeaders;
ExpandProperty="SignedIdentifiers";
}
$TableACls=InvokeAzureStorageRequest @RequestParams
if($TableACls -ne $null -and $TableACls.SignedIdentifier -ne $null)
{
foreach ($item in $TableACls.SignedIdentifier)
{
Write-Output $item
}
}
}
<#
.SYNOPSIS
Sets an ACL on the table
.PARAMETER StorageAccountName
The storage account name
.PARAMETER TableName
The name of the table
.PARAMETER StorageAccountDomain
The FQDN for the storage account service
.PARAMETER AccessKey
The storage service access key
.PARAMETER UseHttp
Use Insecure requests
.PARAMETER ApiVersion
The storage API version
.PARAMETER ODataServiceVersion
The OData service version
#>
Function Set-AzureTableACL
{
[CmdletBinding()]
param
(
[Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)]
[String]$StorageAccountName,
[Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)]
[String]$TableName,
[Parameter(ValueFromPipeline=$true,Mandatory = $true,ValueFromPipelineByPropertyName = $true)]
[ValidateLength(1,4)]
[ValidateSet('r','a','u','d','ra','ru','rud','rd','rau','rad','raud','au','aud','ad','ud')]
[String]$Acl,
[Parameter(ValueFromPipeline=$true,Mandatory = $false,ValueFromPipelineByPropertyName = $true)]
[System.DateTime]$Start=[DateTime]::UtcNow,
[Parameter(ValueFromPipeline=$true,Mandatory = $false,ValueFromPipelineByPropertyName = $true)]
[System.DateTime]$Expiry=($Start.AddDays(365)),
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)]
[String]$StorageAccountDomain = "table.core.windows.net",
[Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)]
[String]$AccessKey,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName=$true)]
[Switch]$UseHttp,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)]
[String]$ApiVersion = "2016-05-31",
[Parameter(Mandatory=$false,ValueFromPipelineByPropertyName=$true)]
[String]$ODataServiceVersion='3.0;Netfx'
)
$TableUri=GetStorageUri -AccountName "$StorageAccountName" -StorageServiceFQDN $StorageAccountDomain -IsInsecure $UseHttp.IsPresent
$TableUriBld=New-Object System.UriBuilder($TableUri)
$TableUriBld.Path=$TableName
$TableUriBld.Query = "comp=acl"
$TableHeaders=[ordered]@{
'x-ms-version'=$ApiVersion
'DataServiceVersion'=$ODataServiceVersion
'Accept-Charset'='UTF-8'
'Date'=[DateTime]::UtcNow.ToString('R');
}
$TokenParams=@{
Resource=$TableUriBld.Uri;
Verb='PUT';
Headers=$TableHeaders;
ServiceType='Table';
AccessKey=$AccessKey;
ContentType='application/xml'
}
$TableSignature=New-SharedKeySignature @TokenParams
$TableHeaders.Add('Authorization',"SharedKey $($StorageAccountName):$TableSignature")
$AclId=[Convert]::ToBase64String(([Guid]::NewGuid()).ToByteArray())
$StartTime=$Start.ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fffffffK")
$EndTime=$Expiry.ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fffffffK")
$AclBody=$Script:AclRequestTemplate -f $($Script:AclTemplate -f $AclId,$Acl,$StartTime,$EndTime)
Write-Verbose "[Set-AzureTableACL] Creating ACL $AclId for $TableUri $AclBody"
$RequestParams=@{
Uri=$TableUriBld.Uri;
Method='PUT';
Headers=$TableHeaders;
ReturnHeaders=$true;
Body=$AclBody;
ContentType='application/xml'
}
$TableACls=InvokeAzureStorageRequest @RequestParams
Write-Verbose "[Set-AzureTableACL] Created $AclId successfully."
Write-Output $TableACls
}
<#
.SYNOPSIS
Creates a new table on the storage account
.PARAMETER StorageAccountName
The storage account name
.PARAMETER TableName
The name of the table
.PARAMETER StorageAccountDomain
The FQDN for the storage account service
.PARAMETER AccessKey
The storage service access key
.PARAMETER UseHttp
Use Insecure requests
.PARAMETER ApiVersion
The storage API version
.PARAMETER ODataServiceVersion
The OData service version
#>
Function New-AzureTable
{
[CmdletBinding()]
param
(
[Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)]
[String]$StorageAccountName,
[Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)]
[String]$TableName,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)]
[String]$StorageAccountDomain = "table.core.windows.net",
[Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)]
[String]$AccessKey,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName=$true)]
[Switch]$UseHttp,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)]
[String]$ApiVersion = "2016-05-31",
[Parameter(Mandatory=$false,ValueFromPipelineByPropertyName=$true)]
[String]$ODataServiceVersion='3.0;Netfx',
[ValidateSet('application/json;odata=nometadata','application/json;odata=minimalmetadata','application/json;odata=fullmetadata')]
[Parameter(Mandatory=$false,ValueFromPipelineByPropertyName=$true)]
[String]$ContentType='application/json;odata=nometadata',
[Parameter(Mandatory=$false,ValueFromPipelineByPropertyName=$true)]
[Switch]$ReturnDetail
)
$TableUri=GetStorageUri -AccountName "$StorageAccountName" -StorageServiceFQDN $StorageAccountDomain -IsInsecure $UseHttp.IsPresent
$TableUriBld=New-Object System.UriBuilder($TableUri)
$TableUriBld.Path='Tables'
$ReturnContentPref="return-no-content"
if($ReturnDetail.IsPresent)
{
$ReturnContentPref='return-content'
}
$TableHeaders=[ordered]@{
'x-ms-version'=$ApiVersion
'DataServiceVersion'=$ODataServiceVersion
'Accept-Charset'='UTF-8'
'Accept'=$ContentType
'Date'=[DateTime]::UtcNow.ToString('R');
'Prefer'=$ReturnContentPref;
}
$TokenParams=@{
Resource=$TableUriBld.Uri;
Verb='POST';
Headers=$TableHeaders;
ServiceType='Table';
AccessKey=$AccessKey;
ContentType='application/json'
}
$TableSignature=New-SharedKeySignature @TokenParams
$TableHeaders.Add('Authorization',"SharedKey $($StorageAccountName):$TableSignature")
$NewTableBody=New-Object psobject @{
'TableName'=$TableName;
}
$RequestParams=@{
Uri=$TableUriBld.Uri;
Method='POST';
Headers=$TableHeaders;
ContentType='application/json';
Body=$($NewTableBody|ConvertTo-Json);
}
$NewTableResponse=InvokeAzureStorageRequest @RequestParams
if($ReturnDetail.IsPresent)
{
Write-Output $NewTableResponse
}
}
<#
.SYNOPSIS
Deletes the specified azure storage table
.PARAMETER StorageAccountName
The storage account name
.PARAMETER TableName
The name of the table
.PARAMETER StorageAccountDomain
The FQDN for the storage account service
.PARAMETER AccessKey
The storage service access key
.PARAMETER UseHttp
Use Insecure requests
.PARAMETER ApiVersion
The storage API version
.PARAMETER ODataServiceVersion
The OData service version
#>
Function Remove-AzureTable
{
[CmdletBinding()]
param
(
[Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)]
[String]$StorageAccountName,
[Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)]
[String]$TableName,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)]
[String]$StorageAccountDomain = "table.core.windows.net",
[Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)]
[String]$AccessKey,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName=$true)]
[Switch]$UseHttp,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)]
[String]$ApiVersion = "2016-05-31",
[Parameter(Mandatory=$false,ValueFromPipelineByPropertyName=$true)]
[String]$ODataServiceVersion='3.0;Netfx',
[Parameter(Mandatory=$false,ValueFromPipelineByPropertyName=$true)]
[Switch]$ReturnDetail
)
$TableUri=GetStorageUri -AccountName "$StorageAccountName" -StorageServiceFQDN $StorageAccountDomain -IsInsecure $UseHttp.IsPresent
$TableUriBld=New-Object System.UriBuilder($TableUri)
$TableUriBld.Path="Tables('$TableName')"
$TableHeaders=[ordered]@{
'Date'=[DateTime]::UtcNow.ToString('R');
'x-ms-version'=$ApiVersion
'DataServiceVersion'=$ODataServiceVersion;
'Accept'='application/json'
}
$TokenParams=@{
Resource=$TableUriBld.Uri;
Verb='DELETE';
Headers=$TableHeaders;
ServiceType='Table';
AccessKey=$AccessKey;
ContentType='application/json'
}
$TableSignature=New-SharedKeySignature @TokenParams
$TableHeaders.Add('Authorization',"SharedKey $($StorageAccountName):$TableSignature")
$RequestParams=@{
Uri=$TableUriBld.Uri;
Method='DELETE';
Headers=$TableHeaders;
ContentType='application/json';
ReturnHeaders=$true
}
$DeleteTableResponse=InvokeAzureStorageRequest @RequestParams
if($ReturnDetail.IsPresent)
{
Write-Output $DeleteTableResponse
}
}
<#
.SYNOPSIS
Queries the specified azure storage table
.PARAMETER StorageAccountName
The storage account name
.PARAMETER TableName
The name of the table
.PARAMETER StorageAccountDomain
The FQDN for the storage account service
.PARAMETER AccessKey
The storage service access key
.PARAMETER UseHttp
Use Insecure requests
.PARAMETER ApiVersion
The storage API version
.PARAMETER ODataServiceVersion
The OData service version
#>
Function Get-AzureTableEntity
{
[CmdletBinding(DefaultParameterSetName = 'default')]
param
(
[Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true,ParameterSetName = 'default')]
[Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true,ParameterSetName = 'uniqueid')]
[String]$StorageAccountName,
[Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true,ParameterSetName = 'default')]
[Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true,ParameterSetName = 'uniqueid')]
[String]$TableName,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true,ParameterSetName = 'default')]
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true,ParameterSetName = 'uniqueid')]
[String]$StorageAccountDomain = "table.core.windows.net",
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true,ParameterSetName = 'default')]
[String]$Filter,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true,ParameterSetName = 'default')]
[int]$Top,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true,ParameterSetName = 'default')]
[int]$LimitResults,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true,ParameterSetName = 'default')]
[string[]]$Select,
[Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true,ParameterSetName = 'uniqueid')]
[Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true,ParameterSetName = 'default')]
[String]$AccessKey,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true,ParameterSetName = 'default')]
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true,ParameterSetName = 'uniqueid')]
[Switch]$UseHttp,
[Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true,ParameterSetName = 'uniqueid')]
[String]$PartitionKey,
[Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true,ParameterSetName = 'uniqueid')]
[String]$RowKey,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true,ParameterSetName = 'uniqueid')]
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true,ParameterSetName = 'default')]
[String]$ApiVersion = "2016-05-31",
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true,ParameterSetName = 'uniqueid')]
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true,ParameterSetName = 'default')]
[String]$ODataServiceVersion = '3.0;Netfx',
[ValidateSet('application/json;odata=nometadata','application/json;odata=minimalmetadata','application/json;odata=fullmetadata')]
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true,ParameterSetName = 'uniqueid')]
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true,ParameterSetName = 'default')]
[String]$ContentType = 'application/json;odata=nometadata'
)
PROCESS
{
$TableUri = GetStorageUri -AccountName "$StorageAccountName" -StorageServiceFQDN $StorageAccountDomain -IsInsecure $UseHttp.IsPresent
$TableUriBld = New-Object System.UriBuilder($TableUri)
if (-not [string]::IsNullOrEmpty($PartitionKey))
{
if (-not [string]::IsNullOrEmpty($RowKey))
{
$TableUriBld.Path = "$TableName(PartitionKey='$PartitionKey',RowKey='$RowKey')"
}
}
else
{
$TableUriBld.Path = "$TableName()"
}
$TableQuery = ""
$TableHeaders = [ordered]@{
'x-ms-version' = $ApiVersion
'DataServiceVersion' = $ODataServiceVersion
'Accept' = $ContentType
'Date' = [DateTime]::UtcNow.ToString('R');
}
if (-not [String]::IsNullOrEmpty($Filter))
{
$TableQuery = "`$filter=$Filter"
}
if ($PSCmdlet.ParameterSetName -eq 'default' -and $Top -gt 0)
{
$TableQuery += "&`$top=$Top"
}
if (-not [String]::IsNullOrEmpty($TableQuery))
{
$TableUriBld.Query = $TableQuery
}
$TokenParams = @{
Resource = $TableUriBld.Uri;
Verb = 'GET';
Headers = $TableHeaders;
ServiceType = 'Table';
AccessKey = $AccessKey;
ContentType = $ContentType;
}
$TotalResults = 0
$TableSignature = New-SharedKeySignature @TokenParams
$TableHeaders.Add('Authorization',"SharedKey $($StorageAccountName):$TableSignature")
$RequestParams = @{
Uri = $TableUriBld.Uri;
Method = 'GET';
Headers = $TableHeaders;
ContentType = $ContentType
}
$HasMore = $false
try
{
$Response = Invoke-WebRequest @RequestParams
if (-not [string]::IsNullOrEmpty($Response.Content) -and $PSCmdlet.ParameterSetName -eq 'default')
{
$TableResult = $(($Response.Content|ConvertFrom-Json)|Select-Object -ExpandProperty 'value')
$TotalResults += $TableResult.Count
Write-Output $TableResult
#Are there more values??
if (-not [string]::IsNullOrEmpty($Response.Headers['x-ms-continuation-NextPartitionKey']) -and $Top -eq 0)
{
Write-Verbose "[Get-AzureTableEntity] More results available @ PartitionKey $($Response.Headers['x-ms-continuation-NextPartitionKey'])"
$HasMore = $true
}
while ($HasMore)
{
$NextQueryPieces = @()
$NextQueryPieces += "NextPartitionKey=$($Response.Headers['x-ms-continuation-NextPartitionKey'])"
if (-not [string]::IsNullOrEmpty($Response.Headers['x-ms-continuation-NextRowKey']))
{
$NextQueryPieces += "NextRowKey=$($Response.Headers['x-ms-continuation-NextRowKey'])"
}
if (-not [string]::IsNullOrEmpty($TableUriBld.Query))
{
$TablePieces = $TableUriBld.Query.TrimStart('?').Split('&')
foreach ($TableQuery in $TablePieces)
{
if ($TableQuery -notlike 'NextPartitionKey=*' -and $TableQuery -notlike 'NextRowKey=*')
{
$TablePieces += $TableQuery
}
}
}
$TableUriBld.Query = $([string]::Join('&',$NextQueryPieces))
$RequestParams['Uri'] = $TableUriBld.Uri
try
{
$Response = Invoke-WebRequest @RequestParams
if (-not [string]::IsNullOrEmpty($Response.Content))
{
$TableResult = $(($Response.Content|ConvertFrom-Json)|Select-Object -ExpandProperty 'value')
$TotalResults += $TableResult.Count
Write-Output $TableResult
if (-not [string]::IsNullOrEmpty($Response.Headers['x-ms-continuation-NextPartitionKey']))
{
if ($LimitResults -gt 0 -and $TotalResults -ge $LimitResults)
{
Write-Verbose "[Get-AzureTableEntity] Finished Enumerating results at limit $LimitResults"
$HasMore = $false
}
else
{
Write-Verbose "[Get-AzureTableEntity] Total Items:$TotalResults More results available @ Partition Key $(($Response.Headers['x-ms-continuation-NextPartitionKey']))"
$HasMore = $true
}
}
else
{
$HasMore = $false
}
}
}
catch
{
$HasMore = $false
#See if we can unwind an exception from a response
if ($_.Exception.Response -ne $null)
{
$ExceptionResponse = $_.Exception.Response
$ErrorStream = $ExceptionResponse.GetResponseStream()
$ErrorStream.Position = 0
$StreamReader = New-Object System.IO.StreamReader($ErrorStream)
try
{
$ErrorContent = $StreamReader.ReadToEnd()
$StreamReader.Close()
}
catch
{
}
finally
{
$StreamReader.Close()
}
$ErrorMessage = "Error: $($ExceptionResponse.Method) $($ExceptionResponse.ResponseUri) Returned $($ExceptionResponse.StatusCode) $ErrorContent"
}
else
{
$ErrorMessage = "An error occurred $_"
}
Write-Verbose "[Get-AzureTableEntity] $ErrorMessage"
throw $ErrorMessage
}
}
}
elseif (-not [string]::IsNullOrEmpty($Response.Content))
{
$TableResult = $($Response.Content|ConvertFrom-Json)
Write-Output $TableResult
}
}
catch
{
#See if we can unwind an exception from a response
if ($_.Exception.Response -ne $null)
{
$ExceptionResponse = $_.Exception.Response
$ErrorStream = $ExceptionResponse.GetResponseStream()
$ErrorStream.Position = 0
$StreamReader = New-Object System.IO.StreamReader($ErrorStream)
try
{
$ErrorContent = $StreamReader.ReadToEnd()
$StreamReader.Close()
}
catch
{
}
finally
{
$StreamReader.Close()
}
$ErrorMessage = "Error: $($ExceptionResponse.Method) $($ExceptionResponse.ResponseUri) Returned $($ExceptionResponse.StatusCode) $ErrorContent"
}
else
{
$ErrorMessage = "An error occurred $_"
}
Write-Verbose "[Get-AzureTableEntity] $ErrorMessage"
throw $ErrorMessage
}
}
}
<#
.SYNOPSIS
Inserts an Azure Table Entity
.PARAMETER StorageAccountName
The storage account name
.PARAMETER TableName
The name of the table
.PARAMETER StorageAccountDomain
The FQDN for the storage account service
.PARAMETER InputObject
The entity to insert or update
.PARAMETER AccessKey
The storage service access key
.PARAMETER UseHttp
Use Insecure requests
.PARAMETER ApiVersion
The storage API version
.PARAMETER ODataServiceVersion
The OData service version
#>
Function New-AzureTableEntity
{
[CmdletBinding()]
param
(
[Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)]
[String]$StorageAccountName,
[Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)]
[String]$TableName,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)]
[String]$StorageAccountDomain = "table.core.windows.net",
[Parameter(Mandatory = $true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
[Object[]]$InputObject,
[Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)]
[String]$AccessKey,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName=$true)]
[Switch]$UseHttp,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)]
[String]$ApiVersion = "2016-05-31",
[Parameter(Mandatory=$false,ValueFromPipelineByPropertyName=$true)]
[String]$ODataServiceVersion='3.0;Netfx',
[Parameter(Mandatory=$false,ValueFromPipelineByPropertyName=$true)]
[Switch]$ReturnDetail,
[ValidateSet('application/json;odata=nometadata','application/json;odata=minimalmetadata','application/json;odata=fullmetadata')]
[Parameter(Mandatory=$false,ValueFromPipelineByPropertyName=$true)]
[String]$ContentType='application/json;odata=nometadata'
)
BEGIN
{
$ReturnPref="return-no-content"
if($ReturnDetail.IsPresent)
{
$ReturnPref='return-content'
}
$TableUri=GetStorageUri -AccountName $StorageAccountName -StorageServiceFQDN $StorageAccountDomain -IsInsecure $UseHttp.IsPresent
$TableUriBld=New-Object System.UriBuilder($TableUri)
$TableUriBld.Path=$TableName
$TableHeaders=[ordered]@{
'x-ms-version'=$ApiVersion
'DataServiceVersion'=$ODataServiceVersion
'Accept'=$ContentType
'Date'=[DateTime]::UtcNow.ToString('R');
'Prefer'=$ReturnPref;
}
$TokenParams=@{
Resource=$TableUriBld.Uri;
Verb='POST';
Headers=$TableHeaders;
ServiceType='Table';
AccessKey=$AccessKey;
ContentType=$ContentType;
}
$TableToken=New-SharedKeySignature @TokenParams
$TableHeaders.Add('Authorization',"SharedKey $($StorageAccountName):$TableToken")
}
PROCESS
{
foreach ($item in $InputObject)
{
$RequestParams=@{
Method='POST';
Uri=$TableUriBld.Uri;
Body=$($item|ConvertTo-Json);
Headers=$TableHeaders;
ContentType=$ContentType;
}
$Result=InvokeAzureStorageRequest @RequestParams
if($ReturnDetail.IsPresent)
{
Write-Output $Result
}
}
}
}
<#
.SYNOPSIS
Updates an Azure Table Entity
.PARAMETER StorageAccountName
The storage account name
.PARAMETER TableName
The name of the table
.PARAMETER PartitionKey
The entity partition key
.PARAMETER RowKey
The entity row key
.PARAMETER Entity
The entity to update
.PARAMETER StorageAccountDomain
The FQDN for the storage account service
.PARAMETER AccessKey
The storage service access key
.PARAMETER ETag
An optional ETag for verification
.PARAMETER UseHttp
Use Insecure requests
.PARAMETER ApiVersion
The storage API version
.PARAMETER ODataServiceVersion
The OData service version
#>
Function Set-AzureTableEntity
{
[CmdletBinding()]
param
(
[Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)]
[String]$StorageAccountName,
[Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)]
[String]$TableName,
[Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)]
[String]$PartitionKey,
[Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)]
[String]$RowKey,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)]
[String]$ETag='*',
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)]
[String]$StorageAccountDomain = "table.core.windows.net",
[Parameter(Mandatory = $true,ValueFromPipeline = $true,ValueFromPipelineByPropertyName = $true)]
[Object]$Entity,
[Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)]
[String]$AccessKey,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)]
[Switch]$UseHttp,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)]
[String]$ApiVersion = "2016-05-31",
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)]
[String]$ODataServiceVersion = '3.0;Netfx',
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)]
[Switch]$ReturnDetail,
[ValidateSet('application/json;odata=nometadata','application/json;odata=minimalmetadata','application/json;odata=fullmetadata')]
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)]
[String]$ContentType = 'application/json;odata=nometadata'
)
BEGIN
{
$TableUri = GetStorageUri -AccountName $StorageAccountName -StorageServiceFQDN $StorageAccountDomain -IsInsecure $UseHttp.IsPresent
$TableUriBld = New-Object System.UriBuilder($TableUri)
$TableUriBld.Path = "$TableName(PartitionKey='$PartitionKey',RowKey='$RowKey')"
$TableHeaders = [ordered]@{
'Date' = [DateTime]::UtcNow.ToString('R');
'x-ms-version' = $ApiVersion
'DataServiceVersion' = $ODataServiceVersion;
'If-Match' = $ETag;
'Accept-Content' = 'UTF-8';
'Accept' = $ContentType;
}
$TokenParams = @{
Resource = $TableUriBld.Uri;
Verb = 'PUT';
Date = $TableHeaders.Date;
ServiceType = 'Table';
AccessKey = $AccessKey;
ContentType = $ContentType;
}
$TableToken = New-SharedKeySignature @TokenParams
}
PROCESS
{
$ContentString=$($Entity|ConvertTo-Json)
$ContentLength=[System.Text.Encoding]::UTF8.GetBytes($ContentString).Length
$TableHeaders.Add('Authorization',"SharedKey $($StorageAccountName):$($TableToken)")
$TableHeaders.Add('Content-Length',$ContentLength)
$RequestParams = @{
Method = 'PUT';
Uri = $TableUriBld.Uri;
Body = $ContentString;
Headers = $TableHeaders;
ContentType = $ContentType;
ReturnHeaders = $true;
ErrorAction = 'Stop';
}
$Result = InvokeAzureStorageRequest @RequestParams
if ($ReturnDetail.IsPresent)
{
Write-Output $Result
}
}
}
<#
.SYNOPSIS
Merges an Azure Table Entity
.PARAMETER StorageAccountName
The storage account name
.PARAMETER TableName
The name of the table
.PARAMETER PartitionKey
The entity partition key
.PARAMETER RowKey
The entity row key
.PARAMETER Entity
The entity to update
.PARAMETER StorageAccountDomain
The FQDN for the storage account service
.PARAMETER AccessKey
The storage service access key
.PARAMETER ETag
An optional ETag for verification
.PARAMETER UseHttp
Use Insecure requests
.PARAMETER ApiVersion
The storage API version
.PARAMETER ODataServiceVersion
The OData service version
.PARAMETER ReturnDetail
Return detail of the operation
#>
Function Merge-AzureTableEntity
{
[CmdletBinding()]
param
(
[Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)]
[String]$StorageAccountName,
[Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)]
[String]$TableName,
[Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)]
[String]$PartitionKey,
[Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)]
[String]$RowKey,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)]
[String]$ETag='*',
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)]
[String]$StorageAccountDomain = "table.core.windows.net",
[Parameter(Mandatory = $true,ValueFromPipeline = $true,ValueFromPipelineByPropertyName = $true)]
[Object]$Entity,
[Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)]
[String]$AccessKey,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)]
[Switch]$UseHttp,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)]
[String]$ApiVersion = "2016-05-31",
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)]
[String]$ODataServiceVersion = '3.0;Netfx',
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)]
[Switch]$ReturnDetail,
[ValidateSet('application/json;odata=nometadata','application/json;odata=minimalmetadata','application/json;odata=fullmetadata')]
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)]
[String]$ContentType = 'application/json;odata=nometadata'
)
BEGIN
{
$TableUri = GetStorageUri -AccountName $StorageAccountName -StorageServiceFQDN $StorageAccountDomain -IsInsecure $UseHttp.IsPresent
$TableUriBld = New-Object System.UriBuilder($TableUri)
$TableUriBld.Path = "$TableName(PartitionKey='$PartitionKey',RowKey='$RowKey')"
$TableHeaders = [ordered]@{
'Date' = [DateTime]::UtcNow.ToString('R');
'x-ms-version' = $ApiVersion
'DataServiceVersion' = $ODataServiceVersion;
'If-Match' = $ETag;
'Accept-Content' = 'UTF-8';
'Accept' = $ContentType;
}
$TokenParams = @{
Resource = $TableUriBld.Uri;
Verb = 'MERGE';
Date = $TableHeaders.Date;
ServiceType = 'Table';
AccessKey = $AccessKey;
ContentType = $ContentType;
}
$TableToken = New-SharedKeySignature @TokenParams
$TableHeaders.Add('Authorization',"SharedKey $($StorageAccountName):$($TableToken)")
}
PROCESS
{
$RequestParams = @{
Method = 'MERGE';
Uri = $TableUriBld.Uri;
Body = $($Entity|ConvertTo-Json);
Headers = $TableHeaders;
ContentType = $ContentType;
ReturnHeaders = $true;
}
$Result = InvokeAzureStorageRequest @RequestParams
if ($ReturnDetail.IsPresent)
{
Write-Output $Result
}
}
}
<#
.SYNOPSIS
Removes an Azure Table Entity
.PARAMETER StorageAccountName
The storage account name
.PARAMETER TableName
The name of the table
.PARAMETER PartitionKey
The entity partition key
.PARAMETER RowKey
The entity row key
.PARAMETER StorageAccountDomain
The FQDN for the storage account service
.PARAMETER AccessKey
The storage service access key
.PARAMETER ETag
An optional ETag for verification
.PARAMETER UseHttp
Use Insecure requests
.PARAMETER ApiVersion
The storage API version
.PARAMETER ODataServiceVersion
The OData service version
#>
Function Remove-AzureTableEntity
{
[CmdletBinding()]
param
(
[Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)]
[String]$StorageAccountName,
[Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)]
[String]$TableName,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)]
[String]$StorageAccountDomain = "table.core.windows.net",
[Parameter(Mandatory = $true,ValueFromPipelineByPropertyName=$true)]
[string]$PartitionKey,
[Parameter(Mandatory = $true,ValueFromPipelineByPropertyName=$true)]
[string]$RowKey,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName=$true)]
[string]$ETag='*',
[Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)]
[String]$AccessKey,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName=$true)]
[Switch]$UseHttp,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)]
[String]$ApiVersion = "2016-05-31",
[Parameter(Mandatory=$false,ValueFromPipelineByPropertyName=$true)]
[String]$ODataServiceVersion='3.0;Netfx',
[Parameter(Mandatory=$false,ValueFromPipelineByPropertyName=$true)]
[Switch]$ReturnDetail
)
PROCESS
{
$TableUri = GetStorageUri -AccountName $StorageAccountName -StorageServiceFQDN $StorageAccountDomain -IsInsecure $UseHttp.IsPresent
$TableUriBld = New-Object System.UriBuilder($TableUri)
$TableUriBld.Path = "$TableName(PartitionKey='$PartitionKey',RowKey='$RowKey')"
$TableHeaders = [ordered]@{
'Date' = [DateTime]::UtcNow.ToString('R');
'x-ms-version' = $ApiVersion
'DataServiceVersion' = $ODataServiceVersion;
'If-Match' = $ETag;
'Accept' = "application/json;odata=nometadata";
}
$TokenParams = @{
Resource = $TableUriBld.Uri;
Verb = 'DELETE';
Date = [DateTime]::UtcNow.ToString('R');
Headers = $TableHeaders;
ServiceType = 'Table';
AccessKey = $AccessKey;
ContentType = 'application/json'
}
$TableToken = New-SharedKeySignature @TokenParams
$TableHeaders.Add('Authorization',"SharedKey $($StorageAccountName):$($TableToken)")
$RequestParams = @{
Uri = $TableUriBld.Uri;
Headers = $TableHeaders;
ReturnHeaders = $ReturnDetail.IsPresent;
Method = 'DELETE';
ContentType = 'application/json';
}
$Result = InvokeAzureStorageRequest @RequestParams
if ($ReturnDetail.IsPresent)
{
Write-Output $Result
}
}
}
#endregion
#region BLOB
<#
.SYNOPSIS
Returns statistics for the blob service on the storage account
.PARAMETER StorageAccountName
The storage account name
.PARAMETER StorageAccountDomain
The FQDN for the storage account service
.PARAMETER AccessKey
The storage service access key
.PARAMETER UseHttp
Use Insecure requests
.PARAMETER ApiVersion
The version of the BLOB service API
#>
Function Get-AzureBlobServiceStats
{
[CmdletBinding()]
param
(
[Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)]
[String]$StorageAccountName,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)]
[String]$StorageAccountDomain = "blob.core.windows.net",
[Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)]
[String]$AccessKey,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName=$true)]
[Switch]$UseHttp,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)]
[String]$ApiVersion = "2016-05-31"
)
$BlobUri=GetStorageUri -AccountName "$StorageAccountName" -StorageServiceFQDN $StorageAccountDomain -IsInsecure $UseHttp.IsPresent
$BlobUriBld=New-Object System.UriBuilder($BlobUri)
$BlobUriBld.Query = "restype=service&comp=stats"
$BlobHeaders = [ordered]@{
'x-ms-date'=[DateTime]::UtcNow.ToString('R');
"x-ms-version" = $ApiVersion;
}
$TokenParams=@{
Verb="GET";
Resource=$BlobUriBld.Uri;
AccessKey=$AccessKey;
Headers=$BlobHeaders;
}
$SasToken = New-SharedKeySignature @TokenParams
$BlobUriBld.Host="$StorageAccountName-secondary.$StorageAccountDomain"
$RequestParams=@{
Uri=$BlobUriBld.Uri;
Method='GET';
ExpandProperty='StorageServiceStats'
}
$BlobHeaders.Add("Authorization","SharedKey $($StorageAccountName):$($SasToken)")
$RequestParams.Add('Headers',$BlobHeaders)
$BlobResult=InvokeAzureStorageRequest @RequestParams
Write-Output $BlobResult
}
<#
.SYNOPSIS
Retrieves the service properties for the storage account
.PARAMETER StorageAccountName
The storage account name
.PARAMETER StorageAccountDomain
The FQDN for the storage account service
.PARAMETER AccessKey
The storage service access key
.PARAMETER UseHttp
Use Insecure requests
.PARAMETER ApiVersion
The version of the BLOB service API
#>
Function Get-AzureBlobServiceProperties
{
[CmdletBinding()]
param
(
[Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)]
[String]$StorageAccountName,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)]
[String]$StorageAccountDomain = "blob.core.windows.net",
[Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)]
[String]$AccessKey,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName=$true)]
[Switch]$UseHttp,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)]
[String]$ApiVersion = "2016-05-31"
)
$BlobUri=GetStorageUri -AccountName $StorageAccountName -StorageServiceFQDN $StorageAccountDomain -IsInsecure $UseHttp.IsPresent
$BlobUriBld=New-Object System.UriBuilder($BlobUri)
$BlobUriBld.Query = "restype=service&comp=properties"
$RequestParams=@{
Uri=$BlobUriBld.Uri;
Method='GET';
ExpandProperty='StorageServiceProperties'
}
$BlobHeaders = [ordered]@{
'x-ms-date'=[DateTime]::UtcNow.ToString('R');
"x-ms-version" = $ApiVersion;
}
$TokenParams=@{
Verb="GET";
Resource=$BlobUriBld.Uri;
AccessKey=$AccessKey;
Headers=$BlobHeaders;
}
$SasToken = New-SharedKeySignature @TokenParams
$BlobHeaders.Add("Authorization","SharedKey $($StorageAccountName):$($SasToken)")
$RequestParams.Add('Headers',$BlobHeaders)
$BlobResult=InvokeAzureStorageRequest @RequestParams
Write-Output $BlobResult
}
<#
.SYNOPSIS
Retrieves the metadata set for a BLOB container
#>
Function Get-AzureBlobContainerMetadata
{
[CmdletBinding()]
param
(
[Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)]
[String]$StorageAccountName,
[Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)]
[String]$ContainerName,
[Parameter(Mandatory=$false,ValueFromPipelineByPropertyName=$true)]
[String]$StorageAccountDomain="blob.core.windows.net",
[Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)]
[String]$AccessKey,
[Parameter(Mandatory=$false,ValueFromPipelineByPropertyName=$true)]
[Switch]$UseHttp,
[Parameter(Mandatory=$false,ValueFromPipelineByPropertyName=$true)]
[String]$ApiVersion="2016-05-31"
)
$BlobUri=GetStorageUri -AccountName $StorageAccountName -StorageServiceFQDN $StorageAccountDomain -IsInsecure $UseHttp.IsPresent
$BlobUriBld=New-Object System.UriBuilder($BlobUri)
$BlobUriBld.Path="$ContainerName"
$BlobUriBld.Query="restype=container&comp=metadata"
$RequestParams=@{
Method='Get';
Uri=$BlobUriBld.Uri;
ReturnHeaders=$true;
}
$BlobHeaders= @{
"x-ms-date"=[DateTime]::UtcNow.ToString('R');
"x-ms-version"=$ApiVersion;
}
$TokenParams=@{
Verb="GET";
Resource=$BlobUriBld.Uri;
AccessKey=$AccessKey;
Headers=$BlobHeaders;
}
$SasToken=New-SharedKeySignature @TokenParams
$BlobHeaders.Add("Authorization","SharedKey $($StorageAccountName):$($SasToken)")
$RequestParams.Add('Headers',$BlobHeaders)
$Result=InvokeAzureStorageRequest @RequestParams
Write-Output $Result
}
<#
.SYNOPSIS
Updates the metadata set for a BLOB container
.PARAMETER StorageAccountName
The storage account name
.PARAMETER ContainerName
The storage account BLOB container name
.PARAMETER StorageAccountDomain
The FQDN for the storage account service
.PARAMETER AccessKey
The storage service access key
.PARAMETER UseHttp
Use Insecure requests
#>
Function Set-AzureBlobContainerMetadata
{
[CmdletBinding()]
param
(
[Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
[String]$StorageAccountName,
[Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
[String]$ContainerName,
[Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true)]
[String]$StorageAccountDomain = "blob.core.windows.net",
[Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
[String]$AccessKey,
[Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
[System.Collections.IDictionary]$Metadata,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName=$true)]
[Switch]$UseHttp,
[Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true)]
[String]$ApiVersion = "2016-05-31"
)
$BlobUri=GetStorageUri -AccountName $StorageAccountName -StorageServiceFQDN $StorageAccountDomain -IsInsecure $UseHttp.IsPresent
$BlobUriBld=New-Object System.UriBuilder($BlobUri)
$BlobUriBld.Path = "$ContainerName"
$BlobUriBld.Query = "restype=container&comp=metadata"
Write-Verbose "[Set-AzureBlobContainerMetadata] Updating metadata $($Metadata.Keys) on $BlobUri"
$RequestParams=@{
Method='PUT';
Uri=$BlobUriBld.Uri;
ReturnHeaders=$true;
}
$BlobHeaders = [ordered]@{
"x-ms-date" = [DateTime]::UtcNow.ToString('R');
}
foreach($MetaKey in ($Metadata.Keys|Sort-Object))
{
$BlobHeaders.Add("x-ms-meta-$MetaKey",$Metadata[$MetaKey])
}
$BlobHeaders.Add("x-ms-version",$ApiVersion)
$SasToken=New-SharedKeySignature -Verb PUT -Resource $BlobUriBld.Uri -AccessKey $AccessKey -Headers $BlobHeaders
$BlobHeaders.Add("Authorization","SharedKey $($StorageAccountName):$($SasToken)")
$RequestParams.Add('Headers',$BlobHeaders)
InvokeAzureStorageRequest @RequestParams|Out-Null
}
<#
.SYNOPSIS
Retrieves the list of BLOB(s) for a BLOB container
.PARAMETER StorageAccountName
The storage account name
.PARAMETER ContainerName
The storage account BLOB container name
.PARAMETER StorageAccountDomain
The FQDN for the storage account service
.PARAMETER AccessKey
The storage service access key
.PARAMETER UseHttp
Use Insecure requests
.PARAMETER ApiVersion
The version of the BLOB service API
#>
Function Get-AzureBlobContainerBlobs
{
[CmdletBinding()]
param
(
[Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)]
[String]$StorageAccountName,
[Parameter(Mandatory=$false,ValueFromPipelineByPropertyName=$true)]
[String]$ContainerName='$root',
[Parameter(Mandatory=$false,ValueFromPipelineByPropertyName=$true)]
[String]$StorageAccountDomain="blob.core.windows.net",
[Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)]
[String]$AccessKey,
[Parameter(Mandatory=$false,ValueFromPipelineByPropertyName=$true)]
[Switch]$UseHttp,
[Parameter(Mandatory=$false,ValueFromPipelineByPropertyName=$true)]
[String]$ApiVersion="2016-05-31"
)
$BlobUri=GetStorageUri -AccountName $StorageAccountName -StorageServiceFQDN $StorageAccountDomain -IsInsecure $UseHttp.IsPresent
$BlobUriBld=New-Object System.UriBuilder($BlobUri)
$BlobUriBld.Path="$ContainerName"
$BlobUriBld.Query="restype=container&comp=list"
$RequestParams=@{
Uri=$BlobUriBld.Uri;
Method='Get';
Headers=@{};
ExpandProperty='EnumerationResults';
}
$TokenParams=@{
Verb='GET';
Resource=$BlobUriBld.Uri;
Headers=@{
"x-ms-date"=[DateTime]::UtcNow.ToString('R');
"x-ms-version"=$ApiVersion;
};
AccessKey=$AccessKey;
}
Write-Verbose "[Get-AzureBlobContainerBlobs] Creating SAS Token for $($BlobUriBld.Uri)"
$SasToken=New-SharedKeySignature @TokenParams
$TokenParams.Headers.Keys|ForEach-Object{$RequestParams.Headers[$_]=$TokenParams.Headers[$_]}
$RequestParams.Headers.Add("Authorization","SharedKey $($StorageAccountName):$($SasToken)")
$BlobResult=InvokeAzureStorageRequest @RequestParams
Write-Verbose "[Get-AzureBlobContainerBlobs] Blob Response Endpoint:$($BlobResult.ServiceEndpoint) container $($BlobResult.ContainerName)"
if($BlobResult.Blobs -ne $null -and $BlobResult.Blobs.Blob.Count -gt 0)
{
foreach ($Blob in $BlobResult.Blobs.Blob)
{
Write-Output $Blob
}
$HasMore=-not [String]::IsNullOrEmpty($BlobResult.NextMarker)
while ($HasMore)
{
#Set the marker in the URI
$BlobUriBld.Query="restype=container&comp=list&marker=$($BlobResult.NextMarker)"
Write-Verbose "[Get-AzureBlobContainerBlobs] Next set available @ $($BlobUriBld.Uri)"
$RequestParams.Uri=$BlobUriBld.Uri
$TokenParams.Resource=$BlobUriBld.Uri
Write-Verbose "[Get-AzureBlobContainerBlobs] Creating SAS Token for $($BlobUriBld.Uri)"
$SasToken=New-SharedKeySignature @TokenParams
$RequestParams.Headers['Authorization']="SharedKey $($StorageAccountName):$($SasToken)"
$BlobResult=InvokeAzureStorageRequest @RequestParams
if($BlobResult.Blobs -ne $null -and $BlobResult.Blobs.Blob.Count -gt 0)
{
foreach ($NextBlob in $BlobResult.Blobs.Blob)
{
Write-Output $NextBlob
}
}
$HasMore=-not [String]::IsNullOrEmpty($BlobResult.NextMarker)
}
}
}
<#
.SYNOPSIS
Downloads a file from a BLOB container
.PARAMETER StorageAccountName
The storage account name
.PARAMETER ContainerName
The storage account BLOB container name
.PARAMETER BlobName
The name of the BLOB to download
.PARAMETER Uri
The location of the item(s) to be downloaded
.PARAMETER Destination
The download destination folder path
.PARAMETER StorageAccountDomain
The FQDN for the storage account service
.PARAMETER AccessKey
The storage service access key
.PARAMETER UseHttp
Use Insecure requests
.PARAMETER BufferSize
The size of the download buffer
.PARAMETER ApiVersion
The version of the BLOB service API
#>
Function Receive-AzureBlob
{
[CmdletBinding(DefaultParameterSetName='default')]
param
(
[Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true, ParameterSetName='wordy')]
[String]$StorageAccountName,
[Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName='wordy')]
[String]$StorageAccountDomain = "blob.core.windows.net",
[Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName='wordy')]
[String]$ContainerName='$root',
[Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true, ParameterSetName='wordy')]
[String]$BlobName,
[Parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true,ParameterSetName='public')]
[Parameter(Mandatory =$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName = $true,ParameterSetName='default')]
[Uri[]]$Uri,
[Parameter(Mandatory=$false,ValueFromPipelineByPropertyName=$true,ParameterSetName='public')]
[Parameter(Mandatory=$false,ValueFromPipelineByPropertyName=$true,ParameterSetName='default')]
[string]$Destination=$env:TEMP,
[Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true, ParameterSetName='wordy')]
[Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true,ParameterSetName='default')]
[String]$AccessKey,
[Parameter(Mandatory=$false,ValueFromPipelineByPropertyName=$true,ParameterSetName='public')]
[Switch]$IsPublic,
[Parameter(Mandatory=$false,ValueFromPipelineByPropertyName=$true,ParameterSetName='default')]
[Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName='wordy')]
[Parameter(Mandatory=$false,ValueFromPipelineByPropertyName=$true,ParameterSetName='public')]
[String]$ApiVersion="2016-05-31",
[Parameter(Mandatory=$false,ValueFromPipelineByPropertyName=$true,ParameterSetName='default')]
[Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName='wordy')]
[Parameter(Mandatory=$false,ValueFromPipelineByPropertyName=$true,ParameterSetName='public')]
[int]$BufferSize=4096000
)
PROCESS
{
if($PSCmdlet.ParameterSetName -eq 'wordy')
{
$Uri=@(New-Object Uri("https://$StorageAccountName.$StorageAccountDomain/$ContainerName/$BlobName"))
}
foreach ($item in $Uri)
{
if([String]::IsNullOrEmpty($StorageAccountName))
{
$StorageAccountName=$($item.Host.Split('.')|Select-Object -First 1)
}
$DestinationFile=Join-Path $Destination $(Split-Path $item -Leaf)
Write-Verbose "[Receive-AzureBlob] Requesting Azure Storage Blob $item from Storage Account:$StorageAccountName"
$RequestParams=@{
Uri=$item;
Destination=$DestinationFile;
BufferSize=$BufferSize;
}
if ($PSCmdlet.ParameterSetName -in 'default','wordy')
{
$BlobHeaders=@{
'x-ms-date'=[DateTime]::UtcNow.ToString('R');
'x-ms-version'=$ApiVersion;
}
$SasToken=New-SharedKeySignature -Verb GET -Resource $item -AccessKey $AccessKey -Headers $BlobHeaders
$BlobHeaders.Add('Authorization',"SharedKey $($StorageAccountName):$($SasToken)")
$RequestParams.Add('Headers',$BlobHeaders)
Write-Verbose "[Receive-AzureBlob] Using SharedKey $SasToken"
}
DownloadBlob @RequestParams
}
}
}
<#
.SYNOPSIS
Uploads a file to a BLOB storage container
.PARAMETER StorageAccountName
The storage account name
.PARAMETER ContainerName
The storage account BLOB container name
.PARAMETER InputObject
The item(s) to be uploaded
.PARAMETER StorageAccountDomain
The FQDN for the storage account service
.PARAMETER AccessKey
The storage service access key
.PARAMETER UseHttp
Use Insecure requests
.PARAMETER ApiVersion
The version of the BLOB service API
.PARAMETER BlobType
The type of BLOB to be created
.PARAMETER ContentType
The type of content to be uploaded
.PARAMETER CalculateChecksum
Whether to calculate and include an MD5 checksum
.PARAMETER BlobType
The type of BLOB to be created
#>
Function Send-AzureBlob
{
[CmdletBinding()]
param
(
[Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)]
[String]$StorageAccountName,
[Parameter(Mandatory=$false,ValueFromPipelineByPropertyName=$true)]
[String]$StorageAccountDomain = "blob.core.windows.net",
[Parameter(Mandatory=$false,ValueFromPipelineByPropertyName=$true)]
[String]$ContainerName='$root',
[Parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
[System.IO.FileInfo[]]$InputObject,
[Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)]
[String]$AccessKey,
[Parameter(Mandatory=$false,ValueFromPipelineByPropertyName=$true)]
[Switch]$UseHttp,
[Parameter(Mandatory=$false,ValueFromPipelineByPropertyName=$true)]
[String]$ApiVersion="2016-05-31",
[ValidateSet('BlockBlob','PageBlob','AppendBlob')]
[Parameter(Mandatory=$false,ValueFromPipelineByPropertyName=$true)]
[String]$BlobType="BlockBlob",
[Parameter(Mandatory=$false,ValueFromPipelineByPropertyName=$true)]
[String]$ContentType,
[Parameter(Mandatory=$false,ValueFromPipelineByPropertyName=$true)]
[System.Collections.IDictionary]$Metadata,
[Parameter(Mandatory=$false,ValueFromPipelineByPropertyName=$true)]
[Switch]$CalculateChecksum,
[ValidateRange(1MB,4MB)]
[Parameter(Mandatory=$false,ValueFromPipelineByPropertyName=$true)]
[int]$PageBufferSize=4MB
)
PROCESS
{
foreach ($item in $InputObject)
{
$Checksum=[String]::Empty
#Make sure this aligns across a 512-byte boundary
if(($BlobType -eq 'PageBlob') -and ($item.Length % 512 -ne 0))
{
throw "Page BLOB(s) must align to 512 byte boundaries"
}
$BlobUri=GetStorageUri -AccountName $StorageAccountName -StorageServiceFQDN $StorageAccountDomain -IsInsecure $UseHttp.IsPresent
$BlobUriBld=New-Object System.UriBuilder($BlobUri)
$BlobUriBld.Path="$($ContainerName.TrimEnd('/'))/$($item.Name)"
$BlobHeaders=[ordered]@{}
if([String]::IsNullOrEmpty($ContentType))
{
$ContentType=[System.Web.MimeMapping]::GetMimeMapping($item.Name)
Write-Verbose "[Send-AzureBlob] Inferring Content-Type:$ContentType"
}
$TokenParams=@{
Resource=$BlobUriBld.Uri;
Verb='PUT';
ContentType=$ContentType;
AccessKey=$AccessKey;
}
if($BlobType -eq 'BlockBlob')
{
$TokenParams.Add('ContentLength',$item.Length)
$BlobHeaders.Add('x-ms-blob-content-disposition',"attachment; filename=`"$($item.Name)`"")
}
elseif($BlobType -eq 'PageBlob')
{
$BlobHeaders.Add('x-ms-blob-content-length',$item.Length)
}
else
{
throw "AppendBlob not yet supported"
}
if($CalculateChecksum.IsPresent)
{
Write-Verbose "[Send-AzureBlob] Calculating MD5 Hash for $($item.Name)"
$Checksum=$item|GetMd5Hash
Write-Verbose "[Send-AzureBlob] Calculated Hash $Checksum"
$BlobHeaders.Add('x-ms-blob-content-md5',$Checksum)
$TokenParams.Add('ContentMD5',$Checksum)
}
$BlobHeaders.Add('x-ms-blob-content-type',$ContentType)
$BlobHeaders.Add('x-ms-blob-type',$BlobType)
if($Metadata -ne $null)
{
foreach ($MetaKey in $Metadata.Keys)
{
$BlobHeaders.Add("x-ms-meta-$MetaKey",$Metadata[$MetaKey])
}
}
$BlobHeaders.Add('x-ms-date',[DateTime]::UtcNow.ToString('R'))
$BlobHeaders.Add('x-ms-version',$ApiVersion)
$TokenParams.Add('Headers',$BlobHeaders)
$SasToken=New-SharedKeySignature @TokenParams
if([String]::IsNullOrEmpty($Checksum) -eq $false)
{
$BlobHeaders.Add('Content-MD5',$Checksum)
}
$BlobHeaders.Add("Authorization","SharedKey $($StorageAccountName):$($SasToken)")
if($BlobType -eq 'BlockBlob')
{
Write-Verbose "[Send-AzureBlob] Uploading Block Blob $($item.FullName) to $($BlobUriBld.Uri)"
$FileBytes=[System.IO.File]::ReadAllBytes($item.FullName)
$BlobHeaders.Add('Content-Length',$FileBytes.Length)
$BlobHeaders.Add('Content-Type',$ContentType)
$RequestParams=@{
Uri=$BlobUriBld.Uri;
Method='PUT';
Headers=$BlobHeaders;
Body=$FileBytes;
}
$Response=Invoke-WebRequest @RequestParams
Write-Verbose "[Send-AzureBlob] Upload Completed $($Response.StatusCode) - $($Response.StatusDescription)"
Write-Output $Response.Headers
}
else
{
Write-Verbose "[Send-AzureBlob] Creating Page Blob $($item.FullName) @ $($BlobUriBld.Uri) of size $($item.Length/1MB)"
Write-Progress -Activity "Creating Page BLOB" -Status "Creating $($item.FullName) @ $($BlobUriBld.Uri) of size $($item.Length/1MB) MB"
$BlobHeaders.Add('Content-Type',$ContentType)
$RequestParams=@{
Uri=$BlobUriBld.Uri;
Method='PUT';
Headers=$BlobHeaders;
ReturnHeaders=$true;
ErrorAction='Stop';
}
$Response=InvokeAzureStorageRequest @RequestParams
Write-Verbose "[Send-AzureBlob] Creating Page Blob $($item.FullName) @ $($BlobUriBld.Uri) of size $($item.Length/1MB) - Success!"
#Now we can start appending the pages
$InputStream=[System.IO.Stream]::Null
$Stopwatch=New-Object System.Diagnostics.Stopwatch
try
{
$BytesWritten=0
Write-Verbose "[Send-AzureBlob] Appending File Stream to Page BLOB @ $($BlobUriBld.Uri) - Page Size:$PageBufferSize"
$Buffer=New-Object System.Byte[]($PageBufferSize)
$InputStream=$item.OpenRead()
$BytesRead=$InputStream.Read($Buffer,$BytesWritten,$PageBufferSize)
while ($BytesRead -gt 0)
{
$Stopwatch.Start()
$RangeStart=$BytesWritten
$BytesWritten+=$BytesRead
$Page=$Buffer[0..$($BytesRead-1)]
$PutPageResult=Set-AzureBlobPage -Page $Page -StorageAccountName $StorageAccountName -StorageAccountDomain $StorageAccountDomain `
-ContainerName $ContainerName -BlobItem $item.Name -AccessKey $AccessKey -ApiVersion $ApiVersion `
-UseHttp:$UseHttp -CalculateChecksum:$CalculateChecksum -RangeStart $RangeStart -RangeEnd $BytesWritten
$Speed=[Math]::Round($BytesWritten/1MB/$Stopwatch.Elapsed.TotalSeconds,2)
$Stopwatch.Stop()
Write-Verbose "[Send-AzureBlob] ETag:$($PutPageResult.ETag) Transfer-Encoding:$($PutPageResult.'Transfer-Encoding') Request Id:$($PutPageResult.'x-ms-request-id')"
Write-Progress -Activity "Updating Page BLOB" -Status "Updating $($BlobUriBld.Uri) $([Math]::Round($BytesWritten/1MB)) MB written - ($Speed mb/s)" -PercentComplete $($BytesWritten/$item.Length * 100)
$BytesRead=$InputStream.Read($Buffer,0,$PageBufferSize)
}
}
catch
{
throw $_
}
finally
{
$Stopwatch.Stop()
Write-Progress -Activity "Creating Page BLOB" -Completed
if($InputStream -ne $null)
{
$InputStream.Dispose()
}
}
}
}
}
}
<#
.SYNOPSIS
Updates the content of a Page BLOB
.PARAMETER StorageAccountName
The storage account name
.PARAMETER ContainerName
The storage account BLOB container name
.PARAMETER BlobItem
The name of the item to be uploaded
.PARAMETER StorageAccountDomain
The FQDN for the storage account service
.PARAMETER AccessKey
The storage service access key
.PARAMETER UseHttp
Use Insecure requests
.PARAMETER ApiVersion
Tnh
.PARAMETER RangeStart
The byte position of the page range
.PARAMETER RangeEnd
The ending byte position of the page range
.PARAMETER ClearRange
Clear the range of bytes
.PARAMETER CalculateChecksum
Calculate an MD5 checksum of the content
#>
Function Set-AzureBlobPage
{
[CmdletBinding()]
param
(
[Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true,ParameterSetName='clear')]
[Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true,ParameterSetName='update')]
[String]$StorageAccountName,
[Parameter(Mandatory=$false,ValueFromPipelineByPropertyName=$true,ParameterSetName='clear')]
[Parameter(Mandatory=$false,ValueFromPipelineByPropertyName=$true,ParameterSetName='update')]
[String]$StorageAccountDomain = "blob.core.windows.net",
[Parameter(Mandatory=$false,ValueFromPipelineByPropertyName=$true,ParameterSetName='clear')]
[Parameter(Mandatory=$false,ValueFromPipelineByPropertyName=$true,ParameterSetName='update')]
[String]$ContainerName='$root',
[Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true,ParameterSetName='clear')]
[Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true,ParameterSetName='update')]
[String]$BlobItem,
[Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true,ParameterSetName='clear')]
[Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true,ParameterSetName='update')]
[long]$RangeStart,
[Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true,ParameterSetName='clear')]
[Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true,ParameterSetName='update')]
[long]$RangeEnd,
[Parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true,ParameterSetName='update')]
[System.Byte[]]$Page,
[Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true,ParameterSetName='clear')]
[Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true,ParameterSetName='update')]
[String]$AccessKey,
[Parameter(Mandatory=$false,ValueFromPipelineByPropertyName=$true,ParameterSetName='clear')]
[Parameter(Mandatory=$false,ValueFromPipelineByPropertyName=$true,ParameterSetName='update')]
[Switch]$UseHttp,
[Parameter(Mandatory=$false,ValueFromPipelineByPropertyName=$true,ParameterSetName='clear')]
[Parameter(Mandatory=$false,ValueFromPipelineByPropertyName=$true,ParameterSetName='update')]
[String]$ApiVersion="2016-05-31",
[Parameter(Mandatory=$false,ValueFromPipelineByPropertyName=$true,ParameterSetName='clear')]
[Switch]$ClearRange,
[Parameter(Mandatory=$false,ValueFromPipelineByPropertyName=$true,ParameterSetName='update')]
[Switch]$CalculateChecksum
)
$Checksum=[String]::Empty
if($PSCmdlet.ParameterSetName -eq 'update')
{
$WriteAction='Update'
$ContentLength=$Page.Length
if($CalculateChecksum.IsPresent)
{
$Hasher= New-Object System.Security.Cryptography.MD5CryptoServiceProvider
$Checksum=[System.Convert]::ToBase64String($Hasher.ComputeHash($Page))
}
}
else
{
$WriteAction='Clear'
$ContentLength=0
}
$BlobUri=GetStorageUri -AccountName $StorageAccountName -StorageServiceFQDN $StorageAccountDomain -IsInsecure $UseHttp.IsPresent
$BlobUriBld=New-Object System.UriBuilder($BlobUri)
$BlobUriBld.Path="$($ContainerName.TrimEnd('/'))/$($BlobItem)"
$BlobUriBld.Query="comp=page"
Write-Verbose "[Set-AzureBlobPage] Azure BLOB Page Action:$WriteAction $($BlobUriBld.Uri) $RangeStart,$RangeEnd"
$TokenParams=@{
Resource=$BlobUriBld.Uri;
Verb='PUT';
AccessKey=$AccessKey;
#RangeStart=$RangeStart;
#RangeEnd=$RangeEnd;
}
if($ContentLength -gt 0)
{
$TokenParams.Add('ContentLength',$ContentLength)
}
$BlobHeaders=[ordered]@{
'x-ms-blob-type'="PageBlob";
'x-ms-date'=[System.DateTime]::UtcNow.ToString('R');
'x-ms-page-write'=$WriteAction;
'x-ms-range'="bytes=$RangeStart-$($RangeEnd-1)";
'x-ms-version'=$ApiVersion;
}
if([String]::IsNullOrEmpty($Checksum) -eq $false)
{
$TokenParams.Add('ContentMD5',$Checksum)
}
$TokenParams.Add('Headers',$BlobHeaders)
$StopWatch=New-Object System.Diagnostics.Stopwatch
try
{
$SasToken=New-SharedKeySignature @TokenParams
$StopWatch.Start()
if([String]::IsNullOrEmpty($Checksum) -eq $false)
{
$BlobHeaders.Add('Content-MD5',$Checksum)
}
$BlobHeaders.Add("Authorization","SharedKey $($StorageAccountName):$SasToken")
$BlobHeaders.Add('Content-Length',$ContentLength)
$RequestParams=@{
Uri=$BlobUriBld.Uri;
Method='PUT';
Headers=$BlobHeaders;
Body=$Page;
ReturnHeaders=$true
}
$Result=InvokeAzureStorageRequest @RequestParams
$StopWatch.Stop()
Write-Verbose "[Set-AzureBlobPage] $($BlobUriBld.Uri) Page Action:$WriteAction Range:$RangeStart - $RangeEnd bytes succeeded in $($StopWatch.Elapsed.TotalSeconds) secs."
Write-Output $Result
}
catch
{
throw $_
}
finally
{
$StopWatch.Stop()
}
}
<#
.SYNOPSIS
Retrieves the list of containers for the storage account
.PARAMETER StorageAccountName
The storage account name
.PARAMETER StorageAccountDomain
The FQDN for the storage account service
.PARAMETER AccessKey
The storage service access key
.PARAMETER UseHttp
Use Insecure requests
.PARAMETER ApiVersion
The version of the BLOB service API
#>
Function Get-AzureBlobContainer
{
[CmdletBinding()]
param
(
[Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)]
[String]$StorageAccountName,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)]
[String]$StorageAccountDomain = "blob.core.windows.net",
[Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)]
[String]$AccessKey,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName=$true)]
[Switch]$UseHttp,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)]
[String]$ApiVersion = "2016-05-31"
)
$BlobUri=GetStorageUri -AccountName $StorageAccountName -StorageServiceFQDN $StorageAccountDomain -IsInsecure $UseHttp.IsPresent
$BlobUriBld=New-Object System.UriBuilder($BlobUri)
$BlobUriBld.Query = "comp=list"
$BlobHeaders = [ordered]@{
"x-ms-date" = [DateTime]::UtcNow.ToString('R');
"x-ms-version" = $ApiVersion;
}
$TokenParams=@{
Verb="GET";
Resource=$BlobUriBld.Uri;
AccessKey=$AccessKey;
Headers=$BlobHeaders;
}
$SasToken = New-SharedKeySignature @TokenParams
$BlobHeaders.Add("Authorization","SharedKey $($StorageAccountName):$($SasToken)")
$RequestParams=@{
Uri=$BlobUriBld.Uri;
Method='GET';
Headers=$BlobHeaders;
}
$Result = InvokeAzureStorageRequest @RequestParams|Select-Object -ExpandProperty EnumerationResults
Write-Verbose "[Get-AzureBlobContainer] Blob Response Endpoint:$($Result.ServiceEndpoint)"
if($Result -ne $null -and $Result.Containers -ne $null)
{
foreach ($item in $Result.Containers.Container)
{
Write-Output $item
}
}
}
<#
.SYNOPSIS
Retrieves the properties for a Blob container
.PARAMETER StorageAccountName
The storage account name
.PARAMETER StorageAccountDomain
The FQDN for the storage account service
.PARAMETER ContainerName
The name of the container
.PARAMETER AccessKey
The storage service access key
.PARAMETER UseHttp
Use Insecure requests
.PARAMETER ApiVersion
The version of the BLOB service API
#>
Function Get-AzureBlobContainerProperties
{
[CmdletBinding()]
param
(
[Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)]
[String]$StorageAccountName,
[Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)]
[String]$ContainerName,
[Parameter(Mandatory=$false,ValueFromPipelineByPropertyName=$true)]
[String]$StorageAccountDomain="blob.core.windows.net",
[Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)]
[String]$AccessKey,
[Parameter(Mandatory=$false,ValueFromPipelineByPropertyName=$true)]
[Switch]$UseHttp,
[Parameter(Mandatory=$false,ValueFromPipelineByPropertyName=$true)]
[String]$ApiVersion="2016-05-31"
)
$BlobUri=GetStorageUri -AccountName $StorageAccountName -StorageServiceFQDN $StorageAccountDomain -IsInsecure $UseHttp.IsPresent
$BlobUriBld=New-Object System.UriBuilder($BlobUri)
$BlobUriBld.Path="$ContainerName"
$BlobUriBld.Query="restype=container"
$RequestParams=@{
Uri=$BlobUriBld.Uri;
Method='GET';
ReturnHeaders=$true;
}
$BlobHeaders= [ordered]@{
"x-ms-date"=[DateTime]::UtcNow.ToString('R');
"x-ms-version"=$ApiVersion;
}
$TokenParams=@{
Verb="GET";
Resource=$BlobUriBld.Uri;
AccessKey=$AccessKey;
Headers=$BlobHeaders;
}
$SasToken = New-SharedKeySignature @TokenParams
$BlobHeaders.Add("Authorization","SharedKey $($StorageAccountName):$($SasToken)")
$RequestParams.Add('Headers',$BlobHeaders)
$Result=InvokeAzureStorageRequest @RequestParams
Write-Output $Result
}
<#
.SYNOPSIS
Retrieves the public Access Control for a Blob container
.PARAMETER StorageAccountName
The storage account name
.PARAMETER StorageAccountDomain
The FQDN for the storage account service
.PARAMETER ContainerName
The name of the container
.PARAMETER AccessKey
The storage service access key
.PARAMETER UseHttp
Use Insecure requests
.PARAMETER ApiVersion
The version of the BLOB service API
#>
Function Get-AzureBlobContainerAcl
{
[CmdletBinding()]
param
(
[Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)]
[String]$StorageAccountName,
[Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)]
[String]$ContainerName,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)]
[String]$StorageAccountDomain = "blob.core.windows.net",
[Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)]
[String]$AccessKey,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName=$true)]
[Switch]$UseHttp,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)]
[String]$ApiVersion = "2016-05-31"
)
$BlobUri=GetStorageUri -AccountName $StorageAccountName -StorageServiceFQDN $StorageAccountDomain -IsInsecure $UseHttp.IsPresent
$BlobUriBld=New-Object System.UriBuilder($BlobUri)
$BlobUriBld.Path = "$ContainerName"
$BlobUriBld.Query = "restype=container&comp=acl"
$RequestParams=@{
Uri=$BlobUriBld.Uri;
Method='GET';
ReturnHeaders=$true;
}
$BlobHeaders = [ordered]@{
"x-ms-date" = [DateTime]::UtcNow.ToString('R');
"x-ms-version" = $ApiVersion;
}
$TokenParams=@{
Verb="GET";
Resource=$BlobUriBld.Uri;
AccessKey=$AccessKey;
Headers=$BlobHeaders;
}
$SasToken = New-SharedKeySignature @TokenParams
$BlobHeaders.Add("Authorization","SharedKey $($StorageAccountName):$($SasToken)")
$RequestParams.Add('Headers',$BlobHeaders)
$Result = InvokeAzureStorageRequest @RequestParams
Write-Output $Result.'x-ms-blob-public-access'
}
<#
.SYNOPSIS
Set the public access control for a blob container
.PARAMETER StorageAccountName
The storage account name
.PARAMETER StorageAccountDomain
The FQDN for the storage account service
.PARAMETER ContainerName
The name of the container
.PARAMETER AccessKey
The storage service access key
.PARAMETER UseHttp
Use Insecure requests
.PARAMETER ApiVersion
The version of the BLOB service API
.PARAMETER AccessLevel
The public access level for the container
#>
Function Set-AzureBlobContainerAcl
{
[CmdletBinding()]
param
(
[Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)]
[String]$StorageAccountName,
[Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)]
[String]$ContainerName,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)]
[String]$StorageAccountDomain = "blob.core.windows.net",
[ValidateSet('container','blob','private')]
[Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)]
[String]$AccessLevel,
[Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)]
[String]$AccessKey,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName=$true)]
[Switch]$UseHttp,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)]
[String]$ApiVersion = "2016-05-31"
)
$BlobUri=GetStorageUri -AccountName $StorageAccountName -StorageServiceFQDN $StorageAccountDomain -IsInsecure $UseHttp.IsPresent
$BlobUriBld=New-Object System.UriBuilder($BlobUri)
$BlobUriBld.Path = "$ContainerName"
$BlobUriBld.Query = "restype=container&comp=acl"
$RequestParams=@{
Uri=$BlobUriBld.Uri;
Method='PUT';
ReturnHeaders=$true;
}
$BlobHeaders = [ordered]@{
"x-ms-date" = [datetime]::UtcNow.ToString('R');
"x-ms-version" = $ApiVersion;
}
if($AccessLevel -ne 'private')
{
$BlobHeaders.Add('x-ms-blob-public-access',$AccessLevel)
}
$TokenParams=@{
Verb="PUT";
Resource=$BlobUriBld.Uri;
AccessKey=$AccessKey;
Headers=$BlobHeaders;
}
$SasToken = New-SharedKeySignature @TokenParams
$BlobHeaders.Add("Authorization","SharedKey $($StorageAccountName):$($SasToken)")
$RequestParams.Add('Headers',$BlobHeaders)
$Result = InvokeAzureStorageRequest @RequestParams
$Acl=$Result.'x-ms-blob-public-access'
if([String]::IsNullOrEmpty($Acl))
{
$Acl='private'
}
Write-Output $Acl
}
<#
.SYNOPSIS
Creates a new BLOB container
.PARAMETER StorageAccountName
The storage account name
.PARAMETER StorageAccountDomain
The FQDN for the storage account service
.PARAMETER ContainerName
The name of the container
.PARAMETER AccessKey
The storage service access key
.PARAMETER UseHttp
Use Insecure requests
.PARAMETER ApiVersion
The version of the BLOB service API
#>
Function New-AzureBlobContainer
{
[CmdletBinding()]
param
(
[Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)]
[String]$StorageAccountName,
[Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)]
[String]$ContainerName,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)]
[String]$StorageAccountDomain = "blob.core.windows.net",
[Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)]
[String]$AccessKey,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName=$true)]
[Switch]$UseHttp,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)]
[String]$ApiVersion = "2016-05-31"
)
$BlobUri=GetStorageUri -AccountName $StorageAccountName -StorageServiceFQDN $StorageAccountDomain -IsInsecure $UseHttp.IsPresent
$BlobUriBld=New-Object System.UriBuilder($BlobUri)
$BlobUriBld.Path = $ContainerName.ToLower()
$BlobUriBld.Query = "restype=container"
Write-Verbose "[New-AzureBlobContainer] Creating new BLOB container $BlobUri"
$RequestParams=@{
Uri=$BlobUriBld.Uri;
Method='PUT';
ReturnHeaders=$true;
}
$BlobHeaders = [ordered]@{
"x-ms-date" = [DateTime]::UtcNow.ToString('R');
"x-ms-version" = $ApiVersion;
}
$TokenParams=@{
Verb="PUT";
Resource=$BlobUriBld.Uri;
AccessKey=$AccessKey;
Headers=$BlobHeaders;
}
$SasToken = New-SharedKeySignature @TokenParams
$BlobHeaders.Add("Authorization","SharedKey $($StorageAccountName):$($SasToken)")
$RequestParams.Add('Headers',$BlobHeaders)
$Result = InvokeAzureStorageRequest @RequestParams
Write-Output $Result
}
<#
.SYNOPSIS
Deletes a new BLOB container
.PARAMETER StorageAccountName
The storage account name
.PARAMETER StorageAccountDomain
The FQDN for the storage account service
.PARAMETER ContainerName
The name of the container
.PARAMETER AccessKey
The storage service access key
.PARAMETER UseHttp
Use Insecure requests
.PARAMETER ApiVersion
The version of the BLOB service API
#>
Function Remove-AzureBlobContainer
{
[CmdletBinding()]
param
(
[Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)]
[String]$StorageAccountName,
[Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)]
[String]$ContainerName,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)]
[String]$StorageAccountDomain = "blob.core.windows.net",
[Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)]
[String]$AccessKey,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName=$true)]
[Switch]$UseHttp,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)]
[String]$ApiVersion = "2016-05-31"
)
$BlobUri=GetStorageUri -AccountName $StorageAccountName -StorageServiceFQDN $StorageAccountDomain -IsInsecure $UseHttp.IsPresent
$BlobUriBld=New-Object System.UriBuilder($BlobUri)
$BlobUriBld.Path = "$ContainerName"
$BlobUriBld.Query = "restype=container"
Write-Verbose "[Remove-AzureBlobContainer] Removing BLOB Container $BlobUri"
$RequestParams=@{
Uri=$BlobUriBld.Uri;
Method='DELETE';
ReturnHeaders=$true;
}
$BlobHeaders = [ordered]@{
"x-ms-date" = [DateTime]::UtcNow.ToString('R');
"x-ms-version" = $ApiVersion;
}
$TokenParams=@{
Verb="DELETE";
Resource=$BlobUriBld.Uri;
AccessKey=$AccessKey;
Headers=$BlobHeaders;
}
$SasToken = New-SharedKeySignature @TokenParams
$BlobHeaders.Add("Authorization","SharedKey $($StorageAccountName):$($SasToken)")
$RequestParams.Add('Headers',$BlobHeaders)
$Result = InvokeAzureStorageRequest @RequestParams
Write-Output $Result
}
<#
.SYNOPSIS
Creates a new BLOB container lease
.PARAMETER StorageAccountName
The storage account name
.PARAMETER StorageAccountDomain
The FQDN for the storage account service
.PARAMETER ContainerName
The name of the container
.PARAMETER AccessKey
The storage service access key
.PARAMETER UseHttp
Use Insecure requests
.PARAMETER ApiVersion
The version of the BLOB service API
#>
Function Set-AzureBlobContainerLease
{
[CmdletBinding()]
param
(
[Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)]
[String]$StorageAccountName,
[Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)]
[String]$ContainerName,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)]
[String]$StorageAccountDomain = "blob.core.windows.net",
[ValidateSet('Acquire','Renew','Change','Release','Break')]
[Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)]
[String]$LeaseAction,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)]
[Guid]$Id,
[ValidateRange(-1,60)]
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)]
[int]$Duration=-1,
[Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)]
[String]$AccessKey,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName=$true)]
[Switch]$UseHttp,
[Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)]
[String]$ApiVersion = "2016-05-31"
)
$BlobUri=GetStorageUri -AccountName $StorageAccountName -StorageServiceFQDN $StorageAccountDomain -IsInsecure $UseHttp.IsPresent
$BlobUriBld=New-Object System.UriBuilder($BlobUri)
$BlobUriBld.Path = "$ContainerName"
$BlobUriBld.Query = "comp=lease&restype=container"
Write-Verbose "[Set-AzureBlobContainerLease] Performing lease action:$LeaseAction on $BlobUri"
$RequestParams=@{
Uri=$BlobUriBld.Uri;
Method='PUT';
ReturnHeaders=$true;
}
$BlobHeaders = [ordered]@{
"x-ms-date" = [datetime]::UtcNow.ToString('R');
}
$BlobHeaders.Add('x-ms-lease-action',$LeaseAction.ToLower())
if($LeaseAction -in 'Renew','Change','Release')
{
if($Id -eq [guid]::Empty)
{
throw "A Lease Id must be specified for 'Renew','Change','Release' action"
}
$BlobHeaders.Add('x-ms-lease-id',$Id)
if($LeaseAction -eq 'Change')
{
$BlobHeaders.Add('x-ms-proposed-lease-id',[Guid]::NewGuid())
}
}
elseif($LeaseAction -eq 'Break')
{
if($Duration -ne -1)
{
$BlobHeaders.Add('x-ms-lease-break-period',$Duration)
}
}
elseif($LeaseAction -eq 'Acquire')
{
$BlobHeaders.Add('x-ms-lease-duration',$Duration)
}
$BlobHeaders.Add("x-ms-version",$ApiVersion)
$TokenParams=@{
Verb="PUT";
Resource=$BlobUriBld.Uri;
AccessKey=$AccessKey;
Headers=$BlobHeaders;
}
$SasToken = New-SharedKeySignature @TokenParams
$BlobHeaders.Add("Authorization","SharedKey $($StorageAccountName):$($SasToken)")
$RequestParams.Add('Headers',$BlobHeaders)
$Result = InvokeAzureStorageRequest @RequestParams
Write-Output $Result
}
<#
.SYNOPSIS
Retrieves the metadata for a BLOB
.PARAMETER Uri
The URI of the BLOB
.PARAMETER BlobName
The name of the BLOB
.PARAMETER StorageAccountName
The storage account name
.PARAMETER StorageAccountDomain
The FQDN for the storage account service
.PARAMETER ContainerName
The name of the container
.PARAMETER AccessKey
The storage service access key
.PARAMETER UseHttp
Use Insecure requests
.PARAMETER ApiVersion
The version of the BLOB service API
#>
Function Get-AzureBlobMetadata
{
[CmdletBinding()]
param
(
[Parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true,ParameterSetName='direct')]
[Uri[]]$InputObject,
[Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true,ParameterSetName='indirect')]
[String]$StorageAccountName,
[Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true,ParameterSetName='indirect')]
[String]$ContainerName,