Проблема связана с объектами, потоками и попыткой заставить два разных объекта объединиться в один поток.То, что происходит, проиллюстрировано моим SO-ответом здесь: Запуск строки за строкой дает странный результат по сравнению с бегущими строками в виде одной строки с точками с запятой
TLDR: в основном происходит то, что вы пытаетесьчтобы передать 2 разных объекта по одному и тому же конвейеру (см. about_Redirection ), и PowerShell выполняет интерпретацию «из лучших сил», которая представляет собой «bleahh -> blank» интерпретацию, когда она достигает Export-CSV
.Это также объясняет, почему вывод на консоль не отображается.
Лучший способ интерпретировать происходящее по каналу - разбить его и присвоить переменным, чтобы увидеть, что происходит:
Развертывание цикла, Первая команда и тип:
PS C:\> $csv = Import-Csv a.csv
PS C:\> $csv.GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Object[] System.Array
Вторая команда:
PS C:\> $ri = Remove-Item a.csv -Verbose 4>&1 | tee .\log.txt -Append
PS C:\> $ri.GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True False VerboseRecord System.Management.Automation.InformationalRecord
В основном происходит следующее: Первая команда:
Import-CSV ...
Вывести массив Object[]
в поток информации (1).
Вторая команда:
Remove-Item -Verbose
Вывод в поток Verbose (4).
Третья команда, перенаправление: 4> & 1 ...
Выводит содержимое подробного потока (4) в поток информации (1).
Четвертая команда,
... | tee .\log.txt -Append
Принимает перенаправленный вывод Remove-Item
для информации (1).) и выводит в оба потока информации (1) и файла журнала.
Когда мы объединяем их внутри цикла ForEach-Object, мы создаеммассив конкурирующих объектов в потоке информации (1) :
PS C:\> 1..2|foreach{$csv; $ri}
server Database role members
------ -------- ---- -------
server1 DB1 role1 memberx
server1 DB1 role2 membery
VERBOSE: Performing the operation "Remove File" on target "C:\a.csv".
server1 DB1 role1 memberx
server1 DB1 role2 membery
VERBOSE: Performing the operation "Remove File" on target "C:\a.csv".
Затем эти конкурирующие объекты передаются по конвейеру следующей команде Export-Csv
:
1..2 | foreach{$csv,$ri} | Export-Csv .\out.csv -NoTypeInformation
Это дает нам «сырой» CSV:
"server","Database","role","members"
"server1","DB1","role1","memberx"
"server1","DB1","role2","membery"
,,,
"server1","DB1","role1","memberx"
"server1","DB1","role2","membery"
,,,
, где мы можем ясно видеть, как 4 объекта передавались по конвейеру.Export-Csv
получает 4 объекта:
Object[]
массив VerboseRecord
объект (перенаправленный вывод Remove-Item -Verbose
) - Второй
Object[]
массив - второй
VerboseRecord
объект
Именно здесь PowerShell возьмет первый Object[]
объект массива для построения структуры файла Export-Csv
.Затем он возьмет объект VerboseRecord
и, поскольку у него нет способа «вписать» его в CSV, он выводит пустую запись.Затем он берет второй Object[]
и, поскольку он «подходит», выведет его в CSV.Затем он возьмет второй VerboseRecord
объект и, опять же, поскольку у него нет способа «вписать» его в CSV, он выводит пустую запись.
Обратите внимание, что все 4 объектав CSV, даже если PowerShell не знал, что с ними делать.Вот почему вы не видите вывод на консоли PowerShell.Содержимое потока информации (1) полностью направляется вниз по конвейеру для использования командлетом Export-Csv
, а , а не консольным хостом. Именно по этой вы не «видите» вывод -Verbose
команды Remove-Item
на консоли, но видите его в файле.
TLDR2: Урок 1: Не выводите несколько вещей в конвейер, если у вас есть что-то, что потребляет это в конце.С конвейерами старайтесь работать только с одной вещью одновременно.
Код можно исправить двумя способами: если вам нужны конвейеры, разделите две операции на ... ну ... две операции, чтобы предотвратить повреждениеконвейера:
$csvfiles | ForEach-Object {
Import-Csv "$csvLocation\$_";
} | Export-Csv -NoTypeInformation "$csvLocation\$DBName.csv" -Force
$csvfiles | ForEach-Object {
Remove-Item "$csvLocation\$_" -Verbose 4>&1 | tee .\log.txt -Append
}
Или, ИМХО, не переводите ForEach в конвейер и ожидайте, что все будет работать, поскольку перед передачей вещи могут быть накоплены в памяти.Исключите конечного потребителя конвейера, вставьте Export-Csv
в цикл ForEach-Object
и добавьте в него свой контент.
Редактирование: не забудьте сначала начать с пустого файла CSV: -)
Remove-Item "$csvLocation\$DBName.csv" -ErrorAction SilentlyContinue
$csvfiles | ForEach-Object {
Import-Csv "$csvLocation\$_" | Export-Csv -Append -NoTypeInformation "$csvLocation\$DBName.csv" -Force;
Remove-Item "$csvLocation\$_" -Verbose 4>&1 | tee .\log.txt -Append
}