/
Calculate-AzureStorageBlob.ps1
204 lines (181 loc) · 7.58 KB
/
Calculate-AzureStorageBlob.ps1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
<#
.SYNOPSIS
Calculates cost of all blobs in a container or storage account.
.DESCRIPTION
Enumerates all blobs in either one container or one storage account and sums
up all costs associated. This includes all block and page blobs, all metadata
on either blobs or containers. It also includes both committed and uncommitted
blocks in the case that a blob is partially uploaded.
The details of the calculations can be found in this post:
http://blogs.msdn.com/b/windowsazurestorage/archive/2010/07/09/understanding-windows-azure-storage-billing-bandwidth-transactions-and-capacity.aspx
Note: This script requires an Azure Storage Account to run. The storage account
can be specified by setting the subscription configuration. For example:
Set-AzureSubscription -SubscriptionName "MySubscription" -CurrentStorageAccount "MyStorageAccount"
.EXAMPLE
.\CalculateBlobCost.ps1 -StorageAccountName "mystorageaccountname"
.\CalculateBlobCost.ps1 -StorageAccountName "mystorageaccountname" -ContainerName "mycontainername"
#>
param(
# The name of the storage account to enumerate.
[Parameter(Mandatory = $true)]
[string]$StorageAccountName,
# The name of the storage container to enumerate.
[Parameter(Mandatory = $false)]
[ValidateNotNullOrEmpty()]
[string]$ContainerName
)
# The script has been tested on Powershell 3.0
Set-StrictMode -Version 4
# Following modifies the Write-Verbose behavior to turn the messages on globally for this session
#$VerbosePreference = "Continue"
# Check if Windows Azure Powershell is avaiable
if ((Get-Module -ListAvailable Azure) -eq $null)
{
throw "Windows Azure Powershell not found! Please install from http://www.windowsazure.com/en-us/downloads/#cmd-line-tools"
}
<#
.SYNOPSIS
Gets the size (in bytes) of a blob.
.DESCRIPTION
Given a blob name, sum up all bytes consumed including the blob itself and any metadata,
all committed blocks and uncommitted blocks.
Formula reference for calculating size of blob:
http://blogs.msdn.com/b/windowsazurestorage/archive/2010/07/09/understanding-windows-azure-storage-billing-bandwidth-transactions-and-capacity.aspx
.INPUTS
$Blob - The blob to calculate the size of.
.OUTPUTS
$blobSizeInBytes - The calculated sizeo of the blob.
#>
function Get-BlobBytes
{
param (
[Parameter(Mandatory=$true)]
[Microsoft.WindowsAzure.Commands.Common.Storage.ResourceModel.AzureStorageBlob]$Blob)
# Base + blob name
$blobSizeInBytes = 124 + $Blob.Name.Length * 2
# Get size of metadata
$metadataEnumerator = $Blob.ICloudBlob.Metadata.GetEnumerator()
while ($metadataEnumerator.MoveNext())
{
$blobSizeInBytes += 3 + $metadataEnumerator.Current.Key.Length + $metadataEnumerator.Current.Value.Length
}
if ($Blob.BlobType -eq [Microsoft.WindowsAzure.Storage.Blob.BlobType]::BlockBlob)
{
$blobSizeInBytes += 8
$Blob.ICloudBlob.DownloadBlockList() |
ForEach-Object { $blobSizeInBytes += $_.Length + $_.Name.Length }
}
else
{
[int64]$rangeSize = 1GB
[int64]$start = 0; $pages = "Start";
While ($pages)
{
try
{
$pages = $Blob.ICloudBlob.GetPageRanges($start, $rangeSize)
}
catch
{
if ($_ -like "*the range specified is invalid*")
{
$pages = $null
break
}
else
{
write-error $_
}
}
$pages | ForEach-Object { $blobSizeInBytes += 12 + $_.EndOffset - $_.StartOffset }
$start += $rangeSize
}
}
return $blobSizeInBytes
}
<#
.SYNOPSIS
Gets the size (in bytes) of a blob container.
.DESCRIPTION
Given a container name, sum up all bytes consumed including the container itself and any metadata,
all blobs in the container together with metadata, all committed blocks and uncommitted blocks.
.INPUTS
$Container - The container to calculate the size of.
.OUTPUTS
$containerSizeInBytes - The calculated size of the container.
#>
function Get-ContainerBytes
{
param (
[Parameter(Mandatory=$true)]
[Microsoft.WindowsAzure.Commands.Common.Storage.ResourceModel.AzureStorageContainer]$Container)
# Base + name of container
$containerSizeInBytes = 48 + $Container.Name.Length * 2
# Get size of metadata
$metadataEnumerator = $Container.CloudBlobContainer.Metadata.GetEnumerator()
while ($metadataEnumerator.MoveNext())
{
$containerSizeInBytes += 3 + $metadataEnumerator.Current.Key.Length +
$metadataEnumerator.Current.Value.Length
}
# Get size for Shared Access Policies
$containerSizeInBytes += $Container.Permission.SharedAccessPolicies.Count * 512
# Calculate size of all blobs.
$blobCount = 0
Get-AzureStorageBlob -Context $storageContext -Container $Container.Name |
ForEach-Object {
$containerSizeInBytes += Get-BlobBytes $_
$blobCount++
}
return @{ "containerSize" = $containerSizeInBytes; "blobCount" = $blobCount }
}
$storageAccount = Get-AzureStorageAccount -StorageAccountName $StorageAccountName -ErrorAction SilentlyContinue
$ifarm = $false
If (!$storageAccount) {
$StorageAccount = Get-AzureRmStorageAccount | where {$_.StorageAccountName -eq $StorageAccountName}
$ResourceGroupName = $storageAccount.ResourceGroupName
$ifarm = $true
}
if ($storageAccount -eq $null)
{
throw "The storage account specified does not exist in this subscription."
}
# Instantiate a storage context for the storage account.
If ($ifarm) {
$storagePrimaryKey = (Get-AzureRmStorageAccountKey -StorageAccountName $StorageAccountName -ResourceGroupName $ResourceGroupName)[0].Value
}
else
{
$storagePrimaryKey = (Get-AzureStorageKey -StorageAccountName $StorageAccountName).Primary
}
$storageContext = New-AzureStorageContext -StorageAccountName $StorageAccountName -StorageAccountKey $storagePrimaryKey
# Get a list of containers to process.
$containers = New-Object System.Collections.ArrayList
if ($ContainerName.Length -ne 0)
{
$container = Get-AzureStorageContainer -Context $storageContext `
-Name $ContainerName -ErrorAction SilentlyContinue |
ForEach-Object { $containers.Add($_) } | Out-Null
}
else
{
Get-AzureStorageContainer -Context $storageContext | ForEach-Object { $containers.Add($_) } | Out-Null
}
# Calculate size.
$sizeInBytes = 0
if ($containers.Count -gt 0)
{
$containers | ForEach-Object {
$result = Get-ContainerBytes $_ #.CloudBlobContainer
$sizeInBytes += $result.containerSize
Write-Verbose ("Container '{0}' with {1} blobs has a size of {2:F2}MB." -f `
$_.CloudBlobContainer.Name, $result.blobCount, ($result.containerSize / 1MB))
}
Write-Output ("Total size calculated for {0} containers is {1:F2}GB." -f $containers.Count, ($sizeInBytes / 1GB))
# Launch default browser to azure calculator for data management.
# Start-Process -FilePath http://www.windowsazure.com/en-us/pricing/calculator/?scenario=data-management
}
else
{
Write-Warning "No containers found to process in storage account '$StorageAccountName'."
}