Dynamically creating the name of an existing object to Set one of its properties - powershell

I have the following code in Powershell:
function New-Row-Object-Instance {
New-Object PSObject -Property #{
Zeros = 0
Tens = 0
Twentys = 0
Thirtys = 0
Fortys = 0
Fiftys = 0
Sixtys = 0
}
$Row_Details = New-Row-Object-Instance
I Updated $Row_Details with some values. Now I have the following Labels on a Windows Form that is displayed: $Zeros, $Tens, $Twentys, $Thirtys etc.
I want to update the Labels on Form with values using the property Content.
So $Zeros.Content = 2 and so forth
foreach ($property in $Row_Details.PSObject.Properties) {
$property.Name >> $OutFile
# following creates the label names $Zeros,....
$v = -join('$',$property.Name)
# following gives error.. no property named Content
$v.Content = 2
# following gives error.. no property named Content
(-join('$',$property.Name)).Content = 2
# following gives error.. no property named Content
$v | Set-ItemProperty -Name "Content" -Value 2
# following does not update the Labels on the Form itself
Set-Variable $v -Value #{Content = "2"}
# Cannot use Set-ItemProperty -inputObject $v because cannot name property
}
I can hard code name of each Label, but was trying to do it dynamically or Elegantly...

Not sure I really understand your question, but I'll give it a try with a small example that might put you on a track to follow:
$object = New-Object PSObject -Property #{
Zeros = 0;
Tens = 0;
}
$Zeros = New-Object PSObject -Property #{
Content = "0"
}
$Tens = New-Object PSObject -Property #{
Content = "0"
}
$Zeros
$Tens
$object.PSObject.Properties | %{
$property = $_.Name
$expression = "`$$($property).Content = `"2`""
Invoke-Expression $expression
}
$Zeros
$Tens

The question is unclear to me, but maybe this helps
If you just want to modify the values for each of them you an do this:
foreach ($property in $Row_Details.PSObject.Properties)
{
$property.Value = 0
}
If you want to make new variables for each item:
foreach ($property in $Row_Details.PSObject.Properties)
{
New-Variable -Name $property.Name -Value $property.Value
}

You should be able to use Get-Variable for this is interact with those other objects. Shrinking your examples down to two you can proof of concept this fairly easily.
# Simulate your controls by creating object with those respective properties
$Zeros = New-Object PSObject -Property #{Content = 0}
$Tens = New-Object PSObject -Property #{Content = 0}
$Row_Details = New-Object PSObject -Property #{
Zeros = 1
Tens = 2
}
# Display the current Contents
write-host "Zeros: $($Zeros.Content)"
write-host "Tens: $($Tens.Content)"
foreach ($property in $Row_Details.PSObject.Properties){
$singleVariable = Get-Variable $property.name
$singleVariable.Value.content = $property.Value
}
# Show the updated Contents
write-host "Zeros: $($Zeros.Content)"
write-host "Tens: $($Tens.Content)"
The results of this being
Zeros: 0
Tens: 0
Zeros: 1
Tens: 2
The only problem I see is that all of this exists in the same scope so you my example should work as intended. However, depending where your variables are defined, you might have scope issues. If that happens you just need to experiment with the -Scope parameter of Get-Variable

Related

Format-Table in PowerShell inside a ForEach

Not sure what I am doing wrong here with this, I know it has to do with the fact that it is inside a ForEach loop. I have tried moving the below code around. Even with the code half and half (half in and half out of the loop does not seem to work). Still new to PowerShell and I know that I need to variables to $table each iteration or store them some where and read them later.
foreach ($gp in $GPINFO) {
# Code that gets the values for $gp, $aclBefore and $aclAfter is here
$table = new-object psobject -Property #{
GPO_Name = $gp.DisplayName
Old_Owner = $aclBefore
New_Owner = $aclAfter
}
$table | Format-Table GPO_Name,Old_Owner,New_Owner
}
If you can help me figure out what I am doing wrong that would be great, I know that every time the ForEach gets $gp out of the $GPINFO it is running the $table stuff and that is my problem. So instead of one continuous table I end up with multiple tables with one set of data in each.
Thanks in advance
Just simply output the table after the loop completes.
$table = foreach ($gp in $GPINFO) {
# Code that gets the values for $aclBefore and $aclAfter is here
new-object psobject -Property #{
GPO_Name = $gp.DisplayName
Old_Owner = $aclBefore
New_Owner = $aclAfter
}
}
$table | Format-Table
Any output from within the foreach loop will be stored in $table. Each iteration will output an object, ultimately creating an array of those objects stored in $table.
You just can't pipe from foreach (). It's an odd part of the language that comes up a lot. Other ways:
Foreach-object:
$GPINFO | foreach-object {
$gp = $_
new-object psobject -Property #{
GPO_Name = $gp.DisplayName
Old_Owner = $aclBefore
New_Owner = $aclAfter
}
} | Format-Table GPO_Name,Old_Owner,New_Owner
Call operator and scriptblock:
& {
foreach ($gp in $GPINFO) {
new-object psobject -Property #{
GPO_Name = $gp.DisplayName
Old_Owner = $aclBefore
New_Owner = $aclAfter
}
}
} | Format-Table GPO_Name,Old_Owner,New_Owner

Can't display PSObject

I'm trying to display some data my script generates in a PSObject, so I can then export to a CSV, but the only object that shows is whichever one I add to the array first.
$pass=#("1","2","3")
$fail=#("4")
$obj=#()
$pass | % {
$obj+=New-Object PSObject -Property #{Pass=$_}
}
$fail | % {
$obj+=New-Object PSObject -Property #{Fail=$_}
}
$obj
I've also tried this, but I get a blank line showing in the table where the value isn't in that column, which I don't want:
$pass=#("1","2","3")
$fail=#("4")
$obj=#()
$pass | % {
$obj+=New-Object PSObject -Property #{Pass=$_;Fail=""}
}
$fail | % {
$obj+=New-Object PSObject -Property #{Pass="";Fail=$_}
}
$obj
My desired result:
Pass Fail
---- ----
1 4
2
3
I am using Powershell V2.
Another answer is right - you're using objects wrong. That being said, here's a function to help you use them wrong!
Function New-BadObjectfromArray($array1,$array2,$array1name,$array2name){
if ($array1.count -ge $array2.count){$iteratorCount = $array1.count}
else {$iteratorCount = $array2.count}
$obj = #()
$iteration=0
while ($iteration -le $iteratorCount){
New-Object PSObject -Property #{
$array1name=$array1[$iteration]
$array2name=$array2[$iteration]
}
$iteration += 1
}
$obj
}
$pass=#("1","2","3")
$fail=#("4")
New-BadObjectfromArray -array1 $fail -array2 $pass -array1name "Fail" -array2name "Pass"
As you figured out yourself, PowerShell only outputs the properties of the first item in your array. Its not designed to print the ouput you are expecting in the way you are using it.
As a workaround, you could use a for loop to "build" your desired output:
$pass=#("1","2","3")
$fail=#("4")
$obj=#()
for ($i = 0; $i -lt $pass.Count; $i++)
{
if ($fail.Count -gt $i)
{
$currentFail = $fail[$i]
}
else
{
$currentFail = ""
}
$obj+=New-Object PSObject -Property #{Fail=$currentFail;Pass=$pass[$i];}
}
$obj | select Pass, Fail
Output:
Pass Fail
---- ----
1 4
2
3

Iterate through an array of powershell custom objects and output to html

I have an array :
$results =#()
Then i loop with custom logic through wmi and create custom objects that i add to the array like this:
$item= #{}
$item.freePercent = $freePercent
$item.freeGB = $freeGB
$item.system = $system
$item.disk = $disk
$results += $item
I know want to to some stuff on the results array, like converting to html .
I can do it with a foreach and custom html writing but i want to use convertto-html...
P.S. I can print out data like this but only this:.
foreach($result in $results) {
$result.freeGB
}
Custom object creation doesn't work like you seem to think. The code
$item= #{}
$item.freePercent = $freePercent
$item.freeGB = $freeGB
$item.system = $system
$item.disk = $disk
creates a hashtable, not a custom object, so you're building a list of hashtables.
Demonstration:
PS C:\> $results = #()
PS C:\> 1..3 | % {
>> $item = #{}
>> $item.A = $_ + 2
>> $item.B = $_ - 5
>> $results += $item
>> }
>>
PS C:\> $results
Name Value
---- -----
A 3
B -4
A 4
B -3
A 5
B -2
PS C:\> $results[0]
Name Value
---- -----
A 3
B -4
Change your object creation to this:
$item = New-Object -Type PSCustomObject -Property #{
'freePercent' = $freePercent
'freeGB' = $freeGB
'system' = $system
'disk' = $disk
}
$results += $item
so you get the desired list of objects:
PS C:\> $results = #()
PS C:\> 1..3 | % {
>> $item = New-Object -Type PSCustomObject -Property #{
>> 'A' = $_ + 2
>> 'B' = $_ - 5
>> v}
>> $results += $item
>> }
>>
PS C:\> $results
A B
- -
3 -4
4 -3
5 -2
PS C:\> $results[0]
A B
- -
3 -4
Also, appending to an array in a loop is bound to perform poorly. It's better to just "echo" the objects inside the loop and assign the result to the list variable:
$results = foreach (...) {
New-Object -Type PSCustomObject -Property #{
'freePercent' = $freePercent
'freeGB' = $freeGB
'system' = $system
'disk' = $disk
}
}
Pipe $results into ConvertTo-Html to convert the list to an HTML page (use the parameter -Fragment if you want to create just an HTML table instead of an entire HTML page).
$results | ConvertTo-Html
An even better approach would be to pipeline your whole processing like this:
... | ForEach-Object {
New-Object -Type PSCustomObject -Property #{
'freePercent' = $freePercent
'freeGB' = $freeGB
'system' = $system
'disk' = $disk
}
} | ConvertTo-Html
You aren't creating a custom object, you're creating a hash table.
Assuming you've got at least V3:
[PSCustomObject]#{
freePercent = $freePercent
freeGB = $freeGB
system = $system
disk = $disk
}

How to get powershell object properties in the same order that format-list does?

I'm writing some reporting scripts in Powershell and collecting up a summary table of items as a blank object with additional properties added one by one:
$cmClusters = #()
foreach ($Cluster in Clusters) {
$cmCluster = New-Object System.Object
$cmCluster | Add-Member -type NoteProperty -Name VC -Value $strVC
$cmCluster | Add-Member -type NoteProperty -Name Name -Value $Cluster.name
# etc...
$cmClusters += $cmCluster;
}
If I just dump $cmClusters at the end of this, I get a format-list output with the properties in the order that I added them.
However, I was hoping to write a generic "dump this collection of objects to an excel tab" function to produce my report, which will be several similar worksheet tabs from different lists of objects.
That looks like this:
function DumpToExcel($workbook, $tabTitle, $list)
{
$sheet = $workbook.worksheets.add()
$sheet.Name = $tabTitle
$col = 1
$row = 1
$fields = $list[0] | Get-Member -MemberType NoteProperty | Select-Object *
Foreach ($field in $fields) {
$sheet.cells.item($row,$col++) = $field.Name
}
$heading = $sheet.UsedRange
$heading.Font.Bold = $True
$row++
Foreach ($cmCluster in $list) {
$col=1
Foreach ($field in $fields) {
$sheet.cells.item($row,$col++) = $cmCluster.($field.Name)
}
$row++
}
$sheet.UsedRange.EntireColumn.AutoFit() | Out-Null
}
which works, but the property names are now in alphabetical order.
What can I use to get my list of properties in the same order that Format-List does?
Try this:
$fields = $list[0].psobject.properties | select name

Structs or Objects in Powershell 2

Does the latest version of Powershell have the ability to do something like JavaScript's:
var point = new Object();
point.x = 12;
point.y = 50;
If not, what is the equivalent or workaround?
UPDATE
Read all comments
The syntax is not directly supported by the functionality is there via the add-member cmdlet's. Awhile ago, I wrapped this functionality in a general purpose tuple function.
This will give you the ability to one line create these objects.
$point = New-Tuple "x",12,"y",50
Here is the code for New-Tuple
function New-Tuple()
{
param ( [object[]]$list= $(throw "Please specify the list of names and values") )
$tuple = new-object psobject
for ( $i= 0 ; $i -lt $list.Length; $i = $i+2)
{
$name = [string]($list[$i])
$value = $list[$i+1]
$tuple | add-member NoteProperty $name $value
}
return $tuple
}
Blog Post on the subject: http://blogs.msdn.com/jaredpar/archive/2007/11/29/tuples-in-powershell.aspx#comments
For simple ways, first, is a hashtable (available in V1)
$obj = #{}
$obj.x = 1
$obj.y = 2
Second, is a PSObject (easier in V2)
$obj = new-object psobject -property #{x = 1; y =2}
It gives you roughly the same object, but psobjects are nicer if you want to sort/group/format/export them
Sorry, even though the selected answer is good, I couldn't resist the hacky one line answer:
New-Object PsObject | Select-Object x,y | %{$_.x = 12; $_.y = 50; $foo = $_; }
You can do it like this:
$point = New-Object Object |
Add-Member NoteProperty x ([int] 12) -passThru |
Add-Member NoteProperty y ([int] 15) -passThru
Regarding one of your comments elsewhere, custom objects may be more useful than hash tables because they work better with cmdlets that expect objects to have named properties. For example:
$mypoints | Sort-Object y # mypoints sorted by y-value
$point = "" | Select #{Name='x'; Expression={12}} ,#{Name='y'; Expression={15}}
or more intuitively
$point = "" | Select x,y
$point.x=12; $point.y=15