2014-04-03 37 views
0

無法在PowerShell代碼中使用Excel VBA的方法和屬性。excel自動化中的powershell和方法/屬性例外

我嘗試了一些修改,但無法從Power Shell正確調用PasteSpecial方法。另外,我使用微軟Office 2010和電源外殼

Major Minor Build Revision 
----- ----- ----- -------- 
2  0  -1  -1 


# edit formula and fill down 
$objSheet.Range("B1").Value2 = 2 
$objSheet.Range("C1").Value2 = 5 
$objSheet.Range("A1").Activate() 
$objSheet.Range("A1").Select() 
$objSheet.Range("A1").Formula = '=SUM(B1:C1)' 
$objSheet.Range("A1").Copy 
[void] $objSheet.Range("A2").Activate() 
$objRange = $objSheet.Range("A2:A10") 
[void] $objRange.PasteSpecial(-4123,-4142) 

錯誤:

Exception calling "PasteSpecial" with "2" argument(s): "PasteSpecial method of 
Range class failed" 
At C:\Users\anc92044\Desktop\shell\labs\del.ps1:36 char:30 
+ [void] $objRange.PasteSpecial <<<< (-4123,-4142) 
    + CategoryInfo   : NotSpecified: (:) [], MethodInvocationException 
    + FullyQualifiedErrorId : ComMethodTargetInvocation 
+0

嘗試沒有'.Value' - '$ objSheet.Cells.Item(1,3)=「嗨」' –

+0

謝謝!但是,似乎這只是暫時的解決方案,只能在一種情況下起作用。如果我想與公式,字體,註釋等其他屬性一起工作,我無法確定背後的問題。 – msinfo

+0

根據這個鏈接,應該沒有任何問題:http:// learn-powershell。net/2012/12/20/powershell-and-excel-adding-some-formatting-to-your-report/ –

回答

1

所以這裏的問題是,你不熟悉PowerShell的比什麼我想更多。花一些時間閱讀並熟悉語言環境。這將比我想象的任何事情都更有幫助。

所以,如果你打字$objExcel | Get-Member你會看到ActiveCell是一個屬性。對於你來說這應該相當自我解釋......該屬性是活動工作簿中活動工作表的當前活動單元格。如果你這樣做$objExcel.ActiveCell | Get-Member你會看到Value2是活動單元格的屬性。如果您現在執行$objExcel.ActiveCell.Value2 = "Hi",則Excel中當前處於活動狀態的單元格現在將具有文本「Hi」。爲什麼Value2而不是Value?那麼,Value已經是一種方法,因此包含其「值」的單元格的屬性已移至Value2。我認爲這很混亂,但我沒有制定規則,我只是玩遊戲。

並不是所有的事情都很直觀,但是有一點點的試驗和錯誤可以讓你輕鬆解決。您可能想要熟悉將內容傳遞給Get-Member,並且您不需要在寫入輸出前加上前綴。如果你已經完成了$objSheet | Get-Member,你會在那裏看到Range。 (好吧,GM是短期的獲取會員,往後如我使用的別名,我已經厭倦了寫作的獲取會員)

Range        ParameterizedProperty Range Range (Variant, Variant) {get} 

什麼應該告訴你的是

  • 名稱「範圍」
  • 它是什麼,一個參數化的屬性
  • 最後一節有點困難,因爲它包括幾件事情。第一種是item包含的對象,它是一個Range對象,它並沒有真正告訴我們多少。然後它具有範圍(Variant,Variant)的用法。最後它告訴我們,我們是否可以獲得,設置,或兩者兼而有之。它被設置爲{get},這是有道理的,因爲我們沒有設置任何東西,我們只是從Excel獲取信息來處理,我們將設置作爲範圍對象的屬性。

好的,$objRange = $objSheet.Range("A1","A1")是你可能想在你的腳本中。範圍可以包含多個單元格,因此即使它們是相同的點,也必須給它一個起點和一個停止點。從那裏你可以做你以前嘗試過的$objRange | GM,而不會得到一個錯誤(不需要寫輸出,就像我之前提到的那樣)。然後,您可以使用Select()Activate()方法在Excel中創建活動單元格,並且可以使用前面提到的$objExcel.ActiveCell,也可以直接使用$objRange執行大多數任何操作,您可以使用$objExcel.ActiveCell直接執行任何操作,而無需執行此操作活動的細胞。

我希望這有助於爲您清除幾件事。

編輯:好的,你肯定已經嘗試了很多東西,但看起來你仍然無法理解一些概念。如果你打算調用一個方法,那麼(就我所能想到的)而言,你需要方法的參數放在圓括號中(就像你如何調用Range方法一樣)。因此,對於Range.PasteSpecial,您需要將參數放在()中。爲了找出他們應該做的事情,我在Google上快速瀏覽了一下,然後搜索了「excel comobject pastespecial」,並獲得了MSDN page的獎勵。在那個頁面上,我看到4個參數都是可選的,但是您可能希望至少包含XLPasteType。有一個指向該頁面的XLPasteType選項的鏈接,並且它列出了每一個的名稱和值。對我來說,如果一個人不工作,嘗試另一個。我無法讓xlPasteFormulas爲我工作,但我能夠獲得-4123的工作(列出的xlPasteFormulas的值)。 xlPasteSpecialOperationName和-4142的下一個參數xlPasteSpecialOperation同樣適用。我最終什麼樣的主意是這樣的:

$objRange.PasteSpecial(-4123,-4142) 

這回來在PowerShell中有真,並在Excel中它粘貼爲預期的(我複製包含公式=SUM(H2:H4)H1細胞被粘貼到我的A1$objRange如式=SUM(A2:A4)。現在,你可能之前在PowerShell中添加[Void]以取消與如果你想沒有壞處的真實反應。

而且,這不是VBA。所有你要做的就是通過調用它是迷惑人。這是PowerShell,它是一種.Net腳本語言,而不是像VBA那樣的基於Visual Basic的。

+0

嗨,你的回答給了一些功率殼功能參數的洞察力。根據你的建議,我嘗試了所有可能的組合,但未能調用VBA方法。我編輯了更多信息的原始問題。謝謝! – msinfo

+0

請查看編輯問題,我也做了,你說了什麼,但使用Powershell的PasteSpecial方法無法取得成功。 – msinfo

+0

在PasteSpecial行之前出現錯誤。您的副本行最後缺少()。將其更改爲'$ objSheet.Range(「A1」)。Copy()'並查看是否修復了一些事情。現在,當您沒有複製任何東西時,您正在嘗試粘貼。隨着這一變化,我能夠無誤地運行你的代碼。 – TheMadTechnician

0

上面的博客幫了我很大忙,我希望這提供了一個完整的可測試解決方案。
爲了與上述複製粘貼保持一致, 我能夠採取上述建議並將公式複製到一個範圍,然後根據需要計算公式。整體思路是,

  1. 打開CSV文件中的每一列,以免失去YYYY-MM-DD和HH文本:MM:SS日期時間格式,並有列保持前導零在需要的地方。
  2. 插入一些列。
  3. 插入一個公式。
  4. 將公式複製到一個範圍內,從而顯示新的值。
  5. 只將值複製到另一個單元格。
  6. 關閉工作表,工作簿和Excel。

建議的示例數據是ASCII TXT CSV文件命名爲C:\ TEMP \ input.txt.csv

"Col1","Col2","Col3","Col4_is_a_string_of_at_least_32_characters" 
"Row2","R2C2","R2C3","R2C4_is_a_string_leadz_0234_XYZ.zip" 
"row3","r3c2","r3c3","r3c4_keep_leading_zero_0000_XYZ.zip" 

代碼

function Release-Ref ($ref) { 
([System.Runtime.InteropServices.Marshal]::ReleaseComObject([System.__ComObject]$ref) -gt 0) 
[System.GC]::Collect() 
[System.GC]::WaitForPendingFinalizers() 
} 

### Set input and output path 
$inputCSV  = "C:\temp\input.txt.csv" 
$outputXLSX_xlsx = "C:\temp\output.xlsx" 

### Create a new Excel Workbook with one empty sheet 
$excel = New-Object -ComObject Excel.Application 
$workbook = $excel.Workbooks.Add(1) 
$worksheet = $workbook.worksheets.Item(1) 

### Build the QueryTables.Add command 
### QueryTables does the same as when clicking "Data » From Text" in Excel 
$TxtConnector = ("TEXT;" + $inputCSV) 
$Connector = $worksheet.QueryTables.add($TxtConnector,$worksheet.Range("A1")) 
$query = $worksheet.QueryTables.item($Connector.name) 

### Set the delimiter (, or ;) according to your regional settings 
$query.TextFileOtherDelimiter = $Excel.Application.International(5) 

### Set the format to delimited and text for every column 
### A trick to create an array of 2s is used with the preceding comma 
$query.TextFileParseType = 1 
$query.TextFileColumnDataTypes = ,2 * $worksheet.Cells.Columns.Count 
$query.AdjustColumnWidth = 1 

### Execute & delete the import query 
$query.Refresh() 
$query.Delete() 

### 
$xlShiftToRight = -4161 

#$eCol=$worksheet.cells.item(1,4).entireCol 
$eCol=$worksheet.Range("D1").EntireColumn 
[void] $eCol.Insert($xlShiftToRight) 

$eCol=$worksheet.Range("D1").EntireColumn 
[void] $eCol.Insert($xlShiftToRight) 

$eCol=$worksheet.Range("D1").EntireColumn 
$eCol.NumberFormat = "General" 

$eCol=$worksheet.Range("E1").EntireColumn 
$eCol.NumberFormat = "General" 

<# Get the number of rows and columns in the "Used Range" #> 
$objRange=$worksheet.UsedRange 
$rows=$objRange.Rows.Count 
$cols=$objRange.Columns.Count 

<# After inserting new columns, label the columns with headers and 
## insert a formula to copy substring from cells to the right #> 
$worksheet.Range("D1","D1").Value2 = "Ship" 
$formula_ship = "=MID(RC[2],24,4)" 
$worksheet.Cells.Item(2,4).Formula = "=MID(RC[2],24,4)" 

$worksheet.Range("E1","E1").Value2 = "Station" 
$formula_station = "=MID(RC[1],29,3)" 
$worksheet.Cells.Item(2,5).Formula = "=MID(RC[1],29,3)" 

## Copy the formula from D2:E2 to D3:E<rows> ## 
[void] $worksheet.Range("D2","E2").Copy() 
$paste_alpha="D3" 
$paste_omega="E"+$rows.ToString() 
$objRange=$worksheet.Range($paste_alpha,$paste_omega) 
[void] $objRange.PasteSpecial(-4123) 

## Copy the values calculated by the formula ## 
$copy_alpha="D1" 
$copy_omega="E"+$rows.ToString() 
[void] $worksheet.Range($copy_alpha,$copy_omega).Copy() 
$paste_alpha="H1" 
$paste_omega="I"+$rows.ToString() 
$objRange=$worksheet.Range($paste_alpha,$paste_omega) 
[void] $objRange.PasteSpecial(-4163) 

## Ensure the ship number format has leading zeros ## 
$eCol=$worksheet.Range("D1").EntireColumn 
$eCol.NumberFormat = "0000" 

### Save & close the Workbook as XLSX. This may seem like overkill but without something kept a lock on the xlsx file. 
$Workbook.SaveAs($outputXLSX_xlsx,51) 
$excel.Application.Quit() 
$a = Release-Ref($worksheet) 
$a = Release-Ref($workbook) 
$a = Release-Ref($excel)