📑

複数のvCenterへのVM取得、権限削除・付与スクリプト

2024/07/07に公開

はじめに

社内でVMを払い出す業務で複数のvCenterを運用していて、作っておきたかったPowerCLIのスクリプトをまとめておきます。

概要

以下のスクリプトを作ってみました。

  • 各vCenter上で動いているVMを取得
  • 各vCenter上に作られているユーザーに宛がわれている権限を削除する
  • 各vCenter上に作られているユーザーに対して権限を宛がう
    • 今回は指定したVMの起動停止等の権限を宛がっています

やってみた

環境

前回紹介した、VMwareハンズオンラボ環境で行います。

https://zenn.dev/arbr/articles/b5f17dcdfaa089

スクリプト1:各vCenter上で動いているVMを取得

できること

CSVに定義されている各vCenterに接続して、VMの情報を取得して出力します。

スクリプト・ファイル

ファイル構成は以下とします。00_run_get_allVmInfo.batをダブルクリックするだけで実行するようにしています。

─(適当なフォルダ)
   │  get_allVmInfo.ps1
   │  00_run_get_allVmInfo.bat
   ├─conf/
   │       vcenter_info.csv
   └─output/

各ファイルは以下です。

get_allVmInfo.ps1
get_allVmInfo.ps1
param (
    [string]$CsvFilePath = "conf/vcenter_info.csv"
)

# Initialize variable to store VM details
$vmDetails = @()

# Import CSV file containing vCenter connection details
$vcenters = Import-Csv -Path $CsvFilePath

# Loop through each vCenter entry in the CSV file
foreach ($vcenter in $vcenters) {
    $hostname = $vcenter.hostname
    $username = $vcenter.username
    $password = $vcenter.password
    $remarks = $vcenter.remarks

    try {
        # Connect to vCenter
        Write-Host "Connecting to $hostname..."
        Connect-VIServer -Server $hostname -User $username -Password $password -ErrorAction Stop

        # Retrieve VM information
        $currentVMs = Get-VM | Select-Object Name, PowerState, NumCpu, MemoryMB, ProvisionedSpaceGB, UsedSpaceGB, GuestOS
        foreach ($vm in $currentVMs) {
            $vmDetails += [PSCustomObject]@{
                VCENTER          = $hostname
                VM_NAME          = $vm.Name
                POWERSTATE       = $vm.PowerState
                NUM_CPU          = $vm.NumCpu
                MEMORY_MB        = $vm.MemoryMB
                PROVISIONED_GB   = $vm.ProvisionedSpaceGB
                USED_GB          = $vm.UsedSpaceGB
                GUEST_OS         = $vm.GuestOS
                REMARKS          = "$hostname - $remarks"
            }
        }

        # Disconnect from vCenter if necessary
        Disconnect-VIServer -Server $hostname -Confirm:$false
        Write-Host "Disconnected from $hostname."

    } catch {
        Write-Host "Failed to connect to $hostname. Error: $_"
    }
}

# Create output directory if it does not exist
$outputDir = "output"
if (-not (Test-Path -Path $outputDir)) {
    New-Item -ItemType Directory -Path $outputDir
}

# Export collected VM details to a CSV file
$outputFilePath = Join-Path -Path $outputDir -ChildPath "vm_info_output.csv"
$vmDetails | Export-Csv -Path $outputFilePath -NoTypeInformation

Write-Host "VM information has been saved to $outputFilePath."
00_run_get_allVmInfo.bat
00_run_get_allVmInfo.bat
@echo off

:: Change to the directory where the batch file is located
cd /d %~dp0

:: Temporarily bypass PowerShell execution policy to run the script
PowerShell -NoProfile -ExecutionPolicy Bypass -File "get_allVmInfo.ps1" -CsvFilePath "conf/vcenter_info.csv"

pause
vcenter_info.csv
conf/vcenter_info.csv
hostname,username,password,remarks
vcsa-01a.corp.vmbeans.com,administrator@vsphere.local,VMware1!,Primary vCenter

また作成にはChatGPTを用いました。プロンプト文は以下になります。

プロンプト文

PowerShellやPowerCLIのスクリプトを高品質に作成できるあなたにお願いします。
以下のようなスクリプトファイル"get_allVmInfo.ps1"を作ってください。各ファイル内のコメントは全角文字を避けて、英語で記述してください。
・PowerCLIはすでにインポート済みで、スクリプトファイル内ではインポートやアップデートは不要です。
・別のファイル"conf/vcenter_info.csv"に、VMwareへ接続するホスト名、ユーザ名、パスワード、備考がCSVファイルで保存されています。
・スクリプトファイルは、"conf/vcenter_info.csv"を引数として受け取り、CSV各行をループして処理を行っていきます。
・ループ中の処理1:"conf/vcenter_info.csv"各行の接続情報をもとに、PowerCLIでVMwareに接続します。引数でユーザ名とパスワードを直接指定してください(SecureStringに変換不要です)。
・ループ中の処理2:接続先のVM情報を取得し、変数に追記で書き込んでいきます。
・ループ中の処理3:取得した情報の各要素に、"conf/vcenter_info.csv"各行の、接続先ホスト名と備考のテキストを追加します。
・ループ中の処理4:必要であれば、VMwareとの接続を終了します。
・"conf/vcenter_info.csv"の各行のループが終わったら、変数の中身をCSVファイルで"output/"フォルダ以下に出力します。
・このスクリプトファイルをダブルクリックで起動できるような、起動用ファイル"00_run_get_allVmInfo.bat"を別途用意してください。
・"00_run_get_allVmInfo.bat"はPowerShellの実行権限を変更しないよう、一時的に実行を許可するオプションを利用してください。
・"00_run_get_allVmInfo.bat"は最初にカレントディレクトリに移動してから、"get_allVmInfo.ps1"を実行するようにしてください。

また、"conf/vcenter_info.csv"のサンプルファイルも教えてください。

スクリプト2:各vCenter上に作られているユーザーに宛がわれている権限を削除する

できること

各vCenterの特定のユーザーに宛がわれているロールをすべて外します。同じユーザー名が前提です。

事前準備

ユーザー作成

ユーザーはWebコンソールから作成しました。ラボ環境デスクトップにあるFireFoxを起動して、administratorでログインします。

ハンバーガーメニューから、Administartionを選択します。

左ペインで、Users and Groups を選択します。

Domainをvsphere.localに指定して、ADDをクリックします。

Usernameは今回はnewuserとして、パスワードを指定してADDをクリックします。

スクリプト・ファイル

ファイル構成は以下とします。01_run_remove_allPermission.batをダブルクリックするだけで実行するようにしています。

─(適当なフォルダ)
   │  params.ps1
   │  remove_allPermission.ps1
   │  01_run_remove_allPermission.bat
   ├─conf/
   │       vcenter_info.csv
   └─output/

各ファイルは以下です。

remove_allPermission.ps1
remove_allPermission.ps1
# Import necessary modules
# PowerCLI should already be imported

# Load parameters from params.ps1
. .\params.ps1

# Check if the vCenter info CSV file is provided as an argument
if ($args.Count -eq 0) {
    Write-Error "Please provide the path to the vCenter info CSV file as an argument."
    exit 1
}

$vcenterInfoFilePath = $args[0]

# Read vCenter info from CSV
$vcenters = Import-Csv -Path $vcenterInfoFilePath

# Initialize an empty array to store results
$results = @()

# Loop through each vCenter entry
foreach ($vcenter in $vcenters) {
    $hostname = $vcenter.hostname
    $username = $vcenter.username
    $password = $vcenter.password
    $remarks = $vcenter.remarks

    # Connect to the vCenter server
    try {
        Connect-VIServer -Server $hostname -User $username -Password $password -ErrorAction Stop
    } catch {
        Write-Error "Failed to connect to vCenter: $hostname"
        continue
    }

    # Get permissions for the specified principal
    try {
        $permissions = Get-VIPermission -Principal $Principal
        if ($permissions) {
            # Display the permissions and ask for confirmation to delete
            $permissions | Format-Table -Property Entity, Role, Principal

            $confirmation = Read-Host "Do you want to remove these permissions for $Principal on $hostname? (yes/no)"
            if ($confirmation -eq "yes") {
                # Remove each permission
                $permissions | Remove-VIPermission -Confirm:$false

                # Log the removal
                foreach ($perm in $permissions) {
                    $results += [PSCustomObject]@{
                        vCenter    = $hostname
                        Principal  = $Principal
                        Entity     = $perm.Entity
                        Role       = $perm.Role
                        Remarks    = $remarks
                    }
                }
            } else {
            Write-Host "No permissions remove for $Principal on vCenter: $hostname"
        }
        } else {
            Write-Host "No permissions found for $Principal on vCenter: $hostname"
        }
    } catch {
        Write-Error "Failed to get or remove permissions for $Principal on vCenter: $hostname"
    }

    # Disconnect from the vCenter server
    Disconnect-VIServer -Server $hostname -Confirm:$false
}

# Export results to CSV
$outputFilePath = ".\output\removed_permissions.csv"
$results | Export-Csv -Path $outputFilePath -NoTypeInformation

Write-Host "Permissions removal process completed. Results saved to $outputFilePath."
01_run_remove_allPermission.bat
01_run_remove_allPermission.bat
@echo off
setlocal

rem Change to the directory of the script
cd /d %~dp0

rem Temporarily allow script execution and run the PowerShell script
powershell -NoProfile -ExecutionPolicy Bypass -File .\remove_allPermission.ps1 .\conf\vcenter_info.csv

endlocal

pause
params.ps1
params.ps1
# Define the Principal variable
$Principal = "VSPHERE.LOCAL\newuser"

conf/vcenter_info.csvは最初のファイルと同じものになります。

生成に使ったプロンプト文は以下になります。

プロンプト文

PowerShellやPowerCLIのスクリプトを高品質に作成できるあなたにお願いします。
まず、以下の一般的な点に注意してください。

  • 各ファイル内のコメントは全角文字を避けて、英語で記述してください。
  • 変数の名前に予約語を用いないでください。

以下のようなスクリプトファイル"remove_allPermission.ps1"を作ってください。

  • PowerCLIはすでにインポート済みで、スクリプトファイル内ではインポートやアップデートは不要です。
  • 別のファイル"params.ps1"に、次に定義する複数の変数がPowerShell形式で定義されています。
    • Principalに設定する対象ユーザーの名前を格納した文字列変数
  • 別のファイル"conf/vcenter_info.csv"に、VMwareへ接続するホスト名"hostname"、ユーザ名"username"、パスワード"password"、備考"remarks"がCSVファイルで保存されています。
  • スクリプトファイルは、"params.ps1"を実行し、ファイル内の変数定義を実行します。
  • スクリプトファイルは、"conf/vcenter_info.csv"を引数として受け取り、CSV各行をループして処理を行っていきます。
    • ループ中の処理1:"conf/vcenter_info.csv"各行の接続情報をもとに、PowerCLIでVMwareに接続します。引数でユーザ名とパスワードを直接指定してください(SecureStringに変換不要です)。
    • ループ中の処理2:接続したVMware上で、対象ユーザに紐づいている権限をGet-VIPermissionで取得しその内容を画面表示して、ユーザにその後の削除処理を続けるか確認してください。
    • ループ中の処理3:確認がyesであった場合は、対象ユーザに紐づいている権限をGet-VIPermissionで取得し、パイプラインでRemove-VIPermissionに渡して権限を削除します。確認がyes意外であった場合は標準出力にスキップする旨を表示してください。
  • このスクリプトファイルをダブルクリックで起動できるような、起動用ファイル"01_run_remove_allPermission.bat"を別途用意してください。

また、"params.ps1と"conf/vcenter_info.csv"のサンプルファイルも教えてください。

スクリプト3:各vCenter上に作られているユーザーに対して権限を宛がう

できること

各vCenterのユーザーにロールを宛がいます。今回は同じ名前のユーザーに、同じ名前のロール(VMの操作権限)を、VMを指定して宛がっています。

事前準備

権限作成

VMの操作権限のカスタムロールをPowerCLI(PowerShell)で作成します。

# 接続
Connect-VIServer vcsa-01a.corp.vmbeans.com -User administrator@vsphere.local -Password VMware1!

# ロール名を定義
$roleName = "VM Power Operations Role"

# カスタムロールを作成
New-VIRole -Name $roleName  -Privilege (Get-VIPrivilege -Id VirtualMachine.Interact.PowerOn,VirtualMachine.Interact.PowerOff,VirtualMachine.Interact.Suspend,VirtualMachine.Interact.Reset )

スクリプト・ファイル

ファイル構成は以下とします。02_run_add_somePermissions.batをダブルクリックするだけで実行するようにしています。

─(適当なフォルダ)
   │  params.ps1
   │  add_somePermissions.ps1
   │  02_run_add_somePermissions.bat
   ├─conf/
   │       vcenter_info.csv
   └─output/

各ファイルは以下です。

add_somePermissions.ps1
add_somePermissions.ps1
param (
    [string]$CsvFilePath = "conf/vcenter_info.csv"
)

# Load the parameters from the params.ps1 file
. .\params.ps1

# Validate the CSV file path
if (-not (Test-Path -Path $CsvFilePath)) {
    Write-Host "CSV file not found: $CsvFilePath"
    exit
}

# Import the vCenter connection information from the CSV file
$vcenters = Import-Csv -Path $CsvFilePath

# Loop through each vCenter information in the CSV
foreach ($vcenter in $vcenters) {
    $hostname = $vcenter.hostname
    $username = $vcenter.username
    $password = $vcenter.password
    $remarks = $vcenter.remarks

    # Check if the hostname exists in the hash table
    if ($HashVmNames.ContainsKey($hostname)) {
        Write-Host "Connecting to vCenter: $hostname"
        
        # Connect to the vCenter server
        Connect-VIServer -Server $hostname -User $username -Password $password

        # Add Permission to user(Principal)
        $strVms = $HashVmNames[$hostname] -join ","
        Write-Host "Assigning role '$RoleName' to user '$Principal' on VM '$strVms' in $hostname"
        Get-VM -Name $HashVmNames[$hostname] | New-VIPermission -Principal $Principal -Role $RoleName -Confirm:$false

        # Disconnect from the vCenter server
        Disconnect-VIServer -Server $hostname -Confirm:$false
    } else {
        Write-Host "Hostname '$hostname' not found in the hash table. Skipping."
    }
}

Write-Host "Process completed."
02_run_add_somePermissions.bat
02_run_add_somePermissions.bat
@echo off
cd /d "%~dp0"
powershell -ExecutionPolicy Bypass -File .\add_somePermissions.ps1 -CsvFilePath ".\conf\vcenter_info.csv"
pause

params.ps1に、ロール名やVM名を付与します。VMはvCenter毎に違うので、ホスト名をKey・VM名群の配列を値にした連想配列で定義しています。

params.ps1
params.ps1
# Define the Principal variable
$Principal = "VSPHERE.LOCAL\newuser"

# Define the role to be assigned
$RoleName = "VM Power Operations Role"

# Define the hash table for VM names
# Key: Hostname, Value: Array of VM names
$HashVmNames = @{
    "vcsa-01a.corp.vmbeans.com" = @("acct-app-01","acct-db-01")
}

conf/vcenter_info.csvは最初のファイルと同じものになります。

生成に使ったプロンプト文は以下になります。

プロンプト文

PowerShellやPowerCLIのスクリプトを高品質に作成できるあなたにお願いします。
まず、以下の一般的な点に注意してください。

  • 各ファイル内のコメントは全角文字を避けて、英語で記述してください。
  • 変数の名前に予約語を用いないでください。

以下のようなスクリプトファイル"add_somePermissions.ps1"を作ってください。各ファイル内のコメントは全角文字を避けて、英語で記述してください。

  • PowerCLIはすでにインポート済みで、スクリプトファイル内ではインポートやアップデートは不要です。
  • 別のファイル"params.ps1"に、次に定義する複数の変数がPowerShell形式で定義されています。
    • Principalに設定する対象ユーザーの名前を格納した文字列変数"Principal"
    • 付与する権限名を格納した文字列変数"RoleName"
    • 対象ユーザに権限を付与されるVM名を格納した連想配列"HashVmNames"。この連想配列は、Key:ホスト名、値:複数のVM名を格納した文字列変数の配列 としてください。
  • 別のファイル"conf/vcenter_info.csv"に、VMwareへ接続するホスト名"hostname"、ユーザ名"username"、パスワード"password"、備考"remarks"がCSVファイルで保存されています。
  • スクリプトファイルは、"params.ps1"を実行し、ファイル内の変数定義を実行します。
  • スクリプトファイルは、"conf/vcenter_info.csv"を引数として受け取り、CSV各行をループして処理を行っていきます。
    • ループ中の処理1:ホスト名が連想配列"HashVmNames"のKeyとして存在する場合は"conf/vcenter_info.csv"各行の接続情報をもとに、PowerCLIでVMwareに接続します。引数でユーザ名とパスワードを直接指定してください(SecureStringに変換不要です)。ホスト名が連想配列に存在しない場合はスキップしてその旨をメッセージとして標準出力します。
    • ループ中の処理2:連想配列"HashVmNames"の値である文字列変数の配列を引数として接続ホスト内のVM情報を検索し、その出力をパイプラインでNew-VIPermissionで対象ユーザーに対象ロールを付与してください。
  • このスクリプトファイルをダブルクリックで起動できるような、起動用ファイル"02_run_add_somePermissions.bat"を別途用意してください。

また、"params.ps1と"conf/vcenter_info.csv"のサンプルファイルも教えてください。

おわりに

今回は業務で使いそうなスクリプトをラボ環境を使って作ってみました。
ニッチな運用ですが、手作業のままだとミスのリスクがありますので、スクリプトづくりに挑戦してみました。
この記事がどなたかのお役に立てれば幸いです。

Discussion