背景
ある医療組織は、Orthanc PACS サーバーと Radiant DICOM クライアントに基づくソリューションを実装しました。 セットアップ中に、各 DICOM クライアントを PACS サーバーで次のように記述する必要があることがわかりました。
- クライアント名
- AE 名 (一意である必要があります)
- クライアント側で自動的に開き、PACS サーバーから DICOM サーベイを受信する TCP ポート (つまり、サーバーが DICOM サーベイをクライアントにプッシュし、最初に接続を開始します)
- IPアドレス
Radiant をセットアップした後、クライアントは次のような考えの材料を受け取りました。クライアントごとに、上記のパラメーターを使用してソフトウェアをセットアップすると、ファイルがいっぱいになりました。 pacs.xml、ユーザー プロファイルにあります (パス: %APPDATA%RadiantViewerpacs.xml)。 同時に、あるクライアントの構成は、少なくとも XNUMX つのパラメータにおいて別のクライアントとは異なりました (AE 名は全員で異なり、ポートは同じサーバー上で実行されている端末クライアントを除いて基本的に同じです)。そこでは、ポートにも異なるものが割り当てられます)。
pacs.xml ファイルの例
約 XNUMX か月間、すべてが順調に進み、システムが動作し始めました...そして、それが私たちのところにやって来ました。」水中 石»:
- (ディスク容量が不足し始めている) 古い PACS サーバーを置き換える新しい PACS サーバーをいくつか稼働させる必要があります。 仮想マシン内の PACS サーバーですが、それは私たちが話していることではありません。
- 200 台のマシン (その数は定期的に増加していました) 上の固有の構成 (XNUMX つの異なるパラメータ) を何らかの方法で一元的に変更する必要があります。
- 調査量の増加率を考慮すると、ソリューションは 1 回だけではなく、定期的に (たとえば、3 ~ 5 か月に XNUMX 回) 複製される必要があります。
問題を解決するためのツールの選択
最初は、AE 名と TCP ポート設定に影響を与えることなく、クライアント側で pacs.xml ファイルを変更し、PACS サーバーのリストを変更する解決策を見つける試みがありました。 当時の Windows クライアントは Windows XP と Windows 7 の両方に基づいていたため、VBScript に基づいてこのようなものを作成する試みがありました。 しかし、悲しいことに、この言語で複雑で複雑なものを書く経験がまったくなかったため、そのようなタスクを習得することはできませんでした。 検索して書き直す試みも失敗しました (注意すべき点として、頭の中に別の計画がすでにあったため、3 ~ 4 時間以上 VBScript をいじりませんでした)。
最終的には次の解決策に落ち着きました。
- グループ ポリシーを使用して、すべての pacs.xml ファイルをネットワーク リソース内の任意のサーバー上の XNUMX か所に収集します。
- ファイルを一括で変更します (私はすでに Perl を使用してそのような問題を解決した経験があります)。
- また、グループ ポリシーを使用してクライアント設定を更新します。
グループポリシーを使用したファイルの収集
最も単純な部分は、クライアントが自分のプロファイルにログインすると、自分の権限で次のような特定の .bat ファイルを実行することです。
echo off
If exist %APPDATA%RadiantViewerpacs.xml copy %APPDATA%RadiantViewerpacs.xml srv.test.localpconfigs$pacs-%COMPUTERNAME%-%USERNAME%.xml
したがって、pacs.xml ファイルはサーバー上の非表示リソースに蓄積されます。その名前には、この構成がどのコンピューターおよびどのユーザーからコピーされたかという情報が含まれています。
最も困難だったのは、このポリシーがすべてのユーザーに適用されるまで待つことでした。
Perl スクリプトを使用した構成の変更
必要になります
スクリプト自体は非常に単純であることがわかりました。
use XML::Writer;
# Открываем папку с отчетами, обрабатываем ссписок (удаляем лишнее):
$report_dir = "C:Perl64WORKPACS-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:Perl64WORKPACS-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) に配置します。
- ループでは、一度に XNUMX つのファイルを処理し、それを XNUMX 行ずつ読み取ります。
- 分割を使用すると、引用符を区切り文字として使用して、各行を 5 つの部分に分割します。
- 「listener」という単語を含む行を見つけて、各ファイルに固有のデータ (AE クライアント名と TCP ポート番号) を XNUMX つの変数に配置します。
- この後、単純に新しい XML ファイルを生成し、そのファイルに一意のパラメータを入力し、必要な数の PACS サーバーとそのパラメータを挿入します。 それらの。 すべては何のために始まったのか)
- 新しい XML ファイルを古い XML ファイルの上に書き換えます。
実際、私はこのスクリプトを完全に自動的に使用しているわけではないことに注意してください。実際には、収集した構成を別のディレクトリにコピーしてからスクリプトを実行し、すべてをまとめて変更します。 次に、ランダム チェックが行われ、構成がマシンに配布されます。
変更された pacs.xml ファイルをクライアントに配布する
思いついた最も簡単な方法は、クライアントから設定を収集するすでに動作している .bat ファイルに変更を加え、次の行を追加することでした。
If exist %APPDATA%RadiantViewerpacs.xml copy /Y srv.test.localpconfigsnew$pacs-%COMPUTERNAME%-%USERNAME%.xml %APPDATA%RadiantViewerpacs.xml
最終的な .bat ファイルは次のようになります。
@echo off
If exist %APPDATA%RadiantViewerpacs.xml copy %APPDATA%RadiantViewerpacs.xml srv.test.localpconfigs$pacs-%COMPUTERNAME%-%USERNAME%.xml
If exist %APPDATA%RadiantViewerpacs.xml copy /Y srv.test.localpconfigsnew$pacs-%COMPUTERNAME%-%USERNAME%.xml %APPDATA%RadiantViewerpacs.xml
まとめ
こんな感じです "膝" 解決。 すでに2018回(2019年100月とXNUMX年XNUMX月)試しましたが、今のところ飛行は正常です。 もちろん、クライアントの XNUMX% が更新されるわけではありませんが、この値に近い値です。残りはリモートで完了します。 脚本:
出所: habr.com