Open7

PowerShellを使ってTwinCATプロジェクトのプログラム更新を行うまで

よはんよはん

TwinCATのXAEを使って作ったプロジェクトを、実際の量産装置などに展開する場合、TwinCATの操作を行う必要なくインストールを行いたい。これを実現する方法は以下の通りファイル操作にて行うことができる。

https://beckhoff-jp.github.io/TwinCATHowTo/auto_deploy/index.html

しかし、これだとやはりXAEを経由しないので正しくデプロイできているのか信頼できない、という声をよく聞く。

この代替手段として、Powershellを用いてXAEをリモート操作し、装置にプログラムをダウンロードする処理を自動化する方法を検証してみた。

よはんよはん

まず、参考にできそうなサイトから。

https://infosys.beckhoff.com/content/1033/tc3_automationinterface/242929035.html?id=4660678065558732348

このまま実行すると以下のエラーが発生。

PS > .\example.ps1
new-object : CLSID {00000000-0000-0000-0000-000000000000} を含むコンポーネントの COM クラス ファクトリを取得中に、次
のエラーが発生しました: 80040154 クラスが登録されていません (HRESULT からの例外:0x80040154 (REGDB_E_CLASSNOTREG))。   
発生場所 C:\Users\Takashii\Documents\develop\TcAutomationInterface\original_example.ps1:4 文字:8
+ $dte = new-object -com VisualStudio.DTE.10.0
+        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ResourceUnavailable: (:) [New-Object], COMException
    + FullyQualifiedErrorId : NoCOMClassIdentified,Microsoft.PowerShell.Commands.NewObjectCommand
 :
 :
よはんよはん

すると今度は下記のようなエラーが。WindowオブジェクトのプロパティVisibleをTrueにしたいだけのようだが、エラーが。キャスト??

指定されたキャストは有効ではありません。
発生場所 C:\Users\Takashii\Documents\develop\TcAutomationInterface\original_example.ps1:10 文字:23
+ ... indow | % { $_.gettype().InvokeMember("Visible", [System.Reflection.B ...
+                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : OperationStopped: (:) [], InvalidCastException
    + FullyQualifiedErrorId : System.InvalidCastException

エラー原因がgettype()なのか、InvokeMember()なのか区別するため、次の通り書き換える。

$window = $dte.MainWindow.gettype()
$dte.MainWindow | % { $window.InvokeMember("Visible", "SetProperty", $null, $dte.MainWindow, $true) }
#$dte.MainWindow | % { $_.gettype().InvokeMember("Visible", [System.Reflection.BindingFlags]::InvokeMethod, $null, $_, $true) }

結果、以下のエラーが。gettype()が問題らしい。

指定されたキャストは有効ではありません。
発生場所 C:\Users\Takashii\Documents\develop\TcAutomationInterface\original_example.ps1:8 文字:1
+ $window = $dte.MainWindow.gettype()
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : OperationStopped: (:) [], InvalidCastException
    + FullyQualifiedErrorId : System.InvalidCastException
よはんよはん

いろいろググるも原因分からず。ただ、VisibleではないもののちゃんとActiveConfigurationされていてタスクスタートしているので問題なし。

以下の行は無効化だけしておく。どなたか原因わかる方居られましたらアドバイスお願いします。

#$dte.MainWindow | % { $_.gettype().InvokeMember("Visible", [System.Reflection.BindingFlags]::InvokeMethod, $null, $_, $true) }
よはんよはん

なお、SolutionプロジェクトにTwinCAT以外のプロジェクト(MeasurementやDatabaseServer等)がぶら下がっている場合、以下の行に与えるItemの要素番号をTwinCATプロジェクトのものに適宜書き換える必要があります。

$project = $sln.Projects.Item(1)

また、通常通りプロジェクトをXAEで開く際に、何か確認ダイアログが出る状況だとうまく構成の更新とスタートができません。

よはんよはん

なお、ソースとなるソリューションを配置するフォルダ$prjDirは絶対パスでないといけないのですが、このスクリプトを実行するディレクトリを起点とした相対パスにする場合、$PSScriptRootにて、実行するスクリプトのあるディレクトリが取得できます。例えば以下の例では、スクリプトが有る場所と同じディレクトリ以下にサブディレクトリTestSolutionを作って、そこにソリューションプロジェクトを格納しておくことで、相対パスでプロジェクトの場所を指定する事ができます。

$prjDir = $PSScriptRoot + "\TestSolution\"
$prjName = "TestSolution.sln"
$prjPath = $prjDir += $prjName
$dte = new-object -com 	TcXaeShell.DTE.15.0
#$dte = new-object -com VisualStudio.DTE.10.0
$dte.SuppressUI = $false
#$dte.MainWindow | % { $_.gettype().InvokeMember("Visible", [System.Reflection.BindingFlags]::InvokeMethod, $null, $_, $true) }

$sln = $dte.Solution
$sln.Open($prjPath)

$project = $sln.Projects.Item(1)
$systemManager = $project.Object

$systemManager.ActivateConfiguration()
$systemManager.StartRestartTwinCAT()