3
3
# and upload some blobs into the container
4
4
# note: this retrieves all of the blobs in the container in one command.
5
5
# connect Azure with Login-AzureRmAccount before you run the script.
6
+ # requests sent as part of this tool will incur transactional costs.
6
7
# command line usage: script.ps1 -ResourceGroup {YourResourceGroupName} -StorageAccountName {YourAccountName} -ContainerName {YourContainerName}
7
8
#
8
9
@@ -22,20 +23,64 @@ param(
22
23
23
24
$VerbosePreference = " Continue"
24
25
25
- if ((Get-Module - ListAvailable Azure) -eq $null )
26
+ if ((( Get-Module - ListAvailable Azure) -eq $null ) -or (( Get-Module - ListAvailable Azure.Storage) -eq $null ) )
26
27
{
27
- throw " Azure Powershell not found! Please install from http ://www.windowsazure .com/en-us/downloads/#cmd-line-tools "
28
+ throw " Azure Powershell not found! Please install from https ://docs.microsoft .com/en-us/powershell/azure/install-azurerm-ps "
28
29
}
29
30
31
+ # function Retry-OnRequest
32
+ function Retry-OnRequest
33
+ {
34
+ param (
35
+ [Parameter (Mandatory = $true )]
36
+ $Action )
37
+
38
+ # It could encounter various of temporary errors, like network errors, or storage server busy errors.
39
+ # Should retry the request on transient errors
40
+
41
+ # Retry on storage server timeout errors
42
+ $clientTimeOut = New-TimeSpan - Minutes 15
43
+ $retryPolicy = New-Object - TypeName Microsoft.WindowsAzure.Storage.RetryPolicies.ExponentialRetry - ArgumentList @ ($clientTimeOut , 10 )
44
+ $requestOption = @ {}
45
+ $requestOption.RetryPolicy = $retryPolicy
46
+
47
+ # Retry on temporary network errors
48
+ $shouldRetryOnException = $false
49
+ $maxRetryCountOnException = 3
50
+
51
+ do
52
+ {
53
+ try
54
+ {
55
+ return $Action.Invoke ($requestOption )
56
+ }
57
+ catch
58
+ {
59
+ if ($_.Exception.InnerException -ne $null -And $_.Exception.InnerException.GetType () -Eq [System.TimeoutException ] -And $maxRetryCountOnException -gt 0 )
60
+ {
61
+ $shouldRetryOnException = $true
62
+ $maxRetryCountOnException --
63
+ }
64
+ else
65
+ {
66
+ $shouldRetryOnException = $false
67
+ throw
68
+ }
69
+ }
70
+ }
71
+ while ($shouldRetryOnException )
30
72
73
+ }
31
74
32
75
# function Get-BlobBytes
33
76
34
77
function Get-BlobBytes
35
78
{
36
79
param (
37
80
[Parameter (Mandatory = $true )]
38
- $Blob )
81
+ $Blob ,
82
+ [Parameter (Mandatory = $false )]
83
+ [bool ]$IsPremiumAccount = $false )
39
84
40
85
# Base + blobname
41
86
$blobSizeInBytes = 124 + $Blob.Name.Length * 2
@@ -47,19 +92,85 @@ function Get-BlobBytes
47
92
$blobSizeInBytes += 3 + $metadataEnumerator.Current.Key.Length + $metadataEnumerator.Current.Value.Length
48
93
}
49
94
50
- if ( $Blob .BlobType -eq [ Microsoft.WindowsAzure.Storage.Blob.BlobType ]::BlockBlob )
95
+ if ( ! $IsPremiumAccount )
51
96
{
52
- $blobSizeInBytes += 8
53
- # Default is Microsoft.WindowsAzure.Storage.Blob.BlockListingFilter.Committed. Need All
54
- $Blob.ICloudBlob.DownloadBlockList ([Microsoft.WindowsAzure.Storage.Blob.BlockListingFilter ]::All) |
55
- ForEach-Object { $blobSizeInBytes += $_.Length + $_.Name.Length }
97
+ if ($Blob.BlobType -eq [Microsoft.WindowsAzure.Storage.Blob.BlobType ]::BlockBlob)
98
+ {
99
+ $blobSizeInBytes += 8
100
+ # Default is Microsoft.WindowsAzure.Storage.Blob.BlockListingFilter.Committed. Need All
101
+ $action = { param ($requestOption ) return $Blob.ICloudBlob.DownloadBlockList ([Microsoft.WindowsAzure.Storage.Blob.BlockListingFilter ]::All, $null , $requestOption ) }
102
+
103
+ $blocks = Retry- OnRequest $action
104
+
105
+ if ($null -eq $blocks )
106
+ {
107
+ $blobSizeInBytes += $Blob.ICloudBlob.Properties.Length
108
+ }
109
+ else
110
+ {
111
+ $blocks | ForEach-Object { $blobSizeInBytes += $_.Length + $_.Name.Length }
112
+ }
113
+ }
114
+ elseif ($Blob.BlobType -eq [Microsoft.WindowsAzure.Storage.Blob.BlobType ]::PageBlob)
115
+ {
116
+ # It could cause server time out issue when trying to get page ranges of highly fragmented page blob
117
+ # Get page ranges in segment can mitigate chance of meeting such kind of server time out issue
118
+ # See https://blogs.msdn.microsoft.com/windowsazurestorage/2012/03/26/getting-the-page-ranges-of-a-large-page-blob-in-segments/ for details.
119
+ $pageRangesSegSize = 148 * 1024 * 1024L
120
+ $totalSize = $Blob.ICloudBlob.Properties.Length
121
+ $pageRangeSegOffset = 0
122
+
123
+ $pageRangesTemp = New-Object System.Collections.ArrayList
124
+
125
+ while ($pageRangeSegOffset -lt $totalSize )
126
+ {
127
+ $action = {param ($requestOption ) return $Blob.ICloudBlob.GetPageRanges ($pageRangeSegOffset , $pageRangesSegSize , $null , $requestOption ) }
128
+
129
+ Retry- OnRequest $action | ForEach-Object { $pageRangesTemp.Add ($_ ) } | Out-Null
130
+ $pageRangeSegOffset += $pageRangesSegSize
131
+ }
132
+
133
+ $pageRanges = New-Object System.Collections.ArrayList
134
+
135
+ foreach ($pageRange in $pageRangesTemp )
136
+ {
137
+ if ($lastRange -eq $Null )
138
+ {
139
+ $lastRange = New-Object PageRange
140
+ $lastRange.StartOffset = $pageRange.StartOffset
141
+ $lastRange.EndOffset = $pageRange.EndOffset
142
+ }
143
+ else
144
+ {
145
+ if (($lastRange.EndOffset + 1 ) -eq $pageRange.StartOffset )
146
+ {
147
+ $lastRange.EndOffset = $pageRange.EndOffset
148
+ }
149
+ else
150
+ {
151
+ $pageRanges.Add ($lastRange ) | Out-Null
152
+ $lastRange = New-Object PageRange
153
+ $lastRange.StartOffset = $pageRange.StartOffset
154
+ $lastRange.EndOffset = $pageRange.EndOffset
155
+ }
156
+ }
157
+ }
158
+
159
+ $pageRanges.Add ($lastRange ) | Out-Null
160
+ $pageRanges | ForEach-Object {
161
+ $blobSizeInBytes += 12 + $_.EndOffset - $_.StartOffset
162
+ }
163
+ }
164
+ else
165
+ {
166
+ $blobSizeInBytes += $Blob.ICloudBlob.Properties.Length
167
+ }
168
+ return $blobSizeInBytes
56
169
}
57
170
else
58
171
{
59
- $Blob.ICloudBlob.GetPageRanges () |
60
- ForEach-Object { $blobSizeInBytes += 12 + $_.EndOffset - $_.StartOffset }
172
+ $blobSizeInBytes += $Blob.ICloudBlob.Properties.Length
61
173
}
62
-
63
174
return $blobSizeInBytes
64
175
}
65
176
@@ -69,7 +180,9 @@ function Get-ContainerBytes
69
180
{
70
181
param (
71
182
[Parameter (Mandatory = $true )]
72
- [Microsoft.WindowsAzure.Storage.Blob.CloudBlobContainer ]$Container )
183
+ [Microsoft.WindowsAzure.Storage.Blob.CloudBlobContainer ]$Container ,
184
+ [Parameter (Mandatory = $false )]
185
+ [bool ]$IsPremiumAccount = $false )
73
186
74
187
# Base + name of container
75
188
$containerSizeInBytes = 48 + $Container.Name.Length * 2
@@ -104,7 +217,7 @@ function Get-ContainerBytes
104
217
}
105
218
106
219
$Blobs | ForEach-Object {
107
- $blobSize = Get-BlobBytes $_
220
+ $blobSize = Get-BlobBytes $_ $IsPremiumAccount
108
221
$containerSizeInBytes += $blobSize
109
222
$blobCount ++
110
223
@@ -129,6 +242,17 @@ if($storageAccount -eq $null)
129
242
130
243
$storageContext = $storageAccount.Context
131
244
245
+ if (-not ([System.Management.Automation.PSTypeName ]' PageRange' ).Type)
246
+ {
247
+ $Source = "
248
+ public class PageRange
249
+ {
250
+ public long StartOffset;
251
+ public long EndOffset;
252
+ }"
253
+ Add-Type - TypeDefinition $Source
254
+ }
255
+
132
256
$containers = New-Object System.Collections.ArrayList
133
257
if ($ContainerName.Length -ne 0 )
134
258
{
@@ -141,12 +265,13 @@ else
141
265
}
142
266
143
267
$sizeInBytes = 0
268
+ $IsPremiumAccount = ($storageAccount.Sku.Tier -eq " Premium" )
144
269
145
270
if ($containers.Count -gt 0 )
146
271
{
147
272
$containers | ForEach-Object {
148
273
Write-Output (" Calculating container {0} ..." -f $_.CloudBlobContainer.Name )
149
- $result = Get-ContainerBytes $_.CloudBlobContainer
274
+ $result = Get-ContainerBytes $_.CloudBlobContainer $IsPremiumAccount
150
275
$sizeInBytes += $result.containerSize
151
276
152
277
Write-Output (" Container '{0}' with {1} blobs has a sizeof {2:F2} MB." -f $_.CloudBlobContainer.Name , $result.blobCount , ($result.containerSize / 1 MB ))
0 commit comments