Proxmoxで作った仮想マシンのsnapshotはどうやって見えるのか?

Proxmoxで仮想マシンを作った場合、仮想マシンのsnapshotの作られ方が仮想マシンを置く場所(データストア)によって異なっている。

zfsについては簡単に確認できたが、それ以外についてどうなるのかを確認した。

まず、proxmoxのWeb UIからスナップショットを作成した

これをコマンドで確認していく

まず、Proxmox VE側のコマンドで仮想マシンにsnapshotがあるかどうかは「qm listsnapshot <VMID>」を実行して確認できる。これは各ファイルシステムで共通となる。

root@pve3:~# qm listsnapshot 103
`-> test                        2025-04-17 15:19:16     no-description
 `-> current                                            You are here!
root@pve3:~#

次に各ファイルシステムごとにそれぞれ確認していく手法が違う。

ZFSの場合

例えばzfsの場合であれば 「zfs list -t snapshot」で確認できる。

root@pve3:~# qm listsnapshot 101
`-> zfs-test-snap               2025-04-17 15:39:18     no-description
 `-> current                                            You are here!
root@pve3:~# zfs list -t snapshot
NAME                                     USED  AVAIL  REFER  MOUNTPOINT
rpool/data/vm-101-disk-0@zfs-test-snap     0B      -   139K  -
rpool/data/vm-101-disk-1@zfs-test-snap     0B      -  22.8G  -
rpool/data/vm-101-disk-2@zfs-test-snap     0B      -  22.1M  -
rpool/data/vm-101-disk-3@zfs-test-snap     0B      -  85.2K  -
root@pve3:~#

NFSの場合

NFSの場合、仮想マシンをqcow2形式で作成した場合のみsnapshot作成が可能となる。

まず仮想マシンの設定を確認

root@pve3:~# qm config 105
agent: 1
boot: order=sata0;ide0;ide2;net0
cores: 2
cpu: x86-64-v2-AES
ide0: none,media=cdrom
ide2: none,media=cdrom
machine: pc-i440fx-9.2+pve1
memory: 2048
meta: creation-qemu=9.2.0,ctime=1744345484
name: wintest3-nfs
net0: e1000=BC:24:11:FD:D4:F3,bridge=vmbr0,firewall=1
numa: 0
ostype: win10
parent: nfs-snap
sata0: ontap:105/vm-105-disk-0.qcow2,size=40G
scsihw: virtio-scsi-single
smbios1: uuid=7a3e58d8-be9e-4e03-a040-bd1635aa3dfe
sockets: 1
vmgenid: f361fff2-f474-4260-99ac-586c42db009b
root@pve3:~# qm listsnapshot 105
`-> nfs-snap                    2025-04-17 15:39:29     no-description
 `-> current                                            You are here!
root@pve3:~#

該当する領域をlsコマンドで確認

root@pve3:~# ls -l /mnt/pve/ontap/images/105
total 13607536
-rw-r----- 1 root root 45504004165 Apr 17 15:36 vm-105-disk-0.qcow2
root@pve3:~#

見た目には1ファイルしかないように見える。

このファイルに対して「qemu-img snapshot -l ファイル名」を実行するとsnapshotが作成されているかどうかがわかる。

root@pve3:~# qemu-img snapshot -l /mnt/pve/ontap/images/105/vm-105-disk-0.qcow2
Snapshot list:
ID      TAG               VM_SIZE                DATE        VM_CLOCK     ICOUNT
1       nfs-snap              0 B 2025-04-17 15:39:29  0000:00:00.000          0
root@pve3:~#

cephの場合

cephの場合、rbdコマンドのオプションでいろいろ指定していくのだが、確認がちょっとめんどい

まずは、仮想マシンの設定を「qm config <VMID>」を実行して確認する。

root@pve3:~# qm config 103
agent: 1
boot: order=scsi0;ide2;net0
cores: 2
cpu: x86-64-v2-AES
ide2: none,media=cdrom
memory: 2048
meta: creation-qemu=9.2.0,ctime=1744338514
name: linux2-ceph
net0: virtio=BC:24:11:3A:D1:9E,bridge=vmbr0,firewall=1
numa: 0
ostype: l26
parent: test
scsi0: cephpool:vm-103-disk-0,iothread=1,size=40G
scsihw: virtio-scsi-single
smbios1: uuid=37f0d81e-3ed1-417a-9a10-3d8f556e3b37
sockets: 1
vmgenid: 0ea7ac3f-7b05-49d0-90c0-fbba87cc63ae
root@pve3:~# qm listsnapshot 103
`-> test                        2025-04-17 15:19:16     no-description
 `-> current                                            You are here!
root@pve3:~#

scsi0の行にある「cephpool」が使用しているデータストア名となる。

Ceph RDBが使用しているOSD Pool名を「ceph osd pool ls」を実行して確認する

root@pve3:~# ceph osd pool ls
.mgr
cephpool
cephfs_data
cephfs_metadata
root@pve3:~#

cephfs_dataとcephfs_metadataはCeph FSのほうで使っているデータで、仮想マシンをおくデータストアはcephpool のほうとなる。

cephpoolにある仮想マシン用のディスクを「rbd ls cephpool」で確認する

root@pve3:~# rbd ls cephpool
vm-103-disk-0
root@pve3:~#

この仮想マシンについて、snapshotが作成されているかは「rbd snap ls cephpool/<仮想ディスク名>」で確認する

root@pve3:~# rbd snap ls cephpool/vm-103-disk-0
SNAPID  NAME  SIZE    PROTECTED  TIMESTAMP
    10  test  40 GiB             Thu Apr 17 15:19:16 2025
root@pve3:~#

PowerShellでファイルの詳細情報をとる

excelやwordファイルのプロパティを見ると「詳細」タブにいろいろ情報が入っている。

これをPowerShellでファイル情報を収集する際に載せれるように調査した。

面倒なのがPowerShellの標準機能では収集できず、Shell.Application を使って収集するのだが、ストレートに各ファイルの情報をとるのではなく、そのファイルが置いてあるフォルダ情報のなかから取得する、という手法をとる必要がある。

前回作った「PowerShellを使ってドロップしたフォルダ内にあるファイル一覧をテキストファイルに保存する」を修正したものがこちら

# ドラッグされたフォルダの中にあるファイル一覧をつくるやつ
#
# 使い方
#  1. このファイルを保存する
#  2. このファイルのショートカットを作成する
#  3. ショートカットのプロパティを開き"リンク先"の項目の先頭に「powershell.exe -NoProfile -ExecutionPolicy RemoteSigned -File 」をつけて保存
#  4. 作成されたショートカットの上に、フォルダをドロップすると、ウィンドウが開いて確認される
#  5. 作成するファイルリストの保存ファイル名を指定する
#  6. 出力される
#
$Args | foreach{
    echo $_.GetType()
    $searchdir = Get-Item -LiteralPath $_
}

Write-Host $searchdir.FullName "のファイル一覧を作成します"
pause

$shell = New-Object -COMObject Shell.Application

# https://pg-note.com/archives/1144 より
# 必要なアセンブリを読み込む
Add-Type -AssemblyName System.Windows.Forms 
$dialog = New-Object Windows.Forms.SaveFileDialog 

$dialog.Title = "CSVファイルの保存" 
$dialog.Filter = "テキストファイル(*.txt)|*.txt|csvファイル(*.csv)|*.csv|全てのファイル|*.*" 
$dialog.InitialDirectory = [Environment]::GetFolderPath("MyDocuments")
$dialog.FileName = $searchdir.Name

$ret = $dialog.ShowDialog() 
$outputfile=$dialog.FileName

# CSV出力向けの処理
$results=@()
$linecount=0
#


if ($ret -eq "OK"){
    Write-Host ("保存するファイル名、" + $outputfile) 

    # ディレクトリの検索 start
    Get-ChildItem -Recurse $searchdir -Attributes Hidden,System,Archive,ReadOnly,Normal,Compressed,SparseFile| ForEach-Object {
    $filename=$_.FullName
    $fileobject=$_

        if( !$_.PSIsContainer ){
            Write-Host $filename
            
            # CSV向け処理 start
            $output = New-Object -TypeName PSObject
            $output | Add-Member -MemberType NoteProperty -Name "ファイル名" -Value $filename
            $output | Add-Member -MemberType NoteProperty -Name "作成日" -Value ($fileobject.CreationTime|Get-Date -Format "yyyy-MM-dd HH:mm:ss")  # $fileobject.CreationTimeUtc
            $output | Add-Member -MemberType NoteProperty -Name "サイズ" -Value $fileobject.Length
            $output | Add-Member -MemberType NoteProperty -Name "ハッシュ(sha256)" -Value (Get-FileHash -LiteralPath $filename -Algorithm SHA256).Hash

            $Getfolder = $shell.Namespace($fileobject.DirectoryName)
            $Getfile = $Getfolder.ParseName($fileobject.Name)
            $output | Add-Member -MemberType NoteProperty -Name "タイトル" -Value $Getfile.ExtendedProperty('System.Title')
            $output | Add-Member -MemberType NoteProperty -Name "件名" -Value $Getfile.ExtendedProperty('System.Subject')
            #$output | Add-Member -MemberType NoteProperty -Name "作成者" -Value ([string]$Getfile.ExtendedProperty('System.Author'))
            #  なぜか直接出力すると System.strings になるので、 string に変換
            $tmps=[string]$Getfile.ExtendedProperty('System.Author')
            $output | Add-Member -MemberType NoteProperty -Name "作成者" -Value $tmps
            $output | Add-Member -MemberType NoteProperty -Name "前回保存者" -Value $Getfile.ExtendedProperty('System.Document.LastAuthor')
            $output | Add-Member -MemberType NoteProperty -Name "コンテンツの作成日時" -Value $Getfile.ExtendedProperty('System.Document.DateCreated')
            $output | Add-Member -MemberType NoteProperty -Name "前回保存日時" -Value $Getfile.ExtendedProperty('System.Document.DateSaved')
            $output | Add-Member -MemberType NoteProperty -Name "前回印刷日" -Value $Getfile.ExtendedProperty('System.Document.DatePrinted')
            #$output | Add-Member -MemberType NoteProperty -Name "ファイル所有者" -Value $Getfile.ExtendedProperty('System.FileOwner')
            #$output | Add-Member -MemberType NoteProperty -Name "ファイル作成日時" -Value $Getfile.ExtendedProperty('System.DateCreated')
            #$output | Add-Member -MemberType NoteProperty -Name "ファイル更新日時" -Value $Getfile.ExtendedProperty('System.DateModified')
            #$output | Add-Member -MemberType NoteProperty -Name "ファイルアクセス日時" -Value $Getfile.ExtendedProperty('System.DateAccessed')

            $results+=$output
            $linecount++
            # CSV向け処理 end

            if(($linecount % 1000) -eq 0 ){
                $results | Export-Csv $outputfile -Encoding UTF8 -NoTypeInformation -Append -NoClobber
                $results = @()
            }
        }
    }
    # ディレクトリの検索 end

    $results | Export-Csv $outputfile -Encoding UTF8 -NoTypeInformation -Append -NoClobber
} else {
    Write-Host ("キャンセル") 
}


pause

VMware Flingsにあったソフトウェアがbroadcomになって移転した先

ESXi for ARM EditionやUSB Network Native Driver for ESXi といった以前VMware Flings http://flings.vmware.com にあったソフトウェアは、2023年10月に https://developer.vmware.com/samples にリダイレクトされるようになった。

このURLは、 https://developer.broadcom.com/samples にリダイレクトされるのだが、2025年4月2日時点では、errorとなっている。

では、以前VMware Flings にあったものがどこにあるのかというと Broadcom communityの「Welcome to the new home for Flings!」にあった

2024年8月に更新されたvSphere GPU Monitoring を最後に更新はないように見えたけど、

よくみてみたら「Nested ESXi Virtual Appliance」は ESXi 8.0 Update 3c VAが出てた

PowerShellを使ってドロップしたフォルダ内にあるファイル一覧をテキストファイルに保存する

指定したフォルダ内にあるファイルリストを作りたい、という相談を受けた

引数で渡す処理にしてもよかったんだが、簡単に使えるようにするには、ドラック&ドロップ処理でリストが取れるようにした方がいいだろうな、ということで実装した。

また、作成したファイルリストは保存先とファイル名を容易に指定できるようにダイアログを出すようにした。参考にしたのは プログラム★ノートの「PowerShell ファイル保存ダイアログを使用する方法

保存先は基本的にマイドキュメント以下として、ファイル名はドロップしたフォルダ名を使うようにした。

また、作成したPowerShellファイル(ps1)ファイルに直接ドロップしてもうまくいかないので、ショートカットを作成して、リンク先を修正して使用するようにしている。

なお、今回は使用している内容の都合上、Windows OS上でのみ動作することになってるはず。

# ドラッグされたフォルダの中にあるファイル一覧をつくるやつ
#
# 使い方
#  1. このファイルを保存する
#  2. このファイルのショートカットを作成する
#  3. ショートカットのプロパティを開き"リンク先"の項目の先頭に「powershell.exe -NoProfile -ExecutionPolicy RemoteSigned -File 」をつけて保存
#  4. 作成されたショートカットの上に、フォルダをドロップすると、ウィンドウが開いて確認される
#  5. 作成するファイルリストの保存ファイル名を指定する
#  6. 出力される
#
$Args | foreach{
    echo $_.GetType()
    $searchdir = Get-Item -LiteralPath $_
}

Write-Host $searchdir.FullName "のファイル一覧を作成します"
pause

# https://pg-note.com/archives/1144 より
# 必要なアセンブリを読み込む
Add-Type -AssemblyName System.Windows.Forms 
$dialog = New-Object Windows.Forms.SaveFileDialog 

$dialog.Title = "ファイルの保存" 
$dialog.Filter = "テキストファイル(*.txt)|*.txt|csvファイル(*.csv)|*.csv|全てのファイル|*.*" 
$dialog.InitialDirectory = [Environment]::GetFolderPath("MyDocuments")
$dialog.FileName = $searchdir.Name

$ret = $dialog.ShowDialog() 

if ($ret -eq "OK"){
    Write-Host ("保存するファイル名、" + $dialog.FileName) 

    # ディレクトリの検索 start
    Get-ChildItem -Recurse $searchdir | ForEach-Object {
    $filename=$_.FullName
    
        if( !$_.PSIsContainer ){
            Write-Host $filename
            $filename|Out-File -FilePath $dialog.FileName -Append
        }
    }
    # ディレクトリの検索 end
} else {
    Write-Host ("キャンセル") 
}

pause

指定したディレクトリ内にあるexcelファイルに特定の文字列を含むセルがあるかを検索するPowershellスクリプト

たくさんあるexcelファイルのどれに必要な情報が含まれているのかわからないときに、WindowsのPowerShellとExcelアプリを連携させて各セルの中身を検索するスクリプトを作成した。

単純な処理にした場合、excelが保護されている(パスワードあり)ものがあると、スクリプト上でそのexcelファイルを開こうとしたところで、パスワード入力が出てそこで止まってしまう。

そのため、保護されているexcelファイルを効率よく除外する手法はないものか、というのを探したのだが、どうやらPowerShell/Excel連携の機能には、該当するファイルに保護がかかっているかどうかを判定する機能はない模様。

stackoverflowの「Powershell Test for Excel Password Protection」にて解決方法を発見

保護されているexcelファイルというのは、暗号化されたzipファイルで、ヘッダが特定文字列で始まるので、その文字列があれば暗号化されている、と判断して処理を飛ばす、ということが書かれていた。

$sig = [Byte[]] (0x50,0x4b,0x03,0x04)
$bytes = get-content $_.fullname -encoding byte -total 4
if (@(compare-object $sig $bytes -sync 0).length -eq 0) {
  # process unencrypted file
}

これを搭載することで、パスワード入力要求を飛ばすことができた。

で、検索した結果をCSVファイルに保存する処理を付けたものがこちら

CSV出力周りの処理がめんどくさくなってるの「PowerShellで巨大なファイルをGet-Contentし、Export-Csvするのを省メモリで行う」によるもの。これをやらないと速度がだいぶ変わるはず

$excel= New-Object -ComObject Excel.Application
$excel.visible= $false

# 検索対象ディレクトリ
$directory="C:\Users\osakanataro\Documents"

# 検索結果のcsv保存先
$outputfile="c:\tmp\output-tmp.csv"

# 検索キーワード
$keywords="ワード1","ワード2","ワード3"


# CSV出力向けの処理
$results=@()
$linecount=0
#


Get-ChildItem -Recurse $directory -Include *.xlsx,*.xls | ForEach-Object {
    $filename=$_.FullName
    Write-Host "file:", $filename

    # 暗号化チェック簡易版用
    $sig=[Byte[]] (0x50,0x4b,0x03,0x04)
    $bytes= Get-Content -Path $filename -Encoding Byte -TotalCount 4
    if( @(Compare-Object $sig $bytes -Sync 0).Length -eq 0){
        # 暗号化されていないファイルの処理 start
        $workbook=$excel.workbooks.open($filename)
        #Write-Host "ファイル:",$workbook.Name

        $workbook.Sheets|ForEach-Object {
            $worksheet = $_
            #write-host "タブ:", $worksheet.name

            $keywords | ForEach-Object {
                $keyword=$_
                $result1=$worksheet.Cells.Find($keyword)
                while($result1 -ne $null){
                    Write-Host "タブ:",$worksheet.Name," 単語:",$keyword," 場所:",$result1.Column, $result1.row, $result1.text
                    # CSV向け処理 start
                    $output = New-Object -TypeName PSObject
                    $output | Add-Member -MemberType NoteProperty -Name "ファイル名" -Value $filename
                    $output | Add-Member -MemberType NoteProperty -Name "タブ" -Value $worksheet.Name
                    $output | Add-Member -MemberType NoteProperty -Name "単語" -Value $keyword
                    $output | Add-Member -MemberType NoteProperty -Name "Column" -Value $result1.Column
                    $output | Add-Member -MemberType NoteProperty -Name "Row" -Value $result1.row
                    $output | Add-Member -MemberType NoteProperty -Name "文面" -Value $result1.text
                    $results+=$output
                    $linecount++
                    # CSV向け処理 end
                    $result2=$result1
                    $result1=$worksheet.Cells.FindNext($result2)
                    if( $result1.row -le $result2.row ) { $result1=$null }
                }
            }
        }
        # 暗号化されていないファイルの処理 end
    }else{
        # 暗号化されているファイルの処理 start
        Write-Host "   暗号化されている"
        $output = New-Object -TypeName PSObject
        $output | Add-Member -MemberType NoteProperty -Name "ファイル名" -Value $filename
        $output | Add-Member -MemberType NoteProperty -Name "タブ" -Value "パスワード保護につき確認できず"
        $output | Add-Member -MemberType NoteProperty -Name "単語" -Value ""
        $output | Add-Member -MemberType NoteProperty -Name "Column" -Value ""
        $output | Add-Member -MemberType NoteProperty -Name "Row" -Value ""
        $output | Add-Member -MemberType NoteProperty -Name "文面" -Value ""
        $results+=$output
        $linecount++

        # 暗号化されているファイルの処理 end
    }
    if(($linecount % 1000) -eq 0 ){
        $results | Export-Csv $outputfile -Encoding UTF8 -NoTypeInformation -Append -NoClobber
        $results = @()
    }

}

$results | Export-Csv $outputfile -Encoding UTF8 -NoTypeInformation -Append -NoClobber