functions/hashtableTools.ps1
Function Convert-HashtableString { [cmdletbinding()] [OutputType([System.Collections.Hashtable])] Param( [parameter(Mandatory, HelpMessage = "Enter your hashtable string", ValueFromPipeline)] [ValidateNotNullOrEmpty()] [string]$Text ) Begin { Write-Verbose "[BEGIN ] Starting: $($MyInvocation.Mycommand)" } #begin Process { $tokens = $null $err = $null $ast = [System.Management.Automation.Language.Parser]::ParseInput($Text, [ref]$tokens, [ref]$err) $data = $ast.find( {$args[0] -is [System.Management.Automation.Language.HashtableAst]}, $true) if ($err) { Throw $err } else { $data.SafeGetValue() } } End { Write-Verbose "[END ] Ending: $($MyInvocation.Mycommand)" } #end } Function ConvertTo-HashTable { [cmdletbinding()] [OutputType([System.Collections.Specialized.OrderedDictionary])] Param( [Parameter( Position = 0, Mandatory, HelpMessage = "Please specify an object", ValueFromPipeline )] [ValidateNotNullorEmpty()] [object]$InputObject, [switch]$NoEmpty, [string[]]$Exclude, [switch]$Alphabetical ) Process { #get type using the [Type] class because deserialized objects won't have #a GetType() method which is what we would normally use. $TypeName = [system.type]::GetTypeArray($InputObject).name Write-Verbose "Converting an object of type $TypeName" #get property names using Get-Member $names = $InputObject | Get-Member -MemberType properties | Select-Object -ExpandProperty name if ($Alphabetical) { Write-Verbose "Sort property names alphabetically" $names = $names | Sort-Object } #define an empty hash table $hash = [ordered]@{} #go through the list of names and add each property and value to the hash table $names | ForEach-Object { #only add properties that haven't been excluded if ($Exclude -notcontains $_) { #only add if -NoEmpty is not called and property has a value if ($NoEmpty -AND -Not ($inputobject.$_)) { Write-Verbose "Skipping $_ as empty" } else { Write-Verbose "Adding property $_" $hash.Add($_, $inputobject.$_) } } #if exclude notcontains else { Write-Verbose "Excluding $_" } } #foreach Write-Verbose "Writing the result to the pipeline" Write-Output $hash }#close process }#end function Function Convert-HashTableToCode { [cmdletbinding()] [OutputType([system.string])] Param( [Parameter(Position = 0, ValueFromPipeline, Mandatory)] [ValidateNotNullorEmpty()] [hashtable]$Hashtable, [Alias("tab")] [int]$Indent = 1 ) Begin { Write-Verbose "Starting $($myinvocation.mycommand)" } Process { Write-Verbose "Processing a hashtable with $($hashtable.keys.count) keys" $hashtable.GetEnumerator() | foreach-object -begin { $out = @" @{ "@ } -Process { Write-Verbose "Testing type $($_.value.gettype().name) for $($_.key)" #determine if the value needs to be enclosed in quotes if ($_.value.gettype().name -match "Int|double") { write-Verbose "..is an numeric" $value = $_.value } elseif ($_.value -is [array]) { #assuming all the members of the array are of the same type write-Verbose "..is an array" #test if an array of numbers otherwise treat as strings if ($_.value[0].Gettype().name -match "int|double") { $value = $_.value -join ',' } else { $value = "'{0}'" -f ($_.value -join "','") } } elseif ($_.value -is [hashtable]) { $nested = Convert-HashTableToCode $_.value -Indent $($indent + 1) $value = "$($nested)" } else { write-Verbose "..defaulting as a string" $value = "'$($_.value)'" } $tabcount = "`t" * $Indent $out += "$tabcount$($_.key) = $value `n" } -end { $tabcount = "`t" * ($Indent - 1) $out += "$tabcount}`n" $out } } #process End { Write-Verbose "Ending $($myinvocation.mycommand)" } } #end function Function Join-Hashtable { [cmdletbinding()] [OutputType([System.Collections.Hashtable])] Param ( [hashtable]$First, [hashtable]$Second, [switch]$Force ) #create clones of hashtables so originals are not modified $Primary = $First.Clone() $Secondary = $Second.Clone() #check for any duplicate keys $duplicates = $Primary.keys | Where-Object {$Secondary.ContainsKey($_)} if ($duplicates) { foreach ($item in $duplicates) { if ($force) { #force primary key, so remove secondary conflict $Secondary.Remove($item) } else { Write-Host "Duplicate key $item" -ForegroundColor Yellow Write-Host "A $($Primary.Item($item))" -ForegroundColor Yellow Write-host "B $($Secondary.Item($item))" -ForegroundColor Yellow $r = Read-Host "Which key do you want to KEEP [AB]?" if ($r -eq "A") { $Secondary.Remove($item) } elseif ($r -eq "B") { $Primary.Remove($item) } Else { Write-Warning "Aborting operation" Return } } #else prompt } } #join the two hash tables $Primary + $Secondary } #end Join-Hashtable Function Convert-CommandtoHashtable { [cmdletbinding()] [OutputType("Hashtable")] Param( [Parameter(Mandatory)] [ValidateNotNullorEmpty()] #"Enter a PowerShell expression with full parameter names" [string]$Text ) Set-StrictMode -Version latest New-Variable astTokens -force New-Variable astErr -force #trim spaces $Text = $Text.trim() Write-verbose "Converting $text" $ast = [System.Management.Automation.Language.Parser]::ParseInput($Text, [ref]$astTokens, [ref]$astErr) #resolve the command name $cmdType = Get-Command $asttokens[0].text if ($cmdType.CommandType -eq 'Alias') { $cmd = $cmdType.ResolvedCommandName } else { $cmd = $cmdType.Name } #last item is end of input token $r = for ($i = 1; $i -lt $astTokens.count - 1 ; $i++) { if ($astTokens[$i].ParameterName) { $p = $astTokens[$i].ParameterName $v = "" #check next token if ($astTokens[$i + 1].Kind -match 'Parameter|EndOfInput') { #the parameter must be a switch $v = "`$True" } else { While ($astTokens[$i + 1].Kind -notmatch 'Parameter|EndOfInput') { $i++ #test if value is a string and if it is quoted, if not include quotes #if ($astTokens[$i].Kind -eq "Identifier" -AND $astTokens[$i].Text -notmatch """\w+.*""" -AND $astTokens[$i].Text -notmatch "'\w+.*'") { if ($astTokens[$i].Text -match "\D" -AND $astTokens[$i].Text -notmatch """\w+.*""" -AND $astTokens[$i].Text -notmatch "'\w+.*'") { #ignore commas and variables if ($astTokens[$i].Kind -match 'Comma|Variable') { $value = $astTokens[$i].Text } else { #Assume text and quote it $value = """$($astTokens[$i].Text)""" } } else { $value = $astTokens[$i].Text } $v += $value } #while } #don't add a line return if this is going to be the last item if ($i + 1 -ge $astTokens.count - 1) { " $p = $v" } else { " $p = $v`n" } } #if ast parameter name } #for $hashtext = @" `$paramHash = @{ $r } $cmd @paramHash "@ $hashtext } |