Ответ 1
Решение:
Windows содержит еще одну встроенную утилиту сжатия: CreateFromDirectory
в командной строке PowerShell.
Для этого требуется .Net 4.0 или новее:
> Add-Type -AssemblyName System.IO.Compression
> $src = "C:\Users\v1453957\documents\Experiment\rezip\aFolder"
> $zip="C:\Users\v1453957\Documents\Experiment\rezip\my.zip"
> [io.compression.zipfile]::CreateFromDirectory($src, $zip)
Примечание. Возможно, вам придется предоставить полные пути: активный каталог не был неявным на моей машине.
Вышеуказанное сжатие синхронно в командной строке PowerShell, как и запросы OP.
Следующий шаг выполняется синхронно с VBA. Решение есть метод .Run
в Windows Script Модель объекта хоста. В VBA установите ссылку на это и выполните следующие действия, установив третий параметр команды .Run
, bWaitOnReturn
- True
:
Function SynchronousShell(sCmd As String)As Long
Dim oWSH As New IWshRuntimeLibrary.WshShell
ShellSynch = oWSH.Run(sCmd, 3, True)
Set oWSH = Nothing
End Function
Теперь вызовите SynchronousShell
и передайте ему все сжатие script.
Я считаю, что единственный способ для этого процесса - работать, если CreateFromDirectory
выполняется в том же сеансе, что и Add-Type
.
Итак, мы должны передать все это как одну строку. То есть загрузите все 4 команды в одну переменную sCmd
, так что Add-Type
останется связанной с последующим CreateFromDirectory
. В синтаксисе PowerShell вы можете разделить их на ;
https://thomas.vanhoutte.be/miniblog/execute-multiple-powershell-commands-on-one-line/
Кроме того, вам нужно использовать одиночные кавычки вместо двойных кавычек, иначе двойные кавычки вокруг строк удаляются, когда команды с последовательным соединением передаются в файл powershell.exe
fooobar.com/questions/30032/...
sCmd = "ps4 Add-Type -AssemblyName System.IO.Compression; $src = 'C:\Users\v1453957\documents\Experiment\rezip\aFolder'; $zip='C:\Users\v1453957\Documents\Experiment\rezip\my.zip'; [io.compression.zipfile]::CreateFromDirectory($src, $zip)"
Решено. Вышеупомянутое представляет собой полное решение.
Дополнительная информация: Дополнительные комментарии ниже приведены для особых обстоятельств:
Многопользовательские среды .Net
Если .NET < 4.0 - это активная среда вашей ОС, тогда System.IO.Compression
не существует - команда Add-Type
завершится с ошибкой. Но если на вашей машине есть сборки .NET 4, вы все равно можете сделать это:
-
Создайте пакетный файл, который запускает PowerShell с .Net 4. См. fooobar.com/questions/30024/...
-
В приведенной выше команде
Add-Type
используйте точный путь к сборке .Net 4 Compression. На моем Win Server 2008:
Add-Type -Path "C:\Windows\Microsoft.NET\assembly\GAC_MSIL\System.IO.Compression.FileSystem\v4.0_4.0.0.0__b77a5c561934e089\System.IO.Compression.FileSystem.dll"
Портативность
Оказывается, на моей машине я могу скопировать dll компрессии в любую папку и сделать вызовы к копии, и она работает:
Add-Type -Path "C:\MyFunnyFolder\System.IO.Compression.FileSystem.dll"
Я не знаю, что необходимо для обеспечения этого - может потребоваться, чтобы полные .Net 4.0 или 2.0 файлы были расположены в ожидаемых каталогах. Я предполагаю, что dll вызывает вызовы на другие сборки .Net. Может быть, нам просто повезло с этим:)
Лимит символов
В зависимости от глубины наших путей и имен файлов, количество символов может быть проблемой. PowerShell может иметь ограничение в 260 символов (не уверен).
https://support.microsoft.com/en-us/kb/830473
Так как .Run
проходит через оболочку Windows, вам также нужно беспокоиться об этом лимите, но в 8k + это немного просто:
https://blogs.msdn.microsoft.com/oldnewthing/20031210-00/?p=41553
fooobar.com/questions/30045/...
Сайт ниже предлагает метод 24k + character, но я еще не изучил его: http://itproctology.blogspot.com/2013/06/handling-freakishly-long-strings-from.html
Как минимум, поскольку мы можем поместить dll везде, где захотим, мы можем поместить его в папку рядом с C: root - сохраняя наш счетчик символов.
Обновление: Этот пост показывает, как мы можем поместить все это в файл script и вызвать его с помощью ps4. CMD. Это может стать моим предпочтительным ответом:
.\ps4.cmd GC .\zipper.ps1 | IEX
- в зависимости от ответа здесь.
CopyHere:
Возьмем вопрос: может ли команда CopyHere
выполнить команду в командной строке?
CopyHere
может выполняться непосредственно в приглашении PowerShell (код ниже). Однако даже в powershell он асинхронный - управление возвращается к запросу PowerShell до завершения процесса. Поэтому никакого решения для ОП нет. Вот как это делается:
> $shellapp=new-object -com shell.application
> $zippath="test.zip"
> $zipobj=$shellapp.namespace((Get-Location).Path + "\$zippath")
> $srcpath="src"
> $srcobj=$shellapp.namespace((Get-Location).Path + "\$srcpath")
> $zipobj.Copyhere($srcobj.items())