Recently I needed to script some actions for a VM on Nutanix AHV.
I wanted to share with you some of the commands I found and used.
I created a small function (Wait-NTNXTask) that verifies the task and waits until the task is finished.
Pleas note that this is optional and not required to run the commands specified in this blog.
To start with Nutanix AHV and PowerShell you need to install the PowerShell Cmdlets. You can find the snap-ins when you click on your name and select “Download Cmdlets Installer”
Add the snap-ins to your script or session:
if ([string]::IsNullOrEmpty($(Get-PSSnapin -Name NutanixCmdletsPSSnapin -Registered -ErrorAction SilentlyContinue))) { if (Test-Path "C:\Program Files (x86)\Nutanix Inc\NutanixCmdlets\powershell\import_modules\ImportModules.PS1") { . "C:\Program Files (x86)\Nutanix Inc\NutanixCmdlets\powershell\import_modules\ImportModules.PS1" } else { Write-Error "Could not load NutanixCmdletsPSSnapin" } } else { if ([string]::IsNullOrEmpty($(Get-PSSnapin -Name NutanixCmdletsPSSnapin -ErrorAction SilentlyContinue))) { Add-PSSnapin NutanixCmdletsPSSnapin } }
If you want to view all the commands associated to “NutanixCmdletsPSSnapin” run the following command:
Get-Command -PSSnapin NutanixCmdletsPSSnapin | Group-Object Noun | Select-Object Count,Name,@{Name="Verb"; Expression = {$_.Group.Verb -join ","}} | Sort-Object Name
View the Cmdlet (version) information:
Get-NTNXCmdletsInfo
Before we can make changes we need to create a connection:
$hypervisorURI = "nutanixcluster.domain.local" $userName = "john" $password = ConvertTo-SecureString -String "SuperSecretP@ssw0rd" -AsPlainText -Force # Ensure previous Nutanix Sessions are disconnected Disconnect-NTNXCluster * #Connect a new Nutanix Session $connection = Connect-NutanixCluster -Server $hypervisorURI -UserName $username -Password $password -AcceptInvalidSSLCerts -ForcedConnection
NOTE: If you receive the following error “The remote server returned an error: (401) Unauthorized.” You will need to reconnect. May be that the connection has timed out.
Get the VM so we can use the ID’s:
$vm = Get-NTNXVM -SearchString $vmName
Create a new snapshot for a given VM:
$snapshotName = "SnapshotName" $newSnapshot = New-NTNXObject -Name SnapshotSpecDTO $newSnapshot.vmuuid = $vm.uuid $newSnapshot.snapshotname = $snapshotName $task = New-NTNXSnapshot -SnapshotSpecs $newSnapshot Wait-NTNXTask -taskUuid $task.taskUuid -silent
Retrieve all the available snapshots for a given VM:
$snapshots = Get-NTNXSnapshot | Where-Object {$_.vmUuid -eq $vm.uuid}
Get a particular snapshot for a given VM, if there are multiple snapshots with the same name all will be returned. In this example we will retrieve the last available snapshot:
$snapshotName = "SnapshotName" $snapshot = Get-NTNXSnapshot | Where-Object {($_.vmUuid -eq $vm.uuid) -and ($_.snapshotname -eq $snapshotName)} | Select-Object -Last 1
Revert back to a snapshot for a given VM:
$snapshotName = "SnapshotName" $snapshot = Get-NTNXSnapshot | Where-Object {($_.vmUuid -eq $vm.uuid) -and ($_.snapshotname -eq $snapshotName)} | Select-Object -First 1 $task = Restore-NTNXVirtualMachine -Vmid $vm.vmId -SnapshotUuid $snapshot.uuid Wait-NTNXTask -taskUuid $task.taskUuid -silent
Removing one or more snapshots for a given VM:
$snapshotName = "SnapshotName" $snapshots = Get-NTNXSnapshot | Where-Object {($_.vmUuid -eq $vm.uuid) -and ($_.snapshotname -eq $snapshotName)} Foreach ($snapshot in $snapshots){ Write-Verbose "Removing snapshot:$($snapshot | Select-Object snapshotName,uuid | Format-List | Out-String)" -Verbose $task = Remove-NTNXSnapshot -Uuid $snapshot.uuid Wait-NTNXTask -taskUuid $task.taskUuid -silent }
You can also add or remove disk to a given VM. Below is a working example how to remove disks and add them again with the same parameters:
$CurrentDisks = Get-NTNXVMDisk -Vmid $vm.vmId -IncludeDiskSizes | Where-Object {$_.isCdrom -eq $false} $CurrentDisks = $CurrentDisks | Sort-Object id If(-not [string]::IsNullOrEmpty($CurrentDisks)) { #Remove Disk(s) Foreach ($CurrentDisk in $CurrentDisks){ Write-Verbose "Removing disk: $($CurrentDisk.id) with size: $($CurrentDisk.vmDiskSize / 1GB)GB" -Verbose $task = Remove-NTNXVMDisk -Vmid $vm.vmId -Diskaddress $CurrentDisk.id Wait-NTNXTask -taskUuid $task.taskUuid -silent } #Add (new) disks with the same specification Foreach ($CurrentDisk in $CurrentDisks){ Write-Verbose "Creating disk specification. Disksize: $($CurrentDisk.vmDiskSize / 1GB)" -Verbose $diskSpecCreate = New-NTNXObject -Name VmDiskSpecCreateDTO $diskSpecCreate.containerid = $CurrentDisk.containerId $diskSpecCreate.size = $CurrentDisk.vmDiskSize Write-Verbose "Specification:$($diskSpecCreate | Select-Object containerId,size | Format-List | Out-String)" -Verbose $newVMDisk = New-NTNXObject –Name VMDiskDTO $newVMDisk.vmDiskCreate = $diskSpecCreate $task = Add-NTNXVMDisk -Vmid $vm.vmId -Disks $newVMDisk Wait-NTNXTask -taskUuid $task.taskUuid -silent } }
You can also manipulate the CD-ROM drive attached to your VM to mount or un-mount an ISO file.
First we need to retrieve the details for the CD-ROM drive attached to a given VM:
$isoDisk = Get-NTNXVMDisk -Vmid $vm.vmId | Where-Object {$_.isCdrom -eq $true}
It can be that you have multiple CD-ROM drives attached to a given VM. Make sure you have selected only one.
In the next example we will check if there are multiple drives, if so we’ll select the first one. (You can make your selection as you see fit)
$isoDisk = Get-NTNXVMDisk -Vmid $vm.vmId | Where-Object {$_.isCdrom -eq $true} | Select-Object -First 1
To check if a CD-ROM drive already contains an image or is empty:
$isoDisk.isEmpty
To list and get the names of all the available ISO files uploaded you can run the following command
Get-NTNXImage | Where-Object {$_.imageType -eq "ISO_IMAGE"} | Select-Object name
To mount an ISO to a (existing) CD-ROM drive.
#Specify the name of the ISO and retrieve the object $isoImageName = "Windows 10 Business Editions 1803 EN" $isoImage = (Get-NTNXImage | Where-Object {$_.name -eq $isoImageName}) #Create new objects with the required changes $diskSpecClone = New-NTNXObject -Name VMDiskSpecCloneDTO $diskSpecClone.vmDiskUuid = $isoImage.vmDiskId $diskUpdateSpec = New-NTNXObject -Name VMDiskUpdateSpecDTO $diskUpdateSpec.vmDiskClone = $diskSpecClone #Write the changes to the VM $task = Set-NTNXVMDisk -Vmid $vm.vmId -Diskaddress $isoDisk.id -UpdateSpec $diskUpdateSpec Wait-NTNXTask -taskUuid $task.taskUuid -silent
To un-mount an ISO attached the CD-ROM drive:
$diskUpdateSpec = New-NTNXObject -Name VMDiskUpdateSpecDTO $diskUpdateSpec.isEmpty = $true $task = Set-NTNXVMDisk -Vmid $vm.vmId -Diskaddress $isoDisk.id -UpdateSpec $diskUpdateSpec Wait-NTNXTask -taskUuid $task.taskUuid -silent
If you want NIC details, for example if you want to know the MAC Address of a given VM:
Get-NTNXVMNIC -Vmid $vm.vmId
And finally how to turn on or off a given VM.
Power on a given VM:
$task = Set-NTNXVMPowerOn -Vmid $vm.vmId Wait-NTNXTask -taskUuid $task.taskUuid -silent
Power off a given VM:
$task = Set-NTNXVMPowerOff -Vmid $vm.vmId Wait-NTNXTask -taskUuid $task.taskUuid -silent
Specifying the transition, for example to nicely shutdown a given VM:
$task = Set-NTNXVMPowerState -Vmid $vm.vmId -Transition ACPI_SHUTDOWN Wait-NTNXTask -taskUuid $task.taskUuid -silent
The following Transitions can be specified:
- ACPI_REBOOT
- ACPI_SHUTDOWN
- OFF
- ON
- PAUSE
- POWERCYCLE
- RESET
- RESUME
- SUSPEND
Recently Kees Baggerman informed me that Nutanix was working on some new PowerShell Cmdlets. Unfortunately I didn’t had the time to look at them.
Hope this will help you.
TY! This will probably save me a few hours of pull all of this stuff together and looks like most of the items I’ll need to create my automation scripts 😀
You’re welcome
Hi – All I’m trying to do is automate snapshots and I am just not getting it. I can connect to cluster fine, but when i run:
$snapshotName = “SnapNameHere”
$newSnapshot = New-NTNXObject -Name SERVERNAME-HERE
$newSnapshot.vmuuid = $vm.uuid
$newSnapshot.snapshotname = $snapshotName
$task = New-NTNXSnapshot -SnapshotSpecs $newSnapshot
I get errors like ‘vmuuid’ cannot be found on this object.
The Property ‘snapshotname’ cannot be found on this object.
snapshot spec must be specified.
I am sorry for not following any established guidelines for posting code, I could not find them.
Hi Deniece,
Looks like you forgot to retrieve the VM first. Can you try with the following code?
$vmName = "SERVERNAME-HERE"
$snapshotName = "SnapNameHere"
$vm = Get-NTNXVM -SearchString $vmName
$newSnapshot = New-NTNXObject -Name SnapshotSpecDTO
$newSnapshot.vmuuid = $vm.uuid
$newSnapshot.snapshotname = $snapshotName
$task = New-NTNXSnapshot -SnapshotSpecs $newSnapshot
Hi John-That worked awesome. New issue: I want to bring in a list of servers and loop through making snapshots. The following produces no errors until the last statement ($task = New-NTNX………)
My servers.csv looks like this:
svrname
dev-SERVERA
*****************
$vmName= Import-csv “C:\Scripts\NTNX\servers.csv”
ForEach ($svrname in $vmName){
$snapshotName = “$vmName-TESTSNAP01”
$vm = Get-NTNXVM -SearchString $vmName
$newSnapshot = New-NTNXObject -Name SnapshotSpecDTO
$newSnapshot.vmuuid = $vm.uuid
$newSnapshot.snapshotname = $snapshotName
$task = New-NTNXSnapshot -SnapshotSpecs $newSnapshot
}
*******************
error:
PS C:\Scripts\NTNX> $task = New-NTNXSnapshot -SnapshotSpecs $newSnapshot
New-NTNXSnapshot : The operation has timed out
At line:1 char:9
+ $task = New-NTNXSnapshot -SnapshotSpecs $newSnapshot
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (Nutanix.Prism.Common.NutanixCluster:NutanixCluster) [New-NTNXSnapshot],
WebException
+ FullyQualifiedErrorId : Error,Nutanix.Prism.PS.Cmds.Acropolis.NewSnapshot
**************************
I have no problem snapping one at a time, just when I import and do a foreach.
GOOD:
$vmName = “SERVERA”
$snapshotName = “$vmName-B4FebUpdts”
$vm = Get-NTNXVM -SearchString $vmName
$newSnapshot = New-NTNXObject -Name SnapshotSpecDTO
$newSnapshot.vmuuid = $vm.uuid
$newSnapshot.snapshotname = $snapshotName
$task = New-NTNXSnapshot -SnapshotSpecs $newSnapshot
********
Thank you so much for your help John. You are appreciated!
Hi Deniece,
Looks like there is something going wrong with reusing some variables. You are reusing $vmName. When importing a CSV the variable will get different content (most likely will be a PSCustomObject, not a String).
I’ve created an example, I did not have a Nutanix environment at hand currently. But I think the next code is ok.
CSV Example:
"ComputerName","SnapshotName"
"SERVERA","SnapshotA"
"SERVERB","SnapshotB"
"SERVERC","SnapshotC"
With the above CSV (I’ve added also a snapshot name) you could use the following code:
#Variable $machines will get all the content (array of PSCustomObject)
$machines = Get-Content -Path "c:\Path\To\Computernames.csv" | ConvertFrom-Csv
#Then you must loop though each one item, in every loop $machine will get the next item from $machines until the end
ForEach ($machine in $machines) {
#A Check to see if the computername is empty, if empty skip to the next entry
if ([String]::IsNullOrEmpty($($machine.ComputerName))) { Continue }
#Assign the name of the csv-entry to the variable $vmName, you could do it directly but for the clarification uses the same code as before
$vmName = $machine.ComputerName
#Assign the snapshot name, and verify if it is not null (empty)
$snapshotName = $machine.SnapshotName
if ([String]::IsNullOrEmpty($snapshotName)) {
#If the $snapshotName variable is empty, assign a "date" as name for the snapshot
$snapshotName = (Get-Date).ToString("yyyyMMdd-HHmmss")
}
$vm = Get-NTNXVM -SearchString $vmName
$newSnapshot = New-NTNXObject -Name SnapshotSpecDTO
$newSnapshot.vmuuid = $vm.uuid
$newSnapshot.snapshotname = $snapshotName
$task = New-NTNXSnapshot -SnapshotSpecs $newSnapshot
}