Hey there ,
Introduction
i don't have many Experience with Powershell but want to learn it cause it is a great tool to get many Informations about VMs with the PowerCLI.
ToDo:
I want to create a PowerCLI-Code which gives me pretty much all the Information about a virtual machine Hardware
vCPUs
vRAM
NIC with MAC-Address and NIC-type
Disks with their DatastorePath and SCSI IDs
SCSI Controller with their IDs
Whats going on in my mind
I Have my VM "OL-LAB-DC-01"
where i can see from the vSphere Client the following Information:
1 vCPU,
2GB RAM
80GB ThinProvisioned Disk with the Datadsore Path on SCSI-Controller 0 and SCSI ID 0:0
SCSI-Controller 0 = LSI Logic SAS
NIC 3 is a VMXNET 3 NIC with Portgroup VM Network and the MAC-Adress XYZ
Thats the easy way but nobody would like to get this for each virtual Machine and thats why i need PowerCLI
First Steps
So far i can get mostly everything with one specific command:
vCPUs: Get-VM OL-LAB-DC-01
vRAM: Get-VM OL-LAB-DC-01
NICs: Get-VM OL-LAB-DC-01 | Get-NetworkAdapter
Get-VM OL-LAB-DC-01 | Get-Harddisk
Get-VM OL-LAB-DC-01 | Get-ScsiController
Questions
Apart from CPU, Memory and the NICs there is Information which i'm missing
How can i know that the vmdk is ThinProvisioned? I only get the output: Capacyity Persistence Filename?
How can i get the used SCSI IDs for the vmdks? And see on which SCSI ID (0) the SCSI-Controller is?
I Know that i can actually somehow use -ExpandProperty and select Propertys which aren't shown with the normal command (I used that from a code-snipplet to get VMs with their Appropriate Tag)- where do i find all those selectable Propertys?
The Second Question which i have is: found it @{N='NAME';E={(Get-whatiwant $_).Object}}
How can i get a one-liner out of that so that in the End it prints me out a Table where i have everything next to each other? Just Piping it trough will end in giving me errors because the pipe will refer to the command used before piping...
Thx for reading!
It's not like i wanna be a freeloader and get the Code-Snipplet because i'm lazy Rather than that I would like to try it myself but i need answers for my Questions
Best regards!
:Edit:
So far i have this massive one-liner which will get definitely longer...:
Get-VM ol-lab-dc-01 | Select-Object Name,NumCPU,MemoryGB,@{N='NIC-Name';E={(Get-NetworkAdapter $_).Name}},@{N='Portgruppe';E={(Get-NetworkAdapter $_).NetworkName}},@{N='Type';E={(Get-NetworkAdapter $_).Type}},@{N='MAC-Adresse';E={(Get-NetworkAdapter $_).MacAddress}},@{N='vmdk';E={(Get-HardDisk $_).DiskType}}
It's a matter of doing a number of nested ForEach loops.
$vmNames = 'mars','venus','jupiter'
$report = foreach($vm in (Get-View -ViewType VirtualMachine -Filter @{'Name' = "$($vmNames -join '|')"})){
foreach($ctrl in ($vm.Config.Hardware.Device | where{$_ -is [VMware.Vim.VirtualScsiController]})){
foreach($disk in ($vm.Config.Hardware.Device | where{$_ -is [VMware.Vim.VirtualDisk] -and $_.ControllerKey -eq $ctrl.Key})){
$obj = [ordered]@{
SCSIController = $ctrl.DeviceInfo.Label
DiskName = $disk.DeviceInfo.Label
SCSI_Id = "$($ctrl.BusNumber) : $($disk.UnitNumber)"
DiskFile = $disk.Backing.FileName
DiskSize = $disk.CapacityInKB * 1KB / 1GB
VName = $vm.Config.Name
VCPU = $vm.Config.Hardware.NumCPU
VMemory = $vm.Config.Hardware.MemoryMB
VNIC = $vm.config.hardware.Device.DeviceInfo | where {$_.Label -match "Network "} | select -ExpandProperty Label
VMAC = $vm.Config.Hardware.Device.MACAddress
VPG = $vm.Config.Hardware.Device.DeviceInfo | where {$_.Label -match "Network"} | select -Expandproperty Summary
}
New-Object PSObject -Property $obj
}
}
}
$report | Export-Csv report.csv -NoTypeInformation -UseCulture
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
I would start with something like this using get-view (not get-vm)
$vm = get-view -ViewType VirtualMachine -filter @{"Name"="VM"}
Then you can start playing with the related items
$vm.config
$vm.config.hardware
Here is a great getting started article : Get-View Part 1: Introduction to Get-View - VMware PowerCLI Blog - VMware Blogs
If you want to combine objects returned by multiple cmdlets in a one-liner, you will need to use a pipeline variable and calculated properties.
Something like this for example:
Get-VM -PipelineVariable vm |
Get-NetworkAdapter |
select @{N='VM';E={$vm.Name}},
@{N='NumCPU';E={$vm.NumCPU}},
@{N='MemoryGB';E={$vm.MemoryGB}},
Name,Type,NetworkName,MacAddress
The Select will work on the object returned by the Get-NetworkAdapter cmdlet, and via the $vm pipelinevariable you will also have access to the object returned by Get-VM.
The properties from that last object are retrieved through what is called calculated properties.
Update: I would not advise you to use Get-View when you are still in the beginners phase.
That cmdlet returns another type of object, and is more for an intermediate or advanced phase.
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Thx for your answer!
The Example of how to join different cmdlets really helped me out!
But i can't find anything to get the SCSI IDs of the Controller and the Disks +
And many different Scripts which i found won't give me any results:
VMware PowerCLI script to get VM’s virtual and RDM disk information | vStrong.info
https://github.com/CoteRL/VMware-PowerCLI/blob/master/Get-VMDisk.ps1
I tried to lookup the code but i can't even find "DeviceInfo.label" in the Get View .Config.Hardware.Device View...
But i think i found the virutal disk itself with the Get-View command:
$vm.Config.Hardware.Device (Get-View is stored in $vm)
CapacityInKB : 20971520
CapacityInBytes : 21474836480
Shares : VMware.Vim.SharesInfo
StorageIOAllocation : VMware.Vim.StorageIOAllocationInfo
DiskObjectId : 60-2000
VFlashCacheConfigInfo :
Iofilter :
VDiskId :
Key : 2000
DeviceInfo : VMware.Vim.Description
Backing : VMware.Vim.VirtualDiskFlatVer2BackingInfo
Connectable :
SlotInfo :
ControllerKey : 1000
UnitNumber : 0
But i only assume this since there is atleast a capacity shown there. but the other Information seem to me to be useless? Like what does the Controller Key mean and is the UnitNumber my SCSI-ID for the Disk itself?
Regards!
I didn't include any disk info, since I'm not sure how you would incorporate VM, NIC and vDisk information on the same line.
Think of multiple NICs and/or multiple vDisks for a VM.
This would produce a rather large amount of lines, but including properties that have no relation to each other.
VM,NIC1,Disk1
VM,NIC1,Disk2
...
One option is to first calculate the maximum NICs and vDisks are present for the VMs.
Then generate that number of columns for each row, but leave the columns blank is needed.
For example:
VM,NIC1,NIC2,NIC,Disk1,Disk2,Disk3,Disk4
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
well so far and with some help of other code-snipplets i have this code running
#$VISSERVER = Read-Host -Prompt 'Input your vCenter Server Name or IP-Adress'
#Connect-VIServer $VISERVER
#$Vm = Read-Host "Enter VMName"
$Vm = 'mars'
#Create the array for all the Information
$DiskInfo= @()
#Create the $vmview Variable for easy use while referring to the $VM-Variable (Get Infos from 1 Virtual Machine)
$VmView = Get-View -ViewType VirtualMachine -Filter @{"Name" = $VM}
#Create the $vmview Variable for all Virtual Machines in the vCenter
#VmView = Get-View -ViewType Virtualmachine
#Do a Loop and give me all those Informations
foreach ($VirtualSCSIController in ($VMView.Config.Hardware.Device | where {$_.DeviceInfo.Label -match "SCSI Controller"})) {
foreach ($VirtualDiskDevice in ($VMView.Config.Hardware.Device | where {$_.ControllerKey -eq $VirtualSCSIController.Key})) {
$VirtualDisk = "" | Select SCSIController, DiskName, SCSI_Id, DiskFile, DiskSize,VName,VCPU,VMemory,VNIC,VMAC,VPG
$VirtualDisk.SCSIController = $VirtualSCSIController.DeviceInfo.Label
$VirtualDisk.DiskName = $VirtualDiskDevice.DeviceInfo.Label
$VirtualDisk.SCSI_Id = "$($VirtualSCSIController.BusNumber) : $($VirtualDiskDevice.UnitNumber)"
$VirtualDisk.DiskFile = $VirtualDiskDevice.Backing.FileName
$VirtualDisk.DiskSize = $VirtualDiskDevice.CapacityInKB * 1KB / 1GB
$VirtualDisk.VName = $VMview.Config.Name
$VirtualDisk.VCPU = $VMview.Config.Hardware.NumCPU
$VirtualDisk.VMemory = $VmView.Config.Hardware.MemoryMB
$VirtualDisk.VNIC = $VMview.config.hardware.Device.DeviceInfo | where {$_.Label -match "Network "} | select -ExpandProperty Label
$VirtualDisk.VMAC = $VMview.Config.Hardware.Device.MACAddress
$VirtualDisk.VPG = $VMView.Config.Hardware.Device.DeviceInfo | where {$_.Label -match "Network"} | select -Expandproperty Summary
$DiskInfo += $VirtualDisk
}
}
#Export the Results of the array
$DiskInfo | export-csv -Path C:\Users\ol\Documents\_stuff\test.csv
This works fine when i just want the Information for 1 Virtual Machine - of course when a VM has more than 1 NIC it doesn't look that nice but thats not the big problem... (see Diskinfo-singlevm.png)
When i use "vmview = Get-View -viewType Virtualmachine" the Rows gets filled with too much information (check Diskinfo-allvms.png)
I tried to seperate both information into 2 Arrays but i couldn't put them together
So far i can only think of two ways:
1. Create a new Array just for the VM-Names and create a big loop where $VM is getting the new VM-Name out of the Array then get all Informations and after that export it into a single csv-file or append it to a existing csv-file and start with the next VM in the "Name-Array" untill the whole loop is finished
2. Get the script working without calling a single VM out...
I think the first way is in my range of knowledge (as long as i can merge export-csv into a single file together)
Are there better ways which i totally oversee?
regards
It's a matter of doing a number of nested ForEach loops.
$vmNames = 'mars','venus','jupiter'
$report = foreach($vm in (Get-View -ViewType VirtualMachine -Filter @{'Name' = "$($vmNames -join '|')"})){
foreach($ctrl in ($vm.Config.Hardware.Device | where{$_ -is [VMware.Vim.VirtualScsiController]})){
foreach($disk in ($vm.Config.Hardware.Device | where{$_ -is [VMware.Vim.VirtualDisk] -and $_.ControllerKey -eq $ctrl.Key})){
$obj = [ordered]@{
SCSIController = $ctrl.DeviceInfo.Label
DiskName = $disk.DeviceInfo.Label
SCSI_Id = "$($ctrl.BusNumber) : $($disk.UnitNumber)"
DiskFile = $disk.Backing.FileName
DiskSize = $disk.CapacityInKB * 1KB / 1GB
VName = $vm.Config.Name
VCPU = $vm.Config.Hardware.NumCPU
VMemory = $vm.Config.Hardware.MemoryMB
VNIC = $vm.config.hardware.Device.DeviceInfo | where {$_.Label -match "Network "} | select -ExpandProperty Label
VMAC = $vm.Config.Hardware.Device.MACAddress
VPG = $vm.Config.Hardware.Device.DeviceInfo | where {$_.Label -match "Network"} | select -Expandproperty Summary
}
New-Object PSObject -Property $obj
}
}
}
$report | Export-Csv report.csv -NoTypeInformation -UseCulture
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Thx! that really helped me a lot!
And if you don't wanna hardcode the VM-names you can use the following 3-liner as a little help
Get-VM | select -Expandproperty Name | out-file C:\Users\ol\Documents\_stuff\input.txt
$Lines = Get-Content C:\Users\ol\Documents\_stuff\input.txt
$vmNames = $lines
maybe this can be shortened into a one-liner - but this worked for me
But ofcourse a new problem appears...
I do know that some VMs have multiple NICs and stuff which is ok. WHen i use $Report | out-gridview i could live with how it is shown. But unfortunately something goes wrong when i export the $report to a csv because the lines with Multiple Entris (vNIC, MAC, Portgroups) are getting replaced by System.Object[]
Just need to look this up and then i'm done
Yes, Export-Csv doesn't know how to fit the array (multiple values) into a single cell.
A quick and dirty fix for this is to transform the array into a single string.
That can be done with the -join operator
VNIC = ($vm.config.hardware.Device.DeviceInfo | where {$_.Label -match "Network "} | select -ExpandProperty Label) -join ','
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Thx LucD!
i tried the join but i made a mistake because i didn't knew where i had to place the () and googling showed me other
really helped me out and with all those information it helped myself understanding powershell and powercli really good!
Regards!