史前
一家医疗组织实施了基于 Orthanc PACS 服务器和 Radiant DICOM 客户端的解决方案。 在设置过程中,我们发现每个 DICOM 客户端必须在 PACS 服务器中进行如下描述:
- 客户名称
- AE名称(必须是唯一的)
- 自动在客户端打开并从 PACS 服务器接收 DICOM 调查的 TCP 端口(即服务器将它们推送到客户端 - 首先启动连接)
- IP地址
设置 Radiant 后,客户收到以下深思熟虑的信息:对于每个客户,使用上述参数设置软件都会导致文件被填满 pacs.xml,位于用户配置文件中(路径: %APPDATA%RadiantViewerpacs.xml)。 同时,一个客户端的配置至少在两个参数上与另一个客户端不同(每个人的 AE 名称都不同,端口基本相同,除了在同一服务器上运行的终端客户端 - 端口也有被分配不同)。
pacs.xml 文件示例
大约六个月的时间里,一切都很好,系统开始工作......然后它来了我们“水下 石头»:
- 我们需要投入运行几台新的 PACS 服务器来取代旧服务器(磁盘空间已经开始耗尽)。 虚拟机中的 PACS 服务器,但这不是我们讨论的内容;
- 我们需要以某种方式集中更改 200 台机器(它们的数量正在定期增加)上的独特配置(具有两个不同的参数);
- 考虑到调查量的增长率,解决方案不仅需要一次,而且需要定期重复(例如每 1-3 个月一次)。
选择解决问题的工具
起初,我们尝试寻找某种解决方案,修改客户端的 pacs.xml 文件并更改 PACS 服务器列表,而不影响 AE 名称和 TCP 端口设置。 当时的 Windows 客户端基于 Windows XP 和 Windows 7 - 因此有人尝试基于 VBScript 编写类似的东西。 但遗憾的是,由于完全缺乏用这种语言编写复杂而全面的内容的经验,因此不可能掌握这样的任务。 尝试查找和重写也没有成功(需要注意的是,我脑子里已经有了不同的计划,所以我没有花超过 3-4 个小时摆弄 VBScript)。
最终我选择了以下解决方案:
- 使用组策略,将所有 pacs.xml 文件收集到网络资源中任何服务器上的一个位置;
- 批量更改文件(我已经有使用 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);
- 在循环中,我们一次处理一个文件并逐行读取它;
- 使用 split,我们将每一行分成 5 部分,使用引号作为分隔符;
- 我们找到一行包含“listener”一词的行,并将每个文件唯一的数据(AE 客户端名称和 TCP 端口号)放入两个变量中;
- 之后,我们只需生成一个新的 XML 文件,在其中输入唯一的参数,然后插入所需数量的 PACS 服务器及其参数 - 那些。 这一切是为了什么而开始的)
- 我们在旧文件的基础上重写新的 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%的客户端更新,但已经接近这个值了——我们远程完成剩下的工作。 脚本由
来源: habr.com