"$ 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), который по умолчанию идет в консоль.- Успешный вывод, который поступает на консоль, автоматически форматируется с помощью богатой системы форматирования вывода PowerShell.
Write-Host
, напротив, служит другой цели, чемWrite-Output
:Он записывает данные непосредственно в консоль [1], минуя поток вывода успешных данных PowerShell и тем самым также его обычное форматирование. Его основное предназначение - вывод сообщений о состоянии, интерактивных подсказок и т. Д. На дисплей - в отличие от вывода данных.
Write-Host
сам применяет форматирование вывода, но только с помощью простого.ToString()
строковая спецификация, которая часто приводит к бесполезным представлениям (только по имени), как в вашем случае.
См. Этот ответ для получения дополнительной информации о различиях междуWrite-Output
а также Write-Host
.
[1] Технически, начиная с версии PowerShell 5, Write-Host
вывод достигает консоли через поток вывода информации (число6
), но его основная цель по-прежнему - писать на дисплей, а не выводить данные.