【事前準備はCLIコマンドだけ】AWSリソース情報をExcelに取り込んでくれるツール作ってみた
目次
こんにちは、スカイアーチHRSのkuramochiです。
直近のプロジェクトで、毎月AWSリソースの状況をExcelにまとめる必要があったので、VBAとPowerQueryとCLIコマンドを使って自動化ツールを作ってみました。
CLIコマンドを事前に準備しておけば、簡単操作でリソースの情報を取得して、画像のようにテーブルにしてくれます。
前提条件
前提条件として、PowerShellでCLIコマンドを実行でき、かつ、マクロが実行可能な環境が必要です。
ツール
以下のURLからZipをダウンロードできます。マクロ付きExcelと空のdataフォルダが入ってます。
https://drive.google.com/file/d/1ULclHftcWWyPXLPLbjCyYJzTqVePrDzm/view?usp=drivesdk
仕組み
ツールの仕組みとしては以下の通りです。
- Excel内のCLIコマンドをマクロでPowerShellに流し、実行結果をdataフォルダにJSON形式で保存
- 新規のJSONがあればPowerQueryでExcelと接続しテーブル化。接続済みJSONの場合はテーブルを更新
使い方
CLIコマンドさえ準備できれば、あとはちょっとした操作だけです。
CLIコマンドの準備
以下のような形でCLIコマンドを準備します。
aws ec2 describe-instances --profile PROFILE_NAME --query 'Reservations[].Instances[].{Name: Tags[?Key==Name].Value|[0], InstanceId: InstanceId, PlatformDetails: PlatformDetails, InstanceType:InstanceType, LaunchTime: LaunchTime }' >ec2ListPrd.json
コマンドは、プロファイルを「–profile PROFILE_NAME」とし、JSONとして出力するよう最後に「> 任意のファイル名.json」を付け加える必要があります。
用意したコマンドは、ExcelのCLIシートのA列に貼り付けます。複数のコマンドの場合は上に詰めて張り付けます。
CLIシートには例としていくつかコマンドが入っていますが、使用前に削除してください。
プロファイル設定
コマンドに使うプロファイル名をProfileシートのA2に入力します。
マクロの実行ボタンを押す
次に、UPDATEシートにある「CLI実行」ボタンを押します。実行が終わると、「CLIコマンドの実行が完了しました。」というメッセージが表示されます。これでdataフォルダにJSONが出力されます(2回目以降はファイルが上書きされます)。
最後に、「PowerQuery接続 or 更新」ボタンを押せば、リソースがまとまったシートが生成されます(2回目以降は前回生成したシートが更新されます)。
注意点
Excelのファイル名や解凍後のフォルダ名は変更しても動きますが、Excel内のシート名やdataフォルダのフォルダ名は変更すると動かなくなります。
この他、存在しない種類のリソースを取得しようとすると空のJSONが出力されます。空のファイルはエラーにつながりますので、ご注意ください。
(参考)VBAのコード
セキュリティの問題でマクロ付きファイルのダウンロードができない場合もあるかと思いますので、一応VBAのコードも載せておきます。
Sub RunPowerShellCommand()
Dim objShell As Object
Set objShell = CreateObject("WScript.Shell")
' ベースパスを設定
Dim basePath As String
basePath = ThisWorkbook.Path & "\\"
' シート「CLI」のA列のコマンドを取得
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets("CLI")
Dim cmd As Range
Set cmd = ws.Range("A1")
' シート「Profile」からプロファイル名を取得
Dim profileWs As Worksheet
Set profileWs = ThisWorkbook.Worksheets("Profile")
Dim profileName As String
profileName = profileWs.Range("A2").Value
' 空白のセルに行き当たるまでコマンドを順番に実行
Do While Not cmd Is Nothing And cmd.Value <> ""
Dim cmdString As String
cmdString = cmd.Value
cmdString = Replace(cmdString, "PROFILE_NAME", profileName)
Dim strCommand As String
strCommand = "powershell.exe -Command ""& {cd '" & basePath & "data' ; " & cmdString & "}"""
'コマンドを実行する
objShell.Run strCommand, 0, True
Set cmd = cmd.Offset(1, 0) ' 次の行に進む
If cmd.Value = "" Then Exit Do ' 空白の場合ループを抜ける
Loop
' 完了メッセージを表示
MsgBox "CLIコマンドの実行が完了しました。"
Set objShell = Nothing
End Sub
Sub UpdateOrImportJsonFiles()
Dim currentDir As String
Dim dataFolder As String
Dim jsonFiles As Collection
Dim queryName As String
Dim ws As Worksheet
Dim found As Boolean
' current_directoryシートのA2セルからExcelファイルが存在するフォルダのパスを取得
Set ws = ThisWorkbook.Sheets("current_directory")
currentDir = ws.Range("A2").Value
dataFolder = currentDir & "data\\"
' JSONファイルのリストを取得
Set jsonFiles = GetFiles(dataFolder, "*.json")
' 各JSONファイルを処理
For Each jsonFile In jsonFiles
queryName = Replace(jsonFile, ".json", "")
found = False
' 既存のパワークエリを確認し、更新する
On Error Resume Next
found = Not ThisWorkbook.Queries(queryName) Is Nothing
On Error GoTo 0
If found Then
' クエリを更新
RefreshQuery queryName
Else
' 新しいクエリを追加
AddNewQuery queryName, dataFolder & jsonFile
End If
Next jsonFile
End Sub
' 指定されたフォルダ内のファイルを取得する関数
Function GetFiles(folderPath As String, filePattern As String) As Collection
Dim fileSystem As Object
Dim folder As Object
Dim file As Object
Dim files As New Collection
Set fileSystem = CreateObject("Scripting.FileSystemObject")
Set folder = fileSystem.GetFolder(folderPath)
For Each file In folder.files
If LCase(file.Name) Like LCase(filePattern) Then
files.Add file.Name
End If
Next file
Set GetFiles = files
End Function
' クエリを更新するサブルーチン
Sub RefreshQuery(queryName As String)
Dim ws As Worksheet
Dim lo As ListObject
On Error Resume Next
For Each ws In ThisWorkbook.Worksheets
For Each lo In ws.ListObjects
If lo.SourceType = xlSrcQuery Then
If lo.QueryTable.CommandText(1) = "SELECT * FROM [" & queryName & "]" Then
lo.QueryTable.Refresh BackgroundQuery:=False
Exit Sub
End If
End If
Next lo
Next ws
On Error GoTo 0
End Sub
' 新しいクエリを追加するサブルーチン
Sub AddNewQuery(queryName As String, filePath As String)
Dim newSheet As Worksheet
' 新しいクエリを追加
ThisWorkbook.Queries.Add Name:=queryName, Formula:= _
"let" & Chr(13) & Chr(10) & _
" ソース = Json.Document(File.Contents(""" & filePath & """))," & Chr(13) & Chr(10) & _
" データ = if Type.Is(Value.Type(ソース), type list) then ソース else {ソース}," & Chr(13) & Chr(10) & _
" テーブルに変換済み = Table.FromList(データ, Splitter.SplitByNothing(), null, null, ExtraValues.Error)," & Chr(13) & Chr(10) & _
" フィールド名 = if Table.IsEmpty(テーブルに変換済み) then {} else Record.FieldNames(テーブルに変換済み{0}[Column1])," & Chr(13) & Chr(10) & _
" 展開された列 = Table.ExpandRecordColumn(テーブルに変換済み, ""Column1"", フィールド名)" & Chr(13) & Chr(10) & _
"in" & Chr(13) & Chr(10) & _
" 展開された列"
' 新しいシートを追加し、シート名をJSONファイル名と同じにする
Set newSheet = ThisWorkbook.Worksheets.Add
newSheet.Name = queryName
' 新しいシートにクエリをインポート
With newSheet.ListObjects.Add(SourceType:=0, Source:= _
"OLEDB;Provider=Microsoft.Mashup.OleDb.1;Data Source=$Workbook$;Location=" & queryName & ";Extended Properties=""""" _
, Destination:=newSheet.Range("$A$1")).QueryTable
.CommandType = xlCmdSql
.CommandText = Array("SELECT * FROM [" & queryName & "]")
.RowNumbers = False
.FillAdjacentFormulas = False
.PreserveFormatting = True
.RefreshOnFileOpen = False
.BackgroundQuery = True
.RefreshStyle = xlInsertDeleteCells
.SavePassword = False
.SaveData = True
.AdjustColumnWidth = True
.RefreshPeriod = 0
.PreserveColumnInfo = True
.ListObject.DisplayName = queryName
.Refresh BackgroundQuery:=False
End With
End Sub