Зміна налаштувань програм із збереженням персональних параметрів

Передісторія

В одній медичній організації впроваджували рішення на базі PACS-серверів Orthanc та DICOM-клієнта Radiant. У ході налаштування з'ясували, що кожен DICOM-клієнт має бути описаний у PACS-серверах таким чином:

  • Ім'я клієнта
  • AE-ім'я (має бути унікально)
  • TCP-порт, який автоматично відкривається на стороні клієнта та приймає DICOM-обстеження від PACS-сервера (тобто сервер хіба що штовхає їх у бік клієнта – ініціюючи з'єднання першим)
  • IP-адреса

Після налаштування Radiant клієнтів отримали наступну інформацію для роздумів – у кожного клієнта налаштування ПЗ із зазначеними вище параметрами призводило до заповнення файлу pacs.xml, який розташовувався у профілі користувача (шлях: %APPDATA%RadiantViewerpacs.xml). При цьому конфіг одного клієнта від іншого відрізнявся мінімум двома параметрами (AE-ім'я у всіх різне, а порт переважно однаковий, крім термінальних клієнтів, що працюють на тому самому сервері – там порти теж доводилося призначати різними).

Приклад файлу pacs.xml за посиланням:

Приблизно півроку все було добре, система заробила ... і тут до нас дійшлипідводні камені'

  • Нам потрібно ввести в дію кілька нових PACS-серверів, які підмінять старі (де стало закінчуватися місце на дисках). PACS сервера у віртуальних машинах, але не про це;
  • Нам потрібно якось централізовано змінити унікальні конфігурації (двома параметрами) на 200 машинах (їх кількість регулярно збільшувалася);
  • Враховуючи темпи зростання обсягів обстежень, рішення потрібно не разове, а тиражується та регулярне (наприклад, 1 раз на 3-5 місяців).

Рішення нижче.

Вибір інструментарію для розв'язання задачі

Вначале были попытки найти какое-то решение, которое на стороне клиента изменяло файл pacs.xml, и вносило в него изменения в список PACS-серверов, не трогая настройки AE-имени и TCP-порта. Windows клиенты на тот момент были на базе как Windows XP, так и Windows 7 – поэтому были попытки написать что-то такое на базе VBScript. Но увы – осилить такую задачу не получилось, ввиду полного отсутствия опыта написания чего-либо сложного и комплексного на этом языке. Попытки же найти и переписать также не увенчались успехом (тут надо отметить, что в голове уже был другой план, поэтому я не долбился с VBScript больше 3-4 часов).

У результаті я зупинився на наступному рішенні:

  • Зібрати груповою політикою всі файли 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 скрипту

нам буде потрібно Активний Perl під Windows от компании ActiveState, а также модуль XML::Writer, который можно установить с помощью команды ppm install XML-Writer.

А сам скрипт вийшов досить простий:

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% клієнтів, але близько до цього значення - решту доробляємо віддалено. Скрипт по за посиланням.

Джерело: habr.com

Купити надійний хостинг для сайтів із захистом від DDoS, VPS VDS сервери 🔥 Купити надійний хостинг для сайтів із захистом від DDoS, VPS VDS сервери | ProHoster