Hi guys,
We are performing migrations and as part of that we are filling out a checklist containing the properties of the VM prior to moving it. Critical information includes whether or not there is a snapshot, and the name and description of the snapshot. I would then like to export the information to CSV. Sounds simple, but I can't seem to figure out how to get-snapshot as part of a single get command, this is as far as I've gotten:
$Migrationvm1 = Read-Host "Enter the name of the VM you intend to migrate"
$credential = get-credential
$COMVC = "aplvmw015"
$CARVC = "aplvmw016"
Connect-VIServer $COMVC -Credential $credential
Connect-VIServer $CARVC -Credential $credential
get-vm $Migrationvm1 | get-snapshot | Select VM,Description,Created | export-csv c:\output\$Migrationvm1.csv -NoTypeInformation -Append
get-vm $Migrationvm1 | select Notes,NumCpu,MemoryGB | export-csv c:\output\$Migrationvm1.csv -NoTypeInformation -Append
I get an error and the second command doesn't append any information to the csv. Can this be simplified to a single get-vm command which gets the info I need plus the snapshot info?
The Snapshot object contains a VM property, under which you will find the complete VirtualMachine object.
You could do
Get-Snapshot |
Select @{N='VM';E={$_.VM.Name},
@{N='Notes';E={$_.VM.Notes}},
@{N='NumCpu';E={$_.VM.NumCpu}},
@{N='MemoryGB';E={$_.VM.MemoryGB}},
Name,Description,Created |
Export-Csv -Path c:\output\$Migrationvm1.csv -NoTypeInformation -UseCulture
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
The Snapshot object contains a VM property, under which you will find the complete VirtualMachine object.
You could do
Get-Snapshot |
Select @{N='VM';E={$_.VM.Name},
@{N='Notes';E={$_.VM.Notes}},
@{N='NumCpu';E={$_.VM.NumCpu}},
@{N='MemoryGB';E={$_.VM.MemoryGB}},
Name,Description,Created |
Export-Csv -Path c:\output\$Migrationvm1.csv -NoTypeInformation -UseCulture
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
You're a rockstar LucD.
One thing I can't figure out, I would like the output in format-list, however if I use format-list the export-csv exports gibberish. Is there a way to format the data in list rather than horizontally?
Not with Export-Csv I'm afraid.
But you could send it to a regular .txt file
Get-Snapshot |
Format-List -Property @{N='VM';E={$_.VM.Name},
@{N='Notes';E={$_.VM.Notes}},
@{N='NumCpu';E={$_.VM.NumCpu}},
@{N='MemoryGB';E={$_.VM.MemoryGB}},
Name,Description,Created |
Out-String |
Set-Content -Path .\report.txt
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
That worked, however I need to add two fields, IP address and datastore, unfortunately both are coming up blank, any ideas?
$Migrationvm1 = Read-Host "Enter the name of the VM you intend to migrate"
$credential = get-credential
$COMVC = "aplvmw015"
$CARVC = "aplvmw016"
Get-VM -Name $Migrationvm1 |
Get-Snapshot |
Format-List -Property @{N='VM';E={$_.VM.Name}},
@{N='Notes';E={$_.VM.Notes}},
@{N='NumCpu';E={$_.VM.NumCpu}},
@{N='MemoryGB';E={$_.VM.MemoryGB}},
@{N='Folder';E={$_.VM.Folder}},
@{N="IP Address";E={@($_.guest.IPAddress[0])}},
@{N="Datastore";E={[string]::Join(',',(Get-Datastore -Id $_.DatastoreIdList | Select -ExpandProperty Name))}},
Name,Description,Created |
Out-String |
Set-Content -Path c:\output\$Migrationvm1.txt
These are also under the VM property.
$credential = get-credential
$COMVC = "aplvmw015"
$CARVC = "aplvmw016"
Get-VM -Name $Migrationvm1 |
Get-Snapshot |
Format-List -Property @{N='VM';E={$_.VM.Name}},
@{N='Notes';E={$_.VM.Notes}},
@{N='NumCpu';E={$_.VM.NumCpu}},
@{N='MemoryGB';E={$_.VM.MemoryGB}},
@{N='Folder';E={$_.VM.Folder}},
@{N="IP Address";E={@($_.VM.guest.IPAddress[0])}},
@{N="Datastore";E={[string]::Join(',',(Get-Datastore -Id $_.VM.DatastoreIdList | Select -ExpandProperty Name))}},
Name,Description,Created |
Out-String |
Set-Content -Path c:\output\$Migrationvm1.txt
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Well I came in this morning and everything had stopped working, was utterly baffled as to way. Then it came to me, this script is ongoing to work if the VM has a snapshot. Once I'd deleted the snapshot I had taken for testing purposes everything started coming up blank. Do I need to add an IF statement in cases where there is no snapshot?
Not really, if a VM has no snapshot, the Select cmdlet shouldn't be getting any input.
If all your VMs have no snapshots, you will see an empty file of course.
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Can I add a simple message to the script such as this?
$mig1 = Read-Host "Enter the name of the VM you intend to migrate"
$credential = get-credential
$COMVC = "aplvmw015"
$CARVC = "aplvmw016"
$snapcheck = (Get-VM -Name $Migrationvm1 | Get-Snapshot)
if ($snapcheck = $null) {
write-output "NO snapshot"
}else {
write-output "Snapshot detected"
}
You can, but I would avoid having to do the Get-VM and Get-Snapshot twice.
You could do something like this
$credential = get-credential
$COMVC = "aplvmw015"
$CARVC = "aplvmw016"
$snaps = Get-VM -Name $Migrationvm1 | Get-Snapshot
if ($snaps) {
write-output "Snapshot detected"
$snaps | Format-List -Property @{N = 'VM'; E = { $_.VM.Name } },
@{N = 'Notes'; E = { $_.VM.Notes } },
@{N = 'NumCpu'; E = { $_.VM.NumCpu } },
@{N = 'MemoryGB'; E = { $_.VM.MemoryGB } },
@{N = 'Folder'; E = { $_.VM.Folder } },
@{N = "IP Address"; E = { @($_.VM.guest.IPAddress[0]) } },
@{N = "Datastore"; E = { [string]::Join(',', (Get-Datastore -Id $_.VM.DatastoreIdList | Select -ExpandProperty Name)) } },
Name, Description, Created |
Out-String |
Set-Content -Path c:\output\$Migrationvm1.txt
}
else {
write-output "NO snapshot"
}
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Thanks LucD! I ended up going a slightly different route. I added a check to see if there's a snapshot, if there is one the script simply tells the user to delete it before continuing. I couldn't think of a way to have the script write the output to the file and also type the output on the screen so I'm just running the commands twice. How hard would it be to change the script so that I can pull multiple VMs from the spreadsheet rather that enter a VM name each time? Here is my script:
$Migrationvm1 = Read-Host "Enter the name of the VM you intend to migrate"
$credential = get-credential
$COMVC = "aplvmw015"
$CARVC = "aplvmw016"
Connect-VIServer $COMVC -credential $credential
Connect-VIServer $CARVC -credential $credential
$snaps = Get-VM -Name $Migrationvm1 | Get-Snapshot
$Migvm1 = Get-VM -Name $Migrationvm1
if ($snaps) {
write-output "Snapshot Detected. Delete Snaphosts before continuing."
$snaps | Format-List -Property @{N = 'VM'; E = { $_.VM.Name } },
Name, Description, Created
}
else {
write-output "NO snapshot"
$Migvm1 | Format-List -Property @{N = 'VM'; E = { $_.Name } },
@{N='VMhost';E={$_.VMhost}},
@{N='Notes';E={$_.Notes}},
@{N='NumCpu';E={$_.NumCpu}},
@{N='MemoryGB';E={$_.MemoryGB}},
@{N='Folder';E={$_.Folder}},
@{N="IP Address";E={@($_.guest.IPAddress[0])}},
@{N="Datastore";E={[string]::Join(',',(Get-Datastore -Id $_.DatastoreIdList | Select -ExpandProperty Name))}} |
Out-String |
Set-Content -Path c:\output\$Migrationvm1.txt
$Migvm1 | Format-List -Property @{N = 'VM'; E = { $_.Name } },
@{N='VMhost';E={$_.VMhost}},
@{N='Notes';E={$_.Notes}},
@{N='NumCpu';E={$_.NumCpu}},
@{N='MemoryGB';E={$_.MemoryGB}},
@{N='Folder';E={$_.Folder}},
@{N="IP Address";E={@($_.guest.IPAddress[0])}},
@{N="Datastore";E={[string]::Join(',',(Get-Datastore -Id $_.DatastoreIdList | Select -ExpandProperty Name))}}
}
Also, how do you upload you code so that it's properly formatted? Mine keeps coming up at as text. Sorry, I'm really rusty with PowerCLI!
If you use the Visual Studio Code editor, you can copy/paste in HTML format from the editor directly into the VMTN thread editor.
You can use a CSV file to provide a list of VM names.
The Tee-Object cmdlet allows you to write to a file and send the received objects along on the pipeline.
Something like this
# CSV layout
#
# Name
# vm1
# vm2
$Migrationvms = Import-Csv -Path .\vmnames.csv -UseCulture | Select -ExpandProperty Name
$credential = Get-Credential
$COMVC = "aplvmw015"
$CARVC = "aplvmw016"
Connect-VIServer $COMVC -credential $credential
Connect-VIServer $CARVC -credential $credential
$Migvms = Get-VM -Name $Migrationvms
$snaps = Get-Snapshot -VM $Migvms
if ($snaps) {
write-output "Snapshot Detected. Delete Snaphosts before continuing."
$snaps | Format-List -Property @{N = 'VM'; E = { $_.VM.Name } },
Name, Description, Created
}
else {
write-output "NO snapshot"
$Migvms | Format-List -Property @{N = 'VM'; E = { $_.Name } },
@{N = 'VMhost'; E = { $_.VMhost } },
@{N = 'Notes'; E = { $_.Notes } },
@{N = 'NumCpu'; E = { $_.NumCpu } },
@{N = 'MemoryGB'; E = { $_.MemoryGB } },
@{N = 'Folder'; E = { $_.Folder } },
@{N = "IP Address"; E = { @($_.guest.IPAddress[0]) } },
@{N = "Datastore"; E = { [string]::Join(',', (Get-Datastore -Id $_.DatastoreIdList | Select -ExpandProperty Name)) } } |
Out-String | Tee-Object -FilePath c:\output\$Migrationvm1.txt
}
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Hi LucD,
Won't I run into a problem where if a snapshot exists the whole script will stop and say check snapshots before continuing? Do I need a foreach loop instead? I've tried below and it works, but only repeats the first VM in the CSV file repeatedly:
$credential = get-credential
$COMVC = "aplvmw015"
$CARVC = "aplvmw016"
Connect-VIServer $COMVC -credential $credential
Connect-VIServer $CARVC -credential $credential
$Migrationvms = Import-Csv -Path .\Vms4migration.csv -UseCulture | Select -ExpandProperty VMName
$snaps = Get-VM -Name $Migrationvms | Get-Snapshot
$Migvm1 = Get-VM -Name $Migrationvms
Foreach ($VMname in $Migrationvms) {
if ($snaps) {
write-output "Snapshot Detected. Delete Snaphosts before continuing."
$snaps | Format-List -Property @{N = 'VM'; E = { $_.VM.Name } },
Name, Description, Created
}
else {
write-output "NO snapshot"
$Migvm1 | Format-List -Property @{N = 'VM'; E = { $_.Name } },
@{N='VMhost';E={$_.VMhost}},
@{N='Notes';E={$_.Notes}},
@{N='NumCpu';E={$_.NumCpu}},
@{N='MemoryGB';E={$_.MemoryGB}},
@{N='Folder';E={$_.Folder}},
@{N="IP Address";E={@($_.guest.IPAddress[0])}},
@{N="Datastore";E={[string]::Join(',',(Get-Datastore -Id $_.DatastoreIdList | Select -ExpandProperty Name))}} |
Out-String |
Set-Content -Path c:\output\$Migrationvms.txt
$Migvm1 | Format-List -Property @{N = 'VM'; E = { $_.Name } },
@{N='VMhost';E={$_.VMhost}},
@{N='Notes';E={$_.Notes}},
@{N='NumCpu';E={$_.NumCpu}},
@{N='MemoryGB';E={$_.MemoryGB}},
@{N='Folder';E={$_.Folder}},
@{N="IP Address";E={@($_.guest.IPAddress[0])}},
@{N="Datastore";E={[string]::Join(',',(Get-Datastore -Id $_.DatastoreIdList | Select -ExpandProperty Name))}}
}
}
Type, I forgot to change $Migvm1 to $Migvms in the else block.
I corrected the code above, try again.
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Hi LucD,
The first VM in my .csv file has a snapshot. The code is working, but it's only giving the output for that single VM as follows. It's not providing any output for any of the other VMs in the CSV file.
PowerCLI C:\PowerCLI> .\PreMigCheck.ps1
cmdlet Get-Credential at command pipeline position 1
Supply values for the following parameters:
Credential
Name Port User
---- ---- ----
aplvmw015 443 **********
aplvmw016 443 ***********
Snapshot Detected. Delete Snaphosts before continuing.
VM : TestVM1
Name : TEST
Description : Testing migration script, please delete
Created : 10/21/2019 2:58:50 PM
That is correct.
The script only writes all the VMs that have a snapshot.
To get also the report with VMs that have no snapshots, you could do.
Note that this will create 1 file per VM that has no snapshots.
Is that what you intended?
$credential = Get-Credential
$COMVC = "aplvmw015"
$CARVC = "aplvmw016"
Connect-VIServer $COMVC -credential $credential
Connect-VIServer $CARVC -credential $credential
Get-VM -Name $Migrationvms |
ForEach-Object -Process {
$snaps = Get-Snapshot -VM $_
if($snaps){
write-output "Snapshot(s) detected on $($_.VM.Name). Delete Snaphosts before continuing."
$snaps | Format-List -Property @{N = 'VM'; E = { $_.VM.Name } },
Name, Description, Created
}
else{
write-output "NO snapshot on $($_.Name)"
$_ | Format-List -Property @{N = 'VM'; E = { $_.Name } },
@{N = 'VMhost'; E = { $_.VMhost } },
@{N = 'Notes'; E = { $_.Notes } },
@{N = 'NumCpu'; E = { $_.NumCpu } },
@{N = 'MemoryGB'; E = { $_.MemoryGB } },
@{N = 'Folder'; E = { $_.Folder } },
@{N = "IP Address"; E = { @($_.guest.IPAddress[0]) } },
@{N = "Datastore"; E = { [string]::Join(',', (Get-Datastore -Id $_.DatastoreIdList | Select -ExpandProperty Name)) } } |
Out-String | Tee-Object -FilePath "c:\output\$($_.Name).txt"
}
}
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
This is exactly what I need, thanks for all your help!!!