lib/TMD.DataManipulation.ps1
## Data Reduction Functions Function Get-NameAndId { param( [Parameter(Mandatory = $false, ValueFromPipeline = $true)][AllowNull()]$Data = $null, [Parameter(Mandatory = $false, ValueFromPipeline = $false)][string]$IDName = 'id', [Parameter(Mandatory = $false, ValueFromPipeline = $false)][string]$IDValueFrom = 'Id', [Parameter(Mandatory = $false, ValueFromPipeline = $false)]$NameName = 'name', [Parameter(Mandatory = $false, ValueFromPipeline = $false)]$NameValueFrom = 'Name' ) Begin { } Process { ## Get the Name and ID of each of the objects. ## Using the defaults you'll have the JSON equivilent to { id: $_.Id; name: $_.Name } if ($Data) { ## Ensure that our data is wrapped with an array if ($Data.GetType() -eq 'System.Array') { foreach ($Item in $Data) { [System.Collections.Hashtable]@{ $IDName = $Item.$IDValueFrom $NameName = $Item.$NameValueFrom } } } else { [System.Collections.Hashtable]@{ $IDName = $Data.$IDValueFrom $NameName = $Data.$NameValueFrom } } } } End { } } Function ConvertTo-PlainObject { [CmdletBinding()] param ( [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)][AllowNull()] $InputObject ) return [System.Management.Automation.PSSerializer]::Deserialize([System.Management.Automation.PSSerializer]::Serialize($InputObject)) } Function Optimize-DataObject { param( [Parameter(Mandatory = $false, ValueFromPipeline = $true)][AllowNull()]$Data = $null, [Parameter(Mandatory = $false, ValueFromPipeline = $false)][scriptblock]$ProcessingMap, [Parameter(Mandatory = $false, ValueFromPipeline = $false)][String]$StartLabel, [Parameter(Mandatory = $false, ValueFromPipeline = $false)][String]$EndLabel, [Parameter(Mandatory = $false, ValueFromPipeline = $false)][int]$Level = 0 ) Begin { ## Print Start Label, Accomodate Level if ($StartLabel) { for ($i = 0; $i -lt $Level; $i++) { Write-Host " " -NoNewline } Write-Host "$StartLabel" } } Process { if ($Data) { foreach ($Global:Item in $Data) { Invoke-Command -ScriptBlock $ProcessingMap -NoNewScope -ErrorAction Continue } } } End { ## Print Start Label, Accomodate Level if ($EndLabel) { Write-Host "$EndLabel" } } } Function Test-VariableExists { param( [Parameter(Mandatory = $true)][String]$Name, [Parameter(Mandatory = $false)][Switch]$PassThru ) if (Get-Variable -Name $Name -ErrorAction SilentlyContinue) { if ($PassThru) { $var = Get-Variable $Name return $var } else { return $true } return $true } else { return $false } } Function New-VariableName ([String]$string) { if ($string.Length -gt 0) { $delimeters = @(' ', '.', ',', '_', '-', '(', ')', '\', '/', '?', ':', '?') $string = Replace-VariableCharWithCamelCase -string $string -delimeter $delimeters $string = $string.trim() $string = $string.replace('#', "Num") $string = Lowercase-FirstCharacter -string $string $string += "Var" $string } else { $string } } Function ConvertTo-LowercaseFirstCharacter([String]$string) { $string.Substring(0, 1).ToLower() + $string.Substring(1, $string.Length - 1) } Function ConvertTo-UppercaseFirstCharacter([String]$string) { $string.Substring(0, 1).ToUpper() + $string.Substring(1, $string.Length - 1) } Function ConvertTo-VariableCharWithCamelCase( [String]$string, [String[]]$delimeter ) { foreach ($delim in $delimeter) { if ($string.contains($delim)) { $stringArr = $string.Split($delim) $tempString = "" for ($i = 0; $i -lt $stringArr.Count; $i++) { $word = $stringArr[$i].trim() if ($word.length -gt 0) { $tempString += Uppercase-FirstCharacter -string $word } } $string = $tempString } } $string } Function ConvertTo-Array { param( [Parameter(Mandatory = $true, ValueFromPipeline = $True)][AllowNull()]$InputObject ) ## Initalize the Return Array $ResultArray = @() ## Return an empty array on Null objects if (-Not $InputObject) { return $ResultArray } ## Switch based on the Input Object type $ObjectType = $InputObject.GetType().BaseType switch ($ObjectType) { 'string' { ## A string may be an array object, as a Json string, for example $PossibleArray = $InputObject #| ConvertFrom-Json if (($PossibleArray.GetType()).BaseType -eq 'System.Array') { $ResultArray = @($InputObject) break } ## Replace end characters and quotes $InputObject = $InputObject.Replace('[', '') $InputObject = $InputObject.Replace(']', '') $InputObject = $InputObject.Replace("'", '') $InputObject = $InputObject.Replace('"', '') ## Split on a comma if there is one if ($InputObject.contains(',')) { $ResultArray = $InputObject -Split ',', ' ' | ForEach-Object { $_.Trim() } } else { if ($InputObject -ne '') { $ResultArray = @($InputObject) } } break } 'System.Object[]' { if ($ObjectType.BaseType.FullName -eq 'System.Array') { $ResultArray = $InputObject break } break } 'System.Array' { return $InputObject } ## No Array type objects were matched, return whatever was passed in as the only object in an array Default { $ResultArray = @($InputObject) break } } ## The comma below is deliberate. PowerShell will (oddly) strip an array down to it's most basic form (a null, a string). ## It's related to pipeline optimization Reasons. See https://www.reddit.com/r/PowerShell/comments/6yogs2/functions_that_return_arrays/ ## using the Comma ultimately 'returns 2 objects back', of which the first (an empty object before the comma) is discarded, and the array ## then passed through, even if it is @(null) or @('One String') return , $ResultArray } Function ConvertTo-Boolean { param( [AllowNull()]$InputObject ) if ($null -ne $InputObject) { switch ($InputObject.GetType().ToString()) { 'System.String' { $trueStrings = @('yes', 'y', 'true', 't', '1') $falseStrings = @('no', 'n', 'false', 'f', '0') if ($trueStrings.Contains($InputObject.ToLower())) { return $true } if ($falseStrings.Contains($InputObject.ToLower())) { return $false } return $false } 'System.Boolean' { if ($InputObject) { return $true } else { return $false } return $false } 'System.Int32' { if ($InputObject -gt 0) { return $true } else { return $false } return $false } Default { try { $asString = [System.Convert]::ToString($InputObject) $stringLikeTrue = [System.Convert]::ToBoolean($asString) if ($stringLikeTrue) { return $true } else { return $false } } catch { return $false } } } } } function Convert-Size { [cmdletbinding()] param( [validateset("Bytes", "KB", "MB", "GB", "TB")] [string]$From, [validateset("Bytes", "KB", "MB", "GB", "TB")] [string]$To, [Parameter(Mandatory = $true)] [double]$Value, [int]$Precision = 4 ) switch ($From) { "Bytes" { $value = $Value } "KB" { $value = $Value * 1024 } "MB" { $value = $Value * 1024 * 1024 } "GB" { $value = $Value * 1024 * 1024 * 1024 } "TB" { $value = $Value * 1024 * 1024 * 1024 * 1024 } } switch ($To) { "Bytes" { return $value } "KB" { $Value = $Value / 1KB } "MB" { $Value = $Value / 1MB } "GB" { $Value = $Value / 1GB } "TB" { $Value = $Value / 1TB } } return [Math]::Round($value, $Precision, [MidPointRounding]::AwayFromZero) } ## Method to assess an object and return the key at the provided node (Obj.Prop.SubProp.Value) function Get-Value($object, $key) { $p1, $p2 = $key.Split(".") if ($p2) { return Get-Value -object $object.$p1 -key $p2 } else { return $object.$p1 } } ## Method for setting values in an object node.address.format like Get-Value above function Set-Value($object, $key, $Value) { ## Deal with appropriate typing if ($Value -match "^\d+$") { $Value = [Int64]$Value } if ($Value -eq 'true') { $Value = $True } if ($Value -eq 'false') { $Value = $False } ## Split the Key into comparable parts # $p1, $p2 = $key.Split(".") | Select-Object -First 2 $p1, $p2 = $key.Split(".") ## Is the node an array reference if ($p1 -like '*]') { ## This node is an array object, separte the array node and the array pointer $p1Node = $p1 | Select-String -Pattern ".*[a-zA-Z]" | ForEach-Object { $_.Matches[0].Value } $p1Pointer = $p1 | Select-String -Pattern "[0-9]" | ForEach-Object { $_.Matches[0].Value } if ($p2) { Set-Value -object $object.$p1Node[$p1Pointer] -key $p2 -Value $Value } else { $object.$p1 = $Value } } else { ## This object is a flat node object, not an array. # Write-Host "Node is an object" if ($p2) { Set-Value -object $object.$p1 -key $p2 -Value $Value } else { $object.$p1 = $Value } } } |