Запись Powershell в .XLSX приводит к повреждению файлов - PullRequest
0 голосов
/ 13 января 2020

У меня есть скрипт Powershell, который циклически просматривает файлы .xslx в папке, и пароль защищает их с помощью имени файла (на данный момент.) У меня нет проблем с циклическим просмотром и записью в .xls, но когда я пытаюсь открыть. Файл xlsx после записи его с помощью Powershell - я получаю сообщение об ошибке:

Excel не может открыть файл 'abcd.xlsx', так как формат файла или расширение файла недопустимы. Убедитесь, что файл не был поврежден и что расширение файла соответствует формату файла.

Вот сценарий:

function Release-Ref ($ref) { 
    ([System.Runtime.InteropServices.Marshal]::ReleaseComObject( 
    [System.__ComObject]$ref) -gt 0) 
    [System.GC]::Collect() 
    [System.GC]::WaitForPendingFinalizers()  
    } 

$e = $ErrorActionPreference
$ErrorActionPreference="continue"
foreach ($f in Get-ChildItem "C:"){
    try{
        $ff = $f
        $xlNormal = -4143 
        $s = [System.IO.Path]::GetFileNameWithoutExtension($f)
        $xl = new-object -comobject excel.application 
        $xl.Visible = $False
        $xl.DisplayAlerts = $False   
        $wb = $xl.Workbooks.Open($ff.FullName)
        $wb.sheets(1).columns("A:S").entirecolumn.AutoFit()
        $wb.sheets(1).columns("N").NumberFormat = "0.0%"
        $a = $wb.SaveAs("C:\Out\" + $s + ".xls",$xlNormal,$s) #works
        #$a = $wb.SaveAs("C:\Out\" + $s + ".xlsx",$xlNormal,$s) #doesn't work
        $a = $xl.Quit() 

        $a = Release-Ref($ws) 
        $a = Release-Ref($wb) 
        $a = Release-Ref($xl) 
    }
    catch {
        Write-Output "Exception"
        $ErrorActionPreference=$e;
    }
}

Я искал другие вопросы, но могу не найдете других примеров таких же проблем, написанных из Powershell. Спасибо.

Ответы [ 2 ]

1 голос
/ 14 января 2020

Проблема вызвана тем, что формат Xls отличается от формата Xlsx. В предыдущих версиях Excels до версии 2007 использовались двоичные форматы. В Office 2007 были представлены новые форматы, названные Office Open Xml, которые использует Xslx.

Excel достаточно умен, чтобы проверять как расширение файла, так и формат файла. Поскольку сохранение бинарного файла с расширением новых версий создает конфликт, сообщение об ошибке также указывает на эту возможность:

и что расширение файла соответствует формату файла.

Почему Excel все равно не открывает файл? Я предполагаю, что это функция безопасности, которая предотвращает непреднамеренное открытие документов Office. В те времена Офисные макровирусы были проклятием многих офисов. Одним из основных способов заражения было обмануть пользователей, чтобы они открывали файлы без мер предосторожности. В отличие от вирусов classi c, макросы заражают данные приложения (включая файлы шаблонов по умолчанию) вместо двоичных файлов ОС, но это еще одна история.

В любом случае, для работы в правильном формате используйте правильную версию значение . Это будет -4143 для Xls и 51 для Xlsx. Более того, Get-ChildItem возвращает коллекцию объектов FileInfo , а расширение файла содержится в свойстве Extension . Вот так

# Define Xls and Xlsx versions
$typeXls = -4143
$typeXls = 51
foreach ($f in Get-ChildItem "C:"){

    try{
    $ff = $f
    ...
   # Select saveas type to match original file extension
   if($f.extension -eq '.xsl') { $fType = $typeXls }
   else if($f.extension -eq '.xslx') { $fType = $typeXlsx }

   $a = $wb.SaveAs("C:\Out\" + $s + $.extension, $fType, $s)
1 голос
/ 14 января 2020

Работа с com-объектами слишком сложна, иногда с Excel. Я рекомендую модуль import-excel. Install-Module -Name ImportExcel

Тогда вы можете сделать что-то вроде этого.

function Release-Ref ($ref) { 
    $e = $ErrorActionPreference
    $ErrorActionPreference="continue"

foreach ($f in Get-ChildItem $file){
    try{
        $filePass = gci $f
        $path = split-path $f
        $newFile = $path + "\" + $f.BaseName + "-protected.xlsx"
        $f | Export-excel $newFile -password $filePass -NoNumberConversion * -AutoSize
    }
    catch {
        Write-Output "Exception"
        $ErrorActionPreference=$e;
    }
}
}
...