Trying to get the #{Name= out of the output - powershell

I have a script that has an array of custom PSObjects with only 2 items each. I need to sort on the first value in each object and then spit out both items, but they are both coming out with #{Name= and #{Line=. Here's a snippet of my code:
$expinfo = #()
<<<>>>
$dbinfo = New-Object -TypeName PSObject
$dbname = Get-Item $folder | select Name
$dbinfo | Add-Member -NotePropertyName DBName -NotePropertyValue "$dbname"
$dbinfo | Add-Member -NotePropertyName ExportLine -NotePropertyValue "$eline"
$expinfo += $dbinfo
<<<>>>
foreach ($expdb in ($expinfo.GetEnumerator() | Sort-Object DBName))
{
$dbn = $expdb | Select-Object -ExpandProperty DBName
$dbe = $expdb | Select-Object -ExpandProperty ExportLine
$dbn
$dbe
}
Output looks like this:
#{Name=AIT1PD}
#{Line=20180312.1700 20180312.1704 All items successfully completed.}
#{Name=APAC1PD}
#{Line=20180313.0100 20180313.0120 All items successfully completed.}
I would like for it to look like this:
AIT1PD 20180312.1700 20180312.1704 All items successfully completed.
APAC1PD 20180313.0100 20180313.0120 All items successfully completed.

Change your Add-Member statements to add the property value you're interested in:
$dbinfo | Add-Member -NotePropertyName DBName -NotePropertyValue $dbname.Name
$dbinfo | Add-Member -NotePropertyName ExportLine -NotePropertyValue $eline.Line
Assuming you're using PowerShell 3.0 or newer, I'd suggest using the [pscustomobject] type accelerator instead:
$dbinfo = [pscustomobject]#{
DBName = (Get-Item $folder).Name
ExportLine = $eline.Line
}

Related

Sort-Object: Can it use an object's method result for sorting?

Using Add-Member I added a tiny method to an array of objects to calculate sort of a hash from a string:
$arr | Add-Member -MemberType ScriptMethod -Name 'SortedName' -Value {
[string]$name = $this.Name
[int]$start = [int][char]$name[0];
[int]$index = [int]($name -replace '^.+?(\d+)\.[^.]+$','$1')
[int]"$start$('{0:D4}' -f $index)"
}
Now I'd like to sort the array using $arr | Sort-Object -PropertyName 'SortedName'. But that doesn't seem to work as expected.
How can I apply Sort-Object on an array's methods?
To invoke methods on each element you need to use a calculated expression.
For example:
$arr = 0..10 | ForEach-Object {
[pscustomobject]#{ Name = 'Test' + (Get-Random -Maximum 20) }
}
$arr | Add-Member -MemberType ScriptMethod -Name SortedName -Value {
[int] ($this.Name -replace '\D+')
}
$arr | Sort-Object { $_.SortedName() }

Group-Object AsHashTable doesn't work for ScriptProperty

Works:
$Names = 1..5 | % { new-object psobject | add-member -Type NoteProperty -Name Name -Value "MyName" -PassThru } | group Name -AsHashTable
$Names.MyName
Doesn't work:
$Names = 1..5 | % { new-object psobject | add-member -Type ScriptProperty -Name Name -Value {"MyName"} -PassThru } | group Name -AsHashTable
$Names.MyName
The reason you're unable to access the values in the hash-table by prop name or key-based access is that the keys/props are wrapped in PSObjects. There was a Github issue to fix this in Powershell Core, but it will likely remain forever in Windows Powershell.
If you want to convert to a hash-table after grouping, and want to access some of the grouped values by property name or key-based access do this:
$Names = 1..5 | ForEach-Object {
New-Object PsObject | Add-Member -Type ScriptProperty -Name Name -Value { return "MyName"} -PassThru
} | Group-Object -Property 'Name' -AsHashTable -AsString
$Names.MyName
$Names['MyName']
If you want to convert to a hash-table after grouping, and want to access all the grouped values at once, do this:
$Names = 1..5 | ForEach-Object {
New-Object PsObject | Add-Member -Type ScriptProperty -Name Name -Value { return "MyName"} -PassThru
} | Group-Object -Property 'Name' -AsHashTable
$Names.Values
If you're not converting to a hash-table after the grouping, and want to access the data in $Names.Group, you'll need to expand that property.
$Names = 1..5 | % {
new-object psobject | add-member -Type ScriptProperty -Name Name -Value {"MyName"} -PassThru
} | Group-Object -Property 'Name'
$Names | Select-Object -ExpandProperty Group

Create a custom object referencing other objects

I am trying to create a new custom object with data input from another object.
$clusters = Get-EMRClusters
$runningclusters = $clusters | Where-Object {
$_.Status.State -eq "Running" -or
$_.Status.State -eq "Waiting"
}
$runningclusters looks like
id name status
-- ---- ------
j-12345 cluster1 running
j-4567 cluster2 running
I want to create a new PSobject $o with a 4th column named PendingShutdown that's a boolean.
id name status pendingshutdown
-- ---- ------ ---------------
j-12345 cluster1 running False
j-4567 cluster2 running False
I have tried running this:
$o = New-Object PSObject
$o | Add-Member -NotePropertyName id -NotePropertyValue $runningclusters.id
$o | Add-Member -NotePropertyName name -NotePropertyValue $runningclusters.name
$o | Add-Member -NotePropertyName status -NotePropertyValue $runningclusters.status.state
$o | Add-Member -NotePropertyName PendingShutdown -NotePropertyValue $true
But my output for $o for the columns id and name are just objects themselves, not rows of IDs. How do I make an object to look like my desired object above?
You need to loop through each of the cluster-objects. You can loop through them and add the column to the current object, like:
$runningclusters = $clusters |
Where-Object {$_.Status.State -eq "Running" -or $_.Status.State -eq "Waiting"} |
Add-Member -NotePropertyName pendingshutdown -NotePropertyValue $true -PassThru
Or you could create new objects per cluster. Ex:
$MyNewClusterObjects = $runningclusters | ForEach-Object {
New-Object -TypeName psobject -Property #{
id = $_.id
name = $_.name
status = $_.status.state
PendingShutdown = $true
}
}
Simply use calculated properties for adding properties to objects in a pipeline, e.g. like this:
$runningclusters = $clusters | Where-Object {
$_.Status.State -eq "Running" -or
$_.Status.State -eq "Waiting"
} | Select-Object *,#{n='PendingShutdown';e={$false}}

Display output from multiple variables in a for loop

I am trying to output different attributes of a Skype response group queue for documentation purpose.
I want to get Name, TimeoutThreshold, TimeoutAction , Timeouturi, OverflowThreshold, OverflowAction , OverflowCandidate as a .csv file header in row 1 and then the output to be entered in various columns from row 2.
I have tried below, but the formatting is really bad and the headers keep repeating. Can some one please help.
Also tried getting output in HTML, but no luck.
$p = Get-CsRgsQueue | Where-Object {$_.Name -like "IPL*"} | Select-Object Name
foreach ($Name in $p)
{
$q = Get-CsRgsQueue -Name "$Name"
$N = $q.Name
$TT = $q.TimeoutThreshold
$TA = $q.TimeoutAction.Action
$TAU = $q.TimeoutAction.uri
$OF = $q.OverflowThreshold
$OFA = $q.OverflowAction
$OFC = $q.OverflowCandidate
$out = New-Object PSObject
$out | Add-Member NoteProperty QueueName $N
$out | Add-Member NoteProperty Timeout $TT
$out | Add-Member NoteProperty TimeoutAction $TA
$out | Add-Member NoteProperty TransferURI $TAU
$out | Add-Member NoteProperty OverflowThreshhold $OF
$out | Add-Member NoteProperty OverflowAction $OFA
$out | Add-Member NoteProperty OverflowCandidate $OFC
$out | FT -AutoSize | Export-Csv C:\abc.csv -Append
}
I have tried below, but the formatting is really bad and the headers
keep repeating. Can some one please help.
That's because you pipe your objects through FT -AutoSize (Format-Table -AutoSize) - only ever use the Format-* cmdlets when you're about to show/present your data.
You can also save some time by only calling Get-CsRgsQueue once, piping it to ForEach-Object and finally construct a hashtable for the object properties:
Get-CsRgsQueue | Where-Object {$_.Name -like "IPL*"} | ForEach-Object {
New-object psobject -Property #{
QueueName = $_.Name
Timeout = $_.TimoutThreshold
TimeoutAction = $_.TimeoutAction.Action
TransferURI = $_.TimeoutAction.Uri
OverflowThreshhold = $_.OverflowThreshold
OverflowAction = $_.OverflowAction
OverflowCandidate = $_.OverflowCandicate
}
} |Export-Csv c:\abc.csv -NoTypeInformation
short solution of Mathias Jessen
Get-CsRgsQueue | where Name -like "IPL*" | %{
[pscustomobject] #{
QueueName = $_.Name
Timeout = $_.TimoutThreshold
TimeoutAction = $_.TimeoutAction.Action
TransferURI = $_.TimeoutAction.Uri
OverflowThreshhold = $_.OverflowThreshold
OverflowAction = $_.OverflowAction
OverflowCandidate = $_.OverflowCandicate
}
} | Export-Csv C:\result.csv -NoType

Powershell Side by side objects

Heres what I have,
Two objects:
$Global:Object1 = New-Object -TypeName PSObject
$Global:Object1 | Add-Member -MemberType NoteProperty -Name Name1 -Value $Name1.Name1
$Global:Object1 | Add-Member -MemberType NoteProperty -Name Name2 -Value $Name2.Name2
$Global:Object2 = New-Object -TypeName PSObject
$Global:Object2 | Add-Member -MemberType NoteProperty -Name Name3 -Value $Name3.Name3
$Global:Object2 | Add-Member -MemberType NoteProperty -Name Name4 -Value $Name4.Name4
Now when I present that to the user, it appears how underneath each other.
I would like to have them presented side by side:
Object1: Object2:
Name1 Name3
Name2 Name4
I will have one more object, but at the moment only 2. Can anyone help me out please?
If the $variables don't make sense, I replaced them to keep things simple..
I do something similar in that I compare two objects side by side for easy reference, I use the following function:
function Compare-ObjectsSideBySide ($lhs, $rhs) {
$lhsMembers = $lhs | Get-Member -MemberType NoteProperty, Property | Select-Object -ExpandProperty Name
$rhsMembers = $rhs | Get-Member -MemberType NoteProperty, Property | Select-Object -ExpandProperty Name
$combinedMembers = ($lhsMembers + $rhsMembers) | Sort-Object -Unique
$combinedMembers | ForEach-Object {
$properties = #{
'Property' = $_;
}
if ($lhsMembers.Contains($_)) {
$properties['Left'] = $lhs | Select-Object -ExpandProperty $_;
}
if ($rhsMembers.Contains($_)) {
$properties['Right'] = $rhs | Select-Object -ExpandProperty $_;
}
New-Object PSObject -Property $properties
}
}
You can test this out with the following, contrived, example:
$object1 = New-Object PSObject -Property #{
'Forename' = 'Richard';
'Surname' = 'Slater';
'Company' = 'Amido';
'SelfEmployed' = $true;
}
$object2 = New-Object PSObject -Property #{
'Forename' = 'Jane';
'Surname' = 'Smith';
'Company' = 'Google';
'MaidenName' = 'Jones'
}
Compare-ObjectsSideBySide $object1 $object2 | Format-Table Property, Left, Right
Which will result in:
Property Left Right
-------- ---- -----
Company Amido Google
Forename Richard Jane
MaidenName Jones
SelfEmployed True
Surname Slater Smith
It wouldn't be difficult to increase the number of objects being compared side-by-side, or even write it in such a way that the function accepts an array of objects which are printed as a side-by-side table.