How to reverse the properties of pscustomobject? - arrays

Is it possible to reverse the properties of [Pscustomobject] ?
I have to setup resources in queue order. After testing is over , i have to teardown the resources in reverse order.
below is the sample code.
$volume= #{Name='Vol1';size = "100gb"}
$VolumeCollection = #{Name = 'VolColl'; Volume = $volume}
$ResourceQueue = [pscustomobject]#{
Volume = $Volume
VolumeCollection = $VolumeCollection
}
function SEtup-Resources
{
param
(
[psobject]$resource
)
$resource.PSObject.Properties | foreach-object {
switch ($_.name) {
"volume" {
"Volume is created"
}
"VolumeCollection" {
"volcoll is created"
}
}
}
}
function TearDown-Resources
{
param
(
[psobject]$resource
)
# I have to reverse the object properties
$resource.PSObject.Properties | foreach-object {
switch ($_.name) {
"volume" {
"Volume is deleted"
}
"VolumeCollection" {
"volcoll is deleted"
}
}
}
}
Write-host "-------------------------"
Write-host "Setup resources"
Write-host "-------------------------"
SEtup-Resources -resource $ResourceQueue
Write-host "-------------------------"
Write-host "teardown resources"
Write-host "-------------------------"
TearDown-Resources -resource $ResourceQueue
The result should be
-------------------------
Setup resources
-------------------------
Volume is created
volcoll is created
-------------------------
teardown resources
-------------------------
volcoll is deleted
volume is deleted
But i could not find the way to reverse the properties of an object. How to reverse the pscustomobject properties in powershell?

If you only need to alter order of few properties, you could just list them manually to Select-Object:
$ResourceQueue | Select-Object VolumeCollection, Volume
For more generic solution one could use Get-Memberto get an array of properties, use [Array]::reverse to reverse
order and then Select-Object to get the properties in desired order. I came out with this:
$props = #()
$MyObject | Get-Member | ForEach-Object { $props += $_.name }
[Array]::Reverse($props)
$MyObject | Select-Object $props

You can do it this way:
$object = '' | select PropertyA, PropertyB, PropertyC
$object.PropertyA = 1234
$object.PropertyB = 'abcd'
$object.PropertyC = 'xyz'
$properties = ($object | Get-Member -MemberType NoteProperty).Name
[Array]::Reverse($properties)
$object | select $properties
The result is
PropertyC PropertyB PropertyA
--------- --------- ---------
xyz abcd 1234

Related

Slow array operations after DB resultset

I need help optimizing my PowerShell script.
$sorted = #()
$firsttime = 0
$j = 0
$zaehler = $results.Count-1
for ($i=0; $i -le $results.Count-1; $i++) {
$j = $i+1
while ($results.GUID[$i] -eq $results.GUID[$j]) {
$klassen = ""
$rec = $results | where {$_.GUID -eq $results.GUID[$i]}
if ($firsttime -eq 0 -or !$sorted.GUID.contains($rec[0].GUID)) {
$firsttime = 1
foreach ($item in $rec.Klasse) {
if ($klassen -eq "") {
$klassen += $item
} else {
if (!$klassen.Contains($item)) {
$klassen += "," + $item
}
}
}
$rec[0].Klasse = $klassen
$sorted += $rec[0]
}
$j = $j+1
}
Write-Host ($i/$zaehler).ToString("P") "von Schule" $schule
}
if (!$sorted) {
$results
} else {
$sorted
}
Basically in my resultset ($results) I got duplicate lines of teachers and the only difference is the class ("Klasse/Klassen") they are teaching at.
To minimize the output I am checking if the first GUID is the same as the second and then the script appends the second class to the first one. So the $sorted array has just one line per teacher with a comma-seperated string which shows all classes.
Sample line of $results:
#{
GUID={1234567-1234-1234-1234-1234567};
userrole=teacher;
Vorname=Max;
Nachname=Mustermann;
Geburtstag=01.01.2000;
Klasse=9A;
Schule=123456
}
#{
GUID={1234567-1234-1234-1234-1234567};
userrole=teacher;
Vorname=Max;
Nachname=Mustermann;
Geburtstag=01.01.2000;
Klasse=9B;
Schule=123456
}
Sample line of $sorted[0]:
#{
GUID={1234567-1234-1234-1234-1234567};
userrole=teacher;
Vorname=Max;
Nachname=Mustermann;
Geburtstag=01.01.2000;
Klasse=9A,9B,9C,5A;
Schule=123456
}
The sorting process (check if contains, foreach $item, add to $klassen) is pretty slow.
I would be very grateful for any kind of ideas how to optimize the script.
Maybe something like this would work:
$results | ForEach-Object {
New-Object -Type PSObject -Property $_
} | Group-Object GUID | ForEach-Object {
$teacher = $_.Group
$teacher | Select-Object -First 1 -Exclude Klasse -Property *, #{n='Klasse';e={
$teacher | Select-Object -Expand Klasse
}}
}
Convert your hashtables into custom objects, group them by GUID, then replace the original "Klasse" property with a new one containing an array of the values from all objects in that group, and select the first result.
Should $results already be a list of objects you can skip the first ForEach-Object:
$results | Group-Object GUID | ForEach-Object {
$teacher = $_.Group
$teacher | Select-Object -First 1 -Exclude Klasse -Property *, #{n='Klasse';e={
$teacher | Select-Object -Expand Klasse
}}
}

Powershell turn strings into array with headings

I'd like to create a table with headings from a series of strings, which have been pulled from an output. I've already used this...
$Scopearray = #("$server","$ip","$ScopeName","$Comment")
To turn this...
$ip = $Trimmed[0]
$server = $Trimmed[1]
$ScopeName = $Trimmed[2]
$Comment = $Trimmed[3]
Into this:
PS C:\WINDOWS\system32> $Scopearray
MyServer.domain
10.1.1.1
NameofScope
ScopeDetails
But I need to turn that into a table, something like this:
I've tried the below, and a copule of other multidimentional examples, but I'm clearly missing something fundamental.
$table = #()
foreach ($instance in $Scopearray) {
$row = "" | Select ServerName,IP,ScopeName,Comment
$row.Heading1 = "Server Name"
$row.Heading2 = "IP Address"
$row.Heading3 = "Scope Name"
$row.Heading4 = "Comment"
$table += $row
}
Create objects from your input data:
... | ForEach-Object {
New-Object -Type PSObject -Property #{
'Server Name' = $Trimmed[1]
'IP Address' = $Trimmed[0]
'Scope Name' = $Trimmed[2]
'Comment' = $Trimmed[3]
}
}
In PowerShell v3 and newer you can simplify that by using the [PSCustomObject] type accelerator:
... | ForEach-Object {
[PSCustomObject]#{
'Server Name' = $Trimmed[1]
'IP Address' = $Trimmed[0]
'Scope Name' = $Trimmed[2]
'Comment' = $Trimmed[3]
}
}
PowerShell displays objects with up to 4 properties in tabular form by default (unless the objects have specific formatting instructions), but you can force tabular output via the Format-Table cmdlet if required:
... | Format-Table
Note that you need Out-String in addition to Format-Table if for instance you want to write that tabular representation to a file:
... | Format-Table | Out-String | Set-Content 'C:\output.txt'

Output arrays to CSV

I have two CSVs:
Total 19_01_16.csv:
hostname,user,path,size,creation,LastAccess,Copied,NewName,Completed
comp1,user1,\\comp1\users1\file.pst,100,17/02/2015,17/01/2016,Yes,file_user1_.pst,
comp1,user1,\\comp1\users1\file2.pst,200,17/02/2015,17/01/2016,Yes,file2_user1_.pst,
comp2,user2,\\comp2\users2\file.pst,100,17/02/2015,17/01/2016,Yes,file_user2_.pst,
PST Passwords.csv:
user,Path,Password1,Password2,Password3,Error
user1,\\comp1\users1\file.pst,openme,openme,openme,
I'm trying to merge the two with different headers and additional content.
This is what I have so far:
$a = Import-Csv "$PST_PARENT\DailyReports\Total 19_01_16.csv"
"Hostname,User,PST_Name,Original_Path,New_Path,Size,AcceptableLoss,Password1,Password2,Password3" |
Set-Content "$PST_PARENT\DailyReports\New Build.csv"
$a | foreach {
$HOSTNAME = $_.hostname
$USER = $_.User
$PATH = $_.path
$NEW_NAME = $_.NewName
$NEWPATH = "$PST_SHARE\$USER\$NEW_NAME"
$SIZE = $_.Size
$SIZE_FAIL = ( [convert]::ToSingle( $SIZE ) / 2 )
$b = Import-Csv "$PST_PARENT\DailyReports\PST Passwords.csv"
$b | foreach {
if ( $USER -like $b.user ) {
$PASSWORD1 = $b.password1
$PASSWORD2 = $b.password2
$PASSWORD3 = $b.password3
} else {
$PASSWORD1 = "none"
$PASSWORD2 = "none"
$PASSWORD3 = "none"
}
}
$HOSTNAME,$USER,$NEW_NAME,$PATH,$NEWPATH,$SIZE,$SIZE_FAIL,$PASSWORD1,$PASSWORD2,$PASSWORD3 |
Add-Content "$PST_PARENT\DailyReports\New Build.csv"
}
The output of New Build.csv looks like this:
Hostname,User,PST_Name,Original_Path,New_Path,Size,AcceptableLoss,Password1,Password2,Password3
comp1
user1
file.pst
\\comp1\users1\file.pst
\\share\PST_Storage\file_user1_.pst
100
5
none
none
none
In essence the output is working, it's just not scrolling for each line, it's putting each array onto a new line.
I tried adding | ConvertTo-Csv -NoTypeInformation but all that did was convert the arrays to numbers, they still went down not across.
Any ideas? Am I on the right line or doing the whole thing so very wrong?
$HOSTNAME,$USER,... defines an array, which is written to the output file one element per line. You need to put the list in double quotes to turn it into a comma-separated string that you can write to the output file as a single line.
"Hostname,User,PST_Name,Original_Path,New_Path,Size,AcceptableLoss,Password1,Password2,Password3" |
Set-Content "$PST_PARENT\DailyReports\New Build.csv"
$a | foreach {
...
"$HOSTNAME,$USER,$NEW_NAME,$PATH,$NEWPATH,$SIZE,$SIZE_FAIL,$PASSWORD1,$PASSWORD2,$PASSWORD3"
} | Add-Content "$PST_PARENT\DailyReports\New Build.csv"
or you construct a custom object from the elements that you can export via Export-Csv.
$a | foreach {
...
New-Object -Type PSCustomObject -Property #{
'Hostname' = $HOSTNAME
'User' = $USER
'NewName' = $NEW_NAME
'Path' = $PATH
'NewPath' = $NEWPATH
'Size' = $SIZE
'SizeFail' = $SIZE_FAIL
'Password1' = $PASSWORD1
'Password2' = $PASSWORD2
'Password3' = $PASSWORD3
}
} | Export-Csv "$PST_PARENT\DailyReports\New Build.csv" -NoType

Powershell Group Array

I have a custom array
$myresults = #()
$w3svcID = $result.ReturnValue -replace "IISWebServer=", ""
$w3svcID = $w3svcID -replace "'", ""
$vdirName = $w3svcID = "/ROOT";
$vdirs = gwmi -namespace "root\MicrosoftIISv2" -class "IISWebVirtualDirSetting"
foreach($vdir in $vdirs)
{
$vPool = $vdir.Apppoolid
$vName = $vdir.Name
$robj = New-Object System.Object
$robj | Add-Member -type NoteProperty -name Path -value $vName
$robj | Add-Member -type NoteProperty -name Pool -value $vPool
$myresults += $robj
}
$myresults | group-object Pool
I'd like to be able to Group the data in the form of a list where the group values (Path) is under the group-by values (Pool); like so:
DefaultAppPool
W3SVC\
W3VSC\1\ROOT\
MyAppPool
W3SVC\1\ROOT\MyVirtual\
Give this a try:
Get-WmiObject IISWebVirtualDirSetting -Namespace root\MicrosoftIISv2 |
Group-Object AppPoolId | Foreach-Object{
$_.Name
$_.Group | Foreach-Object { "`t$($_.Name)" }
}

Unable to Return output from function

function Get-NaLUNbyMap {
<#
.DESCRIPTION
Gets Lun Information for a particular initiatorgroup name & lunid
.EXAMPLE
Get-Inventory -computername server-r2
.EXAMPLE
Import-Module NaLUNbyMap
Get-NaLUNbyMap -igroup "IA" -lunid 1
#>
[CmdletBinding()]
param(
[Parameter(Mandatory=$True,ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)]
[string[]]$igroup,
[Parameter(Mandatory=$True,ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)]
[string[]]$lunid
)
Process
{
$info = (Get-NaLun |Select #{Name="LUN";Expression={$_.path}},#{Name="Size";Expression={[math]::Round([decimal]$_.size/1gb,0)}},#{Name="OnlineStatus";Expression={$_.online}},#{Name="Group";Expression={([string]::Join(",",(Get-NaLun $_.path | get-nalunmap | select -ExpandProperty initiatorgroupname)))}},#{Name="LunID";Expression={Get-NaLun $_.path | get-nalunmap | select -ExpandProperty lunid}} | ?{$_.group -eq $igroup -and $_.lunid -eq $lunid})
return $info
}
}
Hi Im unable to return output from this function, can some one please help me out!
That is some ugly code. :(
Here is a cleaned up version. I think I found your problem. Your parameters are arrays, when they should be single values based on how you are using them.
function Get-NaLUNbyMap {
<#
.DESCRIPTION
Gets Lun Information for a particular initiatorgroup name & lunid
.EXAMPLE
Get-Inventory -computername server-r2
.EXAMPLE
Import-Module NaLUNbyMap
Get-NaLUNbyMap -igroup "IA" -lunid 1
#>
[CmdletBinding()]
param(
[Parameter(Mandatory = $True, ValueFromPipeline = $True, ValueFromPipelineByPropertyName = $True)]
[string]$igroup
,
[Parameter(Mandatory = $True, ValueFromPipeline = $True, ValueFromPipelineByPropertyName = $True)]
[string]$lunid
)
process {
$Luns = foreach ($Lun in Get-NaLun) {
$LunMap = Get-NaLunMap $_.Path
New-Object PSObject -Property #{
"LUN"= $_.Path
"Size" = [Math]::Round([Decimal]$_.Size / 1gb, 0)
"OnlineStatus" = $_.Online
"Group" = $LunMap | Select-Object -ExpandProperty InitiatorGroupName
"LunId" = $LunMap | Select-Object -ExpandProperty LunId
}
}
$Luns | Where-Object {$_.Group -eq $igroup -and $_.LunId -eq $lunid}
}
}

Resources