Powershell - 自定义对象中的多个值

Powershell - multiple values in custom object

我一直在编写一个脚本,它将采用 IPs/DNSes 并创建一个 2 列输出。当它在 powershell 内部工作时,一旦我尝试将其导出为 CSV,它 return system.object。我该如何解决?这是我的代码:

function Resolve-IPDNS {
[CmdletBinding()]
param(
    [Parameter(Mandatory = $true)]
    [string[]]$IPDNS,

    [string]$DNSServer = "1.1.1.1"

)#param

BEGIN {}

Process {
    foreach ($addrs in $IPDNS ) {

        #Resolve IP or DNS
        IF ($addrs -as [ipaddress]) {
        $resolve_params = @{'Name' = $addrs
            'Server' = $DNSServer
            'Type' = 'PTR'}
        } ELSE {
            $resolve_params = @{'Name' = $addrs
            'Server' = $DNSServer
            'Type' = 'A'}
        }
        $resolve = Resolve-DnsName @resolve_params


        #Create props
        IF ($addrs -as [ipaddress]) {
            $props = @{'IP' = $resolve.Name
                'DNS' = $resolve.NameHost}
        } ELSE {
                $props = @{'IP' = $resolve.IPAddress
                    'DNS' = $resolve.Name}

            }#IF

            #Output data
            $obj = New-Object -TypeName psobject -Property $props
            Write-Output $obj

        }#foreach

    }#Process
    END {}
}#function

Resolve-IPDNS

所以如果尝试提供 bbc.com 我得到结果:

IP                                                            DNS
--                                                            ---
{151.101.0.81, 151.101.64.81, 151.101.128.81, 151.101.192.81} {bbc.com, bbc.com, bbc.com, bbc.com}

有没有办法 expand/unwrap 同时保持对象方式?

确保迭代 每个 来自 Resolve-DnsName:

的结果
function Resolve-IPDNS {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true)]
        [string[]]$IPDNS,

        [string]$DNSServer = "1.1.1.1"

    )

    Process {
        foreach($addrs in $IPDNS) {
            if($addrs -as [ipaddress]) {
                $resolve_params = @{
                    'Name'   = $addrs
                    'Server' = $DNSServer
                    'Type'   = 'PTR'
                }
            } 
            else {
                $resolve_params = @{
                    'Name'   = $addrs
                    'Server' = $DNSServer
                    'Type'   = 'A'
                }
            }

            foreach($resolve in Resolve-DnsName @resolve_params) {
                if($addrs -as [ipaddress]) {
                    $props = @{
                        'IP'  = $resolve.Name
                        'DNS' = $resolve.NameHost
                    }
                }
                else {
                    $props = @{
                        'IP'  = $resolve.IPAddress
                        'DNS' = $resolve.Name
                    }
                }

                #Output data
                $obj = New-Object -TypeName psobject -Property $props
                Write-Output $obj
            }
        }
    }
}

这里的问题是名称解析可以 return 多个结果。这正是您的示例所发生的情况,bbc.com

您的代码没有对结果做任何特殊处理,因此对象的 "column"(实际上是 属性)本身就是一个数组。您可以通过屏幕上看到的结果看到这一点;它呈现为由 { }.

包围的逗号分隔列表

当您导出到 CSV 时,每个 属性 都会调用其 .ToString() 方法,在标准 PowerShell 数组上,它将为您提供 System.Object[] 的确切结果,这可以看到如下:

@(1,2,3).ToString()

所以,你需要做出选择:

  • 将数组 存储在对象中 作为预呈现的字符串,因为您希望它出现在 CSV 中(从而丢失原始数组类型)
  • 将数组作为存储,在导出之前进行字符串渲染
  • 向执行转换或导出的对象添加辅助方法

-join 运算符在这里会很好,因为即使值不是数组,它也能正常工作。

对于第一个选项,您可以在分配时轻松处理它:

@{
    'IP' = $resolve.Name -join '+'
    'DNS' = $resolve.NameHost -join '+'
}

对于第二个选项,在管道中即时更改您的值:

Resolve-IPDNS -IPDNS 'bbc.com' | 
    ForEach-Object -Process {
        New-Object -TypeName PSObject -Property @{
            'IP' = $_.IP -join '+'
            'DNS' = $_.DNS -join '+'
        }
    } |
    Export-Csv MyCsv.csv -NoTypeInformation

对于第三个选项,请考虑:

$obj = New-Object -TypeName psobject -Property $props |
    Add-Member -MemberType ScriptMethod -Name JoinedClone -Value {
        New-Object -TypeName PSObject -Property @{ param([String]$JoinString
            'IP' = $this.IP -join $JoinString
            'DNS' = $this.DNS -join $JoinString
        }
    }

然后,您可以执行以下操作:

(Resolve-IPDNS -IPDNS 'bbc.com').JoinedClone() | Export-Csv MyCsv.csv -NoTypeInformation