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 } } } ## Method for getting a TimeSpan that is Human Readable format function Get-TimeSpanString { [CmdletBinding()] param ( [Parameter(Mandatory = $false)] [datetime] $From = (Get-Date), [Parameter(Mandatory = $True)] [datetime] $To ) process { $SecondsReference = @{ Year = (60 * 60 * 24 * 365) Month = (60 * 60 * 24 * 30) Day = (60 * 60 * 24) Hour = (60 * 60) Minute = 60 } ## Calculate the Timespan $TimespanSeconds = (New-TimeSpan -Start $From -End $To).TotalSeconds ## Create a Span String to collect the required parts to $SpanStringParts = [System.Collections.ArrayList]@() ## Record how many years $Years = [math]::Floor($TimespanSeconds / $SecondsReference.Year) if ($Years -and ($SpanStringParts.Count -lt 2)) { [void]($SpanStringParts.Add("$($Years)y")) $TimespanSeconds -= ($Years * $SecondsReference.Year) } ## Record how many Months $Months = [math]::Floor($TimespanSeconds / $SecondsReference.Month) if ($Months -and ($SpanStringParts.Count -lt 2)) { [void]($SpanStringParts.Add("$($Months)Mo")) $TimespanSeconds -= ($Months * $SecondsReference.Month) } ## Record how many Days $Days = [math]::Floor($TimespanSeconds / $SecondsReference.Day) if ($Days -and ($SpanStringParts.Count -lt 2)) { [void]($SpanStringParts.Add("$($Days)d")) $TimespanSeconds -= ($Days * $SecondsReference.Day) } ## Record how many Hours $Hours = [math]::Floor($TimespanSeconds / $SecondsReference.Hour) if ($Hours -and ($SpanStringParts.Count -lt 2)) { [void]($SpanStringParts.Add("$($Hours)h")) $TimespanSeconds -= ($Hours * $SecondsReference.Hour) } ## Record how many Minutes $Minutes = [math]::Floor($TimespanSeconds / $SecondsReference.Minute) if ($Minutes -and ($SpanStringParts.Count -lt 2)) { [void]($SpanStringParts.Add("$($Minutes)m")) $TimespanSeconds -= ($Minutes * $SecondsReference.Minute) } ## Record how many Seconds if ($TimespanSeconds -and ($SpanStringParts.Count -lt 2)) { [void]($SpanStringParts.Add("$([math]::Floor($TimespanSeconds))s")) } ## Compile the Span String $SpanString = $SpanStringParts -join ' ' ## If the From Date is before the TO date, the time is "In XYZ" if($TimespanSeconds -ge 0){ $SpanString = "In $($SpanString)" } else { $SpanString = "$($SpanString) ago" } $SpanString } } |