Импортировать данные в CSV-массив - PullRequest
2 голосов
/ 28 марта 2019

У меня есть файл CSV, который содержит несколько строк в некоторых ячейках.Я буду использовать эти данные для сравнения значения, полученного из powershell.

Это возвращает различия между объектами, однако значение одинаково.

Ожидаемые результаты не должны возвращать ничего, поскольку оба значения являютсяТо же самое.

Содержимое CSV:

Value
System\CurrentControlSet\Control\ProductOptions
System\CurrentControlSet\Control\Server Applications
Software\Microsoft\Windows NT\CurrentVersion

Код:

PS> $data = Import-Csv .\tr.csv

PS> $data.Value
System\CurrentControlSet\Control\ProductOptions
System\CurrentControlSet\Control\Server Applications
Software\Microsoft\Windows NT\CurrentVersion

PS> $regval = ((Get-ItemProperty HKLM:\SYSTEM\CurrentControlSet\Control\SecurePipeServers\winreg\AllowedExactPaths).machine | Out-String).Trim()

PS> $regval
System\CurrentControlSet\Control\ProductOptions
System\CurrentControlSet\Control\Server Applications
Software\Microsoft\Windows NT\CurrentVersion

PS> Compare-Object $data.Value $regval
System\CurrentControlSet\Control\ProductOptions...                                                                                                  =>
System\CurrentControlSet\Control\ProductOptions...                                                                                                  <=

PS> $Tostring = ($data.Value | out-string).Trim()

PS> Compare-Object $Tostring $regval

InputObject                                                                                                                                         SideIndicator
-----------                                                                                                                                         -------------
System\CurrentControlSet\Control\ProductOptions...                                                                                                  =>
System\CurrentControlSet\Control\ProductOptions...                                                                                                  <=


PS> $Tostring.Length
145

PS> $regval.Length
147

Ответы [ 2 ]

3 голосов
/ 28 марта 2019

Эта публикация больше не отвечает на вопрос ОП напрямую, но содержит справочную информацию, которая полезна для подобных ситуаций. Эта конкретная проблема решается путем обработки символов CR и LF перед сравнением данных. Подробнее см. Отмеченный ответ .

Поскольку $data в данном случае является объектом со свойством value, в котором хранятся ваши данные, вам необходимо сравнить то, что хранится в свойстве value, с вашим $regval:

Compare-Object $data.value $regval

$regval - это массив строк до того, как вы передадите его в Out-String. После канала он становится a строковым объектом . Ниже приведена информация о типе перед подачей на Out-String.

$regval.gettype().fullname
System.String[]

$data - это массив объектов (PSCustomObjects), у каждого из которых есть свойство с именем Value, на которое необходимо напрямую ссылаться, если вы хотите получить его данные:

$data.gettype().fullname
System.Object[]

$data | Get-Member

   TypeName: System.Management.Automation.PSCustomObject

Name        MemberType   Definition
----        ----------   ----------
Equals      Method       bool Equals(System.Object obj)
GetHashCode Method       int GetHashCode()
GetType     Method       type GetType()
ToString    Method       string ToString()
Value       NoteProperty string Value=System\CurrentControlSet\Control\ProductOptions

($regval | Get-member).where({$_.MemberType -eq "Property"})

   TypeName: System.String

Name   MemberType Definition
----   ---------- ----------
Length Property   int Length {get;}

Для сравнения данных двух объектов с использованием Compare-Object наилучшие результаты, по-видимому, достигаются, когда объекты представляют собой коллекции одного типа. PowerShell автоматически выполняет преобразования в фоновом режиме в некоторых случаях, например Compare-Object "1" 1. Может быть, это как-то связано с типами значений, так как я не совсем уверен. Я бы сделал сравнение перед преобразованием любых ваших данных в различные типы. Затем, если вы ссылаетесь на свойство Value $data, это условие становится истинным:

$data.value | Get-member -type Property

   TypeName: System.String

Name   MemberType Definition
----   ---------- ----------
Length Property   int Length {get;}

Вы можете сослаться на объяснение MKlement0 для получения дополнительной информации о том, как PowerShell обрабатывает тип массива.

1 голос
/ 28 марта 2019

Наиболее вероятное объяснение состоит в том, что:

  • многострочное значение из вашего CSV (полученное из одного поля ) содержит LF-только (в стиле Unix) новые строки,
  • , тогда как строка , полученная из значений реестра , имеет CRLF (стиль Windows) новые строки из-за примененияOut-String в массив строк.

Самое прямое решение - удалить символы CR.с $regval (вы можете использовать "`r" в PowerShell для генерации символа CR):

# ...

# Remove all CRs from $regval.
# Note that not providing a replacement string (missing 2nd RHS operand)
# default to the empty string, which effectively *removes* what was matched.
$regval = $regval -replace "`r"

# Should now work as expected.
Compare-Object $data.Value $regval

При этом:

  • Поскольку вы сравниваете толькодва объекта, которые являются строками, вы можете избежать издержек Compare-Object и просто использовать -eq:

    $data.Value -eq $regVal
    
  • В качестве альтернативы, вы можете разбить многострочные значения на массивылинии и сравнить их по отдельности;обратите внимание, что если вы используете регулярное выражение "`r?`n" или ('\r?\n') для сопоставления новых строк, чтобы разделить на - что совпадает как с новыми строками LF, так и с новыми строками CRLF - вам не нужно удалять символы CR.заранее или даже применить Out-String к выводу массива из вызова Get-ItemProperty HKLM:\... для начала;однако со значениями переменных из вашего вопроса вы должны использовать:

    # Newline-style-agnostic
    Compare-Object ($data.Value -split "`r?`n") ($regval -split "`r?`n")
    
    # Or, knowing that $data.Value has LF, and $regval CRLF
    Compare-Object ($data.Value -split "`n") ($regval -split "`r`n")
    
    # Or, by using the [string[]] array of registry values directly:
    $regvals = (Get-ItemProperty HKLM:\SYSTEM\CurrentControlSet\Control\SecurePipeServers\winreg\AllowedExactPaths).machine
    Compare-Object ($data.Value -split "`n") $regvals
    

Что касается того, что вы пытались:

$Tostring = ($data.Value | out-string).Trim()

Если $data.Value является одиночной строкой, в которой нет завершающего символа новой строки - независимо от того, встроен ли переводы строк - выше приведено эффективное бездействие :

  • Входной объект, который уже является строкой, передается через как есть с помощью Out-String.
  • Хотя Out-String добавляет завершающий символ новой строки CRLF (в Windows), последующий вызов .Trim() снова удаляет его.
...