Achtergrond
In een medische organisatie werden oplossingen op basis van PACS-servers Orthanc en DICOM-client Radiant geïmplementeerd. Tijdens de configuratie bleek dat elke DICOM-client op de volgende manier in de PACS-servers moest worden beschreven:
- Klantnaam
- AE-naam (moet uniek zijn)
- TCP-poort die automatisch aan de clientzijde wordt geopend en DICOM-onderzoeken van de PACS-server accepteert (dus de server 'duwt' ze naar de client – door de verbinding als eerste te initiëren)
- IP-adres
Na de configuratie kregen we de volgende informatie om over na te denken – bij elke client leidde de software-instelling met de hierboven genoemde parameters tot het invullen van het bestand pacs.xml, dat zich in het gebruikersprofiel bevond (pad: %APPDATA%RadiantViewerpacs.xml). Hierbij verschilden de configuraties van de ene client naar de andere minimaal in twee parameters (AE-namen zijn bij iedereen verschillend, terwijl de poorten over het algemeen hetzelfde zijn, behalve voor terminalclients die op dezelfde server draaien – daar moesten de poorten ook verschillend worden toegewezen).
Voorbeeld van het pacs.xml-bestand per :
Ongeveer zes maanden ging alles goed, het systeem werkte... en toen kwamen we de "onderwater vallen»:
- tegen. We moeten enkele nieuwe PACS-servers in gebruik nemen, die de oude zullen vervangen (waarop de schijfruimte opraakte). PACS-servers in virtuele machines, maar daar gaat het nu niet om;
- We moeten op een of andere manier centraal de unieke configuraties (met twee verschillende parameters) op 200 machines veranderen (het aantal nam regelmatig toe);
- Gezien de groei van het aantal onderzoeken is de oplossing niet eenmalig, maar reproduceerbaar en regelmatig nodig (bijvoorbeeld eens in de 3-5 maanden).
De oplossing staat hieronder.
Selectie van gereedschappen voor het oplossen van de taak
In het begin waren er pogingen om een oplossing te vinden die aan de clientzijde het bestand pacs.xml wijzigde en aan de lijst van PACS-servers wijzigingen toevoegde, zonder de instellingen van AE-naam en TCP-poort aan te raken. Windows-clients waren toen gebaseerd op zowel Windows XP als Windows 7 – daarom waren er pogingen om iets dergelijks op basis van VBScript te schrijven. Maar helaas – het was niet gelukt om zo'n taak te voltooien, vanwege het complete gebrek aan ervaring met het schrijven van iets complex en geavanceerd in deze taal. Pogingen om ook iets te vinden en opnieuw te schrijven waren ook niet succesvol (hierbij moet worden opgemerkt dat er al een ander plan in mijn hoofd zat, dus ik heb niet meer dan 3-4 uur aan VBScript besteed).
Uiteindelijk heb ik me gericht op de volgende oplossing:
- Verzamel met groepsbeleid alle bestanden pacs.xml op één plek op een server in een netwerkbron;
- Wijzig de bestanden in één keer (ervaringsverhaal met dergelijke taken is al gedaan – met behulp van Perl);
- Ook met behulp van groepsbeleid de instellingen van de clients bijwerken.
Bestanden verzamelen met behulp van groepsbeleid
Het gemakkelijkste deel – wanneer een cliënt zijn profiel binnenkomt, voert hij met zijn rechten een .bat-bestand uit, waarin staat:
echo off
If exist %APPDATA%RadiantViewerpacs.xml copy %APPDATA%RadiantViewerpacs.xml srv.test.localpconfigs$pacs-%COMPUTERNAME%-%USERNAME%.xml
Zo zullen op de server in een verborgen bron bestanden pacs.xml worden verzameld, waarvan de naam informatie bevat over van welke computer en welke gebruiker deze configuratie is gekopieerd.
Het moeilijkste was – wachten tot de beleidsregels bij alle gebruikers zijn uitgevoerd.
Configuraties wijzigen met behulp van een Perl-script
We hebben nodig voor Windows van ActiveState, en ook de module XML::Writer, die kan worden geïnstalleerd met het commando ppm install XML-Writer.
Het script zelf is vrij eenvoudig geworden:
use XML::Writer;
# Open the folder with reports, process the list (remove unnecessary items):
$report_dir = "C:Perl64WORKPACS-xml3";
opendir(DIR, "$report_dir") or die "Cannot open the folder with reports!";
@report_files = readdir DIR;
shift (@report_files); # remove the dot from array elements (.)
shift (@report_files); # remove two dots from array elements (..)
# print "@report_files";
closedir(DIR);
# Begin processing files - one at a time. Need to read the AET parameter and the port number into variables.
foreach $analiz_file (@report_files)
{
$full_path_to_file="C:Perl64WORKPACS-xml3".$analiz_file;
open (INFO, $full_path_to_file);
while ($line = )
{
# Variables $aet and $port contain unique data for each XML file:
my ($other1, $aet, $other2, $port, $other3) = split /"/ , $line, 5;
# If the line 'listener' is encountered, we've reached the necessary line and can form a new XML:
if ($other1 =~ 'listener')
{
# Form a new XML with the necessary fields and data:
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');
# Place the finished XML in a variable:
my $xml = $writer->end();
# Prepare the file for rewriting:
$rewritexml = $full_path_to_file;
# Rewrite XML files with new data:
open (NEWXML, "> $rewritexml");
print NEWXML $xml;
close (NEWXML);
}
}
}
Werking principe:
- We open the catalog where we have gathered configurations pacs.xml from clients and place the list of files in the array scalars (@report_files);
- We process one file at a time in a loop and read it line by line;
- Using split, we break each line into 5 parts, using quotes as a delimiter;
- We find the line containing the word listener and store unique data for each file (AE-client name and TCP port number) in two variables;
- After this, we simply create a new XML file, write the unique parameters into it, and then insert the required number of PACS servers with their parameters – that is, the very reason for the whole endeavor)
- We overwrite the new XML file over the old one.
It should be noted that, in fact, I do not use this script fully automatically – I essentially copy the collected configs into a separate catalog and then, when running the script, change them all at once. Then a selective check – and the configs can be distributed back to the machines.
Distribution of modified pacs.xml files among clients
The simplest thing that came to mind is to make changes to the already functioning .bat file that collects configurations from clients and add the line:
If exist %APPDATA%RadiantViewerpacs.xml copy /Y srv.test.localpconfigsnew$pacs-%COMPUTERNAME%-%USERNAME%.xml %APPDATA%RadiantViewerpacs.xml
The final .bat file looks like this:
@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
Conclusie
This is a "makeshift" solution. We have tested it twice already (in September 2018 and February 2019), and so far the operation is normal. Of course, it does not update 100% of clients, but it's close to that value — we finish the rest remotely. The script on .
Bron: habr.com
