Public Access
Running the wizard under pwsh turned up two things review missed: "...dated folders for $entityName?" rendered as "...dated folders for " - ? is a legal character in an unbraced PowerShell variable name, so this looked up a variable called entityName? and got nothing. Braced. The settings screen showed "over (not set)" for a config whose protocol comes from an ftps:// prefix on the host, which is exactly the case worth spotting. It now reports what the upload will actually use, marked "(assumed)" when it was inferred rather than set.
656 lines
25 KiB
PowerShell
656 lines
25 KiB
PowerShell
# Interactive setup - asks plain questions and writes entity.json so nobody has
|
|
# to hand-edit JSON. Called by setup-entity.bat. Safe to re-run any time.
|
|
|
|
$scriptRoot = Split-Path -Parent $PSCommandPath
|
|
$entitiesDir = Join-Path $scriptRoot "Entities"
|
|
$winscpDll = Join-Path $scriptRoot "WinSCP\WinSCPnet.dll"
|
|
|
|
if (-not (Test-Path $entitiesDir)) { New-Item -ItemType Directory -Path $entitiesDir | Out-Null }
|
|
|
|
# -- Asking questions ---------------------------------------------------------
|
|
|
|
function Read-Answer($question, $default, [switch]$AllowBlank) {
|
|
while ($true) {
|
|
if ($default) {
|
|
Write-Host "$question " -NoNewline -ForegroundColor White
|
|
Write-Host "[$default]" -NoNewline -ForegroundColor DarkGray
|
|
Write-Host ": " -NoNewline -ForegroundColor White
|
|
} else {
|
|
Write-Host "${question}: " -NoNewline -ForegroundColor White
|
|
}
|
|
$answer = Read-Host
|
|
if ([string]::IsNullOrWhiteSpace($answer)) {
|
|
if ($default) { return $default }
|
|
if ($AllowBlank) { return $null }
|
|
Write-Host " (this one is required)" -ForegroundColor Yellow
|
|
continue
|
|
}
|
|
return $answer.Trim()
|
|
}
|
|
}
|
|
|
|
function Read-YesNo($question, $default) {
|
|
$hint = if ($default -eq "y") { "Y/n" } else { "y/N" }
|
|
while ($true) {
|
|
Write-Host "$question " -NoNewline -ForegroundColor White
|
|
Write-Host "($hint)" -NoNewline -ForegroundColor DarkGray
|
|
Write-Host ": " -NoNewline -ForegroundColor White
|
|
$answer = Read-Host
|
|
if ([string]::IsNullOrWhiteSpace($answer)) { $answer = $default }
|
|
switch ($answer.Trim().ToLower()) {
|
|
"y" { return $true }
|
|
"yes" { return $true }
|
|
"n" { return $false }
|
|
"no" { return $false }
|
|
}
|
|
Write-Host " (please answer y or n)" -ForegroundColor Yellow
|
|
}
|
|
}
|
|
|
|
function Read-Choice($question, $options, $default) {
|
|
Write-Host ""
|
|
Write-Host $question -ForegroundColor White
|
|
for ($i = 0; $i -lt $options.Count; $i++) {
|
|
Write-Host (" {0}. {1}" -f ($i + 1), $options[$i])
|
|
}
|
|
while ($true) {
|
|
Write-Host "Choose 1-$($options.Count) " -NoNewline -ForegroundColor White
|
|
Write-Host "[$default]" -NoNewline -ForegroundColor DarkGray
|
|
Write-Host ": " -NoNewline -ForegroundColor White
|
|
$answer = Read-Host
|
|
if ([string]::IsNullOrWhiteSpace($answer)) { $answer = [string]$default }
|
|
$n = 0
|
|
if ([int]::TryParse(([string]$answer).Trim(), [ref]$n) -and $n -ge 1 -and $n -le $options.Count) {
|
|
return $n
|
|
}
|
|
Write-Host " (type a number between 1 and $($options.Count))" -ForegroundColor Yellow
|
|
}
|
|
}
|
|
|
|
function Write-Header($text) {
|
|
Write-Host ""
|
|
Write-Host ("=" * 64) -ForegroundColor Cyan
|
|
Write-Host " $text" -ForegroundColor Cyan
|
|
Write-Host ("=" * 64) -ForegroundColor Cyan
|
|
}
|
|
|
|
function Write-Section($text) {
|
|
Write-Host ""
|
|
Write-Host "--- $text " -NoNewline -ForegroundColor Cyan
|
|
Write-Host ("-" * [Math]::Max(1, (58 - $text.Length))) -ForegroundColor Cyan
|
|
}
|
|
|
|
# -- Config file read/write ---------------------------------------------------
|
|
|
|
function Get-EntityNames {
|
|
if (-not (Test-Path $entitiesDir)) { return @() }
|
|
return @(Get-ChildItem -Path $entitiesDir -Directory |
|
|
Where-Object { $_.Name -ne "EXAMPLE" } |
|
|
ForEach-Object { $_.Name })
|
|
}
|
|
|
|
function Save-EntityConfig($entityName, $config) {
|
|
$dir = Join-Path $entitiesDir $entityName
|
|
if (-not (Test-Path $dir)) { New-Item -ItemType Directory -Path $dir | Out-Null }
|
|
$file = Join-Path $dir "entity.json"
|
|
$config | ConvertTo-Json -Depth 10 | Set-Content -Path $file -Encoding UTF8
|
|
return $file
|
|
}
|
|
|
|
function Get-EntityConfig($entityName) {
|
|
$file = Join-Path (Join-Path $entitiesDir $entityName) "entity.json"
|
|
if (-not (Test-Path $file)) { return $null }
|
|
return Get-Content $file -Raw | ConvertFrom-Json
|
|
}
|
|
|
|
function Copy-RunBat($entityName) {
|
|
$source = Join-Path $scriptRoot "run.bat"
|
|
$target = Join-Path (Join-Path $entitiesDir $entityName) "run.bat"
|
|
if ((Test-Path $source) -and -not (Test-Path $target)) {
|
|
Copy-Item -Path $source -Destination $target
|
|
}
|
|
}
|
|
|
|
# -- Asking about one server --------------------------------------------------
|
|
|
|
# Returns a hashtable of connection settings, or $null if the user backs out.
|
|
function Read-ServerDetails($label, $existing) {
|
|
$defaultHost = $null
|
|
$defaultUser = $null
|
|
$defaultProto = 1
|
|
if ($existing -and $existing.host) {
|
|
$defaultHost = (([string]$existing.host) -replace '^\w+://', '').Split('/')[0].Trim()
|
|
$defaultUser = $existing.username
|
|
switch (Get-ConnProtocol $existing "sftp") {
|
|
"ftps" { $defaultProto = 2 }
|
|
"ftp" { $defaultProto = 3 }
|
|
}
|
|
}
|
|
|
|
Write-Host ""
|
|
Write-Host "Server address for $label" -ForegroundColor White
|
|
Write-Host " Just the name - no sftp:// or ftp:// in front." -ForegroundColor DarkGray
|
|
Write-Host " Example: sft.polluxsystems.com" -ForegroundColor DarkGray
|
|
$serverHost = Read-Answer "Server address" $defaultHost
|
|
|
|
# Strip a pasted scheme/path so it can't break the connection later.
|
|
$serverHost = ($serverHost -replace '^\w+://', '').Split('/')[0].Trim()
|
|
|
|
$protoChoice = Read-Choice "How does $serverHost receive files?" @(
|
|
"SFTP - secure, port 22 (most common)",
|
|
"FTPS - secure FTP, port 21",
|
|
"FTP - plain, no encryption, port 21"
|
|
) $defaultProto
|
|
|
|
$protocol = @("sftp", "ftps", "ftp")[$protoChoice - 1]
|
|
|
|
Write-Host ""
|
|
$username = Read-Answer "Username" $defaultUser
|
|
|
|
$password = $null
|
|
if ($existing -and $existing.password) {
|
|
Write-Host ""
|
|
Write-Host "A password is already saved for this server." -ForegroundColor DarkGray
|
|
if (Read-YesNo "Keep the saved password?" "y") {
|
|
$password = $existing.password
|
|
}
|
|
}
|
|
if (-not $password) {
|
|
$password = Read-Answer "Password" $null
|
|
}
|
|
|
|
return @{
|
|
host = $serverHost
|
|
protocol = $protocol
|
|
username = $username
|
|
password = $password
|
|
}
|
|
}
|
|
|
|
function Read-RemotePath($what, $default) {
|
|
Write-Host ""
|
|
Write-Host "Where do $what go on the server?" -ForegroundColor White
|
|
Write-Host " Type {practice} where the practice name belongs and it gets" -ForegroundColor DarkGray
|
|
Write-Host " filled in automatically for each one - so one line covers all." -ForegroundColor DarkGray
|
|
Write-Host " Example: /home/clients/CAMBS/{practice}" -ForegroundColor DarkGray
|
|
return Read-Answer "Folder path" $default
|
|
}
|
|
|
|
# -- New / edit entity --------------------------------------------------------
|
|
|
|
function New-Entity {
|
|
Write-Header "Set up a new entity"
|
|
|
|
Write-Host ""
|
|
Write-Host "The entity name is the folder name you use for this group of" -ForegroundColor DarkGray
|
|
Write-Host "practices - for example CAMBS, RMI, INLAND." -ForegroundColor DarkGray
|
|
$entityName = $null
|
|
while (-not $entityName) {
|
|
$candidate = Read-Answer "Entity name" $null
|
|
if ($candidate.IndexOfAny([System.IO.Path]::GetInvalidFileNameChars()) -ge 0) {
|
|
Write-Host " A folder name cannot contain \ / : * ? "" < > | - try again." -ForegroundColor Yellow
|
|
continue
|
|
}
|
|
$entityName = $candidate
|
|
}
|
|
|
|
$entityDir = Join-Path $entitiesDir $entityName
|
|
if (Test-Path (Join-Path $entityDir "entity.json")) {
|
|
Write-Host ""
|
|
Write-Host "$entityName is already set up." -ForegroundColor Yellow
|
|
if (-not (Read-YesNo "Start over and replace its settings?" "n")) { return }
|
|
}
|
|
|
|
Write-Section "The daily upload"
|
|
Write-Host "These are the dated folders (like 20260826) full of scanned images." -ForegroundColor DarkGray
|
|
|
|
$daily = Read-ServerDetails "the daily files" $null
|
|
$tiffPath = Read-RemotePath "the daily image files" $null
|
|
|
|
Write-Host ""
|
|
$pdfPath = $null
|
|
Write-Host "Some entities get PT STMT files mixed into the same dated folder," -ForegroundColor DarkGray
|
|
Write-Host "and those go to a different folder on the server." -ForegroundColor DarkGray
|
|
if (Read-YesNo "Do PT STMT files show up in the dated folders for ${entityName}?" "n") {
|
|
$pdfPath = Read-RemotePath "the PT STMT files" $null
|
|
}
|
|
|
|
Write-Section "Patient files"
|
|
Write-Host "These come from Patient\Export\PT STMT_<date>\ - the folders the" -ForegroundColor DarkGray
|
|
Write-Host "rename script creates. Many entities do not use this at all." -ForegroundColor DarkGray
|
|
|
|
$patient = $null
|
|
$patientPath = $null
|
|
if (Read-YesNo "Does $entityName send patient files too?" "n") {
|
|
$samePlace = Read-Choice "Which server do the patient files go to?" @(
|
|
"The same server as the daily files ($($daily.host))",
|
|
"A different server"
|
|
) 1
|
|
if ($samePlace -eq 1) {
|
|
$patient = @{
|
|
host = $daily.host
|
|
protocol = $daily.protocol
|
|
username = $daily.username
|
|
password = $daily.password
|
|
}
|
|
} else {
|
|
$patient = Read-ServerDetails "the patient files" $null
|
|
}
|
|
$patientPath = Read-RemotePath "the patient .txt/.tif files" $null
|
|
}
|
|
|
|
$config = New-ConfigObject $daily $tiffPath $pdfPath $patient $patientPath
|
|
$file = Save-EntityConfig $entityName $config
|
|
Copy-RunBat $entityName
|
|
|
|
Write-Host ""
|
|
Write-Host "Saved $file" -ForegroundColor Green
|
|
|
|
Add-Practices $entityName
|
|
Write-Host ""
|
|
if (Read-YesNo "Test the connection now?" "y") { Test-Entity $entityName }
|
|
}
|
|
|
|
function New-ConfigObject($daily, $tiffPath, $pdfPath, $patient, $patientPath) {
|
|
$workflow = if ($patient) { "insurance+patient" } else { "insurance" }
|
|
|
|
$ftps = [ordered]@{
|
|
host = $daily.host
|
|
protocol = $daily.protocol
|
|
port = $null
|
|
username = $daily.username
|
|
password = $daily.password
|
|
tiff_path = $tiffPath
|
|
pdf_path = $pdfPath
|
|
}
|
|
|
|
$sftp = [ordered]@{
|
|
host = $null
|
|
protocol = $null
|
|
port = $null
|
|
username = $null
|
|
password = $null
|
|
patient_path = $null
|
|
}
|
|
if ($patient) {
|
|
$sftp.host = $patient.host
|
|
$sftp.protocol = $patient.protocol
|
|
$sftp.username = $patient.username
|
|
$sftp.password = $patient.password
|
|
$sftp.patient_path = $patientPath
|
|
}
|
|
|
|
return [PSCustomObject][ordered]@{
|
|
"_note" = "Written by setup-entity.bat - run it again to change anything. The 'ftps' section is the daily upload (it can be SFTP too - see protocol); the 'sftp' section is the patient files."
|
|
workflow = $workflow
|
|
ftps = [PSCustomObject]$ftps
|
|
sftp = [PSCustomObject]$sftp
|
|
}
|
|
}
|
|
|
|
function Add-Practices($entityName) {
|
|
$export1 = Join-Path (Join-Path $entitiesDir $entityName) "Export1"
|
|
if (-not (Test-Path $export1)) { New-Item -ItemType Directory -Path $export1 | Out-Null }
|
|
|
|
$existing = @(Get-ChildItem -Path $export1 -Directory | ForEach-Object { $_.Name })
|
|
Write-Section "Practices under $entityName"
|
|
|
|
if ($existing.Count -gt 0) {
|
|
Write-Host "Already there: $($existing -join ', ')" -ForegroundColor Gray
|
|
Write-Host ""
|
|
if (-not (Read-YesNo "Add more practice folders?" "n")) { return }
|
|
} else {
|
|
Write-Host "Type each practice name and press Enter." -ForegroundColor DarkGray
|
|
Write-Host "Press Enter on an empty line when you are done." -ForegroundColor DarkGray
|
|
}
|
|
|
|
while ($true) {
|
|
$name = Read-Answer "Practice name (blank to finish)" $null -AllowBlank
|
|
if (-not $name) { break }
|
|
if ($name.IndexOfAny([System.IO.Path]::GetInvalidFileNameChars()) -ge 0) {
|
|
Write-Host " A folder name cannot contain \ / : * ? "" < > | - try again." -ForegroundColor Yellow
|
|
continue
|
|
}
|
|
$dir = Join-Path $export1 $name
|
|
if (Test-Path $dir) {
|
|
Write-Host " $name already exists - skipped." -ForegroundColor Gray
|
|
continue
|
|
}
|
|
New-Item -ItemType Directory -Path $dir | Out-Null
|
|
New-Item -ItemType Directory -Path (Join-Path $dir "Archive sent to FTP") | Out-Null
|
|
New-Item -ItemType Directory -Path (Join-Path $dir "Patient\Export\Archive Sent to FTP") -Force | Out-Null
|
|
Write-Host " Created $name" -ForegroundColor Green
|
|
}
|
|
}
|
|
|
|
function Edit-Entity($entityName) {
|
|
$config = Get-EntityConfig $entityName
|
|
if (-not $config) {
|
|
Write-Host "No entity.json found for $entityName." -ForegroundColor Red
|
|
return
|
|
}
|
|
|
|
# A hand-written entity.json may be missing whole sections.
|
|
foreach ($section in @("ftps", "sftp")) {
|
|
if (-not $config.$section) {
|
|
Set-Field $config $section ([PSCustomObject]@{})
|
|
}
|
|
}
|
|
|
|
while ($true) {
|
|
Write-Header "$entityName - current settings"
|
|
Show-Settings $config
|
|
|
|
$choice = Read-Choice "What do you want to change?" @(
|
|
"The daily-upload server (address, protocol, login)",
|
|
"Where the daily image files go on the server",
|
|
"Where PT STMT files from the dated folder go",
|
|
"Patient files (server and folder)",
|
|
"Add practice folders",
|
|
"Nothing - save and go back"
|
|
) 6
|
|
|
|
switch ($choice) {
|
|
1 {
|
|
$d = Read-ServerDetails "the daily files" $config.ftps
|
|
Set-Field $config.ftps "host" $d.host
|
|
Set-Field $config.ftps "protocol" $d.protocol
|
|
Set-Field $config.ftps "username" $d.username
|
|
Set-Field $config.ftps "password" $d.password
|
|
}
|
|
2 {
|
|
Set-Field $config.ftps "tiff_path" (Read-RemotePath "the daily image files" $config.ftps.tiff_path)
|
|
}
|
|
3 {
|
|
Write-Host ""
|
|
if (Read-YesNo "Do PT STMT files show up in the dated folders?" "n") {
|
|
Set-Field $config.ftps "pdf_path" (Read-RemotePath "the PT STMT files" $config.ftps.pdf_path)
|
|
} else {
|
|
Set-Field $config.ftps "pdf_path" $null
|
|
Write-Host " PT STMT files from the dated folder will be ignored." -ForegroundColor Gray
|
|
}
|
|
}
|
|
4 {
|
|
Write-Host ""
|
|
if (Read-YesNo "Does $entityName send patient files?" "n") {
|
|
$same = Read-Choice "Which server do the patient files go to?" @(
|
|
"The same server as the daily files ($($config.ftps.host))",
|
|
"A different server"
|
|
) 1
|
|
if ($same -eq 1) {
|
|
Set-Field $config.sftp "host" $config.ftps.host
|
|
Set-Field $config.sftp "protocol" $config.ftps.protocol
|
|
Set-Field $config.sftp "username" $config.ftps.username
|
|
Set-Field $config.sftp "password" $config.ftps.password
|
|
} else {
|
|
$p = Read-ServerDetails "the patient files" $config.sftp
|
|
Set-Field $config.sftp "host" $p.host
|
|
Set-Field $config.sftp "protocol" $p.protocol
|
|
Set-Field $config.sftp "username" $p.username
|
|
Set-Field $config.sftp "password" $p.password
|
|
}
|
|
Set-Field $config.sftp "patient_path" (Read-RemotePath "the patient .txt/.tif files" $config.sftp.patient_path)
|
|
Set-Field $config "workflow" "insurance+patient"
|
|
} else {
|
|
Set-Field $config "workflow" "insurance"
|
|
Write-Host " Patient files turned off for $entityName." -ForegroundColor Gray
|
|
}
|
|
}
|
|
5 { Add-Practices $entityName }
|
|
6 {
|
|
$file = Save-EntityConfig $entityName $config
|
|
Copy-RunBat $entityName
|
|
Write-Host ""
|
|
Write-Host "Saved $file" -ForegroundColor Green
|
|
return
|
|
}
|
|
}
|
|
|
|
Save-EntityConfig $entityName $config | Out-Null
|
|
}
|
|
}
|
|
|
|
function Set-Field($object, $name, $value) {
|
|
$object | Add-Member -NotePropertyName $name -NotePropertyValue $value -Force
|
|
}
|
|
|
|
function Show-Settings($config) {
|
|
Write-Host ""
|
|
Write-Host " Daily upload" -ForegroundColor White
|
|
Write-Host " Server : $(Show-Value $config.ftps.host) over $(Show-Protocol $config.ftps 'ftp')"
|
|
Write-Host " Login : $(Show-Value $config.ftps.username) / $(Show-Password $config.ftps.password)"
|
|
Write-Host " Images to : $(Show-Value $config.ftps.tiff_path)"
|
|
Write-Host " PT STMT to: $(Show-Value $config.ftps.pdf_path)"
|
|
Write-Host ""
|
|
Write-Host " Patient files" -ForegroundColor White
|
|
if ($config.workflow -eq "insurance+patient") {
|
|
Write-Host " Server : $(Show-Value $config.sftp.host) over $(Show-Protocol $config.sftp 'sftp')"
|
|
Write-Host " Login : $(Show-Value $config.sftp.username) / $(Show-Password $config.sftp.password)"
|
|
Write-Host " Files to : $(Show-Value $config.sftp.patient_path)"
|
|
} else {
|
|
Write-Host " Not used for this entity." -ForegroundColor Gray
|
|
}
|
|
}
|
|
|
|
# Reports the protocol the upload will actually use, so a legacy config that
|
|
# only carries an "ftps://" prefix on the host doesn't read as unset.
|
|
function Show-Protocol($conn, $fallback) {
|
|
if ([string]::IsNullOrWhiteSpace([string]$conn.host)) { return "(not set)" }
|
|
$protocol = (Get-ConnProtocol $conn $fallback).ToUpper()
|
|
if ($conn.protocol) { return $protocol }
|
|
return "$protocol (assumed)"
|
|
}
|
|
|
|
function Show-Value($value) {
|
|
if ([string]::IsNullOrWhiteSpace([string]$value)) { return "(not set)" }
|
|
return [string]$value
|
|
}
|
|
|
|
function Show-Password($value) {
|
|
if ([string]::IsNullOrWhiteSpace([string]$value)) { return "(not set)" }
|
|
return "*" * ([string]$value).Length
|
|
}
|
|
|
|
# -- Connection test ----------------------------------------------------------
|
|
|
|
# Works out the protocol exactly the way engine.ps1 does, so a passing test
|
|
# here means the real run connects the same way.
|
|
function Get-ConnProtocol($conn, $fallback) {
|
|
if ($conn.protocol) {
|
|
$p = ([string]$conn.protocol).ToLower().Trim()
|
|
if ($p -in @("sftp", "ftps", "ftp")) { return $p }
|
|
}
|
|
if (([string]$conn.host) -imatch '^(\w+)://') {
|
|
$scheme = $Matches[1].ToLower()
|
|
if ($scheme -in @("sftp", "ftps", "ftp")) { return $scheme }
|
|
}
|
|
if ($conn.tls -eq $true) { return "ftps" }
|
|
return $fallback
|
|
}
|
|
|
|
function Get-SessionOptions($conn, $fallback) {
|
|
$opts = New-Object WinSCP.SessionOptions
|
|
# Older configs kept the protocol as an "sftp://" prefix on the host.
|
|
$opts.HostName = (([string]$conn.host) -replace '^\w+://', '').Split('/')[0].Trim()
|
|
$opts.UserName = $conn.username
|
|
$opts.Password = $conn.password
|
|
|
|
$protocol = Get-ConnProtocol $conn $fallback
|
|
if ($protocol -eq "sftp") {
|
|
$opts.Protocol = [WinSCP.Protocol]::Sftp
|
|
$opts.PortNumber = if ($conn.port) { [int]$conn.port } else { 22 }
|
|
$opts.GiveUpSecurityAndAcceptAnySshHostKey = $true
|
|
} else {
|
|
$opts.Protocol = [WinSCP.Protocol]::Ftp
|
|
$opts.PortNumber = if ($conn.port) { [int]$conn.port } else { 21 }
|
|
if ($protocol -eq "ftps") {
|
|
$opts.FtpSecure = [WinSCP.FtpSecure]::Explicit
|
|
$opts.GiveUpSecurityAndAcceptAnyTlsHostCertificate = $true
|
|
} else {
|
|
$opts.FtpSecure = [WinSCP.FtpSecure]::None
|
|
}
|
|
}
|
|
return $opts
|
|
}
|
|
|
|
function Test-ServerConnection($label, $conn, $pathTemplate, $practices, $fallback) {
|
|
Write-Host ""
|
|
Write-Host " $label" -ForegroundColor White
|
|
|
|
if ([string]::IsNullOrWhiteSpace([string]$conn.host)) {
|
|
Write-Host " Not set up - nothing to test." -ForegroundColor Gray
|
|
return
|
|
}
|
|
|
|
$opts = Get-SessionOptions $conn $fallback
|
|
$protocol = (Get-ConnProtocol $conn $fallback).ToUpper()
|
|
Write-Host " Connecting to $($opts.HostName) over $protocol as $($conn.username) ... " -NoNewline
|
|
|
|
$session = New-Object WinSCP.Session
|
|
try {
|
|
$session.Open($opts)
|
|
Write-Host "OK" -ForegroundColor Green
|
|
} catch {
|
|
Write-Host "FAILED" -ForegroundColor Red
|
|
Write-Host " $($_.Exception.Message)" -ForegroundColor Red
|
|
Write-Host ""
|
|
Write-Host " $(Get-ConnectionHint $_.Exception.Message)" -ForegroundColor Yellow
|
|
$session.Dispose()
|
|
return
|
|
}
|
|
|
|
if ([string]::IsNullOrWhiteSpace([string]$pathTemplate)) {
|
|
Write-Host " No folder path set yet - skipping the folder check." -ForegroundColor Gray
|
|
$session.Dispose()
|
|
return
|
|
}
|
|
|
|
try {
|
|
foreach ($practice in $practices) {
|
|
$remote = $pathTemplate -replace '\{practice\}', $practice
|
|
Write-Host " $remote ... " -NoNewline
|
|
if ($session.FileExists($remote)) {
|
|
Write-Host "found" -ForegroundColor Green
|
|
} else {
|
|
Write-Host "NOT THERE" -ForegroundColor Red
|
|
}
|
|
}
|
|
} catch {
|
|
Write-Host "could not check - $($_.Exception.Message)" -ForegroundColor Yellow
|
|
} finally {
|
|
$session.Dispose()
|
|
}
|
|
}
|
|
|
|
function Get-ConnectionHint($message) {
|
|
if ($message -imatch "cannot connect to an SFTP server using an FTP") {
|
|
return "This server wants SFTP. Run setup again and pick SFTP for this server."
|
|
}
|
|
if ($message -imatch "cannot connect to an FTP server using an SFTP|expected SSH") {
|
|
return "This server wants FTP or FTPS. Run setup again and pick FTPS for this server."
|
|
}
|
|
if ($message -imatch "authentication|password|login incorrect|530") {
|
|
return "The username or password was rejected. Run setup again and retype the login."
|
|
}
|
|
if ($message -imatch "host does not exist|no such host|could not resolve") {
|
|
return "That server address could not be found. Check it for a typo."
|
|
}
|
|
if ($message -imatch "timed out|timeout|refused") {
|
|
return "No answer from the server. Check the address, or ask IT whether the firewall allows it."
|
|
}
|
|
return "Write down this message - it says what the server objected to."
|
|
}
|
|
|
|
function Test-Entity($entityName) {
|
|
Write-Header "Testing $entityName"
|
|
|
|
if (-not (Test-Path $winscpDll)) {
|
|
Write-Host "WinSCP is not installed yet - run setup.bat first." -ForegroundColor Red
|
|
return
|
|
}
|
|
Get-ChildItem -Path (Join-Path $scriptRoot "WinSCP") -Recurse -File |
|
|
Unblock-File -ErrorAction SilentlyContinue
|
|
try {
|
|
Add-Type -Path $winscpDll
|
|
} catch {
|
|
Write-Host "Could not load WinSCP - $($_.Exception.Message)" -ForegroundColor Red
|
|
Write-Host "Try deleting the WinSCP folder and running setup.bat again." -ForegroundColor Yellow
|
|
return
|
|
}
|
|
|
|
$config = Get-EntityConfig $entityName
|
|
if (-not $config) {
|
|
Write-Host "No entity.json found for $entityName." -ForegroundColor Red
|
|
return
|
|
}
|
|
|
|
$export1 = Join-Path (Join-Path $entitiesDir $entityName) "Export1"
|
|
$practices = @()
|
|
if (Test-Path $export1) {
|
|
$practices = @(Get-ChildItem -Path $export1 -Directory | ForEach-Object { $_.Name })
|
|
}
|
|
if ($practices.Count -eq 0) {
|
|
Write-Host "No practice folders yet - testing the login only." -ForegroundColor Gray
|
|
}
|
|
|
|
Test-ServerConnection "Daily upload" $config.ftps $config.ftps.tiff_path $practices "ftp"
|
|
if ($config.ftps.pdf_path) {
|
|
Test-ServerConnection "PT STMT folders" $config.ftps $config.ftps.pdf_path $practices "ftp"
|
|
}
|
|
if ($config.workflow -eq "insurance+patient") {
|
|
Test-ServerConnection "Patient files" $config.sftp $config.sftp.patient_path $practices "sftp"
|
|
}
|
|
|
|
Write-Host ""
|
|
Write-Host "A folder marked NOT THERE means the upload will fail for that" -ForegroundColor Yellow
|
|
Write-Host "practice. Either the path is wrong, or the partner has not made" -ForegroundColor Yellow
|
|
Write-Host "the folder yet - check the path first, then ask them." -ForegroundColor Yellow
|
|
}
|
|
|
|
# -- Main menu ----------------------------------------------------------------
|
|
|
|
function Select-Entity($purpose) {
|
|
$names = Get-EntityNames
|
|
if ($names.Count -eq 0) {
|
|
Write-Host ""
|
|
Write-Host "No entities set up yet - pick 'Set up a new entity' first." -ForegroundColor Yellow
|
|
return $null
|
|
}
|
|
$choice = Read-Choice "Which entity do you want to $purpose" $names 1
|
|
return $names[$choice - 1]
|
|
}
|
|
|
|
Write-Header "Melissa Uploader - Setup"
|
|
Write-Host ""
|
|
Write-Host "This asks a few questions and writes the settings files for you." -ForegroundColor Gray
|
|
Write-Host "You never have to open one by hand." -ForegroundColor Gray
|
|
|
|
while ($true) {
|
|
$names = Get-EntityNames
|
|
Write-Host ""
|
|
if ($names.Count -gt 0) {
|
|
Write-Host "Entities set up so far: $($names -join ', ')" -ForegroundColor Gray
|
|
} else {
|
|
Write-Host "No entities set up yet." -ForegroundColor Gray
|
|
}
|
|
|
|
$choice = Read-Choice "What do you want to do?" @(
|
|
"Set up a new entity",
|
|
"Change an entity's settings",
|
|
"Test an entity's connection and folders",
|
|
"Quit"
|
|
) 4
|
|
|
|
switch ($choice) {
|
|
1 { New-Entity }
|
|
2 { $name = Select-Entity "change"; if ($name) { Edit-Entity $name } }
|
|
3 { $name = Select-Entity "test"; if ($name) { Test-Entity $name } }
|
|
4 {
|
|
Write-Host ""
|
|
Write-Host "Done. Double-click run-all.bat when you are ready to upload." -ForegroundColor Green
|
|
Write-Host ""
|
|
exit 0
|
|
}
|
|
}
|
|
}
|