Private/Abstracts.psm1
|
using namespace System.IO using namespace System.Collections.Generic using namespace System.Collections.Specialized using namespace System.Management.Automation using module .\Enums.psm1 # Core Abstractions class Measurement { [int]$Min [int]$Max Measurement([int]$min, [int]$max) { $this.Min = $min $this.Max = $max } } class IAnsiConsoleCursor { } class IAnsiConsoleInput { } class IExclusivityMode { } class IAnsiConsole { [object]$Profile [IAnsiConsoleCursor]$Cursor [IAnsiConsoleInput]$Input [IExclusivityMode]$ExclusivityMode [object] GetWriter() { return $null } [void] Clear() { $this.Clear($true) } [void] Clear([bool]$_Home) {} [void] Write([IRenderable]$renderable) { } [void] WriteAnsi([object]$action) { # Action[AnsiWriter] } } class PsRecord { hidden [uri] $Remote # usually a gist uri hidden [string] $File hidden [datetime] $LastWriteTime = [datetime]::Now PsRecord() { $this._init_() } PsRecord($hashtable) { $this.Add(@($this.ToHashtable($hashtable))); $this._init_() } PsRecord([hashtable[]]$array) { $this.Add($array); $this._init_() } hidden [void] _init_() { $this.PsObject.Methods.Add([PSScriptMethod]::new('GetCount', [ScriptBlock]::Create({ ($this | Get-Member -Type *Property).count }))) $this.PsObject.Methods.Add([PSScriptMethod]::new('GetKeys', [ScriptBlock]::Create({ ($this | Get-Member -Type *Property).Name }))) } [void] Edit() { $this.Set([PsRecord]::EditFile([IO.FileInfo]::new($this.File))) $this.Save() } [void] Add([hashtable]$table) { [ValidateNotNull()][hashtable]$table = $table $Keys = $table.Keys | Where-Object { !$this.HasProperty($_) -and ($_.GetType().FullName -eq 'System.String' -or $_.GetType().BaseType.FullName -eq 'System.ValueType') } foreach ($key in $Keys) { if ($key -notin ('File', 'Remote', 'LastWriteTime')) { $nval = $table[$key]; [string]$val_type_name = ($null -ne $nval) ? $nval.GetType().Name : [string]::Empty if ($val_type_name -eq 'ScriptBlock') { $this.PsObject.Properties.Add([PsScriptProperty]::new($key, $nval, [scriptblock]::Create("throw [System.Management.Automation.SetValueException]::new('$key is read-only')"))) } else { $this | Add-Member -MemberType NoteProperty -Name $key -Value $nval } } else { $this.$key = $table[$key] } } } [void] Add([hashtable[]]$items) { foreach ($item in $items) { $this.Add($item) } } [void] Add([string]$key, [System.Object]$value) { [ValidateNotNullOrWhiteSpace()][string]$key = $key if (!$this.HasProperty($key)) { $htab = [hashtable]::new(); $htab.Add($key, $value); $this.Add($htab) } else { Write-Warning "Config.Add() Skipped $Key. Key already exists." } } [void] Add([List[hashtable]]$items) { foreach ($item in $items) { $this.Add($item) } } [void] Set([OrderedDictionary]$dict) { $dict.Keys.Foreach({ $this.Set($_, $dict["$_"]) }); } [void] Set([hashtable]$table) { [ValidateNotNull()][hashtable]$table = $table $Keys = $table.Keys | Where-Object { $_.GetType().FullName -eq 'System.String' -or $_.GetType().BaseType.FullName -eq 'System.ValueType' } | Sort-Object -Unique foreach ($key in $Keys) { $nval = $table[$key]; [string]$val_type_name = ($null -ne $nval) ? $nval.GetType().Name : [string]::Empty if ($val_type_name -eq 'ScriptBlock') { $this.PsObject.Properties.Add([PsScriptProperty]::new($key, $nval, [scriptblock]::Create("throw [System.Management.Automation.SetValueException]::new('$key is read-only')") )) } else { $this | Add-Member -MemberType NoteProperty -Name $key -Value $nval -Force } } } [void] Set([hashtable[]]$items) { foreach ($item in $items) { $this.Set($item) } } [void] Set([string]$key, [System.Object]$value) { $htab = [hashtable]::new(); $htab.Add($key, $value) $this.Set($htab) } # work in progress static [hashtable[]] Read([string]$FilePath) { $cfg = $null return $cfg } [bool] HasProperty([object]$Name) { [ValidateNotNullOrWhiteSpace()][string]$Name = $($Name -as 'string') return $this.PsObject.Properties.Name -contains "$Name" } [void] Import([String]$FilePath) { Write-Host "Import records: $FilePath ..." -ForegroundColor Green $this.Set([PsRecord]::Read($FilePath)) Write-Host "Import records Complete" -ForegroundColor Green } [byte[]] ToByte() { return $this | xconvert ToBytes } [hashtable] ToHashtable([object]$InputObject) { return $this.ToHashtable($InputObject, 64) } [hashtable] ToHashtable([object]$InputObject, [int] $MaxDepth) { # Base cases if ($null -eq $InputObject) { return $null } if ($MaxDepth -le 0) { return $InputObject } # Already a dictionary/hashtable — re-recurse its values if ($InputObject -is [System.Collections.IDictionary]) { $hash = @{} foreach ($key in $InputObject.Keys) { $hash[$key] = $this.ToHashtable($InputObject[$key], $MaxDepth - 1) } return $hash } # Enumerable (but not a string) — map each element if ($InputObject -is [System.Collections.IEnumerable] -and $InputObject -isnot [string]) { $collection = [System.Collections.Generic.List[object]]::new() foreach ($item in $InputObject) { $collection.Add($this.ToHashtable($item, $MaxDepth - 1)) } # Return a typed array so PowerShell doesn't unwrap a single-element list return , $collection.ToArray() } # PSObject (e.g. deserialized JSON, Select-Object output, custom objects) if ($InputObject -is [psobject] -and $InputObject.PSObject.Properties.Count -gt 0) { $hash = @{} foreach ($prop in $InputObject.PSObject.Properties) { $hash[$prop.Name] = $this.ToHashtable($prop.Value, $MaxDepth - 1) } return $hash } # Scalar / value type — return as-is return $InputObject } [void] Import([uri]$raw_uri) { } [void] Upload() { if ([string]::IsNullOrWhiteSpace($this.Remote)) { throw [System.ArgumentException]::new('remote') } } [array] ToArray() { $array = @(); $props = $this | Get-Member -MemberType NoteProperty if ($null -eq $props) { return @() } $props.name | ForEach-Object { $array += @{ $_ = $this.$_ } } return $array } [string] ToJson() { return [string]($this | Select-Object -ExcludeProperty count | ConvertTo-Json -Depth 3) } [System.Collections.Specialized.OrderedDictionary] ToOrdered() { $dict = [System.Collections.Specialized.OrderedDictionary]::new(); $Keys = $this.PsObject.Properties.Where({ $_.Membertype -like "*Property" }).Name if ($Keys.Count -gt 0) { $Keys | ForEach-Object { [void]$dict.Add($_, $this."$_") } } return $dict } [string] ToString() { $r = $this.ToArray(); $s = '' $shortnr = [ScriptBlock]::Create({ while ($str.Length -gt $MaxLength) { $str = $str.Substring(0, [Math]::Floor(($str.Length * 4 / 5))) } return $str } ) if ($r.Count -gt 1) { $b = $r[0]; $e = $r[-1] $0 = $shortnr.Invoke("{'$($b.Keys)' = '$($b.values.ToString())'}", 40) $1 = $shortnr.Invoke("{'$($e.Keys)' = '$($e.values.ToString())'}", 40) $s = "@($0 ... $1)" } elseif ($r.count -eq 1) { $0 = $shortnr.Invoke("{'$($r[0].Keys)' = '$($r[0].values.ToString())'}", 40) $s = "@($0)" } else { $s = '@()' } return $s } } class NetRouteDiagnostics { [string]$ComputerName [string]$RemoteAddress [string]$ConstrainSourceAddress [int]$ConstrainInterfaceIndex [bool]$Detailed [bool]$RouteDiagnosticsSucceeded [string[]]$RouteSelectionEvents = @() [string[]]$SourceAddressSelectionEvents = @() [string[]]$DestinationAddressSelectionEvents = @() [string]$LogFile [object]$SelectedNetRoute [object]$SelectedSourceAddress [object]$OutgoingNetAdapter [string]$OutgoingInterfaceAlias [int]$OutgoingInterfaceIndex [string]$OutgoingInterfaceDescription [string[]]$ResolvedAddresses } class TestNetConnectionResult { [string]$ComputerName [bool]$Detailed [string[]]$ResolvedAddresses [bool]$NameResolutionSucceeded [string]$RemoteAddress [bool]$TcpTestSucceeded [int]$RemotePort [bool]$PingSucceeded [object]$PingReplyDetails [string[]]$TraceRoute [object[]]$DNSOnlyRecords [object[]]$LLMNRNetbiosRecords [object[]]$BasicNameResolution [object[]]$AllNameResolutionResults [bool]$IsAdmin [string]$NetworkIsolationContext [object[]]$MatchingIPsecRules [string]$SourceAddress [object]$NetRoute [object]$NetAdapter [string]$InterfaceAlias [int]$InterfaceIndex [string]$InterfaceDescription } class RenderOptions : PsRecord { [ColorSystem]$ColorSystem = [ColorSystem]::NoColors [bool]$Ansi = $false [bool]$SingleLine = $false [Nullable[int]]$Height = $null [Nullable[Justify]]$Justification = $null [bool]$Unicode = $true RenderOptions() : base() {} RenderOptions($options) : base($options) {} static [RenderOptions] Create([object]$writer, [object]$capabilities) { $options = [RenderOptions]::new() if ($null -ne $capabilities) { $options.ColorSystem = $capabilities.ColorSystem $options.Ansi = $capabilities.Ansi } return $options } } class IRenderable { [Measurement] Measure([RenderOptions]$options, [int]$maxWidth) { $safeWidth = [Math]::Max(0, $maxWidth) return [Measurement]::new($safeWidth, $safeWidth) } [object[]] Render([RenderOptions]$options, [int]$maxWidth) { return [object[]]@() } } |