【问题标题】:Select-Object Cmdlet Returns Different Formatted Results for Get-NetIPConfiguration (different type)Select-Object Cmdlet 为 Get-NetIPConfiguration(不同类型)返回不同格式的结果
【发布时间】:2020-09-06 11:26:31
【问题描述】:

我试图获取物理网络适配器的 IP 配置详细信息,同时排除所有虚拟网络适配器。我的脚本如下:

$NetAdaptIndex = Get-NetAdapter -Physical | Select -Property InterfaceIndex -ExpandProperty InterfaceIndex

## Get Ip address, Gateway and DNS details as per configuration
$IPAddressConfig = foreach ($II in $NetAdaptIndex) {
    Write-Host $II -ForegroundColor Yellow
    
    Get-NetIPConfiguration | 
        Where-Object { $_.InterfaceIndex -eq $II} |
        Select-Object InterfaceAlias, InterfaceDescription, InterfaceIndex, Ipv4Address, IPv4DefaultGateway, DNSServer
    } 

当我调用该变量时,我得到以下结果,其中 IPv4Address、IPv4DefaultGateway 和 DNSServer 未以字符串格式返回。

PS C:\WINDOWS\system32> $IPAddressConfig


InterfaceAlias       : WiFi 2
InterfaceDescription : D-Link DWA-171 Wireless AC Dual Band Adapter
InterfaceIndex       : 46
IPv4Address          : {192.168.0.103}
IPv4DefaultGateway   : {MSFT_NetRoute (InstanceID = ":8:8:8:9:55?@55;C?8;@B8:8;55;")}
DNSServer            : {MSFT_DNSClientServerAddress (Name = "46", CreationClassName = "", SystemCreationClassName = "", SystemName = "23"), MSFT_DNSClientServerAddress (Name = "46", CreationClassName = "", SystemCreationClassName = "", SystemName = "2")}

InterfaceAlias       : Ethernet
InterfaceDescription : Broadcom NetLink (TM) Gigabit Ethernet
InterfaceIndex       : 10
IPv4Address          : {169.254.149.208}
IPv4DefaultGateway   :
DNSServer            : {MSFT_DNSClientServerAddress (Name = "10", CreationClassName = "", SystemCreationClassName = "", SystemName = "23"), MSFT_DNSClientServerAddress (Name = "10", CreationClassName = "", SystemCreationClassName = "", SystemName = "2")}

但如果我要手动删除 Select-Object 代码,它会返回格式正确的结果。

Get-NetIPConfiguration | 
        Where-Object { $_.InterfaceIndex -eq 46}

观察 IPv4Address、IPv4DefaultGateway 和 DNSServer 如何返回格式正确的结果。

InterfaceAlias       : WiFi 2
InterfaceIndex       : 46
InterfaceDescription : D-Link DWA-171 Wireless AC Dual Band Adapter
NetProfile.Name      : <removed>
IPv6Address          : <removed>
IPv4Address          : 192.168.0.103
IPv6DefaultGateway   : <removed>
IPv4DefaultGateway   : 192.168.0.1
DNSServer            : 2001:f40:0:3::12:68
                       2001:4860:4860::8888
                       1.1.1.1
                       8.8.8.8

我的问题是为什么会这样?有什么方法可以用来将它们转换为正确的格式吗?后一种格式是我想要的格式。

【问题讨论】:

  • Select-object 将类型从 netipconfiguration 更改为 pscustomobject,但是没有这样的类型可以将其转换回来?
  • @js2010 好吧,这个快速而肮脏的黑客没有奏效:(Get-NetIPConfiguration | Select-Object ComputerName, DNSServer) | %{$_.PSTypeNames.Insert(0, 'NetIPConfiguration') ; $_}
  • @beatcracker 或这个Get-NetIPConfiguration | % { [pscustomobject]@{ipv4address = $_.ipv4address;dnsserver=$_.dnsserver;ipv4defaultgateway=$_.ipv4defaultgateway;pstypename='netipconfiguration'}}
  • 我在下面添加了一个伪答案,以解释我为达到最终解决方案而采取的进一步步骤。 @beatcracker 的答案是正确的答案。

标签: powershell


【解决方案1】:

PowerShell 中的所有内容都是一个对象。具有多个嵌套属性的对象可能会变得相当复杂。

PS > (Get-NetIPConfiguration | Select-Object DNSServer)[0]

DNSServer                                                                                                                                                                                      
---------                                                                                                                                                                                      
{MSFT_DNSClientServerAddress (Name = "11", CreationClassName = "", SystemCreationClassName = "", SystemName = "23"), MSFT_DNSClientServerAddress (Name = "11", CreationClassName = "", Syste...

PS > (Get-NetIPConfiguration | Select-Object -ExpandProperty DNSServer)[0]

InterfaceAlias               Interface Address ServerAddresses                                                                                                                                 
                             Index     Family                                                                                                                                                  
--------------               --------- ------- ---------------                                                                                                                                 
LAN                                 11 IPv6    {}

为了让您的生活更轻松,PowerShell 会在对象显示在屏幕上时对其进行格式化。格式化规则存储在xml 文件中:Formatting File Overview。对于NetTCPIP 模块,文件为C:\Windows\System32\WindowsPowerShell\v1.0\Modules\NetTCPIP\Tcpip.Format.ps1xml。这是DNSServer项目格式代码:

<ListItem>
<Label>DNSServer</Label>
<ItemSelectionCondition>
    <ScriptBlock>
    ($_.DNSServer.Count -ne 0) -and
    (($_.NetIPv4Interface.ConnectionState -eq "Connected") -or
        ($_.NetIPv6Interface.ConnectionState -eq "Connected"))
    </ScriptBlock>
</ItemSelectionCondition>
<ScriptBlock>
    $output = "";
    foreach($Server in $_.DNSServer) {
    foreach($Address in $Server.ServerAddresses) {
        $output += $Address + "`n";
    }
    };
    $output.Trim("`n");
</ScriptBlock>
</ListItem>

应用的格式由每个对象上存在的PSTypeNames 属性控制:

PS > (Get-NetIPConfiguration)[0].PSTypeNames
NetIPConfiguration
System.Object

当您使用Select-Object 时,它会修改该属性,因此生成的对象会丢失其格式:

PS > (Get-NetIPConfiguration | Select-Object DNSServer)[0].PSTypeNames
Selected.NetIPConfiguration
System.Management.Automation.PSCustomObject
System.Object

唉,简单地设置它是行不通的(对象没有正确的结构),但你可以使用calculated property来模拟它:

Get-NetIPConfiguration  | Select-Object InterfaceAlias, InterfaceDescription, InterfaceIndex, Ipv4Address, IPv4DefaultGateway, @{ n='DNSServer' ; e={$_.DNSServer.ServerAddresses -join "`n"}}

这会将DNSServer 压缩为字符串,因此您以后将无法正确重用它。或许,只输出ServerAddresses 集合会更方便,看起来也一样:

Get-NetIPConfiguration  | Select-Object InterfaceAlias, InterfaceDescription, InterfaceIndex, Ipv4Address, IPv4DefaultGateway, @{ n='DNSServer' ; e={@($_.DNSServer.ServerAddresses)}}

【讨论】:

  • 感谢您的进一步阅读。这是我现在使用的解决方案,只有 DNSServer 看起来有点奇怪,因为一切都在一条线上。我用 ''`n " 加入 DNSServer,这样它至少具有更好的可读性。
【解决方案2】:

我省略了包含我将整个输出传送到 ConvertTo-HTML cmdlet 的内容,以免问题超出范围。但由于我将输出转换为 HTML,这意味着给猫换皮的方法不止一种。我不需要强制将 DNSServer 对象改回之前的格式。

因此,我没有使用“,”加入 DNSServer,而是使用&lt;br&gt; 标记加入它。

Select-Object InterfaceAlias, InterfaceDescription, InterfaceIndex, @{n='IPv4 Address';e={$_.IPv4Address.IPAddress}}, @{n='IPv4 Default Gateway';e={$_.IPv4DefaultGateway.NextHop}}, @{n='DNS Server';e={$_.DNSServer.ServerAddresses -split " " -join "<br>"}}

由于 ConvertTo-HTML 将 符号分别翻译为 &amp;lt; 和 &amp;gt;,我添加了以下代码将 &amp;lt; 和 &amp;gt; 翻译回 。

$IPAddressConfigTemp = $IPAddressConfig | ConvertTo-Html -fragment -As List -PreContent "<h2>IP Address Configuration Details</h2>"
$IPAddressConfigHTML = $IPAddressConfigTemp -replace "&lt;", "<" -replace "&gt;", ">" -replace "&#39;", "'"

代码的部分结果看起来有点像这样:

<table>
<tr><td>DNS Server:</td><td>2001:f40:0:3::12:68<br>2001:4860:4860::8888<br>1.1.1.1<br>8.8.8.8</td></tr>
</table>

这不是最优雅的解决方案,但至少符合我想要实现的目标。因此,由于我使用计算属性来达到最终解决方案,因此我选择了@beatcracker 的回复作为正确答案。他的回答回答了原因并帮助我进一步学习,这很有帮助。

【讨论】:

    【解决方案3】:

    将 Select-Object 与 -Property 参数一起使用会产生具有新类型的新对象(Selected.NetIPConfiguration,通过管道连接到 Get-Member 以查看此内容)。

    PowerShell 中的格式化是基于类型的,因此格式化会看到新类型,而不是应用旧类型的格式化。

    您可以应用一个新的类型名(使用 PSTypeNames 属性),并将旧类型名 (NetIPConfiguration) 中的格式说明复制到新的类型名中。

    请注意,格式的差异并不意味着属性值的任何差异,它纯粹是装饰性的。

    【讨论】:

    • 谢谢。我不需要对属性值进行进一步处理,所以化妆品已经足够好了,正是我想要的。稍后我会试一试,看看是否可以从旧类型名中复制旧格式。
    • 我很抱歉地说我不需要对属性值进行进一步处理。由于我将输出通过管道传输到 ConvertTo-HTML,因此上述内容不准确。抱歉信息有误,感谢您的帮助。
    猜你喜欢
    • 1970-01-01
    • 2014-07-10
    • 2016-08-30
    • 2019-06-06
    • 1970-01-01
    • 2021-07-19
    • 2018-09-02
    • 2021-06-22
    • 1970-01-01
    相关资源
    最近更新 更多