将Powershell脚本嵌入VBA宏中并从那里运行

时间:2018-06-28 14:42:42

标签: vba powershell cmd

我正在尝试编写这段简洁的代码,并且在最后部分遇到一些重大问题。因此,目的是编写一个代码,将其放入文件夹中的所有.zip文件中,按名称在每个文件夹中找到一个文件夹,进入内部,找到以“ _nl.inp”结尾的文件,然后将其复制到归档文件之外。 / p>

在深入研究VBA的过程中,我只能找到如何解压缩整个存档的方法,而不仅仅是找到文件并将其拉出。但是我设法找到了如何使用Powershell语言来做到这一点。因此,我编写了一个功能精美的Powershell脚本。该脚本在下面。

$zZipFileName = "C:\Users\ccapsun2\Desktop\New loads formatting\load decks"
      $shap = new-object -com shell.application
      $folderitems = get-childitem $zZipFileName
      foreach($archive in $folderitems){
        $archive.name.substring(0,$archive.name.length -4)
        $zipFile = $shap.Namespace($archive.fullname) 
        $i = $zipFile.items()
        foreach($si in $i){ 
            if($si.getfolder -ne $null){
                 if($si.name -eq "LR_Front_Upper_Control_Arm"){ 
                     $fileSearch = $si.getfolder.Items()
                     foreach($sii in $fileSearch){
                         if ($sii.name.substring(($sii.name.length - 7),7) -eq "_nl.inp"){
                              $shap.namespace($zZipFileName).copyhere($sii)
                              rename-item ($zZipFileName + "\" + $sii.name) -newname ($archive.name.substring(0,$archive.name.length -4) + ".inp")
                         }
                     }
                 } 
            }
        }
     }

现在,此脚本可以正常工作,但我需要将vba代码中赋予$ zZipFileName的变量和字符串“ LR_Front_Upper_Control_Arm”传递给它,并且我也想将此powershell脚本嵌入到我的VBA代码中,以便一张Excel工作表都是独立的。这将被我的团队中其他人使用,他们对编程一无所知,我或他们都不希望花费时间教育他们他们具有多个脚本文件和类似的东西。

我将继续自己进行研究,但希望在这里能有所帮助。到目前为止,我用VBA代码尝试过的操作如下

ShellVar = Shell("$zZipFileName = """ & folderPath & """" & vbNewLine & _
      "$shap = new-object -com shell.application" & vbNewLine & _
      "$folderitems = get-childitem $zZipFileName" & vbNewLine & _
      "foreach($archive in $folderitems){" & vbNewLine & _
      "$archive.name.substring(0,$archive.name.length -4)" & vbNewLine & _
      "$zipFile = $shap.Namespace($archive.fullname)" & vbNewLine & _
      "$i = $zipFile.items()" & vbNewLine & _
      "foreach($si in $i){" & vbNewLine & _
      "if($si.getfolder -ne $null){" & vbNewLine & _
      "if($si.name -eq """ & targetFolderName & """){" & vbNewLine & _
      "$fileSearch = $si.getfolder.Items()" & vbNewLine & _
      "foreach($sii in $fileSearch){" & vbNewLine & _
      "if ($sii.name.substring(($sii.name.length - 7),7) -eq ""_nl.inp""){" & vbNewLine & _
      "$shap.namespace($zZipFileName).copyhere($sii)" & vbNewLine & _
      "rename-item ($zZipFileName + ""\"" + $sii.name) -newname ($archive.name.substring(0,$archive.name.length -4) + "".inp"")" & vbNewLine & _
      "}" & vbNewLine & _
      "}" & vbNewLine & _
      "}" & vbNewLine & _
      "}" & vbNewLine & _
      "}" & vbNewLine & _
      "}", vbHide)

要尝试查看它如何工作并产生更小的恐慌,并提示您首先需要将cmd窗口置于Powershell模式,我尝试了以下小命令:

Shell "powershell && new-item 'C:\Users\ccapsun2\Desktop\New loads formatting\load decks\LR_Front_Upper_Control_Arm' -itemtype directory", vbNormalFocus

良好的旧互联网建议使用&&将使cmd窗口按顺序使用命令,但再次无效。

我还尝试了以下link的建议,但也没有成功。

大约3天以来,我一直在缓慢前进,以挫败为代价。任何帮助将非常感激。我可能会精神崩溃,并很快开始哭泣哈哈。

2 个答案:

答案 0 :(得分:3)

不是您的Powershell问题的答案,但是这是您在VBA中的解决方法。 我喜欢这种非递归的方法来遍历“常规”(非压缩)子文件夹,并设法使其适应于zip存档。

调整以适合!

Public Sub UnzipSpecificFiles()

    Const LOCAL_ZIP As Variant = "C:\_Stuff\temp\test.zip"
    Const DEST_FLDR As Variant = "C:\_Stuff\temp\"

    Dim Sh As Object, ns, itm, colFolders, fldr

    Set Sh = CreateObject("Shell.Application")

    Set colFolders = New Collection '<< zip folders to be processed
    colFolders.Add LOCAL_ZIP     '<<    ...starting here

    Do While colFolders.Count > 0
        Set fldr = Sh.Namespace(colFolders(1))
        colFolders.Remove 1
        For Each itm In fldr.Items
            If itm.IsFolder Then
                'add this subfolder to the collection for processing
                colFolders.Add fldr.self.Path & "\" & itm.Name
            Else
                'is a file, so see if it's the one we want...
                If itm.Name Like "*_nl.inp" Then
                    Debug.Print itm.Name
                    Sh.Namespace(DEST_FLDR).CopyHere itm
                    Exit Do '<< if you only expect one match
                End If
            End If
        Next itm
    Loop

End Sub

答案 1 :(得分:1)

Tim的答案比我过于复杂的解决方案要好得多,但是如果有人想知道如何使它起作用,我将代码更改为以下代码。

Public FSO As New FileSystemObject
Dim b
Set b = VBA.CreateObject("WScript.Shell")
Set a = FSO.CreateTextFile("C:\Temp\temp.ps1")
a.WriteLine ("$zZipFileName = '" & folderPath & "'")
a.WriteLine ("      $shap = new-object -com shell.application")
a.WriteLine ("      $folderitems = get-childitem $zZipFileName")
a.WriteLine ("      foreach($archive in $folderitems){")
a.WriteLine ("        $archive.name.substring(0,$archive.name.length -4)")
a.WriteLine ("        $zipFile = $shap.Namespace($archive.fullname)")
a.WriteLine ("        $i = $zipFile.items()")
a.WriteLine ("        foreach($si in $i){")
a.WriteLine ("            if($si.getfolder -ne $null){")
a.WriteLine ("                 if($si.name -eq '" & targetFolderName & "'){")
a.WriteLine ("                     $fileSearch = $si.getfolder.Items()")
a.WriteLine ("                     foreach($sii in $fileSearch){")
a.WriteLine ("                         if ($sii.name.substring(($sii.name.length - 7),7) -eq '_nl.inp'){")
a.WriteLine ("                              $shap.namespace($zZipFileName).copyhere($sii)")
a.WriteLine ("                              rename-item ($zZipFileName + '\' + $sii.name) -newname ($archive.name.substring(0,$archive.name.length -4) + '.inp')")
a.WriteLine ("                         }")
a.WriteLine ("                     }")
a.WriteLine ("                 }")
a.WriteLine ("            }")
a.WriteLine ("         }")
a.WriteLine ("      }")

ShellVar.Run "powershell ""C:\Temp\temp.ps1""", vbNormalFocus

与此有关的最后一个问题是,我无法弄清楚如何使VBA代码等待powershell脚本完成。我尝试在.Run命令的末尾添加, WaitOnReturn,但没有等待。如果那是固定的,那么我只会添加一些东西来摆脱创建的脚本文件。像Kill a之类的东西。

folderPath和targetFolderName是从主宏传递的变量。