PS Скрипт экспортирует пустые CSV

Я чертовски стараюсь понять, почему этот скрипт не работает так, как задумано. Это простой скрипт, в котором я пытаюсь импортировать CSV, выбрать несколько нужных столбцов, затем экспортировать CSV и скопировать сам. (По сути, мы заархивировали данные, из-за которых мне не хватало объема памяти, мне нужно всего несколько столбцов для другого проекта). Этот сценарий очень прост, и, очевидно, имеет обратную зависимость от того, какое разочарование он вызывает, когда он не работает... Прямо сейчас конечный результат - я получаю пустой CSV вместо CSV, содержащего только выбранные мной столбцы. с помощью Select-Object.

$RootPath = "D:\SomeFolder"

$csvFilePaths = Get-ChildItem $RootPath -Recurse -Include *.csv | 
    ForEach-Object{
        Import-CSV $_ |
        Select-Object Test_Name, Test_DataName, Device_Model, Device_FW, Data_Avg_ms, Data_StdDev | 
        Export-Csv $_.FullName -NoType -Force
}

3 ответа

Решение

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

В частности, такая команда, как Import-Csv file.csv | ... | Export-Csv file.csv сотрет содержимое file.csv,

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

  • Содержимое файла (преобразованное в объекты) должно помещаться в памяти в целом.

  • Существует риск потери данных, если конвейер прерывается до того, как все (преобразованные) объекты будут записаны обратно в файл.

Применительно к вашей команде:

$RootPath = "D:\SomeFolder"

Get-ChildItem $RootPath -Recurse -Include *.csv -OutVariable csvFiles | 
    ForEach-Object{
        (Import-CSV $_.FullName) | # NOTE THE (...)
          Select-Object Test_Name, Test_DataName, Device_Model, Device_FW, 
                        Data_Avg_ms, Data_StdDev | 
            Export-Csv $_.FullName -NoType -Force
}

Обратите внимание, что я использовал -OutVariable csvFiles для того, чтобы собрать объекты CSV file-info в выходной переменной $csvFiles, Ваша попытка собрать пути к файлам через $csvFilePaths = ... не работает, потому что пытается собрать Export-Csv выходной, но Export-Csv не производит никакого вывода.

Кроме того, чтобы быть в безопасности, я изменил Import-Csv аргумент от $_ в $_.FullName чтобы убедиться, что Import-Csv находит входной файл (потому что, к сожалению, объект file-info $_ связан как строка, которая иногда расширяется до простого имени файла).


Более безопасным решением было бы сначала вывести во временный файл и (только) при успешном завершении заменить исходный файл.

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

Как прокомментировал Мэтт, ваш последний $PSItem ($_) не связано с Get-ChildItem больше, но для Select-Object Командлет, который не имеет FullName Имущество

Вы можете использовать другой подход foreach:

$RootPath = "D:\SomeFolder"
$csvFilePaths = Get-ChildItem $RootPath -Recurse -Include *.csv

foreach ($csv in $csvFilePaths)
{
Import-CSV $csv.FullName |
Select-Object Test_Name,Test_DataName,Device_Model,Device_FW,Data_Avg_ms,Data_StdDev | 
Export-Csv $csv.FullName -NoType -Force
}

Или сохраняя свой код, добавьте $CsvPath Переменная, содержащая путь CSV и использовать его позже:

$RootPath = "D:\SomeFolder"
Get-ChildItem $RootPath -Recurse -Include *.csv | ForEach-Object{
$CsvPath = $_.FullName
Import-CSV $CsvPath |
Select-Object Test_Name,Test_DataName,Device_Model,Device_FW,Data_Avg_ms,Data_StdDev | 
Export-Csv $CsvPath -NoType -Force
}

Итак, я понял это. Я пытался напрямую передать командлет Import-Csv вместо объявления его в качестве переменной в коде og. Вот фрагмент кода, который получает то, что я хотел сделать. Я пытался передать конвейер непосредственно в командлет Import-Csv, мне просто нужно было объявить переменную, использующую командлет Import-Csv в качестве определения, и направить эту переменную в Select-Object, а затем в командлеты Export-Csv. Спасибо всем за помощь, я ценю это!

$RootPath = "\someDirectory\"
$CsvFilePaths = @(Get-ChildItem $RootPath -Recurse -Include *.csv)
$ColumnsWanted = @('Test_Name','Test_DataName','Device_Model','Device_FW','Data_Avg_ms','Data_StdDev')
for($i=0;$i -lt $CsvFilePaths.Length; $i++){
  $csvPath = $CsvFilePaths[$i]
  Write-Host $csvPath
  $importedCsv = Import-CSV $csvPath 
  $importedCsv | Select-Object $ColumnsWanted | Export-CSV $csvPath -NoTypeInformation
}
Другие вопросы по тегам