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
Related
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
Import-Module <JAMS>
$JAMSHistories = Get-JAMSHistory -Server TESTDUMMY2 -StartDate "01/20/2020" -EndDate "01/24/2020"
$historyTable = #()
foreach($JAMSHistory in $JAMSHistories)
{
$row = New-Object -TypeName PSObject
Write-Host $JAMSHistory.FinalSeverity
if($JAMSHistory.FinalSeverity -match 'Success')
{
$row | Add-Member -NotePropertyName JobSeveritySuccess ($JAMSHistory.FinalSeverity)
}
else {
if ($JAMSHistory.FinalSeverity -match 'Error') {
$row | Add-Member -NotePropertyName JobSeverityError ($JAMSHistory.FinalSeverity) }
} $historyTable += $row
}
$historyTable
You can do the following, which will output an array of objects ($historyTable) with a properties called JobSeveritySuccess and JobSeverityError.
$JAMSHistories = Get-JAMSHistory -Server TESTDUMMY2 -StartDate "01/20/2020" -EndDate "01/24/2020"
$historyTable = foreach ($JAMSHistory in $JAMSHistories) {
$row = "" | Select JobSeveritySuccess,JobSeverityError
if ($JAMSHistory.FinalSeverity -match 'Success') {
$row.JobSeveritySuccess = $JAMSHistory.FinalSeverity
}
elseif ($JAMSHistory.FinalSeverity -match 'Error') {
$row.JobSeverityError = $JAMSHistory.FinalSeverity
}
$row
}
# Output
$historyTable
# Output in Table Format
$historyTable | Format-Table
The problem with this approach is that every object will have JobSeveritySuccess and JobSeverityError properties, and they may be empty. The only time both properties will have data is if $JAMSHistory.FinalSeverity contains Error and Success for the same object. There is probably a better way to do your design if provided more requirements.
When doing this type of exercise, there are always some gotchas. Consider creating a new PSObject or PSCustomObject for loop iteration. Then output that object at the end of the loop code. When collecting the foreach loop output, just set a variable equal to the foreach loop. There's rarely a need to use += to build an array of foreach loop output. There could be some exceptions to this, but most of the time they are good things to consider.
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
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
}
I am trying to find the matching names in two different types of Powershell objects
$Object1 has two properties - Name (string), ResourceID (uint32)
$object2 has one noteproperty - Name (system.string)
This gives me a list of the matching names but I also want the corresponding resourceID property from $object1.
$computers = Compare-Object $Object1.name $WSD_CM12 | where {$_.sideindicator -eq "=>"} | foreach {$_.inputobject}
These are big objects with over 10,000 items so I'm looking for the most efficient way to accomplish this.
If I'm understanding what you're after, I'd start by creating a hash table from your Object1 collection:
$object1_hash = #{}
Foreach ($object1 in $object1_coll)
{ $object1_hash[$object1.Name] = $object1.ResourceID }
Then you can find the ResourceID for any given Object2.name with:
$object1_hash[$Object2.Name]
Test bed for creating hash table:
$object1_coll = $(
New-Object PSObject -Property #{Name = 'Name1';ResourceID = 001}
New-Object PSObject -Property #{Name = 'Name2';ResourceID = 002}
)
$object1_hash = #{}
Foreach ($object1 in $object1_coll)
{ $object1_hash[$object1.Name] = $object1.ResourceID }
$object1_hash
Name Value
---- -----
Name2 2
Name1 1
Alternative method:
# Create sample list of objects with both Name and Serial
$obj1 = New-Object -Type PSCustomObject -Property:#{ Name = "Foo"; Serial = "1234" }
$obj2 = New-Object -Type PSCustomObject -Property:#{ Name = "Cow"; Serial = "4242" }
$collection1 = #($obj1, $obj2)
# Create subset of items with only Name
$objA = New-Object -Type PSCustomObject -Property:#{ Name = "Foo"; }
$collection2 = #($objA)
#Everything above this line is just to make sample data
# replace $collection1 and $collection2 with $Object1, $WSD_CM12
# Combine into one list
($collection1 + $collection2) |
# Group by name property
Group-Object -Property Name |
# I only want items that exist in both
Where { $_.Count -gt 1 } |
# Now give me the object
Select -Expand Group |
# And get the properties
Where { $_.Serial -ne $null }