Files
FT546-WCS/tools/shadow/ShadowScriptCommon.ps1

158 lines
5.4 KiB
PowerShell

function Resolve-ShadowFile {
param([Parameter(Mandatory = $true)][string]$Path)
$item = Get-Item -LiteralPath $Path -ErrorAction Stop
if ($item.PSIsContainer) { throw "FILE_REQUIRED:$Path" }
return $item.FullName
}
function Resolve-ShadowDirectory {
param(
[Parameter(Mandatory = $true)][string]$Path,
[switch]$Create
)
if ($Create -and -not (Test-Path -LiteralPath $Path)) {
New-Item -ItemType Directory -Path $Path -Force | Out-Null
}
$item = Get-Item -LiteralPath $Path -ErrorAction Stop
if (-not $item.PSIsContainer) { throw "DIRECTORY_REQUIRED:$Path" }
return $item.FullName
}
function Write-ShadowJson {
param(
[Parameter(Mandatory = $true)]$Value,
[Parameter(Mandatory = $true)][string]$Path,
[int]$Depth = 12
)
$parent = Split-Path -Parent ([IO.Path]::GetFullPath($Path))
if (-not (Test-Path -LiteralPath $parent)) {
New-Item -ItemType Directory -Path $parent -Force | Out-Null
}
$Value | ConvertTo-Json -Depth $Depth | Set-Content -LiteralPath $Path `
-Encoding UTF8
}
function Read-ShadowJson {
param([Parameter(Mandatory = $true)][string]$Path)
$resolved = Resolve-ShadowFile $Path
return Get-Content -LiteralPath $resolved -Raw | ConvertFrom-Json
}
function Get-ShadowSha256 {
param([Parameter(Mandatory = $true)][string]$Path)
return (Get-FileHash -LiteralPath (Resolve-ShadowFile $Path) `
-Algorithm SHA256).Hash.ToLowerInvariant()
}
function Get-ShadowCommandLine {
param([Parameter(Mandatory = $true)][int]$ProcessId)
try {
$row = Get-CimInstance Win32_Process -Filter "ProcessId=$ProcessId" `
-ErrorAction Stop
return $row.CommandLine
}
catch { return $null }
}
function Get-ShadowListeningPorts {
param([Parameter(Mandatory = $true)][int]$ProcessId)
try {
return @(Get-NetTCPConnection -OwningProcess $ProcessId -State Listen `
-ErrorAction Stop | Sort-Object LocalPort | ForEach-Object {
[pscustomobject]@{
address = $_.LocalAddress
port = [int]$_.LocalPort
state = $_.State.ToString()
}
})
}
catch { return @() }
}
function Test-ShadowPathWithin {
param(
[Parameter(Mandatory = $true)][string]$Candidate,
[Parameter(Mandatory = $true)][string]$Directory
)
$candidatePath = [IO.Path]::GetFullPath($Candidate)
$directoryPath = [IO.Path]::GetFullPath($Directory).TrimEnd('\', '/')
if ($candidatePath.Equals($directoryPath,
[StringComparison]::OrdinalIgnoreCase)) { return $true }
$prefix = $directoryPath + [IO.Path]::DirectorySeparatorChar
return $candidatePath.StartsWith($prefix,
[StringComparison]::OrdinalIgnoreCase)
}
function Get-ShadowFreeBytes {
param([Parameter(Mandatory = $true)][string]$Path)
$root = [IO.Path]::GetPathRoot([IO.Path]::GetFullPath($Path))
return ([IO.DriveInfo]::new($root)).AvailableFreeSpace
}
function Resolve-ShadowScalarPlaceholder {
param([AllowNull()][string]$Value)
if ($null -eq $Value) { return $null }
if ($Value -match '^\$\{([A-Za-z_][A-Za-z0-9_]*):(.*)\}$') {
$environmentValue = [Environment]::GetEnvironmentVariable($matches[1])
return if ($null -eq $environmentValue) { $matches[2] } `
else { $environmentValue }
}
return $Value
}
function Read-ShadowYamlScalars {
param([Parameter(Mandatory = $true)][string]$Path)
$resolved = Resolve-ShadowFile $Path
$parents = @{}
$values = @{}
foreach ($line in Get-Content -LiteralPath $resolved) {
if ($line -match '^\s*(#.*)?$') { continue }
if ($line -notmatch '^(\s*)([A-Za-z0-9_-]+):(?:\s*(.*))?$') {
continue
}
$indent = $matches[1].Length
$key = $matches[2]
$raw = if ($null -eq $matches[3]) { '' } else { $matches[3].Trim() }
foreach ($level in @($parents.Keys | Where-Object { [int]$_ -ge $indent })) {
$parents.Remove($level)
}
if ([string]::IsNullOrWhiteSpace($raw)) {
$parents[$indent] = $key
continue
}
$segments = @($parents.Keys | Sort-Object { [int]$_ } | ForEach-Object {
$parents[$_]
}) + $key
if (($raw.StartsWith('"') -and $raw.EndsWith('"')) -or `
($raw.StartsWith("'") -and $raw.EndsWith("'"))) {
$raw = $raw.Substring(1, $raw.Length - 2)
}
$values[($segments -join '.')] = Resolve-ShadowScalarPlaceholder $raw
}
return $values
}
function Get-ShadowSqlServerJdbcIdentity {
param([Parameter(Mandatory = $true)][string]$JdbcUrl)
if ($JdbcUrl -notmatch '(?i)^jdbc:sqlserver://([^;]+)(?:;(.*))?$') {
throw 'SQLSERVER_JDBC_URL_REQUIRED'
}
$server = $matches[1].Trim()
$properties = @{}
foreach ($part in @($matches[2] -split ';')) {
if ($part -match '^\s*([^=]+)=(.*)$') {
$properties[$matches[1].Trim().ToLowerInvariant()] =
$matches[2].Trim()
}
}
$database = $properties['databasename']
if ([string]::IsNullOrWhiteSpace($database)) {
$database = $properties['database']
}
if ([string]::IsNullOrWhiteSpace($server) -or `
[string]::IsNullOrWhiteSpace($database)) {
throw 'SQLSERVER_JDBC_IDENTITY_INCOMPLETE'
}
return [pscustomobject]@{ server = $server; database = $database }
}