PowerShell 操作 Azure Blob Storage
本文假设已经存在了一个 Azure Storage Account,需要进行文件的上传,下载,复制,删除等操作。
为了方便查看 PowerShell 代码执行的结果,本文使用了 MS 发布的一个 Azure Storage 客户端工具:Microsoft Azure Storage Explorer,文中简称为 Storage Explorer。
安装 PowerShell Azure 模块
操作 Azure 的模块是不随 PowerShell 一起安装的,使用前需要单独的安装。
PowerShellGet 模块
如果要从 PowerShell Gallery 安装 Azure 模块,需要确保已经安装了 PowerShellGet 模块。下面的命令检查已安装 PowerShellGet 模块的版本:
Get-Module PowerShellGet -list | Select-Object Name,Version,Path
安装 Azure PowerShell 模块
下面的命令安装 Azure Resource Manager 模块:
Install-Module AzureRM -AllowClobber
注意,安装过程中有确认安装的交互过程。
载入 Azure 模块
在使用 Azure 相关的命令前需要通过 Import-Module 命令加载 Azure 模块:
Import-Module AzureRM
创建 Azure Storage 上下文
如果我们要对一个 Storage Account 中的文件进行操作,需要提供访问 Storage Account 的认证信息。我们的方式是直接通过 New-AzureStorageContext 命令创建一个 AzureStorageContext 类型的对象,这个对象中包含了认证信息,所以接下来所有对 storage 的访问操作都需要使用它:
$ctx = New-AzureStorageContext -ConnectionString "DefaultEndpointsProtocol=https;AccountName=youraccountname;AccountKey=youraccesskey;"
除了使用 -ConnectionString 选项,还可以把参数分开来写:
$StorageAccountName = "youraccountname" $StorageAccountKey = "youraccesskey" $ctx = New-AzureStorageContext -StorageAccountName $StorageAccountName -StorageAccountKey $StorageAccountKey -Protocol Https
注意,在上面的命令中除了添加必要的认证选项外,我们还显式的指定了通信协议。指定 https 是非常重要的,因为以 https 协议上传下载的数据默认会进行数据的完整性校验。也就是说在进行文件的上传或者下载时,我们不需要再做额外的数据完整性校验了。
除了 New-AzureStorageContext 命令,还有其他的方式可以获得 AzureStorageContext 对象。比如可以先通过 Login-AzureRmAccount 登录,然后找到某个(或者是创建一个) Storage Account,并获取其 Context 属性。
创建 Container
任何的 blob 对象都必须被包含在一个 Container 中,所以在进行 blob 文件的操作前,我们需要先创建一个 Container:
$ContainerName = "containertest" New-AzureStorageContainer -Name $ContainerName -Permission Off -Context $ctx
为 Container 设置的权限会控制 Container 中的所有文件,当前一共有三个权限类型:
Container:匿名用户可以访问文件内容,并且可以枚举 Container 中的所有文件。
Blob:匿名用户可以访问文件内容,但是不能枚举 container 中的文件。
Off:匿名用户不能访问文件。
-Permission 选项用来设置 Container 的权限,默认值是 Off(笔者喜欢总是显式的指定这个选项以提高脚本的可读性)。
-Context 选项指定该命令的执行上下文,主要是认证信息,这里我们使用前面生成的对象 $ctx。
上传文件
我们可以通过 Set-AzureStorageBlobContent 命令来上传文件,需要指定文件存放的 Container 和 访问 Storage Account 的上下文:
Set-AzureStorageBlobContent -Container $ContainerName -File ".\cortana.jpg" -Blob "cortana.jpg" -Context $ctx
上传成功后我们可以通过 Storage Explorer 直观的检查一下:
这样上传的文件都是直接放在 Container 的根目录下的,如果要对文件存放的目录进行管理,需要在上传时指定包含目录名称的文件名:
Set-AzureStorageBlobContent -Container $ContainerName -File ".\cortana.jpg" -Blob "images/cortana.jpg" -Context $ctx
这样上传后,文件 cortana.jpg 会存放在 images 目录下。
上传目录下的多个文件
我们还可以通过一个命令一次上传某个目录下的所有文件:
Get-ChildItem -Path "D:\ConsoleApplication1" -File -Recurse | Set-AzureStorageBlobContent -Container $ContainerName -Context $ctx
D:\ConsoleApplication1 目录中是一个简单的 C# 控制台应用,通过管道组合 Get-ChildItem 命令,可以完成多个文件的上传,并且这些文件的目录结构和原来都是一样的。
覆盖已经存在的 blob
如果我们要上传一个文件,并指定了一个已经存在的 blob 名称,此时会与用户交互以确定是否覆盖已经存在的 blob。对于各种自动化的任务,我们不希望交互的行为,所以可以加上 -Force 选项强制覆盖已有文件:
Set-AzureStorageBlobContent -Container $ContainerName -File ".\cortana.jpg" -Blob "cortana.jpg" -Context $ctx -Force
下载文件
Get-AzureStorageBlobContent 命令用来下载文件。下载文件的前提是你知道某个 blob 对象的名称:
$localFileDirectory = "D:\" Get-AzureStorageBlobContent -Destination $localFileDirectory -Container $ContainerName -Blob "images/cortana.jpg" -Context $ctx -Force
注意,下载到本地的文件路径为:"D:\images\cortana.jpg"。
其实在很多的情况下我们都没有这么明确的 blob 名称,我们需要下载满足某些情况的 blob,比如下载 images 目录下的所有文件。这里的问题是我们不知道 images 究竟是哪级目录,所以可能的做法是遍历 Container 下的所有文件,然后检查文件名称中包含 images 目录的文件并下载它。为了遍历 Container 中的文件,需要使用 Get-AzureStorageBlob 命令:
$localFileDirectory = "D:\" $blobs = Get-AzureStorageBlob -Container $ContainerName -Context $ctx foreach($blob in $blobs) { if($blob.Name.Contains("images/")) { Get-AzureStorageBlobContent -Destination $localFileDirectory -Container $ContainerName -Blob $blob.Name -Context $ctx -Force } }
这段代码中我们用 Get-AzureStorageBlob 命令拿到 Container 下的所有文件信息,然后检查文件的路径中有没有包含 "images/" 字符串,如果包含,就下载这个文件。
复制文件
自动化的脚本操作可以轻松愉快的备份各种数据,当然也包含存储在 Storage Account 中的文件。Start-AzureStorageBlobCopy 命令用于 blob 文件的复制操作。单从名字上看这应该是个异步方法,但是真实的情况稍微复杂一些。因为这个命令既可以用于同步操作也可以用于异步操作,关键在于调用这个命令的方式!下面的命令在同一个 Container 中执行文件复制操作:
Start-AzureStorageBlobCopy -SrcBlob "cortana.jpg" ` -SrcContainer $ContainerName ` -DestContainer $ContainerName ` -DestBlob "myimages/cortana.jpg" ` -Context $ctx
这个操作是同步执行的,它把 Container 根目录下的 cortana.jpg 文件拷贝到同一个 Container 的 myimages 目录下。
如果你要跨地域的在不同的 Storage Account 中复制大量的文件,建议你通过异步的方式进行:
# 把 Start-AzureStorageBlobCopy 命令的返回值存储到变量中会让复制过程以异步的方式进行。 $blobResult = Start-AzureStorageBlobCopy -SrcBlob $blobName ` -SrcContainer $containerName ` -DestContainer $containerName2 ` -DestBlob $blobName ` -Context $ctx ` -DestContext $ctx2 # 然后通过检查返回值的方式确定复制操作是否完成。 $status = $blobResult | Get-AzureStorageBlobCopyState # 通过循环,当检查到结果的状态不为 "Pending" 时,表示复制操作已经完成。 while ($status.Status -eq "Pending") { $status = $blobResult | Get-AzureStorageBlobCopyState $status Start-Sleep 10 }
删除文件
Remove-AzureStorageBlob 命令删除指定的 blob 文件:
Remove-AzureStorageBlob -Container $ContainerName -Blob "myimages/cortana.jpg" -Context $ctx
要是有复杂点的要求,就得通过遍历 Contaner 中的文件来完成。
权限管理
在创建 Container 时我们已经提到,可以给 Container 设置三种不同的访问控制权限:Container,Blob,Off。我们也可以在创建 Container 之后通过 Set-AzureStorageContainerAcl 命令改变它的访问控制权限。下面的命令把 Container 的访问控制权限设置为 Blob:
Set-AzureStorageContainerAcl -Name $containerName -Context $ctx -Permission Blob