在Powershell中运行Access宏

10

我试图使用以下代码在PowerShell(v4.0 Windows 8.1)中运行Access 2010宏:

$Access = New-Object -com Access.Application

$Access.OpenCurrentDatabase("SomePath", $False, "Password")
$Access.Run("SomeProc")
$Access.CloseCurrentDatabase()
$Access.Quit()

[System.Runtime.InteropServices.Marshal]::ReleaseComObject($Access)
Remove-Variable Access

$Access.Run("SomeProc")这一行出现错误,提示没有指定足够的参数:

调用带有"1"个参数的"Run"时出错: "无效的参数数量。(来自 HRESULT: 0x8002000E (DISP_E_BADPARAMCOUNT))"

过程SomeProc不需要任何参数。

我已经阅读了关于run方法的MSDN文章,并且只需要一个参数。

我也尝试了这个解决方法,但由于与问题无关而未能正常工作。

是否有人知道这个错误的原因以及如何使方法有效?


1
@Vesper 抱歉,我应该澄清一下,过程不需要任何参数。 - Gareth
你是否遇到了一个最小化的程序问题,其中包含 $Access.Run("SayHello"),其中 SayHello 是一个公共子程序,仅包括 MsgBox "Hello Word!" - HansUp
@HansUp 谢谢,我刚试着创建了一个基本的过程,但没有成功,仍然收到相同的错误。 - Gareth
1
糟糕!我刚测试了你PowerShell代码的VBScript等效版本,但并不清楚为什么会有问题。很抱歉,我对PowerShell并不熟练。你能给我们展示SomeProc过程中的代码吗?如果它非常复杂,请提供一个最简版本,能够触发相同的错误。 - HansUp
1
@HansUp 谢谢 - 我实际上正在从vbscript迁移到powershell,该过程和vbscript等效部分绝对有效!这就是令人烦恼的部分,因此可以假设这是一个powershell问题。 - Gareth
显示剩余12条评论
2个回答

4
这是一个驱动程序问题,OLEDB库未能正确加载。
我能够准确重现您的错误,并通过从SysWow目录而不是System32目录打开Powershell来解决它。
尝试打开此版本的Powershell(您将不得不再次运行set-executionpolicy),并查看是否可以执行您的脚本。

%SystemRoot%\syswow64\WindowsPowerShell\v1.0\powershell.exe

有用的链接:https://social.msdn.microsoft.com/Forums/en-US/4500877f-0031-426e-869d-bda33d9fe254/microsoftaceoledb120-provider-cannot-be-found-it-may-not-be-properly-installed?forum=adodotnetdataproviders


MicrosoftACEOLEDB120提供程序无法找到,可能未正确安装。

2

C#的签名通常是这样的:

public object Run(string Procedure, ref object Arg1, ... ref object Arg30) ...

这意味着在.NET中,COM的Arg可选参数不是可选的,因为它们明确标记为[ref]。即使您不使用它们,也需要提供所有32个参数。


假设您有以下VBA代码:

Public Sub Greeting(ByVal strName As String)
 MsgBox ("Hello, " & strName & "!"), vbInformation, "Greetings"
End Sub

你可以这样调用它:
$Access = New-Object -com Access.Application
$Access.OpenCurrentDatabase("Database1.accdb")
$runArgs = @([System.Reflection.Missing]::Value) * 31
$runArgs[0] = "Greeting" #Method Name
$runArgs[1] = "Jeno" #First Arg
$Access.GetType().GetMethod("Run").Invoke($Access, $runArgs)

在您的情况下,应该是这样的:
$runArgs = @([System.Reflection.Missing]::Value) * 31
$runArgs[0] = "SomeProc" 
$Access.GetType().GetMethod("Run").Invoke($Access, $runArgs)

我会尝试向访问对象添加一个助手(helper):
Add-Member -InputObject $Access -MemberType ScriptMethod -Name "Run2" -Value {
    $runArgs = @([System.Reflection.Missing]::Value) * 31
    for($i = 0; $i -lt $args.Length; $i++){ $runArgs[$i] = $args[$i] }
    $this.GetType().GetMethod("Run").Invoke($this, $runArgs)
}

然后您可以像预期的那样使用Run2:
$Access.Run2("Greeting", "Jeno")
$Access.Run2("SomeProc")

.Run() 方法肯定有一个重载,只需要一个参数:过程的名称。正如我在对问题的评论中提到的那样,当我在我的几台机器上尝试了提问者的示例代码时,没有出现任何问题。 - Gord Thompson
您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - Jeno Laszlo
$Access.GetType().GetMethod("Run").Count # 将会给我返回1 - Jeno Laszlo
$Access.GetType().GetMethod("Run").GetParameters() | Format-Table

给我一个包含31个必须参数的列表

- Jeno Laszlo
1
我在这里插话,声明只有Run()方法的第一个参数是必需的,正如TechNet页面所述。 - TheMadTechnician
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接