2016-11-14 220 views
1

我一直在尝试执行从VBA获取输入参数fileName的PowerShell功能(countLines)。我提到了thisthis的一些答案,但他们不适合我。以下是我尝试做相同的(fname是我送的参数包含代码的下面一行VBA程序的VBA变量):如何使用VBA传递参数来执行PowerShell功能

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

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

  • powershell "D:\Temp\fileReader.ps1";countLines -fileName ...
    这可不行,因为当你调用父上下文功能的脚本文件在子上下文中执行。您需要dot-source文件才能使其内容在当前上下文中可用。
  • Set WshShellExec = WshShell.Run(strCommand)
    在这里你很困惑的RunExec方法。前者返回一个整数(外部命令的退出代码),后者返回一个对象(并且只有该对象提供对外部进程的访问StdIn,StdOutStdErr)。由于您尝试使用关键字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窗口),并调用Shell功能与选项vbNormalFocus在前台运行的过程。

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

哎呀...对不起,我的坏...我会尽快编辑它...谢谢指出 – Rishi

+0

这工作! :)而且你隐含地解决了我忘记问的一个疑问,那就是如何阻止PowerShell窗口自动关闭。我无法确定路径没有得到解决的问题,你正确地指出了这一点......布拉沃为这样一个很好的描述性答案!我需要做大量的阅读...... – Rishi

+0

如果您可以指定如何正确捕获我的VBA中的PowerShell函数的返回值,那将会很棒。正如您已经指出的那样,使用上面的返回值实际上会将我退出代码,所以这对我不起作用。 – Rishi