首页 > 解决方案 > All VMs PowerCLI Info output /Console and Custom Object Not Working Properly

问题描述

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

标签: powershellpowercli

解决方案


你已经非常接近完成这项工作了。您只需要在循环$object内移动创建和检索。ForEach

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 的有用答案暗示了一些关于处理IPAddress属性和删除不必要命令的想法,即Get-VMGuest达到预期目标。他使用一种快捷方法来创建$row将保存虚拟机属性的对象。但是,使用数组替换和加法技术存在固有的低效率,$Report += Row因为每次循环迭代时都会创建一个更大的新数组对象。对于较小的数据集,这可能无关紧要,但对于较大的数据集,这可能很重要。

一旦[PSCustomObject]创建,您可以编辑属性中的值,只要该对象未被破坏和/或这些属性定义保留在对象上。这意味着您可以在循环的每次迭代期间为相同的属性设置所有新值(如果您愿意)。我添加了[ordered]属性,以便$object属性顺序在您的输出中保持一致。

我添加了$Output变量来存储$Object循环的每次迭代期间的值。$Output成为具有您要跟踪的三个属性的对象数组。现在,您Export-Csv将这些属性值转换为 CSV 文件的字符串。

我删除了该Get-VMGuest命令,因为该$name变量是一个包含您已经需要的所有信息的对象。Guest属性提供提供的信息Get-VMGuest

您可以将该IPAddress值转换为字符串,因为有时可能存在多个 IP,因为该属性是一个数组。您可以选择只抓取一个索引值 ( $Name.Guest.IPAddress[0]);但是,您必须小心这一点,因为您想要的 IP 地址可能位于另一个索引中。强制转换将使用空格分隔符返回该[string]属性的所有值。我改用-join运算符并使用了空格分隔符。IPAddress也可能包含 IPv6 地址。我只想捕获 IPv4 地址,所以我使用了正则表达式匹配,例如$Name.Guest.IPAddress -match "\.",它与文字.字符匹配。您可以结合多种技术来获取所需的数据。

考虑以下对象和示例:

$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

根据您的代码结构方式,您似乎在尝试创建其值是通过引用而不是通过值的属性。为了进一步解释,您似乎希望属性值随着属性值自动$Object更改而更新,而无需显式分配。我不知道这是否是您的意图,但我相信这会增加您想要完成的任务的复杂性。我没有为您的代码执行此操作。每次循环迭代时,我都会明确设置属性值。$info$Object

我也没有看到你的Export-Csv命令;但是,您描述了具有该Length属性的输出。当您Export-Csv[string]对象作为输入对象时,可能会发生这种情况。由于 的目的Export-Csv是将属性值转换为字符串,因此常规字符串的唯一属性值是Length. 所以这是可以预料的。您可以在下面看到此行为:

$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"

推荐阅读