PowerShellから直接ssh接続でNetAppにログインして設定情報を取得してCSV化するスクリプト


先日「NetAppの設定内容をcsvファイルに出力したい」という記事で手動でやる手法について記載した。

最近のWindowsだと直接sshコマンドが実行できるようになっているので、NetApp側に公開鍵を登録して、パスワードなしでアクセスできるように設定した上で、PowerShellスクリプトを実行することで、設定をスクリプト化できないかを実施してみた。

とりあえず全項目とればいいか、と「-showallfields true」設定でやっているが、下記スクリプトはONTAP 9.10.1の場合のもので、バージョンが異なると全部の項目数が変わる可能性があるので、一度手動で「set -privilege admin -rows 0 -units GB -showallfields true ; vserver cifs share show”」を実行し、出力される項目名を確認しておくこと

# タブ区切りのため `t を指定
$count=0
$flag=0
$results=@()

$results=cmd /c ssh.exe -l admin NetAppクラスタ "set -privilege admin -rows 0 -showseparator `t -units GB -showallfields true ; vserver cifs share show" | ForEach-Object {
    $line=$_.split("`t")
    if(($line[0] -eq "vserver") -and ($flag -eq 0)){
        $flag=1
        $titlecount=$count
    }
    if(($flag -eq 1) -and ($count -gt ($titlecount+1))){
        $output = New-Object -TypeName psobject
        $output | Add-Member -MemberType NoteProperty -Name "vserver" -Value $line[0]
        $output | Add-Member -MemberType NoteProperty -Name "share-name" -Value $line[1]
        $output | Add-Member -MemberType NoteProperty -Name "cifs-server" -Value $line[2]
        $output | Add-Member -MemberType NoteProperty -Name "path" -Value $line[3]
        $output | Add-Member -MemberType NoteProperty -Name "share-properties" -Value $line[4]
        $output | Add-Member -MemberType NoteProperty -Name "symlink-properties" -Value $line[5]
        $output | Add-Member -MemberType NoteProperty -Name "file-umask" -Value $line[6]
        $output | Add-Member -MemberType NoteProperty -Name "dir-umask" -Value $line[7]
        $output | Add-Member -MemberType NoteProperty -Name "comment" -Value $line[8]
        $output | Add-Member -MemberType NoteProperty -Name "acl" -Value $line[9]
        $output | Add-Member -MemberType NoteProperty -Name "attribute-cache-ttl" -Value $line[10]
        $output | Add-Member -MemberType NoteProperty -Name "volume" -Value $line[11]
        $output | Add-Member -MemberType NoteProperty -Name "offline-file" -Value $line[12]
        $output | Add-Member -MemberType NoteProperty -Name "vscan-fileop-profile" -Value $line[13]
        $output | Add-Member -MemberType NoteProperty -Name "max-connections-per-share" -Value $line[14]
        $output | Add-Member -MemberType NoteProperty -Name "force-group-for-create" -Value $line[15]
        $output
    }
    $count++
}

$results | Export-Csv test.csv -Encoding UTF8 -NoTypeInformation  -NoClobber

PowerShellにパスワード文字列を直接書かない手法


PowerShellで用意されているGet-Credential 関連を駆使して、PowerShellスクリプト内に直接パスワードを書かないで済む手法でスクリプトを作成した。

スクリプトを配置したディレクトリにscript.cred というファイルを作り、そこに暗号化されたパスワード文字列を配置する、という仕組み。

$authfile=$PSScriptRoot+".\script.cred"
$username="admin" #ユーザ名
$passwdstr="" # この変数にパスワード文字列が入る。
if((Test-Path $authfile) -eq $false){
    $creds = Get-Credential -UserName $username -Message $($username+"ユーザのパスワードを入力してください")
    $creds.Password | ConvertFrom-SecureString | Set-Content -Path $authfile | Out-Null
    $passwdstr=[Runtime.InteropServices.Marshal]::PtrToStringBSTR([Runtime.InteropServices.Marshal]::SecureStringToBSTR($creds.Password))
}else{
    $passwdstr=[Runtime.InteropServices.Marshal]::PtrToStringBSTR([Runtime.InteropServices.Marshal]::SecureStringToBSTR($(Get-Content $authfile | ConvertTo-SecureString)))
}

# この段階の $passwdstr には暗号化されていないパスワード文字列が入っている

なお、メモリ上の$passwdstr には暗号化されていない文字列が保存されているため、そこは注意が必要。

CommvaultのREST APIをPowerShellで使って見る


Commvaultバックアップの操作にREST APIを使うことができる。

・Commvault V11SP24の「REST API Overview
Commvault Rest APIの出力サンプル群

ログインして、指定したクライアントのサブクライアント情報を取得するPowerShellで作成してみた。

# CommCellユーザ情報
$restapiuser="admin"
$restapipasswd="パスワード"

# REST APIで使用するURL
# どちらを使うかについて https://documentation.commvault.com/11.24/expert/45592_available_web_services_for_rest_api.html
#$restapiurlbase="http://~:81/SearchSvc/CVWebService.svc/"
$restapiurlbase="http://~/webconsole/api/"

# 検索用文字列
$clientname="クライアント名"

# CommCell環境にログイン
$restapipasswdbase64=[Convert]::ToBase64String(([System.Text.Encoding]::Default).GetBytes($restapipasswd))
$headers=@{
    "Accept"="application/json"
    "Content-Type"="application/json"
}
$loginReq = @{
    username=$restapiuser
    password=$restapipasswdbase64
}
$loginresponse=Invoke-RestMethod -Method post -Uri $($restapiurlbase+"Login") -Body $($loginReq|ConvertTo-Json) -ContentType 'application/json' -Headers $headers

# 指定クライアントのサブクライアント情報取得
$headers=@{
    "Accept"="application/json"
    "Authtoken"=$loginresponse.token
}
$response=Invoke-RestMethod -Method Get -Uri $($restapiurlbase+"Subclient?clientName="+$clientname) -Headers $headers

# $response.subClientProperties.subClientEntity にサブクライアントの情報が入っているが
# 複数のサブクライアントがあると $response.subClientProperties.subClientEntity.subclientName が複数行になるので注意

# 表示
$response.subClientProperties.subClientEntity | ForEach-Object {
    $subcliententory=$_
    Write-host $subcliententory
 }

# CommCellログアウト
$headers=@{
    "Accept"="application/json"
    "Authtoken"=$loginresponse.token
}
$logoutresponse=Invoke-RestMethod -Method post -Uri $($restapiurlbase+"Logout") -Headers $headers

ただ、このスクリプトを使うとCommvault Event viewerに表示されるログイン情報が「Machine:unknown Locale:unknown」となる。

これを設定できるか調べて見たが、無いように思える。

vSphere 7.0 Update 1以降 vCLSという仮想マシンが勝手に起動してUPS連動シャットダウンに失敗する


vSphere 7.0 Update 1にアップデートして以降、UPS連動シャットダウンに失敗するようになった。

ログを確認していくと、仮想マシンがシャットダウンできない模様。

しかし、vCenter Serverから確認しても動いている仮想マシンは見えない。

そこでESXi のHost Clientに接続して確認すると、vCLSという作った覚えない仮想マシンが起動している。
そして、vCLSを手動で停止しても勝手に起動してくる。

確認してみると、vSphere 7.0 Update 1以降、vSphere DRS/vSphere HAなどのクラスタについて、起動するまでに時間がかかり重いvCenterサーバ仮想マシンではなく、クラスタの可用性のみを面倒見る仮想マシンとして vSphere Cluster Services を提供するようになったようである。

vSphere 7.0 Update 1 の vSphere Cluster Services (vCLS) (80472)
vSphere 7.0 documentation 「vSphere Cluster Services (vCLS)

これをUPS連動シャットダウンと組み合わせる場合の資料を探したところ、下記があった。

APC「PowerChute Network Shutdown v4.3/v4.4によるvSphere 7.0 Update 1でのvCLSの制御について
DELL「もう迷わない!HCI環境のUPS選定 シャットダウンについて

vSphereのクラスタをのvCLSをRetreatモードに変更することでvCLS仮想マシンが停止/削除することができる、というもの。

PowerShellでvCenterに接続して下記の様なスクリプトを実行して無効化を実行(APCのサンプルスクリプト disable_HA.ps1)

#!/usr/bin/pwsh

$server = "10.179.232.198" #"provide Vcenter server IP/hostname"
$username = "pcnsadmin" #"provide username to access vCenter"
$password = "APCapc@123" #"Provide Password to access vCenter server"
$cluster = "C" #"provide Name of the Cluster where Retreat mode needs to be enabled"

$env:HOME = '/root'
Set-PowerCLIConfiguration -InvalidCertificateAction Ignore -Confirm:$false
Connect-VIServer $server -Protocol https -User $username -password $password
$clid = (Get-Cluster $cluster).ID
Write-Host $clid
$myclid = $clid -replace 'ClusterComputeResource-',''
Write-Host $myclid
Get-AdvancedSetting -Entity $server -Name config.vcls.clusters.${myclid}.enabled | Set-AdvancedSetting -Value False -Confirm:$false

##Additional step for VSAN to turn off HA on the cluster
Get-Cluster -Name $cluster | Set-Cluster -HAEnabled:$false -Confirm:$false

Disconnect-VIServer -Force -Confirm:$false

PowerShellでvCenterに接続して下記の様なスクリプトを実行して有効化を実行(APCのサンプルスクリプト enable_HA.ps1)

#!/usr/bin/pwsh

$server = "10.179.232.198" #"provide Vcenter server IP/hostname"
$username = "pcnsadmin" #"provide username to access vCenter"
$password = "APCapc@123" #"Provide Password to access vCenter server"
$cluster = "C" #"provide Name of the Cluster where Retreat mode needs to be disabled"

$env:HOME = '/root'
Connect-VIServer $server -Protocol https -User $username -password $password
$clid = (Get-Cluster $cluster).ID
$myclid = $clid -replace 'ClusterComputeResource-',''
Write-Host $myclid
Get-AdvancedSetting -Entity $server -Name config.vcls.clusters.${myclid}.enabled | Set-AdvancedSetting -Value True  -Confirm:$false

##Additional step for VSAN to turn off HA on the cluster
Get-Cluster -Name $cluster | Set-Cluster -HAEnabled:$true -Confirm:$false

Disconnect-VIServer -Force -Confirm:$false

もう1つはAPCの資料および「PowerChute(TM) Network Shutdown v4.3 for Virtualization 補足説明書 日立編」には設定フローと共に掲載されている手法。

PowerChute Network Shutdownで「VM優先度付け」設定を有効にした上でvCLS仮想マシンを「優先度 高」で設定。vCenterサーバ仮想マシンを「優先度 中」、それ以外を優先度 低などに入れる。

「VMシャットダウン所要時間設定」と「VM起動所要時間設定」で「高」と「中」に対して0秒以上の値を設定

仮想化設定にある”仮想マシンと仮想装置、シャットダウンと起動”設定の「仮想マシンvApp 起動」にチェックを入れる

“ホストメンテナンスモード”の「タイムアウト」を「60秒」に設定

というもの。

綺麗に実行するのであればPowerShellを使った手法のほうが良さそうだ。

ESXiのみ環境でPowerCLIを使ってテンプレートもどきの動作をする手法


vCenterサーバがない、ESXiサーバのみ環境ではテンプレート機能が使用できない。

とはいえ、テンプレート化した仮想マシンの中身を見ると、ふつうと同じく仮想ハードディスクのvmdkファイルが存在しているので、vmdkファイルをコピーして、新規仮想マシンを作成するPowerCLIスクリプトをかけば、似たようなことができるな、と実験。

準備するもの

・PowerCLIをインストールした環境
Windows 10で実行したが、Linux環境にPowerShell+PowerCLIをセットアップしてもいけるはず。

・Windowsの場合、sysprepを実行してシャットダウンしたvmdkファイル
sysprepを実行して、次回起動時に初期セットアップが開始されるようにしたvmdkファイル。
VMware-toolsはインストール済みであることが望ましい。

・Linuxの場合、下記の情報などを削除
RHEL7の仮想化の導入および管理ガイド第4章 仮想マシンのクローン作成によれば
/etc/udev/rules.d/70-persistent-net.rules を削除
/etc/ssh/ssh_host_* を削除
/etc/sysconfig/network-scripts/ifcfg-eth* などから IPADDRESS,NETMASK,HWADDRなどの値削除

スクリプト本体

Import-Module VMware.VimAutomation.Core

#Set-PowerCLIConfiguration -InvalidCertificateAction Ignore -Confirm:$false

$vcenterserver="ESXiサーバ"
$vcenteruser="ユーザ名"
$vcenterpassword="パスワード"

$targetdatastore="仮想マシンをおくデータストア名"

# 仮想マシンの名前 / ランダムで作成して、あとから変更する手法
$vmnamebase="NewVM_"
$vmnametmp=Get-Random
$vmname=$vmnamebase+$vmnametmp

# 仮想マシンスペックと接続ネットワーク指定
$vcpu=2
$vmem=6
$network="VM Network"

# 指定できるGuestOSのIDを調べるには下記を実行すること
#   PowerCLIがサポートしている一覧 
#   [VMware.Vim.VirtualMachineGuestOsIdentifier].GetEnumValues()
# 代表的なもの
# windows8Server64Guest = Windows2012
# windows9Server64Guest = Windows2016
#$vmguestosid="windows9Server64Guest"

# 元ネタのWindowsが入ったvmdkファイルの指定
# 構築時にBIOS環境かEFI環境のどちらで作ったのか注意
$vmdkfilepath="[データストア名] windows2019/windows2019.vmdk"
$vmguestosid="windows9Server64Guest"
#$vmdkfilepath="[データストア名] win2016/win2016.vmdk"
#$vmguestosid="windows9Server64Guest"
#$vmdkfilepath="[データストア名] win2012/win2012.vmdk"
#$vmguestosid="windows8Server64Guest"
# 上記の元ネタが置いてあるデータストア名を下記でも指定する
$sourcedatastore ="データストア名"

# vCenterまたはESXiサーバに接続
Connect-VIServer -Server $vcenterserver -User $vcenteruser -Password $vcenterpassword -WarningAction 0
# パスワードを書きたくない場合は
# New-VICredentialStoreItem -Host $vcenterserver -User $vcenteruser -Password $vcenterpassword
# を実行すると、資格情報保存域に登録され、以降は下記だけで接続できるようになる
# Connect-VIServer -Server $vcenterserver

$virtualportgroup=Get-VirtualPortGroup -Name $network
$datastore=Get-Datastore -Name $targetdatastore
$vm=New-VM -Name $vmname -NumCpu $vcpu -MemoryGB $vmem -Portgroup $virtualportgroup -Datastore $datastore -DiskStorageFormat Thin -GuestID $vmguestosid -HardwareVersion vmx-14


$olddiskinfo=Get-Vm $vmname|Get-Harddisk # 一時的に作られたディスクの情報を保存
$sourcevmdk=Get-HardDisk -Datastore $sourcedatastore -DatastorePath $vmdkfilepath
# ディスクの削除
Remove-HardDisk -HardDisk $olddiskinfo -Confirm:$false


# コピー先データストアのパスを生成
$targetvmdktmp=$olddiskinfo.Filename
$ed=$targetvmdktmp.LastIndexOf("/")
$targetvmdk=$targetvmdktmp.Substring(0,$ed+1) # コピー先のパス

# OSが入ったvmdkのコピー
$adddiskinfo=Copy-HardDisk -Harddisk $sourcevmdk -DestinationPath $targetvmdk -DestinationStorageFormat Thin

#$vm = get-Vm $vmname
New-HardDisk -VM $vm -DiskPath $adddiskinfo.Filename

Get-ScsiController -VM $vm | Set-ScsiController -Type VirtualLsiLogicSAS

# 仮想マシン設定変更用オブジェクト定義
$newSpec = New-Object VMware.Vim.VirtualMachineConfigSpec

# USBコントローラの追加
# これがないとWindows環境でマウスが動かない
# https://communities.vmware.com/t5/VMware-PowerCLI-Discussions/Where-is-the-quot-Get-USBController-quot-cmdlet-Same-with-Remove/td-p/2155582
# 上記だとUSB 2.0コントローラ追加
$newSpec.deviceChange = New-Object VMware.Vim.VirtualDeviceConfigSpec[] (1)
$newSpec.deviceChange[0] = New-Object VMware.Vim.VirtualDeviceConfigSpec
$newSpec.deviceChange[0].operation = "add"
#$newSpec.deviceChange[0].device = New-Object VMware.Vim.VirtualUSBController # USB2.0コントローラ
$newSpec.deviceChange[0].device = New-Object VMware.Vim.VirtualUSBXHCIController # USB3.0コントローラ

# EFIかBIOSか
# https://docs.vmware.com/jp/VMware-Cloud-on-AWS/services/com.vmware.vsphere.vmc-aws-manage-vms.doc/GUID-898217D4-689D-4EB5-866C-888353FE241C.html
#https://github.com/vmware/PowerCLI-Example-Scripts/blob/master/Scripts/SecureBoot.ps1
# BIOSを設定する場合は、SecureBootをdisableにする必要がある
#$newSpec = New-Object VMware.Vim.VirtualMachineConfigSpec
# 仮想マシン起動オプション変更用オブジェクト定義
$bootOptions = New-Object VMware.Vim.VirtualMachineBootOptions
#$newSpec.Firmware = [VMware.Vim.GuestOsDescriptorFirmwareType]::efi
#$bootOptions.EfiSecureBootEnabled = $true
$newSpec.Firmware = [VMware.Vim.GuestOsDescriptorFirmwareType]::bios
$bootOptions.EfiSecureBootEnabled = $false
$newSpec.BootOptions=$bootOptions


# 仮想マシンへの設定反映
#(get-view $vm).ReconfigVM_Task($newSpec)
$vm.ExtensionData.ReconfigVM($newSpec)


# 接続切断
Disconnect-VIServer -Server $vcenterserver -Confirm:$false

解説

仮想マシンにハードディスクを追加する

仮想マシンに新しく空っぽのハードディスクを追加する場合は、「New-HardDisk -VM 仮想マシン ~」で指定するが、Copy-HardDiskでコピーしてきたハードディスクを登録する場合が分かりづらかった。

結果としては、新規と同じく「New-HardDisk -VM 仮想マシン ~」でよかった。

今回の場合は、CopyHardDiskを実行した結果を変数にいれて、それをNew-HardDIskで登録、という形にした。

$adddiskinfo=Copy-HardDisk -Harddisk $sourcevmdk -DestinationPath $targetvmdk -DestinationStorageFormat Thin

$vm = get-Vm $vmname
New-HardDisk -VM $vm -DiskPath $adddiskinfo.Filename

仮想マシンハードウェアにUSB 3.0コントローラを追加する

Host Clientから作成した場合は、USB 3.0コントローラが作成されていたが、New-VMコマンドでは作成されなかった。このため、Windowsが起動した後にUSBマウスが存在できず、マウス操作ができなかった。(キーボードはPS/2キーボード扱いとして使えたようだった)

このUSB 3.0コントローラを追加するための操作がわからず、いろいろ調べたところ「Where is the “Get-USBController” cmdlet? (Same with Remove- and New-)」の記述を見て、USB 2.0コントローラの追加手法が分かった。

その後、VirtualUSBController を起点に調べることで、 xHCIはVirtualUSBXHCIControllerという名前であることがわかり、解決した

$vm=Get-VM -Name 仮想マシン名
$newSpec = New-Object VMware.Vim.VirtualMachineConfigSpec
$newSpec.deviceChange = New-Object VMware.Vim.VirtualDeviceConfigSpec[] (1)
$newSpec.deviceChange[0] = New-Object VMware.Vim.VirtualDeviceConfigSpec
$newSpec.deviceChange[0].operation = "add"
#$newSpec.deviceChange[0].device = New-Object VMware.Vim.VirtualUSBController # USB2.0コントローラ
$newSpec.deviceChange[0].device = New-Object VMware.Vim.VirtualUSBXHCIController # USB3.0コントローラ

# 仮想マシンへの設定反映
#(get-view $vm).ReconfigVM_Task($newSpec)
$vm.ExtensionData.ReconfigVM($newSpec)

設定を反映する部分は、ネタ元では「Get-View」を使っていたが、後述のSecureBootについての結果ではGet-VM経由で実施しているスクリプトがあったので、それを使用している。

BIOS/EFI切り替え

仮想マシンをBIOS起動にするか、EFI起動にするかを設定する手法。

2021現在のPowerCLIでNew-VMした時のデフォルトはEFI起動でセキュアブート有効になっている。

これをBIOS起動に設定する場合は、セキュアブートを無効にしてからBIOSに切り替える必要があるので下記にようになる。

$vm=Get-VM -Name 仮想マシン名
$newSpec = New-Object VMware.Vim.VirtualMachineConfigSpec

$bootOptions = New-Object VMware.Vim.VirtualMachineBootOptions
$bootOptions.EfiSecureBootEnabled = $false
$newSpec.BootOptions=$bootOptions

$newSpec.Firmware = [VMware.Vim.GuestOsDescriptorFirmwareType]::bios

$vm.ExtensionData.ReconfigVM($newSpec)