"$ xyz" и "Write-Host" $xyz"" дают разные результаты

Я хэширую все файлы в одном месте, в исходной папке, и записываю хеши в переменную, а затем делаю то же самое для всех файлов в другом месте, в целевой папке:

$origin = Get-ChildItem .\Test1 | Get-FileHash | Format-Table -Property Hash -HideTableHeaders
$destination = Get-ChildItem .\Test2 | Get-FileHash | Format-Table -Property Hash -HideTableHeaders

Затем я сравниваю их с Compare-Object вот так:

Compare-Object $origin $destination

Теперь в моем тесте у меня целенаправленно есть отклонения, поэтому, когда приведенный выше код не дал никаких различий, я знал, что у меня проблема.

Затем я обнаружил, что если я сделаю следующее, хеш-значений там не будет:

PS> Write-Host "$origin"
Microsoft.PowerShell.Commands.Internal.Format.FormatStartData Microsoft.PowerShell.Commands.Internal.Format.GroupStartData Microsoft.PowerShell.Commands.Internal.Format.FormatEntryData Microsoft.PowerShell.Commands.Internal.Format.Format.EntryData Microsoft.PowerShell.Commands.Internal.Format.Format.EntryData Internal.Format.FormatEntryData Microsoft.PowerShell.Commands.Internal.Format.GroupEndData Microsoft.PowerShell.Commands.Internal.Format.FormatEndData

Однако, если я просто наберу следующее и нажму ввод, то значения хешей будут присутствовать (как я хочу):

PS> $origin

6B86B273FF34FCE19D6B804EFF5A3F5747ADA4EAA22F1D49C01E52DDB7875B4B
D4735E3A265E16EEE03F59718B9B5D03019C07D8B6C51F90DA3A666EEC13AB35
4E07408562BEDB8B60CE05C1DECFE3AD16B72230967DE01F640B7E4729B49FCE

Я предполагаю, когда использую Compare-Object, что мои переменные не представляют хеш-значения, как я ожидал.

Кто-нибудь знает, что происходит или есть какие-то рекомендации? Это используется для обеспечения перемещения файлов из исходного местоположения в целевое (это одна проверка в сценарии, над которым я работаю). Я сохраняю эту чисто PowerShell, а это значит, что нетxcopy или robocopy.

1 ответ

Решение

Повторное использование Format-Table для создания входных коллекций для Compare-Object:

Только когда-либо использовать Format-*командлеты для форматирования дисплея; никогда не используйте их, если данные должны обрабатываться программно.

Format-*командлеты выводят инструкции по форматированию, а не данные - см. этот ответ.

Следовательно:

  • опуститьFormat-Table вызовы из ваших команд определения коллекции ввода:
$origin=Get-ChildItem .\Test1 | Get-FileHash
$destination=Get-ChildItem .\Test2 | Get-FileHash
  • Затем передайте имена свойств для сравнения объектов сCompare-Object:
Compare-Object $origin $destination -Property Path, Hash

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

В качестве отступления: если вы не указали-Property, объекты по умолчанию будут сравниваться по их .ToString() значение - и поскольку Microsoft.PowerShell.Commands.FileHashInfo экземпляров, выводимых Get-FileHashтолько когда-либо преобразовывать в строку с этим именем типа (независимо от их конкретных значений свойств), никаких различий не будет найдено.


Что касается $origin vs. Write-Host $orgin:

  • Просто выполняю $origin неявно похоже на выполнение Write-Output $origin- записывает в поток вывода успеха (см. about_Redirection), который по умолчанию идет в консоль.

  • Write-Host, напротив, служит другой цели, чемWrite-Output:

    • Он записывает данные непосредственно в консоль [1], минуя поток вывода успешных данных PowerShell и тем самым также его обычное форматирование. Его основное предназначение - вывод сообщений о состоянии, интерактивных подсказок и т. Д. На дисплей - в отличие от вывода данных.

    • Write-Host сам применяет форматирование вывода, но только с помощью простого.ToString()строковая спецификация, которая часто приводит к бесполезным представлениям (только по имени), как в вашем случае.

См. Этот ответ для получения дополнительной информации о различиях междуWrite-Output а также Write-Host.


[1] Технически, начиная с версии PowerShell 5, Write-Hostвывод достигает консоли через поток вывода информации (число6), но его основная цель по-прежнему - писать на дисплей, а не выводить данные.

Другие вопросы по тегам