我有一个PowerShell脚本,该脚本也调用Access数据库中的VBA脚本。当我尝试运行PowerShell脚本时,它不起作用,并引发以下错误:
The remote procedure call failed. (Exception from HRESULT: 0x800706BE)
At Z:\Report\Run\RUN.ps1:18 char:1
+ $wb_con1 = $excel.Workbooks.Open($FilePath_con1)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : OperationStopped: (:) [], COMException
+ FullyQualifiedErrorId : System.Runtime.InteropServices.COMException
You cannot call a method on a null-valued expression.
At Z:\Report\Run\RUN.ps1.ps1:19 char:1
+ $ws_con1 = $wb_con1.sheets.Item(1)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
下面还会有更多的错误发生,You cannot call a method on a null-valued expression.
当我重新启动计算机时,脚本可以正常工作。该驱动器是网络共享驱动器。即使我确保Excel和Access都没有运行,似乎文件仍在某个地方打开。我不太确定。我的PowerShell脚本在下面,我也很高兴提供我的Access VBA脚本,但是我相信问题出在PowerShell脚本上,因为错误是在Excel的初始步骤中发生的。
我的代码如下。任何指导或协助将不胜感激。
# start Excel
$excel = New-Object -comobject Excel.Application
$ms_access = New-Object -comobject Access.Application
#set path files
$FilePath_con1 = 'Z:\Report\Data\StatusReport_C.xls'
$FilePath_eval1 = 'Z:\Report\Data\StatusReport_E.xls'
$FilePath_con2 = 'Z:\Report\Data\StatusReport_E.xlsx'
$FilePath_eval2 = 'Z:\Report\Data\StatusReport_E.xlsx'
$FilePath_date = 'Z:\Report\Data\ReportDate.xlsx'
$FilePath_access = "Z:\Report\Data\Access\Processing.accdb"
#Open workbook where the data will be copied from
$wb_con1 = $excel.Workbooks.Open($FilePath_con1)
$ws_con1 = $wb_con1.sheets.Item(1)
#Open workbook where the data will be copied to
$wb_con2 = $excel.Workbooks.Open($FilePath_con2)
$ws_con2 = $wb_con2.sheets.Item(1)
#Clear the workbook that the data will be copied to
$ws_con2.Cells.Clear()
#make Excel visible ($true) or invisible ($false)
$excel.Visible = $false
#Find the row count and column count of the data
$lrow1 = $ws_con1.usedRange.Rows.Count
$lcol1 = $ws_con1.usedRange.Columns.Count
#Copy from the header row which is located on Row 3
$range1=$ws_con1.Range("A3:V$lrow1")
$range1.copy()
#Copy the Report Date
$cpy_range_con = $ws_con2.Range("A1")
$ws_con2.Paste($cpy_range_con)
#Save the workbook where the data was copied to and close it
$wb_con2.Save()
$wb_con2.Close()
$wb_con1.Close()
#Open workbook where the data will be copied from
$wb_eval1 = $excel.Workbooks.Open($FilePath_eval1)
$ws_eval1 = $wb_eval1.sheets.Item(1)
#Open workbook where the data will be copied to
$wb_eval2 = $excel.Workbooks.Open($FilePath_eval2)
$ws_eval2 = $wb_eval2.sheets.Item(1)
#Open workbook where the data will be copied from
$wb_date = $excel.Workbooks.Open($FilePath_date)
$ws_date = $wb_date.sheets.Item(1)
#Clear the workbook where the data will be copied to
$ws_eval2.Cells.Clear()
#Count the rows where the data will be copied from in E
$lrow2 = $ws_eval1.usedRange.Rows.Count
#Define the range as the cell starting in A3 until the last row
$range2=$ws_eval1.Range("A3:V$lrow2")
#Copy the data range
$range2.copy()
#Define the cell where the data will start in the workbook where the data will be copied to
$cpy_range_eval = $ws_eval2.Range("A1")
#Paste the data
$ws_eval2.Paste($cpy_range_eval)
#Define the cell for the ReportDate and copy it
$date_range = $ws_eval1.Range("B1")
$date_range.copy()
#Define the cell where the Report date will be copied to and paste it
$cpy_range_date = $ws_date.Range("A2")
$ws_date.Paste($cpy_range_date)
#Save and close the workbooks
$wb_date.Save()
$wb_date.Close()
$wb_eval2.Save()
$wb_eval2.Close()
$wb_eval1.Close()
#$excel.quit() | Out-Null
$ms_access.OpenCurrentDatabase($Filepath_access)
$ms_access.Run("ExportExcel")
#$ms_access.Quit() | Out-Null
$wshell = New-Object -ComObject Wscript.Shell
$output = $wshell.Popup("The task has finished")
Add-Type -AssemblyName System.Windows.Forms
$global:balloon = New-Object System.Windows.Forms.NotifyIcon
$path = (Get-Process -id $pid).Path
$balloon.Icon = [System.Drawing.Icon]::ExtractAssociatedIcon($path)
$balloon.BalloonTipIcon = [System.Windows.Forms.ToolTipIcon]::Info
$balloon.BalloonTipText = 'The reports are completed.'
$balloon.BalloonTipTitle = "Attention $Env:USERNAME"
$balloon.Visible = $true
$balloon.ShowBalloonTip(20000)
答案 0 :(得分:2)
您已注释掉Excel和Access上的Quit()
操作。
这样,您将使这些应用程序保持运行状态,并且每次运行脚本时,都会创建新的Com对象,并且永远不会从内存中清除它们。
您需要使用
退出并将其从内存中删除$excel.Quit()
$ms_access.Quit()
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($wb_con1) | Out-Null
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($wb_con2) | Out-Null
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($wb_eval1) | Out-Null
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($wb_eval2) | Out-Null
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($wb_date) | Out-Null
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($excel) | Out-Null
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($ms_access) | Out-Null
[System.GC]::Collect()
[System.GC]::WaitForPendingFinalizers()
$excel = $ms_access = $null
完成这些对象后。
我想您需要检查所有文件路径以查看文件是否全部存在:
if (!(Test-Path -Path $FilePath_con1 -PathType Leaf)) {
Write-Error "The file $FilePath_con1 could not be found"
exit
}
对您要打开的所有文件执行该操作。
但是。.检查文件是否确实存在是一回事,但这仍然并不意味着您可以使用$excel.Workbooks.Open($FilePath_con1)
打开文件,因为也许另一个Excel进程已经打开了文件。另一个原因可能是您无权访问文件权限。
也许实用程序功能可以帮助您。它会测试是否可以找到文件,如果可以找到,是否已经锁定了文件。
function Test-IsFileAvailable {
[CmdletBinding()]
param (
[parameter(Mandatory = $true, ValueFromPipeline = $true, Position = 0)]
[string]$Path
)
if (!(Test-Path -Path $Path -PathType Leaf)) {
# the file is not found
Write-Verbose "File '$Path' not found."
return $false
}
try {
$file = New-Object System.IO.FileInfo $Path
$stream = $file.Open([System.IO.FileMode]::Open,
[System.IO.FileAccess]::ReadWrite,
[System.IO.FileShare]::None)
if ($stream) { $stream.Close() }
Write-Verbose "File '$Path' is not locked."
return $true
}
catch {
# file is locked by a process.
Write-Verbose "File '$Path' is locked by another process."
return $false
}
}
像这样使用它:
if (!(Test-IsFileAvailable $FilePath_con1 -Verbose)) { exit }
P.S。现在,我看到您还创建了一个Com对象来显示消息框。
也许更简单的方法是这样的:
Add-Type -AssemblyName Microsoft.VisualBasic
$Buttons = "OKOnly" # other options are "OKCancel", "AbortRetryIgnore", "YesNoCancel", "YesNo", "RetryCancel"
$Icon = "Information" # other options are "Critical", "Question", "Exclamation"
# show the messagebox
[Microsoft.VisualBasic.Interaction]::MsgBox("The task has finished", "$Buttons,SystemModal,$Icon", $Title)
希望有帮助