如何通过使用VBA传递参数来执行PowerShell功能

时间:2016-11-14 09:13:44

标签: excel-vba powershell parameter-passing vba excel

我一直在尝试执行从VBA获取输入参数countLines的PowerShell函数(fileName)。我已经提到了thisthis的一些答案,但它们对我不起作用。以下是我尝试做同样的事情(fname是一个VBA变量,我将其作为参数发送到包含以下代码行的VBA例程中):

fileReader.ps1的内容是:

function countLines {
    param([string]$logFile);
      #The directory path may differ for others according to the machine's source code repository
    $scriptPath = Resolve-Path "..\..\testFolder";
    $varHolder = -join($scriptPath, "\logFileCount.txt");
    $linesb4Exec = Get-Content $logFile;
    $nLines = $linesb4Exec.Count;
    Clear-Content $varHolder
    $nLines | Out-File $varHolder
    #For second attempt, I am adding the following too
    #echo $nLines;
}

第一次尝试:

Call Shell("powershell  -ExecutionPolicy Unrestricted ""D:\Temp\fileReader.ps1"";countLines -fileName """ & fname & """", vbMaximizedFocus))

第二次尝试:

Dim strCommand As Variant, WshShell As Variant, WshShellExec As Variant, output As Variant
strCommand = "powershell -command ""& { . ""D:\Temp\fileReader.ps1"";countLines -logFile """ & fname & """ }"""
Set WshShell = CreateObject("WScript.Shell")
Set WshShellExec = WshShell.Run(strCommand)
output = WshShellExec.StdOut.ReadAll

使用此功能,我收到错误:输入错误。

第三次尝试(我尝试在我的PowerShell文件中硬编码所有内容并删除了该函数,只是运行了一段代码):

Call Shell("powershell -ExecutionPolicy Bypass -file ""D:\Temp\fileReader.ps1""", vbMaximizedFocus)

并将上述powershell脚本更改为:

$logFile = "C:\somepath\Logs\Log.txt";
$varHolder = "D:\testing\testFolder\logFileCount.txt";
$linesb4Exec = Get-Content $logFile;
$nLines = $linesb4Exec.Count;
Clear-Content $varHolder
$nLines | Out-File $varHolder

这似乎有效。

如果有人可以帮助我使用VBA调用任何带有参数的PowerShell函数,我将很高兴。

1 个答案:

答案 0 :(得分:1)

你的尝试基本上有两个错误:

  • powershell "D:\Temp\fileReader.ps1";countLines -fileName ...
    这不起作用,因为当您在父上下文中调用该函数时,脚本文件在子上下文中执行。您需要dot-source该文件才能在当前上下文中提供其内容。
  • Set WshShellExec = WshShell.Run(strCommand)
    在这里,您会混淆RunExec方法。前者返回一个整数(外部命令的退出代码),后者返回WshScriptExec个对象(只有该对象提供对StdInStdOutStdErr的访问权限。外部过程)。您遇到类型不匹配的原因是您尝试使用Set关键字分配整数返回值,该关键字只能在将对象分配给变量时使用。

如果您想坚持使用-Command并对文件进行点源,那么您第二次尝试的命令行是正确的方法。在PowerShell脚本块中使用单引号以避免quotefusion并使用Shell函数执行命令行:

cmd = "powershell -ExecutionPolicy Bypass -Command ""&{. 'D:\Temp\fileReader.ps1';countLines -logFile '" & fname & "'}"""
Shell cmd

话虽如此,如果函数是脚本中唯一的代码,那么参数化脚本并直接从它运行代码会更简单:

[CmdletBinding()]
Param(
  [string]$LogFile
)

$scriptPath = Resolve-Path "..\..\testFolder"
$varHolder  = Join-Path $scriptPath "logFileCount.txt"
@(Get-Content $logFile).Count | Out-File $varHolder

使用参数-File运行脚本,如下所示:

cmd = "powershell -ExecutionPolicy Bypass -File ""D:\Temp\fileReader.ps1"" -LogFile """ & fname & """"
Shell cmd

请注意路径..\..\testFolder是相对于当前工作目录的,而不是相对于脚本的位置。对于后者使用$MyInvocation.MyCommand.Path

如果某些内容无效,请将参数-NoExit添加到命令行(因此PowerShell窗口不会自动关闭),并使用选项vbNormalFocus调用Shell函数在前台运行该过程。

cmd = "powershell -ExecutionPolicy Bypass -NoExit -File ""D:\Temp\fileReader.ps1"" -LogFile """ & fname & """"
Shell cmd, vbNormalFocus