This tutorial walks you through setting up the DICOM Proxy and performing your first DICOM echo test.
Step 1: Installation
# Extract the application
unzip DicomProxyRTWindows.zip -d C:\DicomProxy
# Navigate to directory
cd C:\DicomProxy
Step 2: Basic Configuration
Create appsettings.json
:
{
"DicomPort": 11112,
"HttpPort": 8080,
"StoragePath": "C:\\DicomStorage",
"ThisModality": {
"AE_Title": "DICOMPROXY",
"Port": 11112,
"IPAddress": "0.0.0.0"
}
}
Step 3: Start the Service
DicomProxyRTWindows.exe
Step 4: Test DICOM Connectivity
# Using DCMTK echoscu tool
echoscu localhost 11112 -aet TESTCLIENT -aec DICOMPROXY
# Expected output:
# I: Requesting Association
# I: Association Accepted (Max Send PDV: 16372)
# I: Sending Echo Request (MsgID 1)
# I: Received Echo Response (Success)
Step 1: Prepare a DICOM File Download a sample DICOM file or use your own medical image.
Step 2: Store via DICOM Protocol
# Using DCMTK storescu tool
storescu localhost 11112 -aet TESTCLIENT -aec DICOMPROXY sample.dcm
# Expected output:
# I: Requesting Association
# I: Association Accepted (Max Send PDV: 16372)
# I: Sending file: sample.dcm
# I: Transfer Syntax: Little Endian Implicit
# I: Sending C-STORE Request (MsgID 1)
# I: Received C-STORE Response (Success)
Step 3: Verify Storage via HTTP API
curl http://localhost:8080/wado/studies
Using DCMTK findscu:
# Query all studies
findscu localhost 11112 -aet TESTCLIENT -aec DICOMPROXY -k QueryRetrieveLevel=STUDY -k StudyInstanceUID
# Query studies for specific patient
findscu localhost 11112 -aet TESTCLIENT -aec DICOMPROXY \
-k QueryRetrieveLevel=STUDY \
-k PatientName="DOE^JOHN" \
-k StudyDate="" \
-k StudyInstanceUID=""
# Query studies by date range
findscu localhost 11112 -aet TESTCLIENT -aec DICOMPROXY \
-k QueryRetrieveLevel=STUDY \
-k StudyDate="20240101-20241231" \
-k StudyInstanceUID=""
# Retrieve entire study
getscu localhost 11112 -aet TESTCLIENT -aec DICOMPROXY \
-k QueryRetrieveLevel=STUDY \
-k StudyInstanceUID="1.2.3.4.5.6.7.8.9" \
--output-directory ./retrieved
# Retrieve specific series
getscu localhost 11112 -aet TESTCLIENT -aec DICOMPROXY \
-k QueryRetrieveLevel=SERIES \
-k StudyInstanceUID="1.2.3.4.5.6.7.8.9" \
-k SeriesInstanceUID="1.2.3.4.5.6.7.8.9.10" \
--output-directory ./retrieved
# Move study to another PACS
movescu localhost 11112 -aet TESTCLIENT -aec DICOMPROXY \
-aem DESTINATION_AE \
-k QueryRetrieveLevel=STUDY \
-k StudyInstanceUID="1.2.3.4.5.6.7.8.9"
Basic Study Search:
# Search all studies
curl "http://localhost:8080/wado/studies"
# Search with patient name filter
curl "http://localhost:8080/wado/studies?PatientName=DOE*"
# Search with date range
curl "http://localhost:8080/wado/studies?StudyDate=20240101-20241231"
# Complex search with multiple filters
curl "http://localhost:8080/wado/studies?PatientName=DOE*&ModalitiesInStudy=CT&StudyDate=20240101-20241231&limit=10"
Series Search:
# Get all series for a study
curl "http://localhost:8080/wado/studies/1.2.3.4.5.6.7.8.9/series"
# Filter series by modality
curl "http://localhost:8080/wado/studies/1.2.3.4.5.6.7.8.9/series?Modality=CT"
Instance Search:
# Get all instances in a series
curl "http://localhost:8080/wado/studies/1.2.3.4.5.6.7.8.9/series/1.2.3.4.5.6.7.8.9.10/instances"
Retrieve Study Metadata:
curl -H "Accept: application/json" \
"http://localhost:8080/wado/studies/1.2.3.4.5.6.7.8.9/metadata"
Retrieve Instance as DICOM:
curl -H "Accept: application/dicom" \
"http://localhost:8080/wado/studies/1.2.3.4.5.6.7.8.9/series/1.2.3.4.5.6.7.8.9.10/instances/1.2.3.4.5.6.7.8.9.10.11" \
-o image.dcm
Retrieve Rendered Image:
curl -H "Accept: image/jpeg" \
"http://localhost:8080/wado/studies/1.2.3.4.5.6.7.8.9/series/1.2.3.4.5.6.7.8.9.10/instances/1.2.3.4.5.6.7.8.9.10.11/rendered?viewport=512,512" \
-o image.jpg
Store Single DICOM File:
curl -X POST \
-H "Content-Type: multipart/related; type=\"application/dicom\"" \
--data-binary @image.dcm \
"http://localhost:8080/wado/studies"
Store Multiple Files:
# Using multipart form data
curl -X POST \
-H "Content-Type: multipart/related; type=\"application/dicom\"" \
-F "file1=@image1.dcm" \
-F "file2=@image2.dcm" \
"http://localhost:8080/wado/studies"
servers.json Configuration:
{
"servers": [
{
"id": "primary_pacs",
"name": "Primary PACS Server",
"ae_title": "PRIMARYPACS",
"hostname": "192.168.1.100",
"port": 11112,
"enabled": true,
"priority": 1,
"max_connections": 20,
"timeout_seconds": 30,
"supported_services": ["C-STORE", "C-FIND", "C-GET", "C-MOVE", "C-ECHO"]
},
{
"id": "archive_pacs",
"name": "Archive PACS Server",
"ae_title": "ARCHIVEPACS",
"hostname": "192.168.1.101",
"port": 11112,
"enabled": true,
"priority": 2,
"max_connections": 10,
"timeout_seconds": 60,
"supported_services": ["C-STORE", "C-FIND", "C-GET", "C-ECHO"]
},
{
"id": "cloud_pacs",
"name": "Cloud PACS",
"ae_title": "CLOUDPACS",
"hostname": "cloud.pacs.example.com",
"port": 11112,
"enabled": true,
"priority": 3,
"max_connections": 5,
"timeout_seconds": 120,
"supported_services": ["C-STORE", "C-FIND", "C-GET"]
}
]
}
Testing Multi-PACS Setup:
# Test connectivity to each PACS
curl -X POST "http://localhost:8080/proxy/echo/primary_pacs"
curl -X POST "http://localhost:8080/proxy/echo/archive_pacs"
curl -X POST "http://localhost:8080/proxy/echo/cloud_pacs"
# Query specific PACS
curl "http://localhost:8080/proxy/wado/primary_pacs/rs/studies?PatientName=DOE*"
curl "http://localhost:8080/proxy/wado/archive_pacs/rs/studies?StudyDate=20230101-20231231"
PowerShell Script for Batch Operations:
# batch_operations.ps1
param(
[string]$ProxyUrl = "http://localhost:8080",
[string]$InputFolder = "C:\DICOM\Input",
[string]$LogFile = "C:\DICOM\Logs\batch.log"
)
function Write-Log {
param($Message)
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
"$timestamp - $Message" | Add-Content -Path $LogFile
Write-Host "$timestamp - $Message"
}
function Upload-DicomFile {
param($FilePath)
try {
$response = Invoke-RestMethod -Uri "$ProxyUrl/wado/studies" `
-Method Post `
-ContentType "application/dicom" `
-InFile $FilePath
Write-Log "Successfully uploaded: $FilePath"
return $true
}
catch {
Write-Log "Failed to upload $FilePath : $($_.Exception.Message)"
return $false
}
}
# Main processing loop
Write-Log "Starting batch upload from $InputFolder"
$dicomFiles = Get-ChildItem -Path $InputFolder -Filter "*.dcm" -Recurse
$successCount = 0
$failureCount = 0
foreach ($file in $dicomFiles) {
if (Upload-DicomFile -FilePath $file.FullName) {
$successCount++
# Move successful files to processed folder
$processedFolder = Join-Path $InputFolder "Processed"
if (!(Test-Path $processedFolder)) { New-Item -Path $processedFolder -ItemType Directory }
Move-Item -Path $file.FullName -Destination $processedFolder
}
else {
$failureCount++
}
}
Write-Log "Batch upload completed. Success: $successCount, Failures: $failureCount"
Python Script for Monitoring:
# monitoring.py
import requests
import time
import json
import logging
from datetime import datetime
class DicomProxyMonitor:
def __init__(self, proxy_url="http://localhost:8080"):
self.proxy_url = proxy_url
self.setup_logging()
def setup_logging(self):
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler('monitor.log'),
logging.StreamHandler()
]
)
self.logger = logging.getLogger(__name__)
def check_system_status(self):
"""Check overall system status"""
try:
response = requests.get(f"{self.proxy_url}/api/status", timeout=10)
if response.status_code == 200:
status = response.json()
self.logger.info(f"System Status OK - Studies: {status.get('studies_count', 'N/A')}")
return True
else:
self.logger.error(f"System status check failed: {response.status_code}")
return False
except Exception as e:
self.logger.error(f"System status check error: {str(e)}")
return False
def check_pacs_connectivity(self):
"""Check connectivity to all configured PACS servers"""
try:
response = requests.get(f"{self.proxy_url}/api/connections", timeout=10)
if response.status_code == 200:
connections = response.json()
for server in connections.get('configured_servers', []):
server_id = server.get('id')
status = server.get('status')
if status == 'Connected':
self.logger.info(f"PACS {server_id}: Connected")
else:
self.logger.warning(f"PACS {server_id}: {status}")
# Try to reconnect
self.test_pacs_echo(server_id)
except Exception as e:
self.logger.error(f"PACS connectivity check error: {str(e)}")
def test_pacs_echo(self, server_id):
"""Test DICOM echo to specific PACS"""
try:
response = requests.post(f"{self.proxy_url}/proxy/echo/{server_id}", timeout=30)
if response.status_code == 200:
result = response.json()
if result.get('success'):
self.logger.info(f"PACS {server_id} echo successful")
else:
self.logger.error(f"PACS {server_id} echo failed")
except Exception as e:
self.logger.error(f"PACS {server_id} echo error: {str(e)}")
def monitor_loop(self, interval_minutes=5):
"""Main monitoring loop"""
self.logger.info("Starting DICOM Proxy monitoring")
while True:
self.logger.info("--- Monitoring Cycle ---")
# Check system status
if self.check_system_status():
# If system is up, check PACS connectivity
self.check_pacs_connectivity()
# Wait for next cycle
time.sleep(interval_minutes * 60)
if __name__ == "__main__":
monitor = DicomProxyMonitor()
monitor.monitor_loop(interval_minutes=5)
Complete C# Integration Example:
using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Http;
using System.Text.Json;
using System.Threading.Tasks;
using DicomProxyCore;
using DicomProxyCore.Services;
using FellowOakDicom;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
public class DicomProxyIntegration
{
private readonly HttpClient _httpClient;
private readonly ILogger<DicomProxyIntegration> _logger;
private readonly string _proxyUrl;
public DicomProxyIntegration(string proxyUrl = "http://localhost:8080")
{
_proxyUrl = proxyUrl;
_httpClient = new HttpClient();
// Setup logging
var services = new ServiceCollection()
.AddLogging(builder => builder.AddConsole())
.BuildServiceProvider();
_logger = services.GetService<ILogger<DicomProxyIntegration>>();
}
public async Task<List<StudyInfo>> SearchStudiesAsync(StudyQuery query)
{
var queryParams = new List<string>();
if (!string.IsNullOrEmpty(query.PatientName))
queryParams.Add($"PatientName={Uri.EscapeDataString(query.PatientName)}");
if (!string.IsNullOrEmpty(query.StudyDate))
queryParams.Add($"StudyDate={query.StudyDate}");
if (!string.IsNullOrEmpty(query.Modality))
queryParams.Add($"ModalitiesInStudy={query.Modality}");
if (query.Limit.HasValue)
queryParams.Add($"limit={query.Limit}");
var url = $"{_proxyUrl}/wado/studies";
if (queryParams.Count > 0)
url += "?" + string.Join("&", queryParams);
try
{
var response = await _httpClient.GetStringAsync(url);
var jsonResponse = JsonDocument.Parse(response);
var studies = new List<StudyInfo>();
foreach (var element in jsonResponse.RootElement.EnumerateArray())
{
studies.Add(ParseStudyFromJson(element));
}
_logger.LogInformation($"Found {studies.Count} studies");
return studies;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error searching studies");
throw;
}
}
public async Task<bool> StoreStudyAsync(string dicomFilePath)
{
try
{
var fileBytes = await File.ReadAllBytesAsync(dicomFilePath);
var content = new ByteArrayContent(fileBytes);
content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/dicom");
var response = await _httpClient.PostAsync($"{_proxyUrl}/wado/studies", content);
if (response.IsSuccessStatusCode)
{
_logger.LogInformation($"Successfully stored: {dicomFilePath}");
return true;
}
else
{
_logger.LogError($"Failed to store {dicomFilePath}: {response.StatusCode}");
return false;
}
}
catch (Exception ex)
{
_logger.LogError(ex, $"Error storing study: {dicomFilePath}");
return false;
}
}
public async Task<byte[]> RetrieveInstanceAsync(string studyUID, string seriesUID, string instanceUID, string format = "application/dicom")
{
try
{
_httpClient.DefaultRequestHeaders.Accept.Clear();
_httpClient.DefaultRequestHeaders.Accept.Add(
new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue(format));
var url = $"{_proxyUrl}/wado/studies/{studyUID}/series/{seriesUID}/instances/{instanceUID}";
if (format.StartsWith("image/"))
url += "/rendered";
var response = await _httpClient.GetByteArrayAsync(url);
_logger.LogInformation($"Retrieved instance: {instanceUID}");
return response;
}
catch (Exception ex)
{
_logger.LogError(ex, $"Error retrieving instance: {instanceUID}");
throw;
}
}
public async Task<SystemStatus> GetSystemStatusAsync()
{
try
{
var response = await _httpClient.GetStringAsync($"{_proxyUrl}/api/status");
var json = JsonDocument.Parse(response);
var root = json.RootElement;
return new SystemStatus
{
ServiceName = root.GetProperty("service_name").GetString(),
Version = root.GetProperty("version").GetString(),
UptimeSeconds = root.GetProperty("uptime_seconds").GetInt32(),
StudiesCount = root.GetProperty("studies_count").GetInt32(),
StorageUsedGB = root.GetProperty("storage_used_gb").GetDouble(),
StorageAvailableGB = root.GetProperty("storage_available_gb").GetDouble()
};
}
catch (Exception ex)
{
_logger.LogError(ex, "Error getting system status");
throw;
}
}
private StudyInfo ParseStudyFromJson(JsonElement element)
{
var study = new StudyInfo();
if (element.TryGetProperty("0020000D", out var studyUidProp))
study.StudyInstanceUID = studyUidProp.GetProperty("Value")[0].GetString();
if (element.TryGetProperty("00100010", out var patientNameProp))
{
var nameValue = patientNameProp.GetProperty("Value")[0];
if (nameValue.TryGetProperty("Alphabetic", out var alphabetic))
study.PatientName = alphabetic.GetString();
}
if (element.TryGetProperty("00100020", out var patientIdProp))
study.PatientID = patientIdProp.GetProperty("Value")[0].GetString();
if (element.TryGetProperty("00080020", out var studyDateProp))
study.StudyDate = studyDateProp.GetProperty("Value")[0].GetString();
if (element.TryGetProperty("00080061", out var modalityProp))
study.Modality = modalityProp.GetProperty("Value")[0].GetString();
return study;
}
public void Dispose()
{
_httpClient?.Dispose();
}
}
// Supporting classes
public class StudyQuery
{
public string PatientName { get; set; }
public string StudyDate { get; set; }
public string Modality { get; set; }
public int? Limit { get; set; }
}
public class StudyInfo
{
public string StudyInstanceUID { get; set; }
public string PatientName { get; set; }
public string PatientID { get; set; }
public string StudyDate { get; set; }
public string Modality { get; set; }
}
public class SystemStatus
{
public string ServiceName { get; set; }
public string Version { get; set; }
public int UptimeSeconds { get; set; }
public int StudiesCount { get; set; }
public double StorageUsedGB { get; set; }
public double StorageAvailableGB { get; set; }
}
// Usage example
public class Program
{
public static async Task Main(string[] args)
{
using var integration = new DicomProxyIntegration("http://localhost:8080");
// Get system status
var status = await integration.GetSystemStatusAsync();
Console.WriteLine($"System: {status.ServiceName} v{status.Version}");
Console.WriteLine($"Studies: {status.StudiesCount}");
// Search for studies
var query = new StudyQuery
{
PatientName = "DOE*",
StudyDate = "20240101-20241231",
Limit = 10
};
var studies = await integration.SearchStudiesAsync(query);
foreach (var study in studies)
{
Console.WriteLine($"Study: {study.PatientName} - {study.StudyDate}");
}
// Store a DICOM file
await integration.StoreStudyAsync("sample.dcm");
}
}
Bulk Upload Script (PowerShell):
# bulk_upload.ps1
param(
[string]$SourceFolder,
[string]$ProxyUrl = "http://localhost:8080",
[int]$ConcurrentUploads = 5
)
function Upload-DicomFile {
param($FilePath, $Url)
try {
Invoke-RestMethod -Uri "$Url/wado/studies" `
-Method Post `
-ContentType "application/dicom" `
-InFile $FilePath -TimeoutSec 300
return @{ Success = $true; File = $FilePath }
}
catch {
return @{ Success = $false; File = $FilePath; Error = $_.Exception.Message }
}
}
# Get all DICOM files
$files = Get-ChildItem -Path $SourceFolder -Filter "*.dcm" -Recurse
# Process in parallel batches
$batches = @()
for ($i = 0; $i -lt $files.Count; $i += $ConcurrentUploads) {
$batch = $files[$i..([Math]::Min($i + $ConcurrentUploads - 1, $files.Count - 1))]
$batches += ,$batch
}
$totalSuccess = 0
$totalFailure = 0
foreach ($batch in $batches) {
Write-Host "Processing batch of $($batch.Count) files..."
$jobs = foreach ($file in $batch) {
Start-Job -ScriptBlock ${function:Upload-DicomFile} -ArgumentList $file.FullName, $ProxyUrl
}
$results = $jobs | Wait-Job | Receive-Job
$jobs | Remove-Job
foreach ($result in $results) {
if ($result.Success) {
$totalSuccess++
Write-Host "✓ $($result.File)" -ForegroundColor Green
} else {
$totalFailure++
Write-Host "✗ $($result.File): $($result.Error)" -ForegroundColor Red
}
}
}
Write-Host "Upload completed. Success: $totalSuccess, Failures: $totalFailure"
Optimized Configuration:
{
"DicomPort": 11112,
"HttpPort": 8080,
"StoragePath": "D:\\DicomStorage",
"Performance": {
"MaxConcurrentConnections": 100,
"ConnectionPoolSize": 50,
"RequestTimeoutSeconds": 300,
"MaxMemoryUsageMB": 4096,
"EnableCompression": true,
"CacheExpirationMinutes": 30
},
"Database": {
"MaxConnections": 20,
"CommandTimeoutSeconds": 60,
"EnableWAL": true
},
"Storage": {
"MaxConcurrentWrites": 10,
"UseAsyncIO": true,
"BufferSizeKB": 64
}
}
Problem: DICOM operations timing out
Diagnosis:
# Check system status
curl http://localhost:8080/api/status
# Check specific server connectivity
curl -X POST http://localhost:8080/proxy/echo/pacs1
# Review logs
tail -f C:\DicomStorage\logs\dicom-proxy-*.log
Solution:
{
"servers": [
{
"id": "pacs1",
"timeout_seconds": 120,
"max_connections": 5,
"retry_count": 3,
"retry_delay_seconds": 5
}
]
}
Automated Cleanup Script:
# cleanup_storage.ps1
param(
[string]$StoragePath = "C:\DicomStorage",
[int]$MaxStorageGB = 500,
[int]$RetentionDays = 90
)
function Get-FolderSize {
param($Path)
return (Get-ChildItem -Path $Path -Recurse -File | Measure-Object -Property Length -Sum).Sum / 1GB
}
function Remove-OldStudies {
param($Path, $Days)
$cutoffDate = (Get-Date).AddDays(-$Days)
$studyFolders = Get-ChildItem -Path "$Path\studies" -Directory
$removedCount = 0
$freedSpace = 0
foreach ($folder in $studyFolders) {
if ($folder.CreationTime -lt $cutoffDate) {
$folderSize = Get-FolderSize $folder.FullName
Remove-Item -Path $folder.FullName -Recurse -Force
$removedCount++
$freedSpace += $folderSize
Write-Host "Removed study: $($folder.Name) ($('{0:N2}' -f $folderSize) GB)"
}
}
Write-Host "Cleanup complete: $removedCount studies removed, $('{0:N2}' -f $freedSpace) GB freed"
}
# Check current usage
$currentSize = Get-FolderSize $StoragePath
Write-Host "Current storage usage: $('{0:N2}' -f $currentSize) GB"
if ($currentSize -gt $MaxStorageGB) {
Write-Host "Storage limit exceeded. Starting cleanup..."
Remove-OldStudies -Path $StoragePath -Days $RetentionDays
}
Real-time Monitoring Script:
# performance_monitor.py
import requests
import time
import psutil
import json
from datetime import datetime
class PerformanceMonitor:
def __init__(self, proxy_url="http://localhost:8080"):
self.proxy_url = proxy_url
self.metrics_history = []
def get_system_metrics(self):
"""Get system performance metrics"""
return {
'timestamp': datetime.now().isoformat(),
'cpu_percent': psutil.cpu_percent(interval=1),
'memory_percent': psutil.virtual_memory().percent,
'disk_usage_percent': psutil.disk_usage('C:').percent,
'network_io': dict(psutil.net_io_counters()._asdict())
}
def get_dicom_metrics(self):
"""Get DICOM proxy specific metrics"""
try:
response = requests.get(f"{self.proxy_url}/api/metrics", timeout=5)
if response.status_code == 200:
return response.json()
except:
pass
return {}
def monitor(self, duration_minutes=60, interval_seconds=30):
"""Monitor system for specified duration"""
end_time = time.time() + (duration_minutes * 60)
print(f"Starting {duration_minutes}-minute monitoring session...")
print("Timestamp,CPU%,Memory%,Disk%,DICOM_Requests/min")
while time.time() < end_time:
system_metrics = self.get_system_metrics()
dicom_metrics = self.get_dicom_metrics()
# Combine metrics
combined_metrics = {**system_metrics, **dicom_metrics}
self.metrics_history.append(combined_metrics)
# Print summary
dicom_rpm = dicom_metrics.get('dicom_stats', {}).get('c_store_requests_per_minute', 0)
print(f"{system_metrics['timestamp'][:19]},"
f"{system_metrics['cpu_percent']:.1f},"
f"{system_metrics['memory_percent']:.1f},"
f"{system_metrics['disk_usage_percent']:.1f},"
f"{dicom_rpm}")
# Check for alerts
if system_metrics['cpu_percent'] > 80:
print(f"ALERT: High CPU usage: {system_metrics['cpu_percent']:.1f}%")
if system_metrics['memory_percent'] > 85:
print(f"ALERT: High memory usage: {system_metrics['memory_percent']:.1f}%")
time.sleep(interval_seconds)
# Save metrics to file
with open(f"metrics_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json", 'w') as f:
json.dump(self.metrics_history, f, indent=2)
print("Monitoring session completed. Metrics saved to file.")
if __name__ == "__main__":
monitor = PerformanceMonitor()
monitor.monitor(duration_minutes=60, interval_seconds=30)
Generate and Configure SSL Certificate:
# ssl_setup.ps1
param(
[string]$CertPath = "C:\DicomProxy\certificate.pfx",
[string]$Password = "DicomProxy2024!",
[string]$DnsName = "localhost"
)
# Generate self-signed certificate
$cert = New-SelfSignedCertificate -DnsName $DnsName -CertStoreLocation "cert:\LocalMachine\My" -KeyUsage DigitalSignature,KeyEncipherment -TextExtension @("2.5.29.37={text}1.3.6.1.5.5.7.3.1")
# Export to PFX file
$securePassword = ConvertTo-SecureString $Password -AsPlainText -Force
Export-PfxCertificate -Cert $cert -FilePath $CertPath -Password $securePassword
Write-Host "Certificate created: $CertPath"
Write-Host "Certificate thumbprint: $($cert.Thumbprint)"
# Update configuration
$configPath = "appsettings.json"
if (Test-Path $configPath) {
$config = Get-Content $configPath | ConvertFrom-Json
$config.Security.EnableTLS = $true
$config.Security.CertificatePath = "certificate.pfx"
$config.Security.CertificatePassword = $Password
$config | ConvertTo-Json -Depth 10 | Set-Content $configPath
Write-Host "Configuration updated with SSL settings"
}
This comprehensive examples and tutorials document provides practical, real-world scenarios for implementing and using the DICOM Proxy system across various integration patterns and use cases.