Bakgrund
In a medical organization, solutions based on Orthanc PACS servers and the Radiant DICOM client were implemented. During the configuration, it was found that each DICOM client must be described in PACS servers as follows:
- Client Name
- AE name (must be unique)
- TCP port, which is automatically opened on the client side and accepts DICOM studies from the PACS server (i.e., the server pushes them toward the client â initiating the connection first)
- IP-adress
After configuring the Radiant clients, the following information was received for consideration â for each client, the software settings with the specified parameters above led to the filling of the file pacs.xml, which was located in the user profile (path: %APPDATA%RadiantViewerpacs.xml). At the same time, the configuration of one client differed from another by at least two parameters (the AE name was different for everyone, while the port was mostly the same, except for terminal clients working on the same server â there, ports also had to be assigned differently).
Example of the pacs.xml file :
For about six months, everything was fine, the system was up and running⊠and then we encountered the âunderwater rocks»:
- . We need to introduce several new PACS servers that will replace the old ones (where disk space has started to run out). PACS servers in virtual machines, but that's not the point;
- We need to centrally change the unique configurations (with two differing parameters) on 200 machines (their number was regularly increasing);
- Given the growth rates of examination volumes, the solution needs to be not a one-time effort, but scalable and regular (for example, once every 3-5 months).
The solution is below.
Choosing the toolset for the task
Initially, attempts were made to find a solution that would modify the pacs.xml file on the client side, making changes to the list of PACS servers without touching the AE name and TCP port settings. Windows clients at that time were based on both Windows XP and Windows 7 â therefore, there were attempts to write something based on VBScript. But alas â accomplishing such a task proved impossible due to a complete lack of experience in writing anything complex and sophisticated in this language. Attempts to find and rewrite it also did not succeed (it should be noted that there was already another plan in mind, so I didn't spend more than 3-4 hours on VBScript).
In the end, I decided on the following solution:
- Samla alla pacs.xml-filer med en gruppolitik pÄ en valfri server i nÀtverksresursen;
- Ăndra filerna i bulk (erfarenhet av att lösa sĂ„dana uppgifter har redan funnits - med hjĂ€lp av Perl);
- Ăven uppdatera klientinstĂ€llningarna med hjĂ€lp av gruppolitik.
Insamling av filer med hjÀlp av gruppolitik
Den enklaste delen - nÀr en klient loggar in pÄ sin profil körs en .bat-fil med sina rÀttigheter dÀr det stÄr:
echo off
If exist %APPDATA%RadiantViewerpacs.xml copy %APPDATA%RadiantViewerpacs.xml srv.test.localpconfigs$pacs-%COMPUTERNAME%-%USERNAME%.xml
PÄ sÄ sÀtt kommer pacs.xml-filer att samlas pÄ servern i en dold resurs, dÀr filnamnen innehÄller information om frÄn vilken dator och vilken anvÀndare den aktuella konfigurationen kopierades.
Det svÄraste var att vÀnta pÄ att denna politik skulle tillÀmpas pÄ alla anvÀndare.
Ăndring av konfigurationer med hjĂ€lp av ett Perl-skript
Vi kommer att behöva för Windows frÄn ActiveState, samt modulen XML::Writer som kan installeras med kommandot ppm install XML-Writer.
SjÀlva skriptet blev ganska enkelt:
use XML::Writer;
# Ăppnar mappen med rapporter, bearbetar listan (tar bort överflödigt):
$report_dir = "C:Perl64WORKPACS-xml3";
opendir(DIR, "$report_dir") or die "Kan inte öppna mappen med rapporter!";
@report_files = readdir DIR;
shift (@report_files); # tar bort punkten frÄn array-elementen (.)
shift (@report_files); # tar bort de tvÄ punkterna frÄn array-elementen (..)
# print "@report_files";
closedir(DIR);
# Börjar bearbeta filer - en i taget. Behöver lÀsa parameter AET och portnummer i variabler.
foreach $analiz_file (@report_files)
{
$full_path_to_file="C:Perl64WORKPACS-xml3".$analiz_file;
open (INFO, $full_path_to_file);
while ($line = )
{
# Variablerna $aet och $port innehÄller unika data för varje XML-fil:
my ($other1, $aet, $other2, $port, $other3) = split /"/, $line, 5;
# Om raden 'listener' hittas har vi nÄtt den önskade raden och kan börja skapa en ny XML:
if ($other1 =~ 'listener')
{
# Skapar ny XML med nödvÀndiga fÀlt och 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');
# SÀtter fÀrdig XML i en variabel:
my $xml = $writer->end();
# Förbereder filen för skrivning:
$rewritexml = $full_path_to_file;
# Skriver om XML-filer med nya data:
open (NEWXML, "> $rewritexml");
print NEWXML $xml;
close (NEWXML);
}
}
}
Principen för dess arbete:
- Vi öppnar katalogen dÀr vi har samlat pacs.xml-konfigurationer frÄn kunder och lÀgger filerna i en array av skalÀrer (@report_files);
- I en loop behandlar vi en fil i taget och lÀser den rad för rad;
- Med hjÀlp av split delar vi varje rad i 5 delar, med citattecken som avgrÀnsare;
- Vi letar efter raden med ordet listener och placerar i tvÄ variabler unika data för varje fil (AE-kundnamn och TCP-portnummer);
- DĂ€refter skapar vi helt enkelt en ny XML-fil, skriver in de unika parametrarna och sĂ€tter in det nödvĂ€ndiga antalet PACS-servrar med deras parametrar â dvs. det vi gjorde det för)
- Vi skriver över den gamla XML-filen med den nya.
Det Ă€r vĂ€rt att nĂ€mna att jag faktiskt inte anvĂ€nder detta skript helt automatiskt â i grunden kopierar jag de insamlade konfigurationerna till en separat katalog och nĂ€r jag kör skriptet Ă€ndrar jag dem alla samtidigt. Sedan en stickprovsgranskning â och konfigurationerna kan spridas tillbaka till maskinerna.
Spridning av Àndrade pacs.xml-filer till kunder
Det enklaste som kom mig att tÀnka pÄ var att göra Àndringar i den redan fungerande .bat-filen, som samlar konfigurationerna frÄn kunder och lÀgga till raden:
If exist %APPDATA%RadiantViewerpacs.xml copy /Y srv.test.localpconfigsnew$pacs-%COMPUTERNAME%-%USERNAME%.xml %APPDATA%RadiantViewerpacs.xml
Den slutliga .bat-filen ser ut sÄ hÀr:
@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
Slutsats
SĂ„ hĂ€r Ă€r ett âprovisorisktlösning. Vi har testat det tvĂ„ gĂ„nger redan (i september 2018 och februari 2019), och hittills fungerar det bra. SjĂ€lvklart uppdaterar det inte 100% av kunderna, men nĂ€ra det vĂ€rdet â resten gör vi pĂ„ distans. Skriptet pĂ„ .
KĂ€lla: habr.com
