PowerShell: Adding "rows" to custom object - powershell

I want to create an object in powershell that stores information about the state of a script. I can do this:
$myScriptObject =
#("status", "Selected Operation(s):", "None"),
("status", "Current Operation:", "None"),
("status", "Current Step:", "Prompting for Script Action" ),
("test", "This is just for testing", "1,2,3") `
| ForEach-Object {[pscustomobject]#{kind = $_[0]; name = $_[1]; value
= $_[2]}}
And that works:
$myScriptObject
kind name value
---- ---- -----
status Selected Operation(s): None
status Current Operation: None
status Current Step: Prompting for Script Action
test This is just for testing 1,2,3
...and I can even do this:
foreach($myObject in $myScriptObject) {
if ($myObject.kind -eq 'status') {
Write-Host $myObject.name $myObject.value
}
}
which outputs this:
Selected Operation(s): None
Current Operation: None
Current Step: Prompting for Script Action
My questions are:
1. how do I add something like the following to $myScriptObject:
-kind "ActionMenuChoice" -Name "Do This" -Value 1
-kind "ActionMenuChoice" -Name "Do That" -Value 2
How do I change items already in the object?
status Current Step: Prompting for Script Action
to
status Current Step: Prompting for Login
Or am I going about it all wrong? The idea came from the difficulty in returning numerous variables back from a function, and I read using objects is much better to pass back and forth in functions, and found using objects to be much easier to keep track of and to a certain extent manipulate.
Cheers!

If we are keeping your current object array structure, you can create $myScriptObject as an generic list type by casting [collections.generic.list[object]]. Then you can use the .Add() method to add items to your collection.
[collections.generic.list[object]]$myScriptObject =
#("status", "Selected Operation(s):", "None"),
("status", "Current Operation:", "None"),
("status", "Current Step:", "Prompting for Script Action" ),
("test", "This is just for testing", "1,2,3") |
ForEach-Object {[pscustomobject]#{kind = $_[0]; name = $_[1]; value = $_[2]}}
[void]$myScriptObject.add([pscustomobject]#{"Kind" = "ActionMenuChoice"; "Name" = "Do This"; "Value" = 1})
[void]$myScriptObject.add([pscustomobject]#{"Kind" = "ActionMenuChoice"; "Name" = "Do That"; "Value" = 2})
If you want to update an item property in that collection, you will first need to find the object/item within the collection and then access the property you want to update.
($myScriptObject | Where-Object {$_.name -eq 'Current Step:'}).value = "Prompting for Login"
Where-Object can provide the condition needed to locate the target object. Then you can use the object.property syntax to access the property. With PowerShell objects, you can do direct assignment syntax (object.property = value) to update the property value.

I would use a datatable instead:
Add-Type -AssemblyName System.Collections
$dt = New-Object system.Data.DataTable
[void]$dt.Columns.Add('kind',[string]::empty.GetType() )
[void]$dt.Columns.Add('name',[string]::empty.GetType() )
[void]$dt.Columns.Add('value',[string]::empty.GetType() )
# Add new rows:
$newRow = $dt.NewRow()
$newRow.kind = 'status'
$newRow.name = 'Selected Operation(s):'
$newRow.value = 'None'
[void]$dt.Rows.Add( $newRow )
$newRow = $dt.NewRow()
$newRow.kind = 'status'
$newRow.name = 'Selected'
$newRow.value = 'None'
[void]$dt.Rows.Add( $newRow )
# Find row(s):
$rows = $dt.Select("kind = 'status'")
"Found:"
$dt
# Change first row by condition:
$rows = $dt.Select("kind = 'status'")
$rows[0].value = 'test'
[void]$dt.AcceptChanges()
"Changed one row:"
$dt
# Change all rows:
$rows = $dt.Select("")
$rows | % { $_.value = 'new' }
[void]$dt.AcceptChanges()
"Changed all:"
$dt
# Change all rows by condition:
$rows = $dt.Select("name = 'Selected'")
$rows | % { $_.value = 'newer' }
[void]$dt.AcceptChanges()
"Changed by condition:"
$dt

Related

Powershell: Arrays index acess and check if previous is substring to next

I need to link the job to the subjob: the job is of this format for example ACGN100Q while the subjobs that are attached are sequential and of this format: ACGN-100Q-000T;ACGN-100Q-010T;ACGN-100Q-020T;ACGN-100Q-030T
In my csv file the type of this job ACGN100Q is "TechnologyInteraction" while the subjobs are of type "TechnologyService". I am developing a script that allows me to say for example that the link between ACGN-100Q-000T and ACGN-100Q-010T is of type "TrigerringRelation" and the link between ACGN100Q and ACGN-100Q-000T is of type "RealizationRelation". I need help because I can't make the link.
Here is my starting csv file :
newElements.csv
ID,"Type","Name","Documentation"
eb214110-2b6a-48b2-ba5a-7c13dc3bba39,"TechnologyInteraction","ACGN100Q","Begin Of JobStream"
a46681e7-19a8-4fc5-b747-09679c15ff26,"TechnologyService","ACGN-100Q-000T","Transfert UDM (xACGN000)"
85761a09-1145-4037-a527-66a743def45f,"TechnologyService","ACGN-100Q-010T","move fichier REF to work"
27b126fb-c708-427d-b0a6-ce4747114ac4,"TechnologyService","ACGN-100Q-020T","w_read_account"
bb0c5e42-5fad-4bd9-8ee9-f41d0b824e82,"TechnologyService","ACGN-100Q-030T","w_read_referential"
0b8b76e3-62fa-4527-9f05-2eb4dbaa8e97,"TechnologyService","ACGN-100Q-040T","w_load_CompanyGroup"
1f487986-3cac-4af8-bda2-6400a1c71f48,"TechnologyService","ACGN-100Q-050T","w_load_Company"
And I want to get a file that looks like this:
relation.csv
"ID","Type","Name","Documentation","Source","Target"
"New ID","RealizationRelationship","","","eb214110-2b6a-48b2-ba5a-7c13dc3bba39","a46681e7-19a8-4fc5-b747-09679c15ff26"
"New ID","TriggeringRelationship","","","a46681e7-19a8-4fc5-b747-09679c15ff26","85761a09-1145-4037-a527-66a743def45f"
"New ID","TriggeringRelationship","","","85761a09-1145-4037-a527-66a743def45f","27b126fb-c708-427d-b0a6-ce4747114ac4"
"New ID","TriggeringRelationship","","","27b126fb-c708-427d-b0a6-ce4747114ac4","bb0c5e42-5fad-4bd9-8ee9-f41d0b824e82"
"New ID","TriggeringRelationship","","","bb0c5e42-5fad-4bd9-8ee9-f41d0b824e82","0b8b76e3-62fa-4527-9f05-2eb4dbaa8e97"
"New ID","TriggeringRelationship","","","0b8b76e3-62fa-4527-9f05-2eb4dbaa8e97","1f487986-3cac-4af8-bda2-6400a1c71f48"
$result= #()
function linkedRelationCsvToElementsCsv{
#relations.csv headers are ID,"Type","Name","Documentation","Source","Target"
$Type=#()
$Name=#()
$ID=#()
$Documentation=#()
#$pattern="^(WEBX|DWHS|COGN|CLOT|CLAI|BTRE|BISI|BDDO|ARXL|AGSO|AGPC|ACTO|FNET|ARX|AGS|INF|CLA|MEM|SWA|REX)-"
$newElementsCsv=Import-CSV $env:USERPROFILE\Desktop\Archi\newElements.csv |sort ID,"Type","Name","Documentation" -Unique
# Check if type is TechnologyInteraction or TechnologyService and link :TechnologyService to TechnologyInteraction and TechnologyInteraction to TWS id's
ForEach ($line in $newElementsCsv){
$Type += $line.Type
$Name += $line.Name
$ID +=$line.ID
$Documentation += $_.Documentation
#Search for element type in elements.csv
for( $index=0; $index -le $Name.length-1; $index++){
if($Type[$index] -eq 'TechnologyInteraction' -or $Type[$index] -eq 'TechnologyEvent' ){
Write-Warning "Case type TechnologyInteraction founded, new type of RealizationRelationship created "
# if the job is of type "TechnologyInteraction" or "TechnologyEvent", we link it to the TWS id's(TechnologyCollaboration,ef2f510b-924b-439d-8720-0183c7294eb3) in archi.
$newArrayResult= New-Object PsObject -Property #{ID=[guid]::NewGuid().ToString(); "Type"="RealizationRelationship"; "Name"=$Name[$index]; "Documentation"=$Documentation[$index]; "Source"="ef2f510b-924b-439d-8720-0183c7294eb3"; "Target"=$ID[$index]}
$result = $result + $newArrayResult
}elseif ($Type[$index][0].Type -eq 'TechnologyService' -and$Type[$index][1].Type -eq 'TechnologyService' ){
Write-Warning "Case type TechnologyService founded, new type of TriggeringRelationship created "
$newArrayResult2 = New-Object PsObject -Property #{ID=[guid]::NewGuid().ToString(); "Type"="TriggeringRelationship"; "Name"=""; "Documentation"=""; "Source"=$line[$index][0].ID; "Target"=$line[$index][1].ID}
$result = $result + $newArrayResult2
}
}
}
$result |Select-Object -Property ID,"Type","Name","Documentation","Source","Target"| Export-Csv $env:USERPROFILE\Desktop\Archi\relation.csv -NoTypeInformation -Encoding UTF8
}linkedRelationCsvToElementsCsv # Call the function
> the elseIf() not return value.
Thanks you in advance.
The following code generates exactly the output you want for exactly the input you've given. There might be unexpected edge cases, so you should write some tests (e.g. with Pester) to confirm it behaves how you want it to in those edge cases.
The key is that the output for any row includes the ID of the previous row as well as the current row, so we keep the previous row in a variable during the foreach loop so we can inspect it when we process the next row, and the Type in the output just depends on the Type of the previous row.
Note that I've also moved the conversion to / from csv out of the main function so it's easier to unit test the function in isolation.
function ConvertTo-ElementItems
{
param
(
[object[]] $Relations
)
$jobTypes = #( "TechnologyInteraction", "TechnologyEvent" );
$subTypes = #( "TechnologyService" );
$previousItem = $null;
foreach( $item in $Relations )
{
if( $item.Type -in $jobTypes )
{
# start of a new job, but don't output anything
}
elseif( $item.Type -notin $subTypes )
{
# not a subjob type that we recognise
throw "unrecognised subjob type '$($item.Type)' for subjob '$($item.ID)'";
}
elseif( $null -eq $previousItem )
{
# we've got a subjob, but there was no previous job or subjob
throw "no preceding item for subjob '$($item.ID)'";
}
elseif( $previousItem.Type -in $jobTypes )
{
# this is the first subjob after the parent job
new-object PSCustomObject -Property ([ordered] #{
"ID" = "New ID"
"Type" = "RealizationRelationship"
"Name" = "";
"Documentation" = ""
"Source" = $previousItem.ID
"Target" = $item.ID
});
}
else
{
# the preceding item was a subjob as well
new-object PSCustomObject -Property ([ordered] #{
"ID" = "New ID"
"Type" = "TriggeringRelationship"
"Name" = ""
"Documentation" = ""
"Source" = $previousItem.ID
"Target" = $item.ID
});
}
$previousItem = $item;
}
}
And here's an example of using the function:
$ErrorActionPreference = "Stop";
Set-StrictMode -Version "Latest";
$inputCsv = #"
ID,"Type","Name","Documentation"
eb214110-2b6a-48b2-ba5a-7c13dc3bba39,"TechnologyInteraction","ACGN100Q","Begin Of JobStream"
a46681e7-19a8-4fc5-b747-09679c15ff26,"TechnologyService","ACGN-100Q-000T","Transfert UDM (xACGN000)"
85761a09-1145-4037-a527-66a743def45f,"TechnologyService","ACGN-100Q-010T","move fichier REF to work"
27b126fb-c708-427d-b0a6-ce4747114ac4,"TechnologyService","ACGN-100Q-020T","w_read_account"
bb0c5e42-5fad-4bd9-8ee9-f41d0b824e82,"TechnologyService","ACGN-100Q-030T","w_read_referential"
0b8b76e3-62fa-4527-9f05-2eb4dbaa8e97,"TechnologyService","ACGN-100Q-040T","w_load_CompanyGroup"
1f487986-3cac-4af8-bda2-6400a1c71f48,"TechnologyService","ACGN-100Q-050T","w_load_Company"
"#
$expectedCsv = #"
"ID","Type","Name","Documentation","Source","Target"
"New ID","RealizationRelationship","","","eb214110-2b6a-48b2-ba5a-7c13dc3bba39","a46681e7-19a8-4fc5-b747-09679c15ff26"
"New ID","TriggeringRelationship","","","a46681e7-19a8-4fc5-b747-09679c15ff26","85761a09-1145-4037-a527-66a743def45f"
"New ID","TriggeringRelationship","","","85761a09-1145-4037-a527-66a743def45f","27b126fb-c708-427d-b0a6-ce4747114ac4"
"New ID","TriggeringRelationship","","","27b126fb-c708-427d-b0a6-ce4747114ac4","bb0c5e42-5fad-4bd9-8ee9-f41d0b824e82"
"New ID","TriggeringRelationship","","","bb0c5e42-5fad-4bd9-8ee9-f41d0b824e82","0b8b76e3-62fa-4527-9f05-2eb4dbaa8e97"
"New ID","TriggeringRelationship","","","0b8b76e3-62fa-4527-9f05-2eb4dbaa8e97","1f487986-3cac-4af8-bda2-6400a1c71f48"
"#;
$relations = $inputCsv | ConvertFrom-Csv;
$elements = ConvertTo-ElementItems -Relations $relations;
$outputCsv = ($elements | ConvertTo-Csv -NoTypeInformation) -join "`n";
if( $outputCsv -ne $expectedCsv )
{
throw "output csv doesn't match expected csv";
} else {
write-host "output csv matches expected csv";
}

Powershell checkbox, put checked items on top

Searched all over the web for a seemingly simple issue:
I have a working script involving a Checkedlistbox:
New-Object System.Windows.Forms.CheckedListBox
I am trying to get it to behave so that all the checked items are put on top like this:
[x]
[x]
[x]
[ ]
[ ]
Now it looks like this:
[ ]
[ ]
[X]
[ ]
[X]
Getting the checklist items to sort alphabetically is easy, but i want them to sort on "selected state"
Is this even possible?
UPDATE -> the code:
$clbGroups = New-Object System.Windows.Forms.CheckedListBox
$UserGroups = $clbGroups.CheckedItems
$formMain.Controls.Add($clbGroups)
$clbGroups.Location = '305, 258'
$clbGroups.Name = "clbGroups"
$clbGroups.Size = '400, 150'
$clbGroups.CheckedItems
$clbGroups.TabIndex = 37
$clbGroups.Sorted = "True"
Write-Verbose "Adding groups to checked list box"
$XML.Options.SecurityGroups.SecurityGroup | %{[Void]$clbGroups.Items.Add($_)}
$cboGroup_SelectedIndexChanged={
Write-Verbose "Updating groups fields with list information"
$Group = #($XML.Options.Groups.Group | ? {$_.Name -match $cboGroup.Text})
$arrayGroups = #($Group | % { $_.List } | ? { $_.Type -match "SecurityGroup" } | % { $_.'#text' } )
for ($i = 0; $i -lt $clbGroups.Items.Count; $i++) { if($arrayGroups -Contains $clbGroups.Items[$i]){ $clbGroups.SetItemChecked( $i, $true ) } else { $clbGroups.SetItemChecked( $i, $false ) } }
}
So, here is a script that will work with CheckedListBox with only CheckedItems property. As there is no builtin sort method, the trick here is to create a custom function that will do it. That is done by function SortItems below. The function will prepare new items (checked and unchecked), clear existing, and add new ones in proper order. Additionally, it must programmatically preserve the checked state of items.
# Simplified form setup
$formMain = New-Object System.Windows.Forms.Form
$clbGroups = New-Object System.Windows.Forms.CheckedListBox
$UserGroups = $clbGroups.CheckedItems
$formMain.Controls.Add($clbGroups)
1..10 | % {[void]$clbGroups.Items.Add("Group '$_'")}
# Function doing actual sort
function SortItems {
$CheckedItems = $clbGroups.CheckedItems | % {$_}
$UncheckedItems = $clbGroups.Items | where {$_ -notin $CheckedItems}
$clbGroups.Items.Clear()
$CheckedItems | % {$clbGroups.Items.Add($_)} | % {$clbGroups.SetItemChecked($_,$true)}
$UncheckedItems | % {$clbGroups.Items.Add($_)}
}
# Add button that will trigger the sort
$sortBtn = New-Object System.Windows.Forms.Button
$sortBtn.Add_Click({SortItems})
$sortBtn.Location = '15, 158'
$sortBtn.Text = 'Sort it!'
$formMain.Controls.Add($sortBtn)
# Show main form as dialog window
$formMain.ShowDialog()
And two comments about code
$CheckedItems = $clbGroups.CheckedItems | % {$_} Second pipeline
element is required to create a copy of items, not just reference. If
we use just reference, variable will point to empty array after
clearing items.
$CheckedItems | % {$clbGroups.Items.Add($_)} | %
{$clbGroups.SetItemChecked($_,$true)} Second pipeline element is
adding items. It is returning index of newly created item. We use
that index in third pipeline element to set its checked state to true
EDIT: Based on additional user input, this is not a suitable solution. I will post a better one.
I am not quite sure about your setup, but you might use something like this.
First, I simulate creating new CheckedListBox with 5 CheckBoxes
$CL = New-Object System.Windows.Forms.CheckedListBox
1..5 | % {$CB = New-Object System.Windows.Forms.CheckBox; $CB.Text = "CheckBox $_"; $CL.Items.Add($CB)}
$CL.Items | Select Text, Checked
Then, lets make third and fifth item checked
$CL.Items[2].Checked = $true
$CL.Items[4].Checked = $true
$CL.Items | Select Text, Checked
And then, lets sort it and print it to screen
$CL.Items | Sort Checked | Select Text, Checked

Displaying user inputs with powershell

say I have an array
$something = #(
"first",
"second"
)
how can I display this to the user as
1. first
2. second
Selection :
I am able to do this by hash table and manually mapping
#{
1="first"
2="second"
};
and doing the following
$something.Keys | sort |% { Write-Host $_ ")" $something.Item($_) }
[int32]$constuctPayload.Action = Read-Host
but if need to perform this using an array how can I do this. I.e looping over the item and displaying with index for user selection. ?
You could use the IndexOf() method, to find the index in the array.
$something | ForEach-Object {Write-Host "$([Array]::IndexOf($something, $_)). $_ "}
Standard warning about being careful with Write-Host. Also you might want to look into Out-GridView.
Use a for loop to iterate over the elements of the array and prepend each value with the index + 1.
$something = 'first', 'second'
for ($i = 0; $i -lt $something.Count; $i++) {
Write-Host ('{0}. {1}' -f ($i+1), $something[$i])
}
[int32]$constuctPayload.Action = Read-Host -Prompt 'Selection'
I would recommend using the PromptForChoice() method over Read-Host, though:
$something = '&first', '&second'
$title = 'The title.'
$msg = 'Selection?'
$choices = $something | ForEach-Object {
New-Object Management.Automation.Host.ChoiceDescription $_
}
$options = [Management.Automation.Host.ChoiceDescription[]] $choices
$default = 0
$constuctPayload.Action = $Host.UI.PromptForChoice($title, $msg, $options, $default)

Powershell [Ref] Value not updating main object

I'm running Powershell V2 on XP:
This is part of a larger script and I'm noticing some anomolies with the way I'm able to use reference objects to update the "master" object. This started off as a way to avoid typing out the complicated name of the property each time - I could easily expand out to the full name but now the reason for this behaviour is seriously bugging me.
[CmdletBinding()]
Param()
Function Breakhere {Write-Verbose " "}
Set-PSBreakpoint -Command Breakhere
$Data = #"
UserID
MyUser1
MyUser2
User3
"#
$Data = $Data|ConvertFrom-Csv
$Domains = "DomainA","DomainB"
$Props = "ParentContainer","AccountIsDisabled","employeeNumber"
$Connection = New-Object HashTable
ForEach ($Domain in $Domains)
{
Write-Verbose "Current Domain: $Domain"
# Add necessary headers to main data
$text1 = "$($Domain)_ADObject"
$text2 = "$($Domain)_Confidence"
$Data = $Data |Select *,$text1
$Data = $Data |Select *,$text2
#Bind to each domain and save the connection contexts into a hashtable
Write-Verbose "Binding to $Domain"
$Connection.Add($Domain,(Connect-QADService -service $Domain))
}
ForEach ($User in $Data)
{
ForEach ($Domain in $Domains)
{
$User."$($Domain)_ADObject" = Get-QADUser -Connection $Connection[$Domain] -SamAccountName $User.UserID -DontUseDefaultIncludedProperties -IncludedProperties $Props|Select $Props
# Referencing the confidence parameter does not seem to work.
$CF = [ref]$User."$($Domain)_Confidence"
# Weirdly, this one does work.
$AD = [ref]$User."$($Domain)_ADObject"
If ($AD.Value)
{
$CF.Value = 1
Breakhere # Break here and allow for opportunity to inspect $user and $CF objects
If ($AD.Value.AccountIsDisabled)
{
Write-Verbose "$Domain\$($User.UserID): Account Disabled"
$CF.Value *= 0.8
}
}
Else
{
Write-Verbose "$Domain\$($User.UserID): No AD Object found"
$CF.Value = 0
}
}
} #End ForEach $UserID
At the breakpoint, if I query $User, I receive something similar to the following:
UserID : MyUser1
DomainA_ADObject : #{ParentContainer=DomainA/Users; AccountIsDisabled=False; employeeNumber=123456}
DomainA_Confidence :
DomainB_ADObject :
DomainB_Confidence :
All good. Should I wish, I can even use the $AD ref object and update DomainA_ADobject:
$AD.Value.employeeNumber = 9999
$User
UserID : MyUser1
DomainA_ADObject : #{ParentContainer=DomainA/Users; AccountIsDisabled=False; employeeNumber=9999}
DomainA_Confidence :
DomainB_ADObject :
DomainB_Confidence :
However, try this with the $CF ref and the same thing doesn't happen
$CF.Value = 2
$CF
Value
-----
2
$User
UserID : MyUser1
DomainA_ADObject : #{ParentContainer=DomainA/Users; AccountIsDisabled=False; employeeNumber=9999}
DomainA_Confidence : *<====== Expecting this to update!*
DomainB_ADObject :
DomainB_Confidence :
Why the difference? Is there any way to query a [ref] object and see what it's pointing to? I can't see why one of these is working and the other isn't. They both seem to be set up in the same way. Tried this in ISE and console, same behaviour in both.
My guess is, that this is caused by dots in the name of domains.
Reducing this to basics $CF.Value = 1 does someting like
$Data[0].domain.name.net.au_Confidence.value = 1
This will not work. This will:
$Data[0]."domain.name.net.au_Confidence".value = 1
Perhaps this will fix it?:
$CF = [ref]$User."`"$($Domain)_Confidence`""

Save hash table in PowerShell object notation (PSON)

The question Loading a PowerShell hashtable from a file? documents how to load a file that contains a hashtable in PSON format into a variable, but how does one save a hashtable to a file in PSON format?
Hashtable:
#{
"name" = "report 0"
"parameters" = #(
#{"name" = "parameter 0"; "default" = 1; "values"=1,2,3,4},
#{"name" = "parameter 1"; "default" = 'A'; "values" = 'A','B','C'}
)
}
After 5 years, the cmdlet I had pasted in the original answer has undergone so many updates that it has become completely outdated. Therefore I have replaced the code and the ReadMe with a link to the latest version.
ConvertTo-Expression
The ConvertTo-Expression cmdlet can be download from PowerShell Gallery using the command:
Install-Script -Name ConvertTo-Expression
ReadMe
The full ReadMe (and source code) is available from the GitHub
Answer
Below are some possible options to serialize the specific example (assigned to $Craig) in the question:
ConvertTo-Expression $Craig
#{
parameters =
#{
name = 'parameter 0'
default = 1
values =
1,
2,
3,
4
},
#{
name = 'parameter 1'
default = 'A'
values =
'A',
'B',
'C'
}
name = 'report 0'
}
To limit the tree view expansion:
(Expand -0 will output a single line and Expand -1 will remove also the unnecessary spaces)
ConvertTo-Expression $Craig -expand 3
#{
parameters =
#{name = 'parameter 0'; default = 1; values = 1, 2, 3, 4},
#{name = 'parameter 1'; default = 'A'; values = 'A', 'B', 'C'}
name = 'report 0'
}
Preserving the explicit types (strong typed):
ConvertTo-Expression $Craig -expand 3 -Strong
[hashtable]#{
parameters = [array](
[hashtable]#{name = [string]'parameter 0'; default = [int]1; values = [array]([int]1, [int]2, [int]3, [int]4)},
[hashtable]#{name = [string]'parameter 1'; default = [string]'A'; values = [array]([string]'A', [string]'B', [string]'C')}
)
name = [string]'report 0'
}
(Note: As per PowerShell design, HashTables are not in order, but if required you might use the [Ordered] type instead.)
Try the *-CliXml cmdlets. To save the object:
#{
"name" = "report 0"
"parameters" = #(
#{"name" = "parameter 0"; "default" = 1; "values"=1,2,3,4},
#{"name" = "parameter 1"; "default" = 'A'; "values" = 'A','B','C'}
)
} | Export-Clixml -Path c:\hash.xml
To read it back:
Import-Clixml c:\hash.xml
One way would be to put the hashtable definition in a scriptblock:
$hashtable = {
#{
"name" = "report 0"
"parameters" = #(
#{"name" = "parameter 0"; "default" = 1; "values"=1,2,3,4},
#{"name" = "parameter 1"; "default" = 'A'; "values" = 'A','B','C'}
)
}
}
$hashtable.tostring()
#{
"name" = "report 0"
"parameters" = #(
#{"name" = "parameter 0"; "default" = 1; "values"=1,2,3,4},
#{"name" = "parameter 1"; "default" = 'A'; "values" = 'A','B','C'}
)
}
Within the script, you'd need to invoke the script block to instantiate the hashtable:
$hash = .$hashtable
How to use a shorthand "object notation" to generate an object in PowerShell:
$object = New-Object -TypeName PSObject -Property #{name="foo";age=21}
DISCLAIMER: I know this does not answer OP's question directly but it might help folks like me searching for a very similar issue and landing here.