前提・実現したいこと
最終的には
エラーが起きないように、もしくはVBAでいうところのresume のような
一括でのリトライ処理 をしたいです。
Excel操作時 リトライしたり スリープを挟まないと シートの削除 、ブックの保存などが多々失敗します。
Excel操作一つ一つに リトライ処理を施すのはつらいですし
スリープは処理時間が入れた分だけ伸びますし、実行環境によって必要な時間が変わってきてしまうと思うので避けたいです。
一つの処理の実行中に次の処理が実行されて失敗しているような感じがするのですが、
powershellでのExcel操作で あり得るのでしょうか?
思い当たる節としてはExcel.Applicationのインスタンスを別スレッドで作成、取得 していることくらいですが
影響はあるのでしょうか?
別スレッドは過去の質問にあるクラス _MultiThread
を使った方法とほぼ同じです。
発生している問題・エラーメッセージ
Worksheet クラスの Delete プロパティを取得できません。 発生場所 ****************** + $BK.Sheets($($Page + $Index + 1)).Delete() + ~~~~~~~~~~~~~~~~~~ + CategoryInfo : OperationStopped: (:) [], COMException + FullyQualifiedErrorId : System.Runtime.InteropServices.COMException
該当のソースコードに近いコード(二台以上のPCで問題の再現が出来ました)
powershell
1<# 2 情報源 3 guitarrapc_tech 様 4 タイトル : PowerShell による同期処理、非同期処理、並列処理 を考えてみる 5 URL : http://tech.guitarrapc.com/entry/2013/10/29/100946 6 7 *** 様 8 タイトル : [properties] Powershellクラスはget setプロパティを実装します 9 URL : https://code-examples.net/ja/q/25e096e 10#> 11using namespace System.Management.Automation.Runspaces; 12using namespace System.Collections; 13using namespace System.Threading; 14using namespace System.Runtime.InteropServices 15 16# クラスを定義します 17class _MultiThread 18{ 19 20 # ノーマル プロパティ 21 [array] $RunspaceCollection 22 23 # 非表示 プロパティ 24 hidden [RunspacePool] $runspacePool 25 26 # 完了 プロパティ 27 hidden [bool]$_AllCompleted = $($this | Add-Member ScriptProperty -Name 'AllCompleted' -Value { 28 $($this.runspaceCollection.RunSpace | sort IsCompleted -Unique).IsCompleted -eq $true 29 }) 30 31 # コンストラクター 32 _MultiThread ($MyHost) 33 { 34 # create Runspace 35 [initialsessionstate] $sessionstate = [initialsessionstate]::CreateDefault() 36 [int] $minPoolSize = [int] $maxPoolSize = 5000 37 $this.runspacePool = [runspacefactory]::CreateRunspacePool($minPoolSize, $maxPoolSize, $sessionstate, $MyHost) # create Runspace Pool 38 $this.runspacePool.ApartmentState = "STA" 39 $this.runspacePool.Open() # open pool 40 } 41 42 # スレッドの追加 43 [void]AddThread([scriptblock]$ScriptBlock) 44 { 45 # Main Invokation 46 [powershell] $powershell = [PowerShell]::Create().AddScript($ScriptBlock) 47 $powershell.RunspacePool = $this.runspacePool 48 $this.RunspaceCollection += New-Object -TypeName PSObject -Property @{ 49 Runspace = $powershell.BeginInvoke(); 50 powershell = $powershell 51 } 52 # $powershell.Dispose() 53 } 54 55 # スレッドの追加 56 [void]AddThread([scriptblock]$ScriptBlock,[psobject]$Parameters) 57 { 58 # Main Invokation 59 [powershell] $powershell = [PowerShell]::Create().AddScript($ScriptBlock).AddParameters($Parameters) 60 $powershell.RunspacePool = $this.runspacePool 61 $this.RunspaceCollection += New-Object -TypeName PSObject -Property $( 62 [ordered]@{ 63 Runspace = $powershell.BeginInvoke(); 64 powershell = $powershell 65 } 66 ) 67 } 68 69 70 # 結果の取得 71 [object]GetResult() 72 { 73 # get process result and end powershell session 74 return $(foreach ($runspace in $this.runspaceCollection) 75 { 76 # get reuslt 77 $runspace.powershell.EndInvoke($runspace.Runspace) 78 }) 79 } 80 81 # デストラクタの代わり手動で実行 82 [void]Dispose() 83 { 84 if (!($this.runspacePool.runspacePool.IsDisposed)) 85 { 86 foreach ($Runspace in $this.RunspaceCollection) 87 { 88 $Runspace.powershell.Dispose() 89 } 90 91 # Dispose Runspace 92 $this.runspacePool.Dispose() 93 } 94 } 95} 96 97function _New_MultiThread() 98{ 99[OutputType([_MultiThread])] 100 $Thread = New-Object _MultiThread($host) 101 return $Thread 102} 103 104$ExcelPath = "$PSScriptRoot\Tmp.xlsx" 105$OpenPath = "" 106if (Test-Path -Path $ExcelPath) 107{ 108 $OpenPath = $ExcelPath 109} 110$Thread = _New_MultiThread 111 112$NewBook = { 113 #Param($Path) 114 $App = New-Object -ComObject "Excel.Application" 115 116 #if($Path -eq "") 117 #{ 118 $null = $App.WorkBooks.Add() 119 Write-host "新規ブック" 120 #} 121 #else 122 #{ 123 # $null = $App.WorkBooks.Add("$Path") 124 # Write-host "既存ブックをテンプレートとして立ち上げ" 125 #} 126 127 $App 128} 129 130clear-host 131$Error.Clear() 132try 133{ 134 135 136 137 1..2 | foreach { $Thread.AddThread($NewBook<#,$Add_Args#>) } 138 139 while(!($Thread.AllCompleted)) {Start-Sleep -Milliseconds 5} 140 141 if ($OpenPath -ne "") 142 { 143 Remove-Item -Path $OpenPath 144 } 145 146 $Apps = $($Thread.GetResult()) 147 148 $Apps | foreach { $_.Caption = "Test_Apps" } 149 150 $App = $Apps[0] 151 152 $BK = $App.ActiveWorkbook 153 154 $BK2 = $Apps[1].ActiveWorkbook 155 156 $Sh = $App.ActiveSheet 157 158 $i = 0 159 160 $Tmp = "$PSScriptRoot\tmp2.xlsx" 161 162 if (Test-Path -Path $Tmp) 163 { 164 Remove-Item -Path $Tmp 165 } 166 167 $Bk2.saveAs("$Tmp") 168 169 $Bk2.close($false) 170 171 $Bk2 = $Apps[0].Workbooks.Open($Tmp) 172 173 1..10 | foreach { $Bk2.Sheets(1).Copy($Sh) } 174 175 176 $BK.Sheets(1).Activate() 177 178 $App.DisplayAlerts = $false 179 180 181 Write-host "残りシートが5になるまで削除" 182 while($BK.sheets.Count -gt 5){ 183 $Try = $true 184 while ($Try) 185 { 186 187 try 188 { 189 $BK.Sheets(6).Delete() 190 $Try = $false 191 } 192 catch 193 { 194 Write-host "Delete Retry" 195 } 196 197 } 198 } 199 200 Write-host "$ExcelPath`に保存" 201 $Try = $true 202 while ($Try) 203 { 204 205 try 206 { 207 $null = $BK.SaveAs("$ExcelPath") 208 $Try = $false 209 } 210 catch 211 { 212 Write-host "Save Retry" 213 } 214 215 } 216 217 $Apps | foreach { $_.WorkBooks | foreach {$_.close($false) } } 218 219} 220catch 221{ 222 Write-Host "$Error" 223} 224finally 225{ 226 Write-Host "クリーンアップしています..." 227 228 $null = [Marshal]::FinalReleaseComObject($Sh) 229 $null = [Marshal]::FinalReleaseComObject($Bk) 230 $null = [Marshal]::FinalReleaseComObject($Bk2) 231 $Apps | foreach { $_.quit() } 232 $null = $Apps | foreach { [Marshal]::FinalReleaseComObject($_) } 233 $Thread.Dispose() 234 Remove-Item -Path $ExcelPath 235 Remove-Item -Path $Tmp 236} 237
試したこと
・リトライ
powershell
1 $Try = $true 2 while ($Try) 3 { 4 5 try 6 { 7 $BK.Sheets($($Page + $Index + 1)).Delete() 8 $Try = $false 9 } 10 catch 11 { 12 Write-host "Delete Retry" 13 } 14 15 }
・Start-Sleep
・問題が起きているのと同じようなコードを書いてみたのですが
問題が再現できませんでした....
二台以上のPCで問題の再現が出来ました。
補足情報(FW/ツールのバージョンなど)
Win10
回答2件
あなたの回答
tips
プレビュー