前回はMFA無効版の内容を投稿しましたが、今回はMicrosoft Entra IDの全ユーザーがMFA有効な状態でもAzureに存在するApplicationggatewayとVMを自動起動停止する方法を共有します。
この方法はサービスプリンシパルを利用して操作するため、MFA有効だろうが無効だろうが関係ありませんので、便利です。
前回のブログは以下となります。
【MFA無効版ブログ】:【MFA無効版】Azure Automationを使って複数テナントの複数サブスクリプションに存在する複数のApplicationGatewayを自動起動・停止する方法 – Cloud Steady | パーソルプロセス&テクノロジー株式会社
では、説明を始めます。
▼前提条件
①Microsoft Entra IDの権限:「アプリケーション管理者」、もしくは「グローバル管理者」が必要
②サブスクリプションの権限:「共同作成者」、もしくは「所有者」が必要
※ゲストユーザーはロール割り当て時にMicrosoft Entra IDで登録したアプリが検索ができないため、要注意
③Connect-AzAccount コマンドを使う為、Az.Accounts モジュールが必要
▼流れ
①アプリの登録 ※処理する各テナントで対応必要です。
②ロール割り当て ※処理する各テナントで対応必要です。
③ストレージアカウント作成 ※作成方法は割愛
④Automationアカウント作成 ※作成方法は割愛
⑤スクリプト登録
⑥スケジュール設定 ※作成方法は割愛
⑦最後の確認
アプリの登録
1.「Microsoft Entra ID」から「アプリの登録」を選択
2.「新規登録」を選択
3.「名前」を入力後、「この組織ディレクトリのみに含まれるアカウント」を選択
4.アプリケーションクライアントIDが表示されるので、それをメモして「証明書とシークレット」を選択
5.「新しいクライアントシークレット」を選択
6.「説明」を入力後、「有効期限」を選択して「追加」を選択
7.追加後、シークレット値が表示されるのでメモする
ロール割り当て
1.サブスクリプションを選択
サブスクリプションが複数ある場合、全部のサブスクリプションで対応必要
2.「アクセス制御(IAM)」を選択
3.「追加」を選択後、「ロール割り当ての追加」を選択
4.「特権管理者ロール」を選択
5.「共同作成者」を選択
6.「メンバー」を選択
7.「メンバーを選択する」を選択
8.Microsoft Entra IDで作成したアプリ名で検索し、表示されたものを選択
9.「選択」を選択
10.「レビューと割り当て」を選択
11.「レビューと割り当て」を選択
ストレージアカウント
ストレージアカウントの作成方法は割愛しますが、CSVファイルは今回以下のようなフォーマットを用意しました。
スクリプト登録
■起動用
# テナントA環境の処理
$clientID=”アプリケーションクライアントID“ ←アプリの登録時にメモしたID
$clientPwd = “シークレット値“ ←アプリの登録時にメモしたID
$clientS = $clientPwd |ConvertTo-SecureString -AsPlainText -Force
$cred =New-Object -TypeName System.management.Automation.PSCredential -ArgumentList $clientID,$clientS
$tenantID = “テナントAのID“ ←CSVファイルが保存されているテナントID
Connect-AzAccount -Tenant $tenantID -ServicePrincipal -Credential $cred
# ストレージアカウントとCSVファイルの情報
$storageAccountName = “ストレージアカウント名“
$storageAccountKey = “アクセスキー“
$containerName = “コンテナー名“
$csvFileName = “CSVファイル名“
# ストレージアカウントからCSVファイルを読み取る
$context = New-AzureStorageContext -StorageAccountName $storageAccountName -StorageAccountKey $storageAccountKey
$blob = Get-AzureStorageBlob -Container $containerName -Blob $csvFileName -Context $context
$csvContent = $blob.ICloudBlob.DownloadText()
# CSVファイルの内容を解析する
$ImportCsvs = ConvertFrom-Csv -InputObject $csvContent
# 配列に入れる
$csvtenantid = @()
$appgwsublist = @()
$appgwrglist = @()
$appgwnamelist = @()
$vmsublist = @()
$vmrglist = @()
$vmnamelist = @()
$starttimelist = @()
foreach ($ImportCsv in $ImportCsvs) {
if (![string]::IsNullOrEmpty($ImportCsv.TenantID)) {
$csvtenantid += $ImportCsv.TenantID
}
$appgwsublist += $ImportCsv.SubscriptionID
$appgwrglist += $ImportCsv.Resourcegroup
$appgwnamelist += $ImportCsv.ApplicationGatewayname
$vmsublist += $ImportCsv.VMSubscriptionID
$vmrglist += $ImportCsv.VMResourceGroup
$vmnamelist += $ImportCsv.VMName
$starttimelist += $ImportCsv.StartTime
}
Write-Output “配列に入れました”
for ($i = 0; $i -lt $csvtenantid.Count; $i++) {
if ($tenantID -eq $csvtenantid[$i]) {
# 現在の日時を日本時間で取得
$currentDateTime = (Get-Date).ToUniversalTime().AddHours(9)
Write-Output “現在の日本時間を取得しました:$currentDateTime”
# H:mm:ssで取得した場合、HH:mm:ssに変換
$StartTime = $starttimelist[$i]
if ($StartTime.Length -eq 7) {
$StartTime = “0” + $StartTime
}
# StartTimeをDateTime型に変換
$StartTime = [DateTime]::Today.Add(([TimeSpan]::Parse($StartTime)))
Write-Output “時間を変換しました: $StartTime”
# 現在の日時とStartTimeの差を計算
$diff = $StartTime – $currentDateTime
Write-Output “時間を計算しました:$diff 分”
if ($diff.TotalMinutes -ge 0 -and $diff.TotalMinutes -le 60) {
# AppGW取得
$AppGw = Get-AzApplicationGateway -Name $appgwnamelist[$i] -ResourceGroupName $appgwrglist[$i] -ErrorAction SilentlyContinue
Write-Output “Appgwを取得しました。:$appgwnamelist “
# サブスクリプション情報を取得します
$subscription = Get-AzSubscription | Where-Object {$_.Id -eq $appgwsublist[$i]}
if (($AppGw.Name -eq $appgwnamelist[$i]) -and ($subscription.Id -eq $appgwsublist[$i])){
Start-AzApplicationGateway -ApplicationGateway $AppGw
Write-Output “$AppGw を起動しました”
}
# VM取得
$Vm = Get-AzVM -Name $vmnamelist[$i] -ResourceGroupName $vmrglist[$i] -ErrorAction SilentlyContinue
Write-Output “VMを取得しました。:$Vm “
# サブスクリプション情報を取得します
$subscription = Get-AzSubscription | Where-Object {$_.Id -eq $vmsublist[$i]}
if (($Vm.Name -eq $vmnamelist[$i]) -and ($subscription.Id -eq $vmsublist[$i])){
Start-AzVM -Name $vmnamelist[$i] -ResourceGroupName $vmrglist[$i]
Write-Output “$Vm を起動しました”
}
}
}
}
# テナントB環境の処理
$clientID=”アプリケーションクライアントID“ ←アプリの登録時にメモしたID
$clientPwd = “シークレット値“ ←アプリの登録時にメモしたID
$clientS = $clientPwd |ConvertTo-SecureString -AsPlainText -Force
$cred =New-Object -TypeName System.management.Automation.PSCredential -ArgumentList $clientID,$clientS
$tenantID = “テナントBのID“
Connect-AzAccount -Tenant $tenantID -ServicePrincipal -Credential $cred
for ($i = 0; $i -lt $csvtenantid.Count; $i++) {
if ($tenantID -eq $csvtenantid[$i]) {
# 現在の日時を日本時間で取得
$currentDateTime = (Get-Date).ToUniversalTime().AddHours(9)
Write-Output “現在の日本時間を取得しました:$currentDateTime”
# H:mm:ssで取得した場合、HH:mm:ssに変換
$StartTime = $starttimelist[$i]
if ($StartTime.Length -eq 7) {
$StartTime = “0” + $StartTime
}
# StartTimeをDateTime型に変換
$StartTime = [DateTime]::Today.Add(([TimeSpan]::Parse($StartTime)))
Write-Output “時間を変換しました: $StartTime”
# 現在の日時とStartTimeの差を計算
$diff = $StartTime – $currentDateTime
Write-Output “時間を計算しました:$diff 分”
if ($diff.TotalMinutes -ge 0 -and $diff.TotalMinutes -le 60) {
# AppGW取得
$AppGw = Get-AzApplicationGateway -Name $appgwnamelist[$i] -ResourceGroupName $appgwrglist[$i] -ErrorAction SilentlyContinue
Write-Output “Appgwを取得しました。:$appgwnamelist “
# サブスクリプション情報を取得します
$subscription = Get-AzSubscription | Where-Object {$_.Id -eq $appgwsublist[$i]}
if (($AppGw.Name -eq $appgwnamelist[$i]) -and ($subscription.Id -eq $appgwsublist[$i])){
Start-AzApplicationGateway -ApplicationGateway $AppGw
Write-Output “$AppGw を起動しました”
}
# VM取得
$Vm = Get-AzVM -Name $vmnamelist[$i] -ResourceGroupName $vmrglist[$i] -ErrorAction SilentlyContinue
Write-Output “VMを取得しました。:$Vm “
# サブスクリプション情報を取得します
$subscription = Get-AzSubscription | Where-Object {$_.Id -eq $vmsublist[$i]}
if (($Vm.Name -eq $vmnamelist[$i]) -and ($subscription.Id -eq $vmsublist[$i])){
Start-AzVM -Name $vmnamelist[$i] -ResourceGroupName $vmrglist[$i]
Write-Output “$Vm を起動しました”
}
}
}
}
■停止用
# テナントA環境の処理
$clientID=”アプリケーションクライアントID“ ←アプリの登録時にメモしたID
$clientPwd = “シークレット値“ ←アプリの登録時にメモしたID
$clientS = $clientPwd |ConvertTo-SecureString -AsPlainText -Force
$cred =New-Object -TypeName System.management.Automation.PSCredential -ArgumentList $clientID,$clientS
$tenantID = “テナントAのID“ ←CSVファイルが保存されているテナントID
Connect-AzAccount -Tenant $tenantID -ServicePrincipal -Credential $cred
# ストレージアカウントとCSVファイルの情報
$storageAccountName = “ストレージアカウント名“
$storageAccountKey = “アクセスキー“
$containerName = “コンテナー名“
$csvFileName = “CSVファイル名“
# ストレージアカウントからCSVファイルを読み取る
$context = New-AzureStorageContext -StorageAccountName $storageAccountName -StorageAccountKey $storageAccountKey
$blob = Get-AzureStorageBlob -Container $containerName -Blob $csvFileName -Context $context
$csvContent = $blob.ICloudBlob.DownloadText()
Write-Output “ストレージアカウントのCSVファイルを読み取りました”
# CSVファイルの内容を解析する
$ImportCsvs = ConvertFrom-Csv -InputObject $csvContent
Write-Output “ストレージアカウントのCSVファイルを解析しました”
# 配列に入れる
$csvtenantid = @()
$appgwsublist = @()
$appgwrglist = @()
$appgwnamelist = @()
$vmsublist = @()
$vmrglist = @()
$vmnamelist = @()
$stoptimelist = @()
foreach ($ImportCsv in $ImportCsvs) {
if (![string]::IsNullOrEmpty($ImportCsv.TenantID)) {
$csvtenantid += $ImportCsv.TenantID
}
$appgwsublist += $ImportCsv.SubscriptionID
$appgwrglist += $ImportCsv.Resourcegroup
$appgwnamelist += $ImportCsv.ApplicationGatewayname
$vmsublist += $ImportCsv.VMSubscriptionID
$vmrglist += $ImportCsv.VMResourceGroup
$vmnamelist += $ImportCsv.VMName
$stoptimelist += $ImportCsv.StopTime
}
Write-Output “配列に入れました”
for ($i = 0; $i -lt $csvtenantid.Count; $i++) {
if ($tenantID -eq $csvtenantid[$i]) {
# 現在の日時を日本時間で取得
$currentDateTime = (Get-Date).ToUniversalTime().AddHours(9)
Write-Output “現在の日本時間を取得しました:$currentDateTime”
# H:mm:ssで取得した場合、HH:mm:ssに変換
$StopTime = $stoptimelist[$i]
if ($StopTime.Length -eq 7) {
$StopTime = “0” + $StopTime
}
# StartTimeをDateTime型に変換
$StopTime = [DateTime]::Today.Add(([TimeSpan]::Parse($StopTime)))
Write-Output “時間を変換しました: $StopTime”
# 現在の日時とStoptTimeの差を計算
$diff = $StopTime – $currentDateTime
Write-Output “時間を計算しました:$diff 分”
if ($diff.TotalMinutes -ge 0 -and $diff.TotalMinutes -le 60) {
# サブスクリプション情報を取得します
$subscription = Get-AzSubscription | Where-Object {$_.Id -eq $appgwsublist[$i]}
# サブスクリプションを切り替えます
Set-AzContext -Subscription $subscription
# AppGW取得
$AppGw = Get-AzApplicationGateway -Name $appgwnamelist[$i] -ResourceGroupName $appgwrglist[$i] -ErrorAction SilentlyContinue
if ($null -ne $AppGw) {
Stop-AzApplicationGateway -ApplicationGateway $AppGw
Write-Output “$AppGw を停止しました”
}
# サブスクリプション情報を取得します
$subscription = Get-AzSubscription | Where-Object {$_.Id -eq $vmsublist[$i]}
# サブスクリプションを切り替えます
Set-AzContext -Subscription $subscription
# VM取得
$Vm = Get-AzVM -Name $vmnamelist[$i] -ResourceGroupName $vmrglist[$i] -ErrorAction SilentlyContinue
if ($null -ne $Vm) {
Stop-AzVM -Name $vmnamelist[$i] -ResourceGroupName $vmrglist[$i] -Force
Write-Output “$Vm を停止しました”
}
}
}
}
# テナントB環境の処理
$clientID=”アプリケーションクライアントID“ ←アプリの登録時にメモしたID
$clientPwd = “シークレット値“ ←アプリの登録時にメモしたID
$clientS = $clientPwd |ConvertTo-SecureString -AsPlainText -Force
$cred =New-Object -TypeName System.management.Automation.PSCredential -ArgumentList $clientID,$clientS
$tenantID = “テナントAのID“
Connect-AzAccount -Tenant $tenantID -ServicePrincipal -Credential $cred
for ($i = 0; $i -lt $csvtenantid.Count; $i++) {
if ($tenantID -eq $csvtenantid[$i]) {
# 現在の日時を日本時間で取得
$currentDateTime = (Get-Date).ToUniversalTime().AddHours(9)
Write-Output “現在の日本時間を取得しました:$currentDateTime”
# H:mm:ssで取得した場合、HH:mm:ssに変換
$StopTime = $stoptimelist[$i]
if ($StopTime.Length -eq 7) {
$StopTime = “0” + $StopTime
}
# StartTimeをDateTime型に変換
$StopTime = [DateTime]::Today.Add(([TimeSpan]::Parse($StopTime)))
Write-Output “時間を変換しました: $StopTime”
# 現在の日時とStoptTimeの差を計算
$diff = $StopTime – $currentDateTime
Write-Output “時間を計算しました:$diff 分”
if ($diff.TotalMinutes -ge 0 -and $diff.TotalMinutes -le 60) {
# サブスクリプション情報を取得します
$subscription = Get-AzSubscription | Where-Object {$_.Id -eq $appgwsublist[$i]}
# サブスクリプションを切り替えます
Set-AzContext -Subscription $subscription
# AppGW取得
$AppGw = Get-AzApplicationGateway -Name $appgwnamelist[$i] -ResourceGroupName $appgwrglist[$i] -ErrorAction SilentlyContinue
if ($null -ne $AppGw) {
Stop-AzApplicationGateway -ApplicationGateway $AppGw
Write-Output “$AppGw を停止しました”
}
# サブスクリプション情報を取得します
$subscription = Get-AzSubscription | Where-Object {$_.Id -eq $vmsublist[$i]}
# サブスクリプションを切り替えます
Set-AzContext -Subscription $subscription
# VM取得
$Vm = Get-AzVM -Name $vmnamelist[$i] -ResourceGroupName $vmrglist[$i] -ErrorAction SilentlyContinue
if ($null -ne $Vm) {
Stop-AzVM -Name $vmnamelist[$i] -ResourceGroupName $vmrglist[$i] -Force
Write-Output “$Vm を停止しました”
}
}
}
}
上記スクリプトにテナントAとテナントBのスクリプトのみ作成しましたが、テナントCもある場合、テナントBの部分を丸コピーしてテナントBの下に貼り付け、テナントCの情報に修正すれば良いです。
スケジュール設定
設定は簡単なので今回は割愛します。
最後の確認
上記設定後、CSVファイルに起動停止したい時間を記載してストレージアカウントに保存後、スケジュールを起動停止時間と同じ時間に設定すると対象のリソースの起動停止が確認できます。文章が長くなるため、結果確認まで説明しませんが、問題なく起動停止を確認済みです。
では、次のブログで会いましょう!