[英]Copy and Paste active Word document to active Excel document using VBA
[英]Connecting to Excel from powershell using VBA in an active excel document
我有一個非常奇怪的問題。
我有一些名為 merge1-6 的 vba 腳本,它從不同的 excel 表中提取數據。 這 6 個生成的文本文件使用另一個宏“MergeALL”合並為 1 個文本文件,因此所有內容都在一個字符串上。
到目前為止一切順利,效果很好。
所以我想制作一個 powershell 腳本來訪問我打開的當前 excel 文檔,並獲取 J29 單元格數據,並將此數據與值“0|”合並組合給定的字符串。
實際powershell腳本我要拉取單元格數據如下:
宏:調用 BID_MergeXCleanup_TextOut
#This script opens H:\Temp\PublicFolder-powershell\Create-String-For-Email-Fetch.txt and replace empty parts of "domain/users/0|" with "nothing"
#stripping away all entries not needed. Out-File used as output, with -NoNewline to prevent carriage return inserting empty line.
#$workbook = $excel.Workbooks.Open("H:\Temp\PublicFolder-powershell\Create-String-For-Email-Fetch.xlsm") #open workbook
$xl = [Runtime.InteropServices.Marshal]::GetActiveObject(Excel.Application')
$workbook = $xl.workbooks | ?{$_.FullName -eq "H:\Temp\PublicFolder-powershell\Create-String-For-Email-Fetch.xlsm"}
$workbook.sheets.item(1).activate() #opens the sheet and activates it
$WorkbookTotal=$workbook.Worksheets.item(1) #Set sheet data to variable
$value = $WorkbookTotal.Cells.Item(29, 10) # Fetches data in Column 10, Row 29 which is the cell reference J29 where domain is.
$domain = $value.Text #Fetches "domain/users/" from the Fetch-tab of the excel file, to match the correct domain in use and stores result in the $domain variable
$leftoverdomain = '0|' #last part of domain string after the domain/user part
$joinedvariables = -join($domain,$leftoverdomain,"") #Joines the above variables together to form "domain/users/0|" as searchtag to replace as leftover bits.
$b = Get-Content -Path "H:\Temp\PublicFolder-powershell\Create-String-For-Email-Fetch.txt" #Opens text file to replace in.
#Next part uses the $joinedvariables variable of merged search parametres and replaces it with "nothing" and saves the file back.
@(ForEach ($a in $b) {$a.Replace($joinedvariables, '')}) | Out-File "H:\Temp\PublicFolder-powershell\Create-String-For-Email-Fetch.txt" -NoNewline
Start-Sleep -Seconds 0.3
### INFO ###
#I used a reference to the EXCEL cell here, instead of directly from the TXT-file as given what domain has been specified, the info in the TEXT file would vary
#But text in J29 would always equal the domain being used, and thus also correnspond with the one in the text file at all times.
#This way it will automatically always use the correct domain.
因此,如果我使用對 excel 文檔的獨立引用,
$workbook = $excel.Workbooks.Open("H:\Temp\PublicFolder-powershell\Create-String-For-Email-Fetch.xlsm")
...並直接打開工作簿,在 powershell ISE 中,命令成功。 但是,如果我調用 PS1 腳本或從 excel 文件中手動運行它,則無法正確執行。 這就是為什么我開始尋找如何訪問當前的 excel session 引導我到下一個方法...
如果我使用
$xl = [Runtime.InteropServices.Marshal]::GetActiveObject('Excel.Application')
要引用當前正在運行的應用程序,當我手動運行時,它從 ISE 和 Excel 內部都成功。
在這兩種情況下,只要要修改的 TXT 文件存在並且其中包含要搜索的信息,這項工作就有效。
因此,鑒於我有一個“未修改的文件”,我想通過從另一個宏調用它們來啟動這些宏。
這是 VBA 代碼,用於在同一 excel 表中啟動宏。
Call BID_1_TextOut
Application.Wait Now + TimeSerial(0, 0, 1)
Call BID_2_TextOut
Application.Wait Now + TimeSerial(0, 0, 1)
Call BID_3_TextOut
Application.Wait Now + TimeSerial(0, 0, 1)
Call BID_4_TextOut
Application.Wait Now + TimeSerial(0, 0, 1)
Call BID_5_TextOut
Application.Wait Now + TimeSerial(0, 0, 1)
Call BID_6_TextOut
Application.Wait Now + TimeSerial(0, 0, 1)
Call BID_MergeALL_TextOut 'Macro MergeALL - Merges all BID-TEXTOUT files to 1 file
Application.Wait Now + TimeSerial(0, 0, 3)
Call BID_MergeXCleanup_TextOut 'Macro MergeXCleanup - This script replace empty parts of "domain/users/0|" with "nothing"
Application.Wait Now + TimeSerial(0, 0, 1)
最后兩個宏是重要的。 第二個最后一個宏准備要在“BID_MergeXCleanup”中使用的文件,這是我正在調用的 PS1 腳本。
我調用的宏帶有以下代碼:
' Script to merge all the BID-TEXT-OUT files into 1 string with UTF32LE encoding.
Sub BID_MergeALL_TextOut()
Set objShell = CreateObject("wscript.Shell")
objShell.Run ("powershell.exe H:\Temp\PublicFolder-powershell\MergeALL_UTF32.ps1")
End Sub
和
'This script opens H:\Temp\PublicFolder-powershell\Create-String-For-Email-Fetch.txt and replace empty parts of "domain/users/0|" with "nothing"
'stripping away all entries not needed.
Sub BID_MergeXCleanup_TextOut()
Set objShell = CreateObject("wscript.Shell")
objShell.Run ("powershell.exe -noexit H:\Temp\PublicFolder-powershell\REPLACE_IN_EmptyDomainUsersPart.ps1")
End Sub
奇怪的是,如果我使用“調用腳本”自動連續運行這些命令,最后一個腳本總是失敗
如果我之后檢查 TXT 文件,我會看到只有'0|' 變量已被刪除,因為它似乎無法從 Excel 文檔中獲取 J29 信息。
如果我從 Excel中手動逐個運行每個宏,那么它們會正確執行,並且腳本會按照我的意願執行,不會出現錯誤
merge1-6-then-all-then-cleanup
所以據我所知,我的 powershell 腳本能夠調用活動的 excel 工作簿、工作表、單元格、獲取數據等等。
...但是我不能通過從另一個宏調用宏來做到這一點? 在此示例中,如果我使用“Call BID_MergeXCleanup_TextOut”引用來訪問宏,它將失敗。
PS:我也嘗試“共享”工作簿,以防是權限問題,但運行 Call-VBA 腳本時仍然報錯,但沒有連續手動運行每個宏。
知道如何解決這個問題嗎?
我有一種感覺,我可能不允許原始 PS1 文件退出 $NULL 表達式,但我不確定如何添加它。
第一個失敗的代碼行是
$workbook.sheets.item(1).activate()
我試圖在 Powershell ISE 中添加 $NULL ,然后它失敗了
$null = $workbook.sheets.item(1).activate() <<<--- Fails with *"You cannot call a method on a null-valued expression."*
而且我也看不到主腳本中有任何未清除的變量。
不確定如何解決這個問題。
我最終得到了什么:
所以@postanote在這里建議我使用COM而不是InteropService.Marshal來訪問Excel。
我最初認為這行不通,因為它會打開工作簿的一個新實例,但是 COM 版本有一種隱藏您運行的實例的方法
$objExcel.Visible = $false
現在,[Runtime.InteropServices.Marshal]::GetActiveObject 版本也有這個值,它似乎有所不同,因為如果我將代碼更改為 COM,如下所示:
$objExcel = New-Object -ComObject Excel.Application
$objExcel.Visible = $false
$WorkBook = $objExcel.Workbooks.Open("H:\Temp\PublicFolder-powershell\Create-String-For-Email-Fetch.xlsm")
$WorkSheet = $WorkBook.sheets.item("Fetch")
$domain = $worksheet.Rows.Item(29).Columns.Item(10).Text
$leftoverdomain = '0|' #last part of domain string after the domain/user part
$joinedvariables = -join($domain,$leftoverdomain,"") #Joines the above variables together to form "domain/users/0|" as searchtag to replace as leftover bits.
$b = Get-Content -Path "H:\Temp\PublicFolder-powershell\Create-String-For-Email-Fetch.txt" #Opens text file to replace in.
@(ForEach ($a in $b) {$a.Replace($joinedvariables, '')}) | Out-File "H:\Temp\PublicFolder-powershell\Create-String-For-Email-Fetch.txt" -NoNewline
Start-Sleep -Seconds 0.3
...當從 VBA 調用腳本調用時,腳本執行沒有錯誤...
另一方面,如果我嘗試將不可見成員合並到原始代碼中,如下所示:
$xl = [Runtime.InteropServices.Marshal]::GetActiveObject('Excel.Application') #opens an already open excel session
$xl.Visible = $false
$workbook = $xl.workbooks | ?{$_.FullName -eq "H:\Temp\PublicFolder-powershell\Create-String-For-Email-Fetch.xlsm"}
$workbook.sheets.item(1).activate()
$WorkbookTotal=$workbook.Worksheets.item(1)
$value = $WorkbookTotal.Cells.Item(29, 10)
$domain = $value.Text
$leftoverdomain = '0|'
$joinedvariables = -join($domain,$leftoverdomain,"")
$b = Get-Content -Path "H:\Temp\PublicFolder-powershell\Create-String-For-Email-Fetch.txt"
@(ForEach ($a in $b) {$a.Replace($joinedvariables, '')}) | Out-File "H:\Temp\PublicFolder-powershell\Create-String-For-Email-Fetch.txt" -NoNewline
Start-Sleep -Seconds 0.3
...然后它失敗並顯示以下更改的錯誤消息:
Call was rejected by callee. (Exception from HRESULT: 0x80010001 (RPC_E_CALL_REJECTED))
所以我想最終的結果是,只要你從 Windows window 處理程序中隱藏新的 excel 實例,COMs 就可以多次打開同一個文檔。
但是......很高興知道為什么原始代碼在手動運行時有效,但在從腳本調用時無效,所以如果有人知道,我很想知道那個答案。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.