Powershell Json Array - powershell

In relation to this question that was answered, we now have an issue where some values are arrays and we need to retain that structure
The code as it stands is:
function Get-Node {
[CmdletBinding()][OutputType([Object[]])] param(
[ScriptBlock]$Where,
[AllowNull()]
[Parameter(ValueFromPipeLine = $True, Mandatory = $True)]$InputObject,
[Int]$Depth = 90
)
process {
if ($_ -isnot [String] -and $Depth -gt 0) {
if ($_ -is [Collections.IDictionary]) {
if (& $Where) { $_ }
$_.get_Values() | Get-Node -Where $Where -Depth ($Depth - 1)
}
elseif ($_ -is [Collections.IEnumerable]) {
for ($i = 0; $i -lt $_.get_Count(); $i++) {
$_[$i] | Get-Node -Where $Where -Depth ($Depth - 1)
}
}
elseif ($Nodes = $_.PSObject.Properties.Where{ $_.MemberType -eq 'NoteProperty' }) {
$Nodes.ForEach{
if (& $Where) { $_ }
$_.Value | Get-Node -Where $Where -Depth ($Depth - 1)
Write-Host "In Second If " $_.Value
Write-Host "In Second If 2" $_
}
}
}
}
}
And the above function is called via:
if ($content.properties.policyRule -ne $null){
foreach ($rule in $policyRule){
$Node = $content.properties | Get-Node -Where {$_.name -eq $rule -and $_.value -Match "^\[\w+"}
$Node | ForEach-Object {
$_.Value = '[' + $_.Value
}
}
}
And what we are seeing is this:
"notIn": "[[concat(subscription().id,'/')] [subscription().id] /"
What we ideally want:
"notIn": ["[[concat(subscription().id,'/')]", "[[subscription().id]", "/"]
Any suggestions would be grateful

Related

Is there a way to speed up dynamic member look-up in ps-objects

In the following code, most time is spent in $v = $proc.$columnName and I am wondering if there
is a way to speed up looking up the objects's members's values.
In the code below, I have chosen $objs to be the result of get-process but in my case, $objs could be an array of any type of objects, thus the need to look up the objects's members dynamically.
$objs= get-process
$columnNames = #()
foreach ($member in ($objs | get-member -memberType property, noteproperty)) {
[string]$name = $member.name
$columnNames += $name
}
[Int64 ] $sum = 0
[string] $columnName = ''
foreach ($obj in $objs) {
foreach ($columnName in $columnNames) {
$v = $obj.$columnName
# $v = $obj.psObject.members.Item($columnName).value
if ($v -eq $null) {
}
elseif ($v -is [System.IntPtr]) {
$sum = $sum + ($v -as [int64] )
}
elseif ($v -is [System.Int64] -or $v -is [System.Int32]) {
$sum = $sum + $v
}
}
}
"sum = $sum"
Perhaps there are more ways to speed this up, but below I have taken out the unnecessary bits:
$objs= Get-Process
$columnNames = ($objs | Get-Member -MemberType property, noteproperty).Name
[Int64 ] $sum = 0
foreach ($obj in $objs) {
foreach ($v in $columnNames) {
if ($obj.$v -as [int64]) { $sum += [int64]$obj.$v }
}
}
"sum = $sum"
This is a hidden property on PSObjects called .PSObject that way too many people don't know about, including myself until a few weeks ago despite spending thousands of hours working with PowerShell. From there you can use .where to SIGNIFICANTLY increase filtering performance.
New Code Block
New-Variable -Force -Name:'Processes' -value:(Get-Process)
New-Variable -Force -Name:'Sum' -Value:([Int64]$Null)
ForEach ($Process in $Processes) {
$Process.PSObject.Properties.Where({
($_.MemberType -in #('Property','NoteProperty')) -and
($_.TypeNameOfValue -in #('System.IntPtr','System.Int64','System.Int32')) -and
(-Not [String]::IsNullOrWhiteSpace($_.value))
}) |ForEach-Object {
$Sum = $Sum + ($_.value -as [Int64])
}
}
"Sum = $Sum"
Comparison Result
Name Value
---- -----
BlockBTime 9.18
SameResult True
BlockATime 1.52
BlockASum 1037197387512388
Difference Block A (New Code) is ~7.66s faster than Block B (Old Code)
BlockBSum 1037197387512388
Validation & Comparison
#Stopwatch
New-Variable -Force -Name:'StopWatch' -Value:(New-Object -TypeName 'System.Diagnostics.Stopwatch')
New-Variable -Force -Name:'Result' -Value:#{
BlockATime = [Int]0
BlockASum = [Int64]0
BlockBTime = [Int]0
BlockBSum = [Int64]0
Difference = $Null
SameResult = $Null
}
New-Variable -Force -Name:'Processes' -value:(Get-Process)
$StopWatch.Restart()
New-Variable -Force -Name:'Sum' -Value:([Int64]$Null)
ForEach ($Process in $Processes) {
$Process.PSObject.Properties.Where({
($_.MemberType -in #('Property','NoteProperty')) -and
($_.TypeNameOfValue -in #('System.IntPtr','System.Int64','System.Int32')) -and
(-Not [String]::IsNullOrWhiteSpace($_.value))
}) |ForEach-Object {
$Sum = $Sum + ($_.value -as [Int64])
}
}
$Result.BlockATime = [math]::Round($StopWatch.Elapsed.TotalSeconds,2)
$Result.BlockASum = $Sum
$objs= $Processes
$StopWatch.Restart()
$columnNames = #()
foreach ($member in ($objs | get-member -memberType property, noteproperty)) {
[string]$name = $member.name
$columnNames += $name
}
[Int64 ] $sum = 0
[string] $columnName = ''
foreach ($obj in $objs) {
foreach ($columnName in $columnNames) {
$v = $obj.$columnName
# $v = $obj.psObject.members.Item($columnName).value
if ($v -eq $null) {
}
elseif ($v -is [System.IntPtr]) {
$sum = $sum + ($v -as [int64] )
}
elseif ($v -is [System.Int64] -or $v -is [System.Int32]) {
$sum = $sum + $v
}
}
}
$Result.BlockbTime = [math]::Round($StopWatch.Elapsed.TotalSeconds,2)
$Result.BlockbSum = $Sum
#Which block is faster?
If ($Result.BlockATime -lt $Result.BlockBTime) {
$Result.Difference = "Block A (New Code) is ~$(($Result.BlockBTime - $Result.BlockATime))s faster than Block B (Old Code)"
} Else {
$Result.Difference = "Block A (New Code) is ~$(($Result.BlockBTime - $Result.BlockATime))s Slower than Block B (Old Code)"
}
#Are the results the same?
If ($Result.BlockASum -eq $Result.BlockBSum) {
$Result.SameResult = $True
}

Calling GetPixel from powershell with param error despite correct params

The code snippet below is the debugger output.
Exception calling "GetPixel" with "2" argument(s): "Parameter must be positive and < Height.
Parameter name: y"
At C:\dropbox\Workspace\PowerShellTest\mapGenerator\mapGenerator.ps1:51 char:16
+ if(($map.GetPixel($x, ($y+1)) -eq "ff000000") -or ($map.GetPixel(($x ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : ArgumentOutOfRangeException
Hit Line breakpoint on 'C:\dropbox\Workspace\PowerShellTest\mapGenerator\mapGenerator.ps1:51'
[DBG]: PS C:\dropbox\Workspace\PowerShellTest\mapGenerator>> $y
5
[DBG]: PS C:\dropbox\Workspace\PowerShellTest\mapGenerator>> $map.Height
7
I do not get this error message at all.
"Parameter must be positive and < Height."
Ok. But parameter is (5+1), so positive, and (5+1), so <7
MCVE Code
EDIT 1:
MCVE code removed - I found an error in the MCVE which, when removed, also got rid of the error message. Now to go back and see if I have the same error in the original code.
EDIT 2: This is infuriating. I inserted a write-output for the $x and $y values, just to make sure I didn't have any with bad values (E.g. checking below a pixel with coordinate 0, or above a pixel with coordinate map.height Inserting the write-output made the rest of the code run correctly. And removing the write-output makes the code stop working again. Does write-output coerce something behind the scenes?
EDIT 3: It is very difficult to make an MCVE that retains this weird behavior, so I'll give you the script it happens in.
function markCoastline ($landArray, $map)
{
foreach ($square in $landArray)
{
$x = $square[0]
$y = $square[1]
$top = ($y -eq $map.Height-1)
$bot = ($y -eq 0)
$lef = ($x -eq 0)
$rig = ($x -eq $map.Width-1)
Write-Output $x
Write-Output $y
if( $bot -and $left)
{
if(($map.GetPixel($x, ($y+1)).Name -eq "ff000000")-or ($map.GetPixel(($x+1), $y).Name -eq "ff000000"))
{
$map.SetPixel($x, $y, "lime")
}
}
elseif( $top -and $left)
{
if(($map.GetPixel(($x+1), $y).Name -eq "ff000000") -or ($map.GetPixel($x, ($y-1)).Name -eq "ff000000"))
{
$map.SetPixel($x, $y, "lime")
}
}
elseif( $bot -and $rig)
{
if(($map.GetPixel(($x-1), $y).Name -eq "ff000000") -or ($map.GetPixel($x, ($y+1)).Name -eq "ff000000"))
{
$map.SetPixel($x, $y, "lime")
}
}
elseif( $top -and $rig)
{
if(($map.GetPixel(($x-1), $y).Name -eq "ff000000") -or ($map.GetPixel($x, ($y-1)).Name -eq "ff000000"))
{
$map.SetPixel($x, $y, "lime")
}
}
elseif( $lef)
{
if(($map.GetPixel($x, ($y+1)).Name -eq "ff000000") -or ($map.GetPixel(($x+1), $y).Name -eq "ff000000") -or ($map.GetPixel($x, ($y-1)).Name -eq "ff000000"))
{
$map.SetPixel($x, $y, "lime")
}
}
elseif( $bot)
{
if(($map.GetPixel($x, ($y+1)).Name -eq "ff000000") -or ($map.GetPixel(($x+1), $y).Name -eq "ff000000") -or ($map.GetPixel(($x-1), $y).Name -eq "ff000000"))
{
$map.SetPixel($x, $y, "lime")
}
}
elseif( $rig)
{
if(($map.GetPixel($x, ($y+1)).Name -eq "ff000000")-or ($map.GetPixel(($x-1), $y).Name -eq "ff000000") -or ($map.GetPixel($x, ($y-1)).Name -eq "ff000000"))
{
$map.SetPixel($x, $y, "lime")
}
}
elseif( $top)
{
if(($map.GetPixel(($x+1), $y).Name -eq "ff000000") -or ($map.GetPixel(($x-1), $y).Name -eq "ff000000") -or ($map.GetPixel($x, ($y-1)).Name -eq "ff000000"))
{
$map.SetPixel($x, $y, "lime")
}
}
else
{
if(($map.GetPixel($x, ($y+1)).Name -eq "ff000000") -or ($map.GetPixel(($x+1), $y).Name -eq "ff000000") -or ($map.GetPixel(($x-1), $y).Name -eq "ff000000") -or ($map.GetPixel($x, ($y-1)).Name -eq "ff000000"))
{
$map.SetPixel($x, $y, "lime")
}
}
}
}
#First, get a BMP image
$openFile = New-Object -TypeName System.Windows.Forms.OpenFileDialog
$openFile.AddExtension = $true
$openFile.Filter = 'Bitmap Picture (*.bmp)|*.bmp|All Files|*.*'
$openFile.Multiselect = $false
$openFile.FilterIndex = 0
$openFile.InitialDirectory = "$HOME\Documents"
$openFile.RestoreDirectory = $true
$openFile.ShowReadOnly = $true
$openFile.ReadOnlyChecked = $false
$openFile.Title = 'Select a seed picture (BMP only)'
$openFile.showDialog()
$map = New-Object System.Drawing.Bitmap($openFile.Filename)
$landPixels = #()
$oceanPixels = #()
#Second: Find land/ocean
for ($x = 0; $x -lt $map.Width; $x++)
{
for ($y = 0; $y -lt $map.Height; $y++)
{
$current = $map.GetPixel($x, $y)
if($current.Name -eq "ff000000")
{
$ocean = #($x, $y)
$oceanPixels += , $ocean
}
else
{
$land = #($x, $y)
$landPixels += , $land
}
}
}
#Third, paint coastline green:
markCoastline $landPixels $map
$map.save("b8fcf4351caf4b00af8eb0fa2e5bc17a.bmp")
There's a write-output on lines 16 and 17. Remove those and the script gives the original problem mentioned above - claims $y doesn't fit as a parameter for the GetPixel function. Keep it in and the code runs exactly as intended.
In two places in your code you use $left instead of $lef. And I still got that error message regardless of Write-Output. Error message just got buried under all that output, but it still here.
I recommend to use Set-StrictMode -Version Latest and $ErrorActionPreference='Inquire' when you are debugging your code. It is easier to spot error with them.
P.S.
Does not use array addition it reallocate array or every addition, use lists instead:
$landPixels = New-Object System.Collections.Generic.List[object]
$oceanPixels = New-Object System.Collections.Generic.List[object]
for ($x = 0; $x -lt $map.Width; $x++)
{
for ($y = 0; $y -lt $map.Height; $y++)
{
$current = $map.GetPixel($x, $y)
if($current.Name -eq "ff000000")
{
$oceanPixels.Add(($x,$y))
}
else
{
$landPixels.Add(($x,$y))
}
}
}
P.P.S.
$x,$y = $square
P.P.P.S
if(
(($y+1 -lt $map.Height) -and ($map.GetPixel($x, ($y+1)).Name -eq "ff000000")) -or
(($y-1 -gt 0) -and ($map.GetPixel($x, ($y-1)).Name -eq "ff000000")) -or
(($x+1 -lt $map.Width) -and ($map.GetPixel(($x+1), $y).Name -eq "ff000000")) -or
(($x-1 -gt 0) -and ($map.GetPixel(($x-1), $y).Name -eq "ff000000"))
)
{
$map.SetPixel($x, $y, "lime")
}

oddity using newtonsoft json.net with powershell

I have
function Foo($a, $b)
{
$o = #{}
$o.A = $a
$o.B = $b
$post = #{}
$post.X="x"
$post.entity =$o
$newton::SerializeObject($post)
}
then do
foo "a" "b"
I get
Exception calling "SerializeObject" with "1" argument(s): "Self referencing loop detected for property 'Value' with type 'System.Management.Automation.PSParameterizedProperty'. Path 'entity.Members[0]'."
however
function Foo2($o)
{
$post = #{}
$post.X="x"
$post.entity =$o
$newton::SerializeObject($post)
}
foo2 #{a="a"; b="b"}
works fine. Also
function foo3($a, $b)
{
$o = #{}
$o.A = $a
$o.B = $b
$newton::SerializeObject($o)
}
foo3 "a" "b"
works but
foo3 "a" 1
fails
The latter can be made to work by doing
$o.B= [Int32]::Parse($b.Tostring())
Which all seems very odd
powershell v2 on windows 7, json.net 4.4.5
The JavaScriptSerializer from the .NET framework also has a similar problem with serializing PowerShell's hashes. I suspect it something slightly odd in the PowerShell type system. You could skip Json.Net altogether and roll your own.
Below is something to start you off. It's likely not as robust as PowerShell 3's built-in ConvertTo-Json cmdlet, but I think it's mostly complete.
Here are all of your examples, in working order.
# See below for ConvertTo-Json.psm1
Import-Module ConvertTo-Json
function Foo($a, $b)
{
$o = #{}
$o.A = $a
$o.B = $b
$post = #{}
$post.X="x"
$post.entity =$o
ConvertTo-Json $post
}
function Foo2($o)
{
$post = #{}
$post.X="x"
$post.entity =$o
ConvertTo-Json $post
}
function foo3($a, $b)
{
$o = #{}
$o.A = $a
$o.B = $b
ConvertTo-Json $o
}
PS> foo "a" "b"
{"entity":{"A":"a","B":"b"},"X":"x"}
PS> foo2 #{a="a"; b="b"}
{"entity":{"a":"a","b":"b"},"X":"x"}
PS> foo3 "a" "b"
{"A":"a","B":"b"}
PS> foo3 "a" 1
{"A":"a","B":1}
And here's the PowerShell module that implements ConvertTo-Json.
# Save these contents to Modules\ConvertTo-Json\ConvertTo-Json.psm1 in your
# PowerShell documents folder, and load them in your $profile using the
# "Import-Module ConvertTo-Json" cmdlet. This will make the ConvertTo-Json cmdlet
# available for use.
Set-StrictMode -Version Latest
function convertToJsonNull($InputObject) {
"null"
}
function convertToJsonArray($InputObject) {
$value = ($InputObject | %{ convertToJson $_ }) -join ','
"[$value]"
}
function convertToJsonHash($InputObject) {
$value = ($InputObject.Keys | %{
$name = $_ | asJsonString
$itemValue = convertToJson ($InputObject[$_])
'"{0}":{1}' -f $name, $itemValue
}) -join ','
"{$value}"
}
function convertToJsonObject($InputObject) {
$value = ($InputObject | get-member -membertype *property | %{
$name = $_.Name
$value = convertToJson ($InputObject.($name))
'"{0}":{1}' -f ($name | asJsonString), $value
}) -join ','
"{$value}"
}
function convertToJsonString($InputObject) {
'"{0}"' -f ($InputObject | asJsonString)
}
function convertToJsonBool($InputObject) {
$InputObject.ToString().ToLower()
}
function convertToJsonNumeric($InputObject) {
"$InputObject"
}
function convertToJsonDate($InputObject) {
$epoch = [datetime]"1970-01-01T00:00:00Z"
$elapsed = [long]($InputObject - $epoch).TotalMilliseconds
'"\/Date({0})\/"' -f $elapsed
}
filter isNumeric() {
$_ -is [byte] -or $_ -is [int16] -or $_ -is [int32] -or $_ -is [int64] -or
$_ -is [sbyte] -or $_ -is [uint16] -or $_ -is [uint32] -or $_ -is [uint64] -or
$_ -is [float] -or $_ -is [double] -or $_ -is [decimal]
}
filter asJsonString {
($_ -replace '\\', '\\') -replace '"', '\"'
}
function convertToJson($InputObject) {
if ($InputObject -eq $null) { convertToJsonNull $InputObject }
elseif ($InputObject -is [array]) { convertToJsonArray $InputObject }
elseif ($InputObject -is [hashtable]) { convertToJsonHash $InputObject }
elseif ($InputObject -is [datetime]) { convertToJsonDate $InputObject }
elseif ($InputObject -is [string]) { convertToJsonString $InputObject }
elseif ($InputObject -is [char]) { convertToJsonString $InputObject }
elseif ($InputObject -is [bool]) { convertToJsonBool $InputObject }
elseif ($InputObject | isNumeric) { convertToJsonNumeric $InputObject }
else { convertToJsonObject $InputObject }
}
function ConvertTo-Json {
[CmdletBinding()]
param(
[Parameter(
ValueFromPipeline = $true,
ValueFromPipelineByPropertyName = $true
)]
$InputObject
)
convertToJson $InputObject
}
Export-ModuleMember -Function ConvertTo-Json
The self referencing loop issue sems to be all about.... the order in which you assign things. The below example works:
function Foo($a, $b)
{
$o = #{}
$post = #{}
$post.entity =$o
$o.A = $a
$o.B = $b
$post.X="x"
[Newtonsoft.Json.JsonConvert]::SerializeObject($post)
}
Foo "a" "b"
{"entity":{"A":"a","B":"b"},"X":"x"}
If you convert the type before you pass it in then it will keep your foo3 function generic:
function foo3($a, $b)
{
$o = #{}
$o.A = $a
$o.B = $b
[Newtonsoft.Json.JsonConvert]::SerializeObject($o)
}
$var2 = [Int32]::Parse((1).Tostring())
Foo3 "a" $var2
{"A":"a","B":1}

PSCustomObject to Hashtable

What is the easiest way to convert a PSCustomObject to a Hashtable? It displays just like one with the splat operator, curly braces and what appear to be key value pairs. When I try to cast it to [Hashtable] it doesn't work. I also tried .toString() and the assigned variable says its a string but displays nothing - any ideas?
Shouldn't be too hard. Something like this should do the trick:
# Create a PSCustomObject (ironically using a hashtable)
$ht1 = #{ A = 'a'; B = 'b'; DateTime = Get-Date }
$theObject = new-object psobject -Property $ht1
# Convert the PSCustomObject back to a hashtable
$ht2 = #{}
$theObject.psobject.properties | Foreach { $ht2[$_.Name] = $_.Value }
Keith already gave you the answer, this is just another way of doing the same with a one-liner:
$psobject.psobject.properties | foreach -begin {$h=#{}} -process {$h."$($_.Name)" = $_.Value} -end {$h}
Here's a version that works with nested hashtables / arrays as well (which is useful if you're trying to do this with DSC ConfigurationData):
function ConvertPSObjectToHashtable
{
param (
[Parameter(ValueFromPipeline)]
$InputObject
)
process
{
if ($null -eq $InputObject) { return $null }
if ($InputObject -is [System.Collections.IEnumerable] -and $InputObject -isnot [string])
{
$collection = #(
foreach ($object in $InputObject) { ConvertPSObjectToHashtable $object }
)
Write-Output -NoEnumerate $collection
}
elseif ($InputObject -is [psobject])
{
$hash = #{}
foreach ($property in $InputObject.PSObject.Properties)
{
$hash[$property.Name] = ConvertPSObjectToHashtable $property.Value
}
$hash
}
else
{
$InputObject
}
}
}
My extremely lazy approach, enabled by a new feature in PowerShell 6:
$myhashtable = $mypscustomobject | ConvertTo-Json | ConvertFrom-Json -AsHashTable
This works for PSCustomObjects created by ConvertFrom_Json.
Function ConvertConvertFrom-JsonPSCustomObjectToHash($obj)
{
$hash = #{}
$obj | Get-Member -MemberType Properties | SELECT -exp "Name" | % {
$hash[$_] = ($obj | SELECT -exp $_)
}
$hash
}
Disclaimer: I barely understand PowerShell so this is probably not as clean as it could be. But it works (for one level only).
My code:
function PSCustomObjectConvertToHashtable() {
param(
[Parameter(ValueFromPipeline)]
$object
)
if ( $object -eq $null ) { return $null }
if ( $object -is [psobject] ) {
$result = #{}
$items = $object | Get-Member -MemberType NoteProperty
foreach( $item in $items ) {
$key = $item.Name
$value = PSCustomObjectConvertToHashtable -object $object.$key
$result.Add($key, $value)
}
return $result
} elseif ($object -is [array]) {
$result = [object[]]::new($object.Count)
for ($i = 0; $i -lt $object.Count; $i++) {
$result[$i] = (PSCustomObjectConvertToHashtable -object $object[$i])
}
return ,$result
} else {
return $object
}
}
For simple [PSCustomObject] to [Hashtable] conversion Keith's Answer works best.
However if you need more options you can use
function ConvertTo-Hashtable {
<#
.Synopsis
Converts an object to a hashtable
.DESCRIPTION
PowerShell v4 seems to have trouble casting some objects to Hashtable.
This function is a workaround to convert PS Objects to [Hashtable]
.LINK
https://github.com/alainQtec/.files/blob/main/src/scripts/Converters/ConvertTo-Hashtable.ps1
.NOTES
Base ref: https://community.idera.com/database-tools/powershell/powertips/b/tips/posts/turning-objects-into-hash-tables-2
#>
PARAM(
# The object to convert to a hashtable
[Parameter(ValueFromPipeline = $true, Mandatory = $true)]
$InputObject,
# Forces the values to be strings and converts them by running them through Out-String
[switch]$AsString,
# If set, empty properties are Included
[switch]$AllowNulls,
# Make each hashtable to have it's own set of properties, otherwise,
# (default) each InputObject is normalized to the properties on the first object in the pipeline
[switch]$DontNormalize
)
BEGIN {
$headers = #()
}
PROCESS {
if (!$headers -or $DontNormalize) {
$headers = $InputObject | Get-Member -type Properties | Select-Object -expand name
}
$OutputHash = #{}
if ($AsString) {
foreach ($col in $headers) {
if ($AllowNulls -or ($InputObject.$col -is [bool] -or ($InputObject.$col))) {
$OutputHash.$col = $InputObject.$col | Out-String -Width 9999 | ForEach-Object { $_.Trim() }
}
}
} else {
foreach ($col in $headers) {
if ($AllowNulls -or ($InputObject.$col -is [bool] -or ($InputObject.$col))) {
$OutputHash.$col = $InputObject.$col
}
}
}
}
END {
return $OutputHash
}
}
Maybe this is overkill but I hope it Helps
Today, the "easiest way" to convert PSCustomObject to Hashtable would be so:
$custom_obj | ConvertTo-HashtableFromPsCustomObject
OR
[hashtable]$custom_obj
Conversely, you can convert a Hashtable to PSCustomObject using:
[PSCustomObject]$hash_table
Only snag is, these nifty options may not be available in older versions of PS

Convert a list of key value pairs to a hashtable

What is the best way to convert a List to a Hashtable?
Say I have a list like ("Key",$value,"Key2",$value2)
What is the shortest syntax to convert it into a Hashtable?
Try the following
$table = new-object System.Collections.Hashtable
for ( $i = 0; $i -lt $list.Length; $i += 2 ) {
$table.Add($list[$i],$list[$i+1]);
}
Function ConvertTo-Hashtable($list) {
$h = #{}
while($list) {
$head, $next, $list = $list
$h.$head = $next
}
$h
}
ConvertTo-Hashtable ("Key",1,"Key2",2)
If your list is composed of NameValuePair objects, then you can use:
Function ConvertListOfNVPTo-Hashtable($list) {
$h = #{}
$list | ForEach-Object {
$h[$_.Name] = $_.Value
}
return $h
}
$h = #{}
0..($l.count - 1) | ? {$_ -band 1} | % {$h.Add($l[$_-1],$l[$_])}
$h = #{}
0..($l.count - 1) | ? {$_ -band 1} | % {$h.($l[$_-1]) = $l[$_]}
$h = #{}
$i = 0
while ($i -lt $l.count) {$h.Add($l[$i++],$l[$i++])}
How about:
$ht = #{}
$key = "";
("Key",5,"Key2",6) | foreach `
{
if($key)
{
$ht.$key = $_;
$key="";
} else
{$key=$_}
}
function Select-Hashtable {
[CmdletBinding()]
param(
[Parameter(ValueFromPipeline)]
[PSObject[]]$InputObject,
[Parameter(Mandatory)]
[string]$Property
)
begin { $hashtable = [Hashtable]::new() }
process { $InputObject | %{ $hashtable[$_."$Property"] = $_} }
end { $hashtable }
}
then (a pointless example):
$items = Get-ChildItem -Path $path | Select-Hashtable -Property Name
$documents = $items['Documents']