PowerCLI- get VM cd-mount in 1 table - powershell

I try to get all the vm which have a mounted cd in one table, but the output I get is a line-by line like:
vm1
\vm1_isopath\
vm2
\vm2_isopath\
can it possible to get all the information in 1 table with 2 columns, of VM name, and ISOPath ?
my code is:
$VMs=Get-VM
ForEach ( $vm in $VMs)
{
$VMmount=Get-CDDrive -VM $vm
if ($VMmount.IsoPath)
{
$vm | select Name
$VMmount.IsoPath
}
}
thank you.

I extended your code to:
$VMs=Get-VM
$vmInfos = #()
ForEach ( $vm in $VMs)
{
$VMmount=Get-CDDrive -VM $vm
if ($VMmount.IsoPath)
{
# Store needed info in hashtable
$info = #{}
$info.name = ($vm | select -ExpandProperty Name)
$info.IsoPath = $VMmount.IsoPath
# Convert hashtable to custom object
$object = New-Object –TypeName PSObject –Prop $info
# Add to array
$vmInfos += $object
}
}
# Dump collected infos
$vmInfos | format-table -autosize
Hope that helps

Related

Get VID PID from Device ID in Powershell

I am fairly new to PowerShell and I want for a USB key plugged, to retrieve some info. Right now my script is:
Get-WmiObject win32_diskdrive |
ForEach-Object{
$disk = $_
$_.GetRelated('Win32_PnPEntity')|
ForEach-Object{
$pnp = $_
$_.GetRelated('Win32_USBController') |
ForEach-Object{
$usb = $_
[pscustomobject]#{
SerialNumber = $disk.SerialNumber
Model = $disk.Model
Size = $disk.Size
if ($usb.DeviceID -match '.*VID_(?<vid>[0-9A-F]{4})&PID_(?<pid>[0-9A-F]{4}).*') {VID=$matches['vid']; PID=$matches['pid']}
}
}
}
}
The line beginning with
if ($usb.DeviceID -match '.*VID_(?<vid>[0-9A-F]{4})&PID_(?<pid>[0-9A-F]{4}).*') {VID=$matches['vid']; PID=$matches['pid']}
does not work. I want to translate deviceid (which I can get by doing USBDeviceID = $usb.DeviceID) ID in PID UID directly.
It throws the following error
Error with code “Missing = operator after key in hash literal" for the statement "if ($usb.DeviceID -match '.* ...
What am I missing ? many thanks for helping me .
Gerald
This is because the way you intend to add properties to the PsCustomObject is wrong.
Either do this:
$result = [PsCustomObject]#{
SerialNumber = $disk.SerialNumber
Model = $disk.Model
Size = $disk.Size
}
# add items to the object if the condition is true
if ($usb.DeviceID -match '.*VID_(?<vid>[0-9A-F]{4})&PID_(?<pid>[0-9A-F]{4}).*') {
$result | Add-Member -MemberType NoteProperty -Name 'VID' -Value $matches['vid']
$result | Add-Member -MemberType NoteProperty -Name 'PID' -Value $matches['pid']
}
# output the PsCustomObject
$result
or use a Hashtable as temporary storage:
# create a Hastable to temporarily store results in
$hash = [ordered]#{
SerialNumber = $disk.SerialNumber
Model = $disk.Model
Size = $disk.Size
}
# add items to the hash if the condition is true
if ($usb.DeviceID -match '.*VID_(?<vid>[0-9A-F]{4})&PID_(?<pid>[0-9A-F]{4}).*') {
$hash['VID']=$matches['vid']
$hash['PID']=$matches['pid']
}
# next cast to PsCustomObject and output
[PsCustomObject]$hash

Powershell - Where-Object in forEach Loop

I need some help for executing a little script and filtering results ...
I checkmy VM diskspace with the following script
Get-VM | ForEach-Object {
$VM = $_
$_.Guest.Disks | ForEach-Object {
$Report = "" | Select-Object -Property VM,Path,Capacity,FreeSpace,PercentageFreeSpace
$Report.VM = $VM.Name
$Report.Path = $_.Path
$Report.Capacity = $_.Capacity
$Report.FreeSpace = $_.FreeSpace
if ($_.Capacity) {$Report.PercentageFreeSpace = [math]::Round(100*($_.FreeSpace/$_.Capacity))}
$report
}
}
But I'd like to add a filter that my report only show me PercentageFreeSPace lesser than 20.
I try to add a where-object condition to my report with no success...
Can somebody help me please ? I m a beginner in PS...
Thanks in advance,
Best regards
For future questions you should format your script to be more readable.
I believe I have done it quite well below:
[EDIT] Seems that something gone wrong with displaying your question on my laptop. Just after my answer, the formatting is almost the same as provided below.
Get-VM | ForEach-Object {
$VM = $_
$_.Guest.Disks | ForEach-Object {
$Report = "" | Select-Object -Property VM,Path,Capacity,FreeSpace,PercentageFreeSpace $report
$Report.VM = $VM.Name
$Report.Path = $_.Path
$Report.Capacity = $_.Capacity
$Report.FreeSpace = $_.FreeSpace
if ($_.Capacity) {
$Report.PercentageFreeSpace = [math]::Round(100*($_.FreeSpace/$_.Capacity))
}
$report
}
}
To be honest I do not understand why you are using pipe at line 4.
Regarding your question, you should puy Where-Object clause before you will go to second for each loop.
First off, try and avoid multiple nested pipes to foreach-object, use foreach instead. That is, don't do
Get-VM | ForEach-Object {
$VM = $_
$_.Guest.Disks | ForEach-Object {
but
foreach($vm in Get-VM) {
foreach($disk in $vm.Guest.disks) {
This makes it easy to see what objects are handled later, and there isn't need to save current object on the pipeline into a temp variable (which you do by $VM = $_).
Also, objects can be initialized via a hash table instead of using select-object. Like so,
$pctLimit = 20 # Variable sets percentage limit instead of a magic number
foreach($vm in Get-VM) {
foreach($disk in $vm.Guest.Disks) {
# Report object is created via hash table
$Report = new-object PSObject -Property #{
VM = $VM.Name
Path = $disk.Path
Capacity = $disk.Capacity
FreeSpace = $disk.FreeSpace
ZeroDisk = ($disk.Capacity -gt 0) # NB: calculated property
}
if (-not $Report.ZeroDisk) { # Process only non-zero disks
$Report.PercentageFreeSpace = [math]::Round(100*($Report.FreeSpace/$Report.Capacity))
if($Report.PercentageFreeSpace -lt $pctLimit) {
$report
} else {
# Disk had more than $pctLimit free space. Now what?
}
} else {
# Disk had zero capacity. Now what?
}
}
}
FIrst of all thanks for your help
I manage to filter with the following
Get-VM | ForEach-Object {
$VM = $_
$_.Guest.Disks | ForEach-Object {
$Report = "" | Select-Object -Property VM,Path,Capacity,FreeSpace,PercentageFreeSpace
$Report.VM = $VM.Name
$Report.Path = $_.Path
$Report.Capacity = $_.Capacity
$Report.FreeSpace = $_.FreeSpace
if ($_.Capacity) {$Report.PercentageFreeSpace = [math]::Round(100*($_.FreeSpace/$_.Capacity))}
if( $_.Capacity -and $Report.PercentageFreeSpace -lt 30 ) {
$Report
}
}
}
`
Thanks,
Best regards

How to get all instances of a class?

My knowledge of classes is relatively new. But I want to output all objects/instances of a class with powershell. Is this even possible? Here is an example of how I create two objects of the class Computer.
Class Computer {
[String]$Name
[String]$Description
[String]$Type
}
$NewComputer = New-Object 'Computer'
$NewComputer.Name = 'ultra1'
$NewComputer.Description = 'Lenovo Yoga 900'
$NewComputer.Type = 'Ultrabook'
$NewComputer = New-Object 'Computer'
$NewComputer.Name = 'ultra2'
$NewComputer.Description = 'Lenovo Yoga X1'
$NewComputer.Type = 'Ultrabook'
Now I want to output both objects, how can I do this?
Judging from your comment "if there is a possibility to get the objects of a class without putting them into a collection", I think what you want to do is to create new Computer objects using your class and later on use these objects as separate variables.
For easier creation, I'd suggest you add a constructor to the class, so you can create the objects in a single line:
Class Computer {
[String]$Name
[String]$Description
[String]$Type
# add a constructor
Computer(
[string]$n,
[string]$d,
[string]$t
){
$this.Name = $n
$this.Description = $d
$this.Type = $t
}
}
# now create the computer objects
[Computer]$pcUltra1 = [Computer]::new('ultra1','Lenovo Yoga 900','Ultrabook')
[Computer]$pcUltra2 = [Computer]::new('ultra2','Lenovo Yoga X1','Ultrabook')
# show what you have now
$pcUltra1
$pcUltra2
Output:
Name Description Type
---- ----------- ----
ultra1 Lenovo Yoga 900 Ultrabook
ultra2 Lenovo Yoga X1 Ultrabook
Hope that helps
Maybe this will help
Class Computer {
[String]$Name
[String]$Description
[String]$Type
}
# a collection of computers
$computers =#()
$NewComputer = New-Object 'Computer'
$NewComputer.Name = ‘ultra1’
$NewComputer.Description = ‘Lenovo Yoga 900’
$NewComputer.Type = ‘Ultrabook’
# append a computer to teh collection
$computers += $NewComputer
$NewComputer = New-Object 'Computer'
$NewComputer.Name = ‘ultra2’
$NewComputer.Description = ‘Lenovo Yoga X1’
$NewComputer.Type = ‘Ultrabook’
# append a computer to teh collection
$computers += $NewComputer
# this outputs each of the computers
$computers
# or you can format the data in a table
$computers | Format-Table -AutoSize
# or in a list
$computers | Format-List *
# or as json
$computers | ConvertTo-Json
Assuming you haven't re-bound any names, you can do the following:
Get-Variable | Select-Object -ExpandProperty Value |
Where-Object { $_.GetType().Name -eq 'Computer' }

Powershell output not formatting properly

I'm using this script to get some basic info from virtual machines on our HyperV cluster:
#Establish global variables and MasterList array
$VMList = Get-VM
$MasterList = #()
#Loop through VMs and get Name, Processor count, assigned memory, add to MasterList
foreach($vm in $VMList) {
$ALLVHD = Get-VHD $vm.harddrives.path -ComputerName $vm.computername
$MyObject = New-Object PSObject -Property #{
Name = ($vm).VMName
ProcessorCount = (Get-VMProcessor $vm).Count
AssignedMemory = ($vm).MemoryAssigned
DiskType = $VHD.VhdType
'Total(GB)' = [math]::Round($VHD.Size/1GB)
'Used(GB)' = [math]::Round($VHD.FileSize/1GB)
'Free(GB)' = [math]::Round($VHD.Size/1GB- $VHD.FileSize/1GB)
}
$MasterList += $MyObject
}
$MasterList | Out-GridView
It mostly works, but there are several problems. The column order is wrong, it outputs DiskType,Name,AssignedMemory,Free(GB),ProcessorCount,Used(GB),Total(GB) and I have no idea why because that's now how it's ordered in the code. Also, the Free,Used, and Total amounts are 71, 29, and 100 for all items when that is incorrect.
If any Powershell experts can help me with this, it would be much appreciated.
I figured it out, thanks for the suggestions
#Establish global variables and MasterList array
$VMList = Get-VM
$MasterList = #()
#Loop through all VMs on node
foreach($vm in $VMList) {
$ALLVHD = Get-VHD $vm.HardDrives.path -ComputerName $vm.computername
foreach($VHD in $ALLVHD){
$MyObject = New-Object PSObject -Property #{
Name = $vm.Name
DiskType = $VHD.VhdType
Path = $VHD.Path
'Total(GB)' = [math]::Round($VHD.Size/1GB)
'Used(GB)' = [math]::Round($VHD.FileSize/1GB)
'Free(GB)' = [math]::Round($VHD.Size/1GB- $VHD.FileSize/1GB)
ProcessorCount = (Get-VMProcessor $vm).Count
AssignedMemory = ($vm).MemoryAssigned
}
#Add information to MasterList array
$Masterlist += $MyObject
}
}
#Change this line to print output however you want
$MasterList | select Name,DiskType,Path,'Total(GB)','Used(GB)','Free(GB)',ProcessorCount,#{Expression={$_.AssignedMemory/1GB};Label="AssignedMemory(GB)"}

Adding objects to array to create multiple columns

I'm trying to get the DisplayName of all Software listed in AddRemovePrograms for each computer, add it to an array under the name of the computer, then export. Here's what I have:
$Computers = gc "C:\Get Software.txt"
$CSV = "C:\Get Software.csv"
$Results = #()
If (Test-Path $CSV) {
Remove-Item $CSV
}
Foreach($Computer in $Computers){
#Get DisplayName of Software Installed on Asset
$Software = Get-WmiObject Win32Reg_AddRemovePrograms -ComputerName $Computer | Select-Object -ExpandProperty DisplayName
$counter = 0
While ($counter -lt $Software.count){
#Create a PSObject. Loops through all software and adds to $Results.
$Obj = New-Object PSOBJECT
Add-member –inputobject $Obj –membertype Noteproperty -Name $Computer -Value $Software[$counter]
$counter++
$Results+=$Obj
}
}
$Results | Export-Csv $CSV -NoTypeInformation
Unfortunately, the output only lists the first Computer in the CSV. I've tried stepping through this to understand it, I just don't understand why I can't add the $Obj variable to $Results with a different Name Property (In this case I'm looping and making a new name based on the computer name in my .txt file). It seems to only take the first input and won't put a new column header then spit out the software. Below is an example of what I'm getting and what I'd like to get instead.
OUTPUT
A01234
Program1
Program2
Program3
EXPECTED OUTPUT
A01234 B05678 C09123
Program1 Program97 Program30
Program2 Program98 Program31
Program3 Program99 Program32
Hopefully this makes some sense. Any assistance would be appreciated, I'm clearly doing something wrong with the objects and I'm not seeing it. Thanks!
This is do-able, it just isn't quite as simple as you would think. What I would suggest is setting things up as a hashtable where the keys are your computer names and your values are an array of software titles for each computer. Then you find out how many titles the computer with the most software has (that's how many rows you'll have, so it's how many times you'll have to loop), and create a loop to make that many objects. Each object will have no properties to start, and then we add a property for each computer in the hashtable, and the value for that property will be the Nth item listed in the hashtable for that computer. Here's the code, it might make this all make more sense:
$Computers = 'A01234','B05678','C09123'
$SftwrPerCmp = [ordered]#{}
ForEach($Computer in $Computers){
$SftwrPerCmp.add($Computer,#())
#Randomly generate 7-15 strings as 'Programs' for current computer
$Software = 1..$(get-random -Maximum 15 -Minimum 7)|%{(Get-Random -inputobject $("ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" -split ''|?{$_}) -count 6) -join ''}
ForEach($Title in $Software){
$SftwrPerCmp["$Computer"] += $Title
}
}
$MaxTitleCount = $SftwrPerCmp.Values|%{$_.count}|sort|select -last 1
$Results = #()
For($i=0;$i -lt $MaxTitleCount;$i++){
$Record = New-Object PSObject
$SftwrPerCmp.Keys | ForEach{Add-Member -InputObject $Record -NotePropertyName $_ -NotePropertyValue $SftwrPerCmp["$_"][$i]}
$Results += $Record
Clear-Variable Record
}
$Results|Format-Table -AutoSize
Now obviously you will not randomly generate software titles, you'll use your existing $Software = Get-WmiObject line that's in your existing code instead since that part was at least working for you. This should result in the listings that you were looking for. My code resulted in this:
A01234 B05678 C09123
------ ------ ------
CU7K5E 6GJWOB 97H1TY
7VCZ5T CIPWVK 760NKU
CHKPY0 J4B7D0 1QOSD3
2YEFR4 2VY6DM O68SKU
VI7ZQG WLJQN9 Q5VJAZ
ZQOKNV R9KZG1 H2XZK4
S8IZC4 GRSMPU BIZXKA
LAVNI0 TKBOUC K9DEFU
3U7KVO JZ3X4H
A6GVUK 18AC5H
NMI32Q H14GPJ
50KSZ6 XU0FWC
PAN5TC 9WXR5U
531M04