【问题标题】:Powershell - multiple values in custom objectPowershell - 自定义对象中的多个值
【发布时间】:2018-04-22 21:44:48
【问题描述】:

我一直在编写一个脚本,该脚本将采用 IP/DNS 并创建一个 2 列输出。当它在 powershell 内部工作时,只要我尝试导出到 CSV,它就会返回 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}

有没有办法在保持对象方式的同时展开/展开?

【问题讨论】:

  • 通常,您需要Export-CliXml / Import-CliXml 而不是CSV 格式,以便在序列化/反序列化后近似保留原始类型。目前尚不清楚您的具体问题是什么;请直接更新您的问题以澄清。
  • 一般情况下,争取提供MCVE (Minimal, Complete, and Verifiable Example)

标签: powershell object expand unwrap


【解决方案1】:

确保您遍历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
            }
        }
    }
}

【讨论】:

  • 是的,这也是一个好方法。它不会使行数与您传入的项目数相同,但这可能并不重要。
【解决方案2】:

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

您的代码没有对结果做任何特殊处理,因此对象的“列”(实际上是属性)本身就是一个数组。您可以通过在屏幕上看到的结果看到这一点;它呈现为由{ } 包围的逗号分隔列表。

当您导出到 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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-10-08
    • 2016-01-26
    • 1970-01-01
    • 2018-04-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多