[Powershell]Azure Storageにファイルをアップロードしてみた

Powershell Powershell
この記事は約12分で読めます。

Powershellを利用して、テキストファイルなどをAzureストレージアカウントにアップロードしてみました。

広告

Powershellを利用してストレージアカウントにファイルをアップロードする

サービスプリンシパルを利用してアップロードする方法が汎用的ですが、AzureVM上から実行するときのみ、マネージドIDを利用してアップロードさせる方法もありますので2つ紹介していきます。

サービスプリンシパルを利用してファイル共有にアップロードする

事前準備として以下が必要です

  • サービスプリンシパルを作成
  • ストレージアカウントを作成しファイル共有を作成
  • ストレージアカウントに対する書き込みロールをサービスプリンシパルに追加

それぞれ以下の記事でもAzureCLIでの作成方法等を記載していますので必要であれば参考にしてください。

また、ストレージアカウントのネットワーク設定でIP制限をかけている場合には、IPの許可設定を入れる必要があります。

準備が完了したら以下のコマンドに取得した値を入力して実行するとアップロード可能です。
今回はエラー処理も実装しています。

サービスプリンシパルを利用してファイル共有にアップロードするスクリプト

$TenantId = "<テナントID>"
$ApplicationId = "<アプリケーションID>"
$Secret = "<シークレット>"
$StorageAccountName = "<ストレージアカウント名>"
$Fileshare = "<ファイル共有名>"
$FilePath = "<アップロードしたいファイルのパス>"
$FileName = Get-ChildItem -Path $FilePath -File | Select-Object -ExpandProperty Name
$ScriptFullPath = $MyInvocation.MyCommand.Path
$ScriptFileName = [System.IO.Path]::GetFileName($scriptFullPath)
$RetrySec = 30
$RetryMAXCount = 3

#login
$RetryCount = 0
do{
    try{
        $response = az login --service-principal -u $ApplicationId -p $Secret --tenant $TenantId
        if ($null -eq $response) {
            throw
        }
        break
    } catch {
        $RetryCount++
        if ($RetryCount -lt $RetryMAXCount){
            Start-Sleep -Seconds $RetrySec
        } else {
            Write-Output "ErrorMessage : $($_.Exception.Message)"
            Write-Output "ErrorType : $($_.Exception.GetType().FullName)"
            Write-Output "ErrorLocation : Failed Authentication in $ScriptFileName "
            Write-Output "ErrorDetailsBelow" ($Error[0] | Format-List -Force)
            exit 1
        }
    }
} while ($true)

#file upload
$RetryCount = 0
do{
    try{
        $response = az storage file upload --account-name $StorageAccountName --share-name $Fileshare --source $FilePath --path $FileName
        if ($null -eq $response) {
            throw
        } else {
            Write-Output "Info : $(Get-date) : Completed Fileupload ($FileName) "
        }
        break
    } catch {
        $RetryCount++
        if ($RetryCount -lt $RetryMAXCount){
            Start-Sleep -Seconds $RetrySec
        } else {
            Write-Output "ErrorMessage : $($_.Exception.Message)"
            Write-Output "ErrorType : $($_.Exception.GetType().FullName)"
            Write-Output "ErrorLocation : Failed Fileupload in $ScriptFileName "
            Write-Output "ErrorDetailsBelow" ($Error[0] | Format-List -Force)
            exit 1
        }
    }
} while ($true)

AzureVMからコンテナーにアップロードする

AzureVMからストレージアカウント内のコンテナーにファイルをアップロードすることも可能です。

この場合、事前準備として以下が必要です。

  • VMでシステムマネージドIDを有効化
  • システムマネージドIDにストレージアカウントに対するIAM(ストレージ BLOB 共同作成者)を付与
  • ストレージアカウントのネットワーク設定でVMに対するサービスエンドポイントを有効化

これらを実施した上で、エンドポイントからトークンを取得してファイルをアップロードする流れになります。

[参考] ストレージアカウントでVMに対するサービスエンドポイントを有効化する方法
[参考] トークン取得に関するMicrosoftの公式ドキュメント
Azure リソースのマネージド ID と Azure 仮想マシンの連携 - Managed identities for Azure resources
Azure リソースのマネージド ID と Azure 仮想マシンの連携について説明します。

AzureVMからコンテナーにアップロードするスクリプト

以下のスクリプトでファイルアップロードが可能です。
ただし、コンテナーが未作成の場合には下記スクリプトは失敗するので、事前にコンテナーの作成が必要です。
コンテナーの作成コマンドは下部に記載してますので参考にしてください。

$StorageAccountName = "<ストレージアカウント名>"
$ContainerName = "<コンテナー名>"
$FilePath = "<アップロードしたいファイルのフルパス>"
$FileName = Get-ChildItem -Path $FilePath -File | Select-Object -ExpandProperty Name
$ScriptFullPath = $MyInvocation.MyCommand.Path
$ScriptFileName = [System.IO.Path]::GetFileName($scriptFullPath)
$RetrySec = 30
$RetryMAXCount = 3
$url = "https://$StorageAccountName.blob.core.windows.net/$ContainerName"
function Get-MimeType {
    param (
        [Parameter(Mandatory = $true)]
        [string]$FilePath
    )

    Add-Type -AssemblyName System.Web
    $mimeType = [System.Web.MimeMapping]::GetMimeMapping($FilePath)
    return $mimeType
}
$MimeType = Get-MimeType -FilePath $FilePath

#login
$RetryCount = 0
do{
    try{
        $response = Invoke-Webrequest -Uri 'http://169.254.169.254/metadata/identity/oauth2/token?api-version=2021-12-13&resource=https://storage.azure.com/' -Headers @{Metadata= "true"} -UseBasicParsing
        if ($response.StatusCode -ge 400) {
            throw
        }
        $content = $response.Content | ConvertFrom-Json
        $token = $content.access_token
        break
    } catch {
        $RetryCount++
        if ($RetryCount -lt $RetryMAXCount){
            Start-Sleep -Seconds $RetrySec
        } else {
            Write-Output "ErrorMessage : $($_.Exception.Message)"
            Write-Output "ErrorType : $($_.Exception.GetType().FullName)"
            Write-Output "ErrorLocation : Failed Authentication in $ScriptFileName "
            Write-Output "ErrorDetailsBelow" ($Error[0] | Format-List -Force)
            exit 1
        }
    }
} while ($true)

#file upload
$RetryCount = 0
do{
    try{
        $Headers = @{
            "Authorization" = "Bearer $token"
            "x-ms-version" = "2021-04-10"
            "x-ms-date" = (Get-Date).Tostring("R")
            "x-ms-blob-type" = "BlockBlob"
            "Content-Type" = $MimeType
            "Content-Length" = (Get-Item $FilePath).Length
        }
        $response = Invoke-Webrequest -Method PUT -Uri "$url/$FileName" -Headers $Headers -InFile $FilePath -UseBasicParsing
        if ($response.StatusCode -ge 400) {
            throw
        }
        Write-Output "Info : $(Get-date) : Completed Fileupload ($FileName) "
        break
    } catch {
        $RetryCount++
        if ($RetryCount -lt $RetryMAXCount){
            Start-Sleep -Seconds $RetrySec
        } else {
            Write-Output "ErrorMessage : $($_.Exception.Message)"
            Write-Output "ErrorType : $($_.Exception.GetType().FullName)"
            Write-Output "ErrorLocation : Failed Fileupload in $ScriptFileName "
            Write-Output "ErrorDetailsBelow" ($Error[0] | Format-List -Force)
            exit 1
        }
    }
} while ($true)
[参考] コンテナーの作成(AzureCLI)

以下のコマンドで作成可能です。

$StorageAccountName = "<ストレージアカウント名>"
$ContainerName = "test-container"

az storage container create -n $ContainerName --account-name $StorageAccountName
タイトルとURLをコピーしました