背景
ある医療組織では、Orthanc PACSサーバーとRadiant DICOMクライアントに基づいたソリューションを実装しました。 セットアップ中に、各DICOMクライアントはPACSサーバーで次のように記述される必要があることがわかりました。
- 顧客名
- AE名(一意である必要があります)
- クライアント側で自動的に開かれ、PACSサーバーからDICOM検査を受信するTCPポート(つまり、サーバーは、それらをクライアントにプッシュします。つまり、最初に接続を開始します)
- IPアドレス
Radiantクライアントをセットアップした後、検討のために次の情報を受け取りました-各クライアントについて、上記のパラメーターを使用してソフトウェアをセットアップすると、ユーザープロファイル(パス: %APPDATA%\ RadiantViewer \ pacs.xml )にあるpacs.xmlファイルに入力します。 同時に、あるクライアントと他のクライアントの構成は、少なくとも2つのパラメーターが異なりました(AE名はすべてのユーザーで異なり、ポートは基本的に同じです。ただし、同じサーバーで実行されているターミナルクライアントを除き、異なるポートを割り当てる必要がありました)。
リンクの pacs.xmlファイルの例:
約半年間、すべてがうまくいき、システムは機能しました...そして、「 落とし穴 」が私たちに届きました:
- 古いもの(ディスク容量が不足し始めた場所)を置き換えるいくつかの新しいPACSサーバーを運用する必要があります。 仮想マシンのPACSサーバーですが、これはそれに関するものではありません。
- 200台のマシンで(2つの異なるパラメーターを使用して)何らかの方法で一意の構成を一元的に変更する必要があります(その数は定期的に増加しています)。
- 検査量の増加率を考えると、ソリューションは1回限りのソリューションではなく、複製された定期的なソリューションです(たとえば、3〜5か月に1回)。
解決策は次のとおりです。
問題を解決するためのツールの選択
最初に、クライアント側のpacs.xmlファイルを変更し、AE名とTCPポート設定に触れずにPACSサーバーのリストを変更するソリューションを見つける試みがありました。 当時のWindowsクライアントはWindows XPとWindows 7の両方に基づいていたため、VBScriptに基づいたものを作成しようとする試みがありました。 しかし、残念ながら、この言語で複雑なものや複雑なものを書く経験がまったくないため、このようなタスクを圧倒することはできませんでした。 見つけて書き換える試みも失敗しました(頭の中にはすでに別の計画があったので、3〜4時間以上VBScriptを使用しなかったことに注意してください)。
最終的に、私は次の解決策に決めました。
- グループポリシー内のすべてのpacs.xmlファイルを、ネットワーク共有内のサーバー上の1か所に収集します。
- ファイルを一括で変更します(Perlを使用してこのような問題を解決した経験があります)
- また、グループポリシーを使用してクライアント設定を更新します。
グループポリシーを使用してファイルを収集する
最も単純な部分は、クライアントが自分のプロファイルにログインすると、その権利で特定の.batファイルが実行され、そのファイルに書き込まれることです。
echo off If exist %APPDATA%\RadiantViewer\pacs.xml copy %APPDATA%\RadiantViewer\pacs.xml \\srv.test.local\pconfigs$\pacs-%COMPUTERNAME%-%USERNAME%.xml
したがって、pacs.xmlファイルはサーバー上の隠しリソースに蓄積され、その名前にはどのコンピューターからどのユーザーからこの構成がコピーされたかという情報が含まれます。
最も難しいことは、このポリシーがすべてのユーザーに対して機能するまで待つことでした。
Perlスクリプトを使用して構成を変更する
ActiveStateのActive Perl for Windowsに加え、 ppm install XML-Writerコマンドを使用してインストールできるXML :: Writerモジュールが必要です。
スクリプト自体は非常にシンプルであることがわかりました。
use XML::Writer; # , ( ): $report_dir = "C:\\Perl64\\WORK\\PACS-xml3\\"; opendir(DIR, "$report_dir") or die " !"; @report_files = readdir DIR; shift (@report_files); # (.) shift (@report_files); # (..) # print "@report_files"; closedir(DIR); # - . AET . foreach $analiz_file (@report_files) { $full_path_to_file="C:\\Perl64\\WORK\\PACS-xml3\\".$analiz_file; open (INFO, $full_path_to_file); while ($line = <INFO>) { # $aet $port XML : my ($other1, $aet, $other2, $port, $other3) = split /\"/, $line, 5; # listener - XML: if ($other1 =~ 'listener') { # XML c : my $writer = XML::Writer->new(OUTPUT => 'self', DATA_MODE => 1, DATA_INDENT => 2, ); $writer->xmlDecl('utf-8'); $writer->startTag('pacs'); $writer->startTag('listener', ae => $aet, port => $port); $writer->endTag(); $writer->startTag('hosts'); $writer->startTag('host', name => 'MRT', ae => 'ORTHANC', ip => 'XX.YY.214.17', ts => '1.2.840.10008.1.2.1', port => '4242', maxassoc => '1', allpres => '0', search => '1', protocol => '1', searchcharset => '', wildcards => '3', carets => '0'); $writer->endTag(); $writer->startTag('host', name => 'KT', ae => 'ORTHANC2', ip => 'XX.YY.215.253', ts => '1.2.840.10008.1.2.1', port => '4242', maxassoc => '1', allpres => '0', search => '1', protocol => '1', searchcharset => '', wildcards => '3', carets => '0'); $writer->endTag(); $writer->startTag('host', name => 'R', ae => 'ORTHANC3', ip => 'XX.YY.215.252', ts => '1.2.840.10008.1.2.1', port => '4242', maxassoc => '1', allpres => '0', search => '1', protocol => '1', searchcharset => '', wildcards => '3', carets => '0'); $writer->endTag(); $writer->startTag('host', name => 'KT-20180501-20180831', ae => 'ORTHANC4', ip => 'XX.YY.215.251', ts => '1.2.840.10008.1.2.1', port => '4242', maxassoc => '1', allpres => '0', search => '1', protocol => '1', searchcharset => '', wildcards => '3', carets => '0'); $writer->endTag(); $writer->startTag('host', name => 'KT-20180901-20181130', ae => 'ORTHANC5', ip => 'XX.YY.215.250', ts => '1.2.840.10008.1.2.1', port => '4242', maxassoc => '1', allpres => '0', search => '1', protocol => '1', searchcharset => '', wildcards => '3', carets => '0'); $writer->endTag(); $writer->endTag('hosts'); $writer->startTag('presets'); $writer->endTag(); $writer->startTag('lastsearch', dt => '4', mfid => '1048592'); $writer->endTag(); $writer->endTag('pacs'); # XML : my $xml = $writer->end(); # : $rewritexml = $full_path_to_file; # XML : open (NEWXML, ">$rewritexml"); print NEWXML $xml; close (NEWXML); } } }
彼の仕事の原理:
- クライアントからpacs.xml構成を収集したディレクトリを開き、ファイルのリストをスカラーの配列(@report_files)に入れます。
- ループでは、一度に1つのファイルを処理し、1行ずつ読み取ります。
- splitを使用して、引用符を区切り記号として使用して、各行を5つの部分に分割します。
- リスナーという単語を含む行を見つけ、各ファイルに固有のデータ(クライアントAE名とTCPポート番号)を2つの変数に入れます。
- その後、新しいXMLファイルを作成し、一意のパラメーターを入力して、必要な数のPACSサーバーとそのパラメーターを挿入するだけです。 すべてが開始されたもの )
- 古いXMLファイルを古いXMLファイルの上に書き換えます。
実際、このスクリプトを完全に自動的に使用するわけではないことに注意してください。実際には、収集した構成を別のディレクトリにコピーしてからスクリプトを実行し、それらをすべて連続して変更します。 次に、ランダムチェック-構成をマシンに戻すことができます。
変更されたpacs.xmlファイルをクライアントに配布する
私に起こった最も簡単なことは、クライアントから構成を収集し、次の行を追加する既に動作している.batファイルを変更することでした:
If exist %APPDATA%\RadiantViewer\pacs.xml copy /Y \\srv.test.local\pconfigsnew$\pacs-%COMPUTERNAME%-%USERNAME%.xml %APPDATA%\RadiantViewer\pacs.xml
結果の.batファイルは次のようになります。
@echo off If exist %APPDATA%\RadiantViewer\pacs.xml copy %APPDATA%\RadiantViewer\pacs.xml \\srv.test.local\pconfigs$\pacs-%COMPUTERNAME%-%USERNAME%.xml If exist %APPDATA%\RadiantViewer\pacs.xml copy /Y \\srv.test.local\pconfigsnew$\pacs-%COMPUTERNAME%-%USERNAME%.xml %APPDATA%\RadiantViewer\pacs.xml
おわりに
このような「 ニーハイ 」ソリューション。 飛行は正常でしたが、すでに2回テストしました(2018年9月と2019年2月)。 もちろん、100%のクライアントは更新されませんが、この値に近づきます-残りはリモートで終了します。 参照によるスクリプト。