Не могу понять, почему при запуске следующего скрипта в файле расшифровки не появляется второй "запись-вывод"???
start-transcript -Path "c:\temp\test_transcript.txt" -Append;
$acl = Get-Acl "c:\temp";
$acl | Format-Table -Wrap;
Write-Output "1) A very simple message BEFORE new-item.";
New-Item -Path "C:\temp" -Name "test_file_$(get-date -f "yyyyMMdd_HHmmss").txt" -ItemType File -Verbose -ErrorAction Stop;
#Why is th second message not included int the transcript log file ???
Write-Output "2) A very simple message AFTER new-item.";
Stop-Transcript;
Вот что я получаю в файле стенограммы:
У кого-нибудь есть объяснение этому?
ФАЙЛ ТЕХНОЛОГИИ:
Transcription démarrée, le fichier de sortie est c:\temp\test_transcript.txt
Répertoire : C:\
Path Owner Access
---- ----- ------ temp MyDomain\MyUser BUILTIN\XXX Allow FullControl
AUTORITE NT\XXX Allow FullControl
BUILTIN\XXX Allow ReadAndExecute, Synchronize
AUTORITE NT\XXX authentifiés Allow Modify, Synchronize
1) A very simple message BEFORE new-item.
EN CLAIR : Opération « Créer un fichier » en cours sur la cible « Destination : C:\temp\test_file_20230109_124005.txt ».
**********************
Fin de la transcription Windows PowerShell
Heure de fin : 20230109124005
**********************
КОНСОЛЬ :
Transcription démarrée, le fichier de sortie est c:\temp\test_transcript.txt
Répertoire : C:\
Path Owner Access
---- ----- ------
temp MyDomain\MyUser BUILTIN\XXX Allow FullControl
AUTORITE NT\XXX Allow FullControl
BUILTIN\XXX Allow ReadAndExecute, Synchronize
AUTORITE NT\XXX authentifiés Allow Modify, Synchronize
1) A very simple message BEFORE new-item.
EN CLAIR : Opération « Créer un fichier » en cours sur la cible « Destination : C:\temp\test_file_20230109_124005.txt ».
Répertoire : C:\temp
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 09/01/2023 12:40 0 test_file_20230109_124005.txt
2) A very simple message AFTER new-item.
Transcription arrêtée, le fichier de sortie est C:\temp\test_transcript.txt
Оберните New-Item
в блок try{}catch{}
и посмотрите, что появится в стенограмме: try { New-Item -Path "C:\temp" -Name "test_file_$(get-date -f "yyyyMMdd_HHmmss").txt" -ItemType File -Verbose -ErrorAction Stop} catch {"New-Item failed!"}
— я ожидаю, что если New-Item
не удастся, вы увидите New-Item failed!
в своей стенограмме.
Кроме того, чтобы избежать путаницы между оператором -f и параметром -Format
Get-Date
, используйте -For
вместо -f
в качестве параметра Get-Date
.
Спасибо. Новый элемент завершен успешно. Но я перепроверю, напишу try/catch, как вы говорите, и буду держать вас в курсе.
Точно такое же поведение с try...catch и -For вместо -f. Ошибок нет, но второе сообщение не появляется. Должен признаться, я заблудился...
@Scepticalist - на скриншоте показан нижний колонтитул в файле из Stop-Transcript
, поэтому, предположительно, скрипт завершился. Я подумал, что это может быть связано с задержкой в 300 мс, встроенной в Format-Table
дальше по сценарию, что означает, что Stop-Transcript
вызывается до того, как весь вывод будет записан в расшифровку, но я не смог воспроизвести проблему локально, чтобы проверить это.
Интересно: я не знал об этой задержке в 300 мс: это может быть объяснением. Могу ли я вставить Start-Sleep() в конец моего скрипта? это решит проблему? Или есть какой-то метод flush()? Одно можно сказать наверняка: удаление строки таблицы форматов решает проблему.
Пахнет как эта известная проблема: github.com/PowerShell/PowerShell/issues/10994
Спасибо @BaconBits: очень интересная ссылка. Я еще не все читал, но очень похоже.
Простым обходным решением было бы направить любой «неявный» вывод в Out-Host
или Out-String
, чтобы сделать его «явным». .например. Write-Output … | Out-Host
, что превращает его в операцию блокировки, которая завершится до вызова следующей строки. Однако это добавит много мусора в ваш код. Я не думаю, что Start-Sleep
сработает, потому что он блокирует Format-Table
, насколько я помню, поэтому вы просто окажетесь в том же положении через 2 секунды. Не стесняйтесь попробовать и доказать, что я ошибаюсь :-)
Опираясь на полезные комментарии:
тл;др
Вы видите ошибку (хотя она не классифицируется как таковая), которая является одним из нескольких проявлений асинхронного поведения, когда PowerShell неявно применяет Format-Table
форматирование для отображения.
Обходные пути, все неоптимальные, к сожалению:
Для каждой команды [громоздкий, подверженный ошибкам]: явно используйте командлет Format-*
с любым вызовом, который обычно приводит к форматированию таблицы по умолчанию, чтобы принудительно синхронизировать вывод; в вашем случае поставьте | Format-Table
после звонка New-Item
.
Format-Table
предотвращает захват вывода команды в виде данных, когда вы пытаетесь присвоить значение переменной или обработать вывод дальше в конвейере, потому что командлеты Format-*
выдают инструкции по форматированию, а не данные.Для всего скрипта [вводит задержку в 300 мс]: как вы обнаружили, вставка Start-Sleep в конце помогает при следующих условиях:
Сценарий должен заканчиваться командой, которая синхронно выводит в выходной поток успеха (т. е. он не должен быть неявно отформатирован в виде таблицы), в частности, путем вывода строки, например, в вашем вызове Write-Output "2) A very simple message AFTER new-item."
. (Обратите внимание, что вы можете опустить Write-Output
, чтобы воспользоваться неявным поведением вывода PowerShell).
Start-Sleep -MilliSeconds 300
должен быть размещен непосредственно перед ним, что заставляет следующий синхронный вывод также отображать ожидающий асинхронный вывод.
Однако из-за другого конструктивного ограничения в системе форматирования вывода PowerShell для отображения, которая отделена от асинхронного поведения (обратите внимание, что ни то, ни другое не относится к использованию Start-Transcript
, но последнее проявляется способом, специфичным для этого командлета), существует общее ловушка, если вы не используете вызовы Format-Table
явно:
Format-Table
для каждой команды избегают этой проблемы (а также принудительно синхронизируют вывод) за счет отсутствия вывода данных, как отмечалось выше.Упрощенный пример:
Start-Transcript t.txt
# This triggers *implicit* Format-Table output that is *asynchronous*,
# due to the output object having 4 or fewer properties and
# its type not having formatting-data associated with, as with the
# Get-Acl output in your question.
# NOTE:
# * Curiously, the asynchronous behavior is also triggered in this case
# if you append | Format-Table, but only affects SUBSEQUENT
# implicitly table-formatted statements, including those whose
# output types DO have formatting-data.
[pscustomobject] @{ Foo = 'Bar' }
# WORKAROUND:
# Sleep for 300 msecs., then output *synchronously* to the success output stream.
# This forces pending asynchronous table output to print.
Start-Sleep -Milliseconds 300
"==== Done."
Stop-Transcript
Вы видите еще одно проявление печально известных 300 мс. задержка, которая возникает, когда Format-Table
форматирование неявно применяется к выводу, который идет на дисплей — подробности см. этот ответ.
Хотя типичным проявлением является то, что выходные данные появляются не по порядку (в разных выходных потоках), в вашем случае информация теряется, что, очевидно, является более серьезной проблемой. Потеря данных также может произойти с интерфейсом командной строки PowerShell. См. проблемы GitHub ниже.
Соответствующие проблемы GitHub:
GitHub issue #10994 : существующая проблема ( Start-Transcript).
GitHub issue #4594: обсуждение неожиданного асинхронного поведения в целом (вывод появляется не по порядку).
GitHub issue #13985: потенциальная потеря данных при использовании CLI.
Отличный ответ! В итоге я добавил строку «Start-Sleep -Seconds 1;» перед моим последним вызовом записи-вывода. Конечно, это не элегантное решение msot, но это избавляет от необходимости ставить «| format-table» после каждого нестрокового объекта. Плюс 1-секундная задержка в конце скрипта в моем контексте не имеет большого значения. Спасибо за помощь !
New-Item
завершается успешно? Поскольку-ErrorAction Stop
вызывает эффект, который вы видите, сценарий останавливается в этой точке, если New-Item вызывает ошибку.