Create multiple instances of custom Powershell object - powershell

I am creating a new object in a Powershell script, or actually an object type. I want to create multiple instances of this object. How do I do this?
The code below is what I am working on, it appears that all instances in the array reference the same object, containing the same values.
# Define output object
$projectType = new-object System.Object
$projectType | add-member -membertype noteproperty -value "" -name Project
$projectType | add-member -membertype noteproperty -value "" -name Category
$projectType | add-member -membertype noteproperty -value "" -name Description
# Import data
$data = import-csv $input -erroraction stop
# Create a generic collection object
$projects = #()
# Parse data
foreach ($line in $data) {
$project = $projectType
$project.Project = $line.Id
$project.Category = $line.Naam
$project.Description = $line.Omschrijving
$projects += $project
}
$projects | Export-Csv output.csv -NoTypeInformation -Force

You have to use New-Object for any, well, new object, otherwise being a reference type $projectType in your code refers to the same object. Here is the changed code:
# Define output object
function New-Project {
New-Object PSObject -Property #{
Project = ''
Category = ''
Description = ''
}
}
# Parse data
$projects = #()
foreach ($line in 1..9) {
$project = New-Project
$project.Project = $line
$project.Category = $line
$project.Description = $line
$projects += $project
}
# Continue
$projects
In this particular case instead of using the function New-Project you can just move its body into the loop, e.g. $project = New-Object PSObject …. But if you create your “projects” elsewhere then having this function will be useful there as well.

Related

Array in a foreach loop

What am I doing wrong here?
The mailbox has an active an inactive mailbox so it will return two mailboxes.
However, when trying to capture the output, I am only getting the last account in the array
Note, this is a simplified version of a larger script, but kept it simple for this example.
$guid = import-csv "c:\temp\Mailboxes.csv"
$DAta = New-Object psobject
$Data | Add-Member -MemberType NoteProperty -Name alias -Value $null
$Data | Add-Member -MemberType NoteProperty -Name guid -Value $null
$mbxcol = #()
#$data = $null
foreach ($G in $Guid){
$mbx = Get-mailbox $g.alias -IncludeInactiveMailbox
$data.alias = $mbx.alias
$data.guid = $mbx.guid
$MBXCol += $Data
}
$mbxcol
As explained in comments, every array element is a reference of the same object ($Data), a simple way to demonstrate using Object.ReferenceEquals Mehod with this example:
foreach ($item in 0..10) {
$data.Alias = 'mailbox{0}' -f $item
$data.Guid = [guid]::NewGuid()
$mbxcol += $data
}
[object]::ReferenceEquals($data, $mbxcol[0]) # -> True
As for how to simplify and make your code more efficient, do not add elements (+=) to a fixed collection (#( )):
$result = (Import-Csv "c:\temp\Mailboxes.csv").Alias |
Get-Mailbox -IncludeInactiveMailbox |
Select-Object Alias, Guid
A much more simple example of your code is:
$guid = ("A","B")
$Data = New-Object psobject
$Data | Add-Member -MemberType NoteProperty -Name alias -Value $null
$mbxcol = #()
foreach ($G in $Guid){
$mbx = $g
$data.alias = $mbx
$MBXCol += $Data
}
$mbxcol
As #Santiago mentioned in his comment, $Data is a reference to an object, so each time you update it, you overwrite it, even if it is in an array. To fix this, instantiate the object each loop as follows:
$guid = ("A","B")
$mbxcol = #()
foreach ($G in $Guid){
$Data = New-Object psobject
$Data | Add-Member -MemberType NoteProperty -Name alias -Value $null
$mbx = $g
$data.alias = $mbx
$MBXCol += $Data
}
$mbxcol

Export-Csv doesn't work as I expected

I have written a little script which should be export the output as CSV.
Here is my script:
$Jobs = Get-VBRJob
foreach ($Job in $Jobs) {
$JobName = $Job.Name
$Objects = $Job.GetObjectsInJob()
$RestorePoints = Get-VBRRestorePoint -Backup $JobName
$Day = $Job.ScheduleOptions.OptionsDaily.DaysSrv
$RP = $RestorePoints.Count
$VM = $Objects.Name
$obj = New-Object PSObject
$obj | Add-Member -MemberType NoteProperty -Name "JobName" -Value $JobName
$obj | Add-Member -MemberType NoteProperty -Name "Objects" -Value $Objects
$obj | Add-Member -MemberType NoteProperty -Name "RestorePoints" -Value $RestorePoints
$obj | Add-Member -MemberType NoteProperty -Name "Day" -Value $Day
$obj | Add-Member -MemberType NoteProperty -Name "VM" -Value $VM
}
$obj | Export-Csv $path -NoType
I read something about doing it via New-Object PSObject, so I tried this, but the CSV has only one line and returns the types of the attributes not the value. Only "JobName" and "VM" is working fine.
Can anyone help me to get the value of "Objects", "RestorePoints" and "Day" into CSV?
$obj contains only the object you just created, so after the loop completes, the variable holds the last object created in the loop, which is then exported to the CSV. A better approach would be outputting the created objects in the loop and collecting the loop output in a variable. I'd also recommend avoiding Add-Member unless you need to add members to an object that had been created elsewhere.
$obj = foreach ($Job in $Jobs) {
...
New-Object -Type PSObject -Property #{
'JobName' = $JobName
'Objects' = $Objects
'RestorePoints' = $RestorePoints
'Day' = $Day
'VM' = $VM
}
}
Also, if the values you're assigning to the new object's properties are objects themselves, PowerShell will export the string representation of those objects to the CSV, which usually is the full name of the object's class. If you want particular values in the output you probably need to expand those further (e.g. 'VM' = $VM.Name). What exactly you need to do there depends on the actual object, though, so I can't help much there without knowing more about the structure of the objects.

Append values to Powershell object

I have a PS object and couldnt figure out a way to append values to my object.
$object = New-Object PSObject
Add-Member -InputObject $object -MemberType NoteProperty -Name Col1 -Value ""
Add-Member -InputObject $object -MemberType NoteProperty -Name Col2 -Value ""
Add-Member -InputObject $object -MemberType NoteProperty -Name Type -Value ""
1..10 |ForEach{
$src=$_
11..20 | ForEach{
$dst = $_
$object.Col1=$src
$object.Col2=$dst
$object.Type="New"
}
}
I want my result like
col1 col2 Type
---- ---- ----
1 11 New
1 12 New
1 13 New
1 14 New
...
Use a PSCustomObject:
$values = 1..10 | % {
[pscustomobject]#{ col1=1; col2=10+$_; Type="New" }
}
The output you want is a list of objects, not a single object. You generate that by creating the objects inside the loop. #Burt_Harris already showed you one way to do that (using a type accelerator [PSCustomObject]), but of course you can also use New-Object to the same end:
$list = 1..10 | ForEach-Object {
$src = $_
11..20 | ForEach-Object {
$prop = #{
Col1 = $src
Col2 = $_
Type = 'New'
}
New-Object -Type PSObject -Property $prop
}
}
Create the property hashtable as an ordered hashtable if you want the properties to appear in a particular order in the output (PowerShell v3 and newer only):
$prop = [ordered]#{
Col1 = $src
Col2 = $_
Type = 'New'
}
The list of objects can be captured by assigning the pipeline output to a variable ($list = ...).

Selecting objects from a Custom Object

I have a custom PS Object that is something like the below:
ID Folder
MyServer01 \\Server\Share\Share\MyServer01
MyServer02 \\Server\Share\Share\MyServer02
Naturally the object itself is rather large, with over 1000 entries. I need to be able to select a specific row of the object based on querying the ID.
I thought something like this would work but I'm not having much luck:
$obj | Select-Object | Where-Object ($_.ID -eq "MyServer01")
I need it to return the entire row, so the above (assuming it worked) would return:
MyServer01 \\Server\Share\Share\MyServer01
EDIT:
foreach ($mf in $Folders.Tables[0]) {
$Info = New-Object System.Object
$Info | Add-Member -Type NoteProperty -Name ID -Value $mf.ID
$Info | Add-Member -Type NoteProperty -Name Folder -Value $mf.Folder
$obj += $Info
}
Use a hashtable for storing your objects:
$obj = #{}
foreach ($mf in $Folders.Tables[0]) {
$Info = New-Object -Type System.Object
$Info | Add-Member -Type NoteProperty -Name ID -Value $mf.ID
$Info | Add-Member -Type NoteProperty -Name Folder -Value $mf.Folder
$obj[$mf.ID] = $Info
}
Don't append to an array in a loop, as that tends to perform poorly.
If your code doesn't depend on the objects being created explicitly as System.Object I'd also recommend to create them as custom objects:
$obj = #{}
foreach ($mf in $Folders.Tables[0]) {
$Info = New-Object -Type PSCustomObject -Property #{
'ID' = $mf.ID
'Folder' = $mf.Folder
}
$obj[$mf.ID] = $Info
}

Create Custom PSObject PowerShell 2.0

Is it possible to create a Custom Object (PSObject) and define its properties beforehand and later in the program execution, we keep adding array of values to the object.
For e.g;
$c = #()
$c = New-Object PSObject
$c | Add-Member -type NoteProperty -name Name
$c | Add-Member -type NoteProperty -name Gender
$c | Add-Member -type NoteProperty -name Age
$c | Add-Member -type NoteProperty -name Name -value "John"
$c | Add-Member -type NoteProperty -name Gender -value "Male"
$c | Add-Member -type NoteProperty -name Age -value "30"
Thanks in advance for any leads or advice.
I'm not sure I follow. Do you want an array of objects with your specified properties? Because your sample first creates an array, that you then overwrite into a single object. So you lost your array.
You can create the object using new-object and specify the properties with values as a hashtable in the -Property parameter. Like this:
$c = New-Object psobject -Property #{
Name = "John"
Gender = "Male"
Age = 30
}
To make an array of them, you can use:
$myarray = #()
$myarray += New-Object psobject -Property #{
Name = "John"
Gender = "Male"
Age = 30
}
If you have multiple tests that you run one by one, you can run the tests in a function that tests and creates a "resultobject", then you collect it:
$myresults = #()
function mytests($computer) {
#Test connection
$online = Test-Connection $computer
#Get buildnumber
$build = (Get-WmiObject win32_operatingsystem -ComputerName $computer).buildnumber
#other tests
#output results
New-Object psobject -Property #{
Online = $online
WinBuild = $build
}
}
$myresults += mytests -computer "mycomputername"
Yeah, so I know this is an old post but Don Jones did something like this:
$props = #{
Name = "John"
Gender = "Male"
Age = 30
}
$c = New-Object PSObject -Property $props
You can run the following to see the Properties and Values the new Object:
c$ | Get-Member
I think that's what you're looking for.