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
posted @ 2017-11-22 09:23  sparkdev  阅读(25415)  评论(4编辑  收藏  举报