Командлет Select-Object возвращает разные форматированные результаты для Get-NetIPConfiguration (другой тип)

#powershell

#powershell

Вопрос:

Я пытался получить сведения о конфигурации 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:WINDOWSsystem32> $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
  

Мой вопрос в том, почему это происходит? И есть ли какой-либо метод, который я могу использовать для преобразования их в правильный формат? Последний формат — тот, который я хочу.

Комментарии:

1. Select-object изменяет тип с netipconfiguration на pscustomobject, но нет такого типа, чтобы привести его обратно?

2. @js2010 Ну, этот быстрый и грязный взлом не сработал: (Get-NetIPConfiguration | Select-Object ComputerName, DNSServer) | %{$_.PSTypeNames.Insert(0, 'NetIPConfiguration') ; $_}

3. @beatcracker или это Get-NetIPConfiguration | % { [pscustomobject]@{ipv4address = $_.ipv4address;dnsserver=$_.dnsserver;ipv4defaultgateway=$_.ipv4defaultgateway;pstypename='netipconfiguration'}}

4. Я добавил псевдоответ ниже, чтобы объяснить, какие дальнейшие шаги я предпринял для достижения окончательного решения. ответ @beatcracker является правильным ответом.

Ответ №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 файлах: Обзор файлов форматирования. Для NetTCPIP модуля файл будет C:WindowsSystem32WindowsPowerShellv1.0ModulesNetTCPIPTcpip.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
  

Увы, простая установка его обратно не сработает (у объекта нет правильной структуры для этого), но вы можете эмулировать его, используя вычисляемое свойство:

 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)}}
  

Комментарии:

1. Спасибо за дальнейшее чтение. Это решение, которое я использую прямо сейчас, и только сервер DNSServer выглядит немного странно, поскольку все находится в одной строке. Я подключаюсь к DNSServer с помощью «`n «, чтобы он, по крайней мере, имел лучшую читаемость.

Ответ №2:

Я не стал указывать, что я передаю весь вывод в командлет ConvertTo-HTML, чтобы не выводить вопрос за рамки. Но поскольку я конвертирую выходные данные в HTML, это означает, что существует более 1 способа скинуть cat. Мне не нужно принудительно возвращать объект DNSServer к его предыдущему форматированию.

Итак, вместо того, чтобы присоединяться к DNSServer с помощью ‘, ‘, я присоединил к нему <br> тег вместо этого.

 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;< и amp;> соответственно, я добавил следующий код для перевода amp;< и amp;> обратно в <>.

 $IPAddressConfigTemp = $IPAddressConfig | ConvertTo-Html -fragment -As List -PreContent "<h2>IP Address Configuration Details</h2>"
$IPAddressConfigHTML = $IPAddressConfigTemp -replace "amp;<", "<" -replace "amp;>", ">" -replace "amp;#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 приводит к созданию нового объекта с новым типом (Выбран.NetIPConfiguration, передайте в Get-Member, чтобы увидеть это).

Форматирование в PowerShell основано на типах, поэтому форматирование заключается в том, чтобы видеть новый тип, а не применять форматирование из старого типа.

Предположительно, вы могли бы применить новое имя типа (используя свойство PSTypeNames) и скопировать инструкции по форматированию из старого имени типа (NetIPConfiguration) в новое.

Обратите внимание, что разница в форматировании не подразумевает никакой разницы в значениях свойств, это чисто косметическое.

Комментарии:

1. Спасибо. Мне не нужно выполнять дальнейшую обработку значений свойств, так что косметика достаточно хороша и именно то, что я хочу. Я попробую позже, чтобы посмотреть, смогу ли я скопировать старое форматирование из старого typename.

2. Я извинился, сказав, что мне не нужно выполнять дальнейшую обработку значений свойств. Поскольку я передаю выходные данные в ConvertTo-HTML, поэтому приведенное выше не является точным. Извините за неверную информацию и спасибо за вашу помощь.