Private/cliHelper.xconvert.Utils/cliHelper.xconvert.Utils.psm1
class xObOptions { [bool]$SkipDefaults = $true [string[]]$PropstoExclude [string[]]$PropstoInclude hidden [string[]]$Values [int]$MaxDepth = 10 } class xgen { static [xObOptions] $Options = [xObOptions]::new() # Use a cryptographic hash function (SHA-256) to generate a unique machine ID static [string] UniqueMachineId() { $Id = [string]($Env:MachineId) $vp = (Get-Variable VerbosePreference).Value try { Set-Variable VerbosePreference -Value $([System.Management.Automation.ActionPreference]::SilentlyContinue) $sha256 = [System.Security.Cryptography.SHA256]::Create() $HostOS = $(if ($(Get-Variable PSVersionTable -Value).PSVersion.Major -le 5 -or $(Get-Variable IsWindows -Value)) { "Windows" }elseif ($(Get-Variable IsLinux -Value)) { "Linux" }elseif ($(Get-Variable IsMacOS -Value)) { "macOS" }else { "UNKNOWN" }); if ($HostOS -eq "Windows") { if ([string]::IsNullOrWhiteSpace($Id)) { $machineId = Get-CimInstance -ClassName Win32_ComputerSystemProduct | Select-Object -ExpandProperty UUID Set-Item -Path Env:\MachineId -Value $([convert]::ToBase64String($sha256.ComputeHash([System.Text.Encoding]::UTF8.GetBytes($machineId)))); } $Id = [string]($Env:MachineId) } elseif ($HostOS -eq "Linux") { # $Id = (sudo cat /sys/class/dmi/id/product_uuid).Trim() # sudo prompt is a nono # Lets use mac addresses $Id = ([string[]]$(ip link show | grep "link/ether" | awk '{print $2}') -join '-').Trim() $Id = [convert]::ToBase64String($sha256.ComputeHash([System.Text.Encoding]::UTF8.GetBytes($Id))) } elseif ($HostOS -eq "macOS") { $Id = (system_profiler SPHardwareDataType | Select-String "UUID").Line.Split(":")[1].Trim() $Id = [convert]::ToBase64String($sha256.ComputeHash([System.Text.Encoding]::UTF8.GetBytes($Id))) } else { throw "Error: HostOS = '$HostOS'. Could not determine the operating system." } } catch { throw $_ } finally { $sha256.Clear(); $sha256.Dispose() Set-Variable VerbosePreference -Value $vp } return $Id } static [string[]] ListProperties([System.Object]$Obj) { return [xgen]::ListProperties($Obj, '') } static [string[]] ListProperties([System.Object]$Obj, [string]$Prefix = '') { $Properties = @() $Obj.PSObject.Properties | ForEach-Object { $PropertyName = $_.Name $FullPropertyName = if ([string]::IsNullOrEmpty($Prefix)) { $PropertyName } else { "$Prefix,$PropertyName" } $PropertyValue = $_.Value $propertyType = $_.TypeNameOfValue # $BaseType = $($propertyType -as 'type').BaseType.FullName if ($propertyType -is [System.ValueType]) { Write-Verbose "vt <= $propertyType" $Properties += $FullPropertyName } elseif ($propertyType -is [System.Object]) { Write-Verbose "ob <= $propertyType" $Properties += [xgen]::ListProperties($PropertyValue, $FullPropertyName) } } return $Properties } static [Object[]] ExcludeProperties($Object) { return [xgen]::ExcludeProperties($Object, [xgen]::Options.PropstoExclude) } static [Object[]] ExcludeProperties($Object, [string[]]$PropstoExclude) { $DefaultTypeProps = @() if ([xgen]::Options.SkipDefaults) { try { $DefaultTypeProps = @( $Object.GetType().GetProperties() | Select-Object -ExpandProperty Name -ErrorAction Stop ) } Catch { $null } } $allPropstoExclude = @( $PropstoExclude + $DefaultTypeProps ) | Select-Object -Unique return $Object.psobject.properties | Where-Object { $allPropstoExclude -notcontains $_.Name } } static [PSObject] RecurseObject($Object, [PSObject]$Output) { return [xgen]::RecurseObject($Object, '$Object', $Output, 0) } static [PSObject] RecurseObject($Object, [string[]]$Path, [PSObject]$Output, [int]$Depth) { $Depth++ #Get the children we care about, and their names $Children = [xgen]::ExcludeProperties($Object); #Loop through the children properties. foreach ($Child in $Children) { $ChildName = $Child.Name $ChildValue = $Child.Value # Handle special characters... $FriendlyChildName = $(if ($ChildName -match '[^a-zA-Z0-9_]') { "'$ChildName'" } else { $ChildName } ) $IsInInclude = ![xgen]::Options.PropstoInclude -or @([xgen]::Options.PropstoInclude).Where({ $ChildName -like $_ }) $IsInValue = ![xgen]::Options.Value -or (@([xgen]::Options.Value).Where({ $ChildValue -like $_ }).Count -gt 0) if ($IsInInclude -and $IsInValue -and $Depth -le [xgen]::Options.MaxDepth) { $ThisPath = @( $Path + $FriendlyChildName ) -join "." $Output | Add-Member -MemberType NoteProperty -Name $ThisPath -Value $ChildValue } if ($null -eq $ChildValue) { continue } if (($ChildValue.GetType() -eq $Object.GetType() -and $ChildValue -is [datetime]) -or ($ChildName -eq "SyncRoot" -and !$ChildValue)) { Write-Debug "Skipping $ChildName with type $($ChildValue.GetType().FullName)" continue } # Check for arrays by checking object type (this is a fix for arrays with 1 object) otherwise check the count of objects $IsArray = $(if (($ChildValue.GetType()).basetype.Name -eq "Array") { $true } else { @($ChildValue).count -gt 1 } ) $count = 0 #Set up the path to this node and the data... $CurrentPath = @( $Path + $FriendlyChildName ) -join "." #Get the children's children we care about, and their names. Also look for signs of a hashtable like type $ChildrensChildren = [xgen]::ExcludeProperties($ChildValue) $HashKeys = if ($ChildValue.Keys -and $ChildValue.Values) { $ChildValue.Keys } else { $null } if ($(@($ChildrensChildren).count -ne 0 -or $HashKeys) -and $Depth -lt [xgen]::Options.MaxDepth) { #This handles hashtables. But it won't recurse... if ($HashKeys) { foreach ($key in $HashKeys) { $Output | Add-Member -MemberType NoteProperty -Name "$CurrentPath['$key']" -Value $ChildValue["$key"] $Output = [xgen]::RecurseObject($ChildValue["$key"], "$CurrentPath['$key']", $Output, $depth) } } else { if ($IsArray) { foreach ($item in @($ChildValue)) { $Output = [xgen]::RecurseObject($item, "$CurrentPath[$count]", $Output, $depth) $Count++ } } else { $Output = [xgen]::RecurseObject($ChildValue, $CurrentPath, $Output, $depth) } } } } return $Output } static [hashtable[]] FindHashKeyValue($PropertyName, $Ast) { return [xgen]::FindHashKeyValue($PropertyName, $Ast, @()) } static [hashtable[]] FindHashKeyValue($PropertyName, $Ast, [string[]]$CurrentPath) { if ($PropertyName -eq ($CurrentPath -Join '.') -or $PropertyName -eq $CurrentPath[-1]) { return $Ast | Add-Member NoteProperty HashKeyPath ($CurrentPath -join '.') -PassThru -Force | Add-Member NoteProperty HashKeyName ($CurrentPath[-1]) -PassThru -Force }; $r = @() if ($Ast.PipelineElements.Expression -is [System.Management.Automation.Language.HashtableAst]) { $KeyValue = $Ast.PipelineElements.Expression ForEach ($KV in $KeyValue.KeyValuePairs) { $result = [xgen]::FindHashKeyValue($PropertyName, $KV.Item2, @($CurrentPath + $KV.Item1.Value)) if ($null -ne $result) { $r += $result } } } return $r } static [string] EscapeSpecialCharacters([string]$str) { if ([string]::IsNullOrWhiteSpace($str)) { return $str } else { [string]$ParsedText = $str if ($ParsedText.ToCharArray() -icontains "'") { $ParsedText = $ParsedText -replace "'", "''" } return $ParsedText } } } |