PowerShell を使って、json の値を KeyVault にぶち込むサンプルの解説

TDD は一休みして、たまたま PowerShell を触る機会があったので、忘れないように記述しておこうと思います。

今回のお題は、Json に格納された Key/Value の値を、Azure の KeyVault にぶち込むための、PowerShell です。私は次のような PowerShell を書きました。

# KeyVault に key/value のセットをぶち込む PowerShell

データのファイルはこんな感じです。

secret.json

```
 {
    "ApplicationId": "SOME APPLICATION ID", 
    "ApplicationKey": "SOME APPLICATION KEY",
    "SubscriptionId": "SOME SUBSCRIPTION ID",
    "ActiveDirectoryTenantId": "ACTIVE DIRECTORY TENANT ID",
                   :
 }
```

こういうシークレットをまとめて KeyVault にぶち込むコードです。

```
<#
.SYNOPSIS
    Import JSON file into Azure KeyVault
.DESCRIPTION
    Create `secrets.json` on the current directory then execute this. 
    You need to modify the $keyVaultName to fit your KeyVault
    I encode "" into [empty]. '' is not allowed for KeyVault Secret.
    I decode it on the KeyVaultHelper.cs
.NOTE
    File Name   : ImportSecret.ps1
    Author      : Tsuyoshi Ushio
    Prerequisite: Azure PowerShell
#>
$keyVaultName = "XXXXKey"

Login-AzureRmAccount

$secretJson = Get-Content .\secrets.json -Encoding UTF8 -Raw
$secrets = (New-Object System.Web.Script.Serialization.JavaScriptSerializer).Deserialize($secretJson, [System.Collections.HashTable])
$secrets.GetEnumerator() | ForEach-Object {

    Write-Host "$($_.Key) : $($_.Value)" 
    IF ($_.Value -eq '') {
        $_.Value = "[empty]"
    }
    $secretValue = ConvertTo-SecureString -String $_.Value -AsPlainText -Force
    Set-AzureKeyVaultSecret -VaultName $keyVaultName -Name $_.Key -SecretValue $secretValue
 }
```

初めから解説していきます。

## Login

最初にログインして、サブスクリプションを取得します。サブスクリプションが複数ある人はこれではうまくいなかないかもしれません。また、ブラウザが起動するので、完全に自動化したい人には向いていません。

```
Login-AzureRmAccount
```

ちなみに、自動化したい場合は次の感じで実施すれば OK. ログインした状態で、コンテキストを保存すればいいです。

```
$pwd = Get-Location
$azurejson = $pwd.Path + "\azure.json"
Save-AzureRmContext -Path $azurejson -Force
```

実際にログインするときは

```
$pwd = Get-Location
$azurejson = $pwd.Path + "\azure.json"
Import-AzureRmContext -Path 
```

的な感じでいいです。昔は、コンテキストを保存するのが、`Save-AzureRmProfile` だったのが、なくなったみたいではまりました。補完ででてくるのが、またハマりを長引かせましたｗ

```
Save-AzureRmProfile
Save-AzureRmProfile : The term 'Save-AzureRmProfile' is not recognized as the name of a cmd
let, function, script file, or operable program. Check the spelling of the name, or if a pa
th was included, verify that the path is correct and try again.
```

* [WHAT HAPPENED TO SAVE-AZURERMPROFILE?](https://arcanecode.com/2017/04/19/what-happened-to-save-azurermprofile/)

## JSON の渋い読み込み

```
$secretJson = Get-Content .\secrets.json -Encoding UTF8 -Raw
$secrets = (New-Object System.Web.Script.Serialization.JavaScriptSerializer).Deserialize($secretJson, [System.Collections.HashTable])
```

ちなみに、JSON の読み込みをインターネットで検索すると、Convert-FromJSON とかいうコマンドレットがありますが、あえて使いません。というのも、普通に、JSONをパースすると、`$secrets.ApplicationId` みたいな形でアクセスする必要があるようになるので、ループで処理するのができないからです。だからここは、読み込んで、HashTable に変換する方法を用いています。カッコいい！

## ループと空文字

後はHash にしたものを、ForEach-Object でループしています。KeyVault に値をセットするには、ConvertTo-SecureString で型変換する必要があります。あとは、`Set-AzureKeyVaultSecret` をたたけば終わりで簡単です。一点だけポイントは、"" 空文字が、KeyVault の Secret には受け入れられないので、空文字が来たら`[empty]` にして格納して、アプリのライブラリで対応するようにしました。

```
$secrets.GetEnumerator() | ForEach-Object {

    Write-Host "$($_.Key) : $($_.Value)" 
    IF ($_.Value -eq '') {
        $_.Value = "[empty]"
    }
    $secretValue = ConvertTo-SecureString -String $_.Value -AsPlainText -Force
    Set-AzureKeyVaultSecret -VaultName $keyVaultName -Name $_.Key -SecretValue $secretValue
 }
```

![keyVaultPS.png](https://qiita-image-store.s3.amazonaws.com/0/3470/f8a3eb12-d2db-9f9a-3d13-ba6162013df5.png)

実行するとしっかり格納されている（過去に同じ名前のものがあれば、更新される）ちなみに、見たとおり、Azure Key Vault の　Secret　は、過去のバージョンをみんな格納しています。いい感じですね。何も指定しなければカレントバージョンを取得します。

# おわりに

まだまだ、PowerShell は練度が足りませんがちょっとづつがんばります。