无法在powershell中将自定义对象导出为CSV

无法在powershell中将自定义对象导出为CSV,powershell,powershell-3.0,powershell-4.0,powershell-remoting,Powershell,Powershell 3.0,Powershell 4.0,Powershell Remoting,我编写了powershell scirpt以将IIS信息生成到CSV $bindingip = Get-WmiObject -Namespace root\webadministration -Class sslbinding2 | Select-Object - Property PSComputerName,IPAddress $sitedetails = Get-Website | Select-Object -Property Name,ID,State $report = New-O

我编写了powershell scirpt以将IIS信息生成到CSV

$bindingip = Get-WmiObject -Namespace root\webadministration -Class sslbinding2 | Select-Object - 
Property PSComputerName,IPAddress
$sitedetails = Get-Website | Select-Object -Property Name,ID,State
$report = New-Object psobject
$report | Add-Member -MemberType NoteProperty -Name "Hostname" -Value $bindingip.PSComputerName
$report | Add-Member -MemberType NoteProperty -Name "IPAddress" -Value $bindingip.IPAddress
$report | Add-Member -MemberType NoteProperty -Name "Site Name" -Value $sitedetails.name
$report | Add-Member -MemberType NoteProperty -Name "ID" -Value $sitedetails.id
$report | Add-Member -MemberType NoteProperty -Name "State" -Value $sitedetails.state
$report | Export-Csv C:\content.csv -NoTypeInformation
CSV的输出:

Hostname         IPAddress        Site Name       ID               State
System.Object[]  System.Object[]  System.Object[] System.Object[]  System.Object[]
我是否需要向代码中添加任何内容以获得准确的输出,有人可以提供帮助。

正如他们在评论中指出的,变量
$bindingip
$sitedetails
上的属性值是数组而不是字符串。这就是为什么导出报告时会得到
对象类型
,而不是它的实际值

您可以通过执行以下操作来了解这一点:

$bindingip.PSComputerName.GetType()
这将返回如下内容:

IsPublic IsSerial Name        BaseType    
-------- -------- ----        --------    
True     True     Object[]    System.Array
但是,如果仅选择阵列上的第一个元素
PSComputerName

$bindingip.PSComputerName[0].GetType()
你会看到:

IsPublic IsSerial Name        BaseType     
-------- -------- ----        --------     
True     True     String      System.Object
解决方法是使用
Out string
将值转换为多行字符串,或者使用分隔符连接数组元素,即
-join'/'

$bindingip = Get-WmiObject -Namespace root\webadministration -Class sslbinding2
$sitedetails = Get-Website

# Like this (thanks mklement0):
$report = [pscustomobject]@{
    Hostname = "$($bindingip.PSComputerName)"
    IPAddress = "$($bindingip.IPAddress)"
    'Site Name' = "$($sitedetails.name)"
    ID = "$($sitedetails.id)"
    State = "$($sitedetails.state)"
}

# Or like this:
$report = [pscustomobject]@{
    Hostname = ($bindingip.PSComputerName | Out-String).trim()
    IPAddress = ($bindingip.IPAddress | Out-String).trim()
    'Site Name' = ($sitedetails.name | Out-String).trim()
    ID = ($sitedetails.id | Out-String).trim()
    State = ($sitedetails.state | Out-String).trim()
}

# Or like this:
$report = [pscustomobject]@{
    Hostname = $bindingip.PSComputerName -join '//'
    IPAddress = $bindingip.IPAddress -join '//'
    'Site Name' = $sitedetails.name -join '//'
    ID = $sitedetails.id -join '//'
    State = $sitedetails.state -join '//'
}

$report | Export-Csv C:\content.csv -NoTypeInformation
编辑 这也是我所建议的。它将为属性值上的每个元素创建一个新对象:

$compName = $bindingip.PSComputerName
$ipAddr = $bindingip.IPAddress
$name = $sitedetails.name
$id = $sitedetails.id
$state = $sitedetails.state

$top = ($compName.Count,$ipAddr.Count,$name.Count,$id.Count,$state.Count | Measure-Object -Maximum).Maximum

$report = for($i = 0;$i -lt $top;$i++)
{
    [pscustomobject]@{
        Hostname = $compName[$i]
        IPAddress = $ipAddr[$i]
        'Site Name' = $name[$i]
        ID = $id[$i]
        State = $state[$i]
}

$report | Export-Csv...
正如和在他们的评论中指出的那样,变量
$bindingip
$sitedetails
上的属性值是数组而不是字符串。这就是为什么导出报告时会得到
对象类型
,而不是它的实际值

您可以通过执行以下操作来了解这一点:

$bindingip.PSComputerName.GetType()
这将返回如下内容:

IsPublic IsSerial Name        BaseType    
-------- -------- ----        --------    
True     True     Object[]    System.Array
但是,如果仅选择阵列上的第一个元素
PSComputerName

$bindingip.PSComputerName[0].GetType()
你会看到:

IsPublic IsSerial Name        BaseType     
-------- -------- ----        --------     
True     True     String      System.Object
解决方法是使用
Out string
将值转换为多行字符串,或者使用分隔符连接数组元素,即
-join'/'

$bindingip = Get-WmiObject -Namespace root\webadministration -Class sslbinding2
$sitedetails = Get-Website

# Like this (thanks mklement0):
$report = [pscustomobject]@{
    Hostname = "$($bindingip.PSComputerName)"
    IPAddress = "$($bindingip.IPAddress)"
    'Site Name' = "$($sitedetails.name)"
    ID = "$($sitedetails.id)"
    State = "$($sitedetails.state)"
}

# Or like this:
$report = [pscustomobject]@{
    Hostname = ($bindingip.PSComputerName | Out-String).trim()
    IPAddress = ($bindingip.IPAddress | Out-String).trim()
    'Site Name' = ($sitedetails.name | Out-String).trim()
    ID = ($sitedetails.id | Out-String).trim()
    State = ($sitedetails.state | Out-String).trim()
}

# Or like this:
$report = [pscustomobject]@{
    Hostname = $bindingip.PSComputerName -join '//'
    IPAddress = $bindingip.IPAddress -join '//'
    'Site Name' = $sitedetails.name -join '//'
    ID = $sitedetails.id -join '//'
    State = $sitedetails.state -join '//'
}

$report | Export-Csv C:\content.csv -NoTypeInformation
编辑 这也是我所建议的。它将为属性值上的每个元素创建一个新对象:

$compName = $bindingip.PSComputerName
$ipAddr = $bindingip.IPAddress
$name = $sitedetails.name
$id = $sitedetails.id
$state = $sitedetails.state

$top = ($compName.Count,$ipAddr.Count,$name.Count,$id.Count,$state.Count | Measure-Object -Maximum).Maximum

$report = for($i = 0;$i -lt $top;$i++)
{
    [pscustomobject]@{
        Hostname = $compName[$i]
        IPAddress = $ipAddr[$i]
        'Site Name' = $name[$i]
        ID = $id[$i]
        State = $state[$i]
}

$report | Export-Csv...
除了圣地亚哥的,在我看来,我们只是将一个数组的对象与另一个数组的对象组合起来,以产生所有可能的组合。为了实现这一点,我可能会执行以下操作

$bindingip = @(
    [PSCustomObject]@{
        PSComputerName = 'Public1'
        IPAddress      = '192.168.0.1'
    },
    [PSCustomObject]@{
        PSComputerName = 'Public1'
        IPAddress      = '127.0.0.1'
    }
)

$siteDetails = @(
    [PSCustomObject]@{
        Name  = 'site 1'
        Id    = 'site1'
        State = 'up'
    },
    [PSCustomObject]@{
        Name  = 'site 2'
        Id    = 'site2'
        State = 'down'
    }
)    

$combined = foreach ($ip in $bindingip) {
    foreach ($details in $siteDetails) {
        $out = [ordered]@{}
        $ip.psobject.properties | ForEach-Object {
            $out[$_.Name] = $_.Value
        }
        $details.psobject.properties | ForEach-Object {
            $out[$_.Name] = $_.Value
        }

        [pscustomobject]$out
    }
}

$combined | Format-Table
输出

PSComputerName IPAddress   Name   Id    State
-------------- ---------   ----   --    -----
Public1        192.168.0.1 site 1 site1 up
Public1        192.168.0.1 site 2 site2 down
Public1        127.0.0.1   site 1 site1 up
Public1        127.0.0.1   site 2 site2 down
为了可重用性,可以将其封装在函数中

function Combine-ObjectsFromTwoArrays {
    param (
        [array]$array1,
        [array]$array2
    )

    foreach ($obj1 in $array1) {
        foreach ($obj2  in $array2) {
            $out = [ordered]@{}
            $obj1.psobject.properties | ForEach-Object {
                $out[$_.Name] = $_.Value
            }
            $obj2.psobject.properties | ForEach-Object {
                $out[$_.Name] = $_.Value
            }

            [pscustomobject]$out
        }
    }
}
除了圣地亚哥的,在我看来,我们只是将一个数组的对象与另一个数组的对象组合起来,以产生所有可能的组合。为了实现这一点,我可能会执行以下操作

$bindingip = @(
    [PSCustomObject]@{
        PSComputerName = 'Public1'
        IPAddress      = '192.168.0.1'
    },
    [PSCustomObject]@{
        PSComputerName = 'Public1'
        IPAddress      = '127.0.0.1'
    }
)

$siteDetails = @(
    [PSCustomObject]@{
        Name  = 'site 1'
        Id    = 'site1'
        State = 'up'
    },
    [PSCustomObject]@{
        Name  = 'site 2'
        Id    = 'site2'
        State = 'down'
    }
)    

$combined = foreach ($ip in $bindingip) {
    foreach ($details in $siteDetails) {
        $out = [ordered]@{}
        $ip.psobject.properties | ForEach-Object {
            $out[$_.Name] = $_.Value
        }
        $details.psobject.properties | ForEach-Object {
            $out[$_.Name] = $_.Value
        }

        [pscustomobject]$out
    }
}

$combined | Format-Table
输出

PSComputerName IPAddress   Name   Id    State
-------------- ---------   ----   --    -----
Public1        192.168.0.1 site 1 site1 up
Public1        192.168.0.1 site 2 site2 down
Public1        127.0.0.1   site 1 site1 up
Public1        127.0.0.1   site 2 site2 down
为了可重用性,可以将其封装在函数中

function Combine-ObjectsFromTwoArrays {
    param (
        [array]$array1,
        [array]$array2
    )

    foreach ($obj1 in $array1) {
        foreach ($obj2  in $array2) {
            $out = [ordered]@{}
            $obj1.psobject.properties | ForEach-Object {
                $out[$_.Name] = $_.Value
            }
            $obj2.psobject.properties | ForEach-Object {
                $out[$_.Name] = $_.Value
            }

            [pscustomobject]$out
        }
    }
}


嗯,真奇怪。将其更改为
pscustomobject
,有什么区别吗?此外,您应该开始使用v3中引入的Get-Ciminstance cmdlet。尝试添加
Out字符串
@AbrahamZinala,我已经用{pscustomobject}测试过了,结果是一样的。看起来像
$bindingZip
$sitedetails
对我来说可能包含多个对象。在创建PSObject之前,您是否尝试将信息打印到console?我想您可能想在调用
选择对象
的两次调用中都使用
-ExpandProperty
,而不仅仅是
-Property
@Ash My bad,是的,我已经相应地更新了脚本。我需要在多个服务器上执行这个脚本,所以我添加了Invoke命令和几行代码。将其更改为
pscustomobject
,有什么区别吗?此外,您应该开始使用v3中引入的Get-Ciminstance cmdlet。尝试添加
Out字符串
@AbrahamZinala,我已经用{pscustomobject}测试过了,结果是一样的。看起来像
$bindingZip
$sitedetails
对我来说可能包含多个对象。在创建PSObject之前,您是否尝试将信息打印到console?我想您可能想在调用
选择对象
的两次调用中都使用
-ExpandProperty
,而不仅仅是
-Property
@Ash My bad,是的,我已经相应地更新了脚本。我需要对多台服务器执行此脚本,因此我在脚本中添加了Invoke命令和几行代码。更有效的方法是让字符串插值处理数组字符串化,例如,
“$($bindingip.PSComputerName)”
。至于通过列表构建集合:这是可行的,当然比使用
+=
将数组“追加”更可取,但请注意,将整个
for
循环作为一个表达式来处理更简洁、更有效(
$report=for(…){…}
)-请参阅。(但是+1)。@mklement0谢谢你的洞察力,先生,你的反馈总是正确的。我编辑了我的答案。@SantiagoSquarzon谢谢。我对脚本做了一些相应的修改,我的脚本面临两个问题。当我将内容导出到CSC时,整个输出存储在脚本的一个单元格中。是否有任何方法可以将输出格式化为CSV中的每个单元格。@DKU上次编辑我的答案的代码应该可以做到这一点。@SantiagoSquarzon谢谢,我将在我的实验室进行相应的测试,我已经修改了脚本,以便在多个服务器上运行,为此我添加了Invoke命令。我考虑的新要求是解析绑定IP地址并添加相同的CSV。为此,我使用resolve DNSName$ipadd | select object-property NameHost,无法将数据从IP地址添加到CSV每个解析主机名。更有效的方法是简单地让字符串插值处理数组字符串化,例如,
“$($bindingip.PSComputerName)”
。至于通过列表构建集合:这是可行的,当然比使用
+=
将数组“追加”更可取,但请注意,将整个
for
循环作为一个表达式来处理更简洁、更有效(
$report=for(…){…}
)-请参阅。(但是+1)。@mklement0谢谢你的洞察力,先生,你的反馈总是正确的。我编辑了我的答案。@SantiagoSqua