I want to to get all our VMs with the vSphere PowerCLI and get those outputed with some additional info. But i don't get the output working properly.
I tried it as Console output already but then i dont get the name with the os and IPAddress
$Object = New-Object PSObject -Property @{
Name = $name
OS = $info.OSFullName
IP = $info.IPAddress
}
Connect-VIServer -Server VMServer -Credential admin -Password ASecretPWnoOneKnows
$allnames = Get-VM
foreach($name in $allnames)
{
$info = Get-VMGuest $name | select OSFullName, IPAddress
Add-Member -InputObject $Object
}
This is my "best approach" so far.
My result should look like
SomeVMname SomeOS SomeIP
but I only got so far the Length
of the total String or error as I don't handle the custom object properly:
Therefore if someone can help me either way, Console output or into a object which i can also export to csv I would be really happy with it
You are very close to making this work already. You just need to move the $object
creation and retrieval inside of your ForEach
loop.
Connect-VIServer -Server VMServer -Credential admin -Password ASecretPWnoOneKnows
$allnames = Get-VM
$Output = foreach($name in $allnames)
{
$Object = [PSCustomObject][ordered]@{
Name=$name.Name
OS=$name.Guest.OSFullName
IP=$name.Guest.IPAddress -match "\." -join " "
}
$Object
}
$Output # To output to the console
$Output | Export-Csv -path "file.csv" -NoTypeInformaton # Csv output
AVShalom's helpful answer alludes to some of the ideas regarding handling the IPAddress
property and the removal of unnecessary commands, i.e. Get-VMGuest
, to reach the desired goal. He uses a shortcut method for creating the object $row
that will hold the virtual machine properties. However, there are inherent inefficiencies with using array replacement plus addition technique $Report += Row
because a new array object of larger size is created each time the loop iterates. For smaller data sets, this may not matter, but for larger ones, this could prove significant.
Once the [PSCustomObject]
is created, you can edit the value in the properties as long as that object is not destroyed and/or those property definitions remain on the object. This means you can have all new values (if you wish) for the same properties during each iteration of the loop. I added the [ordered]
attribute so that the $object
property order would remain consistent in your output.
I added the $Output
variable to store the value of $Object
during each iteration of the loop. $Output
becomes an array of objects with the three properties you want to track. Now your Export-Csv
will convert those property values into strings for your CSV file.
I removed the Get-VMGuest
command because the $name
variable is an object that contains all the information you already need. The Guest
property provides the information that Get-VMGuest
provides.
You could cast the IPAddress
value to string because there could be times where there is more than one IP since that property is an array. You can choose to grab just an indexed value ($Name.Guest.IPAddress[0]
); however, you must be careful with this because the IP address(es) you want, may be at another index. The [string]
cast will return all values of that property using a space delimiter. I used the -join
operator instead and used a space delimiter. IPAddress
may also contain IPv6 addresses. I only wanted to capture IPv4 addresses, so I used a Regex match, e.g. $Name.Guest.IPAddress -match "\."
, which matches the literal .
character. You can combine multiple techniques to get the data you want.
Consider the following object and examples:
$name.guest
IPAddress OSFullName
--------- ----------
{1.1.1.1, 2.2.2.2, fe80::ffff:ffff:ffff:ffff} Windows StackOverflow
$name.guest.IPAddress # Retrieves all IPs
1.1.1.1
2.2.2.2
fe80::ffff:ffff:ffff:ffff
$name.guest.IPAddress[0] # Retrieves the first IP in the array
1.1.1.1
$name.guest.IPAddress -match "\." # Retrieves all IPv4 IPs
1.1.1.1
2.2.2.2
$name.guest.IPAddress -match "\." -join " " # Retrieves all IPv4 separated by space
1.1.1.1 2.2.2.2
With the way your code was structured, it appeared as though you were trying to create properties whose values are by reference rather than by value. To explain further, it appears that you want the property values for $Object
to update as the $info
property values change automatically without an explicit assignment. I do not know if that was your intention, but I believe that would add complexity to what you want to accomplish. I did not do this for your code. I am setting the $Object
property values explicitly each time the loop iterates.
I also did not see your Export-Csv
command; however, you described having an output of the Length
property. That can happen when you Export-Csv
with a [string]
object as the input object. Since the purpose of Export-Csv
is to convert property values into strings, the only property value of a regular string is Length
. So that is to be expected. You can see this behavior below:
$str = "this is a string"
($str | Get-Member).where({$_.MemberType -eq "Property"})
TypeName: System.String
Name MemberType Definition
---- ---------- ----------
Length Property int Length {get;}
$str | ConvertTo-Csv
#TYPE System.String
"Length"
"16"