When using the $array.Add()-method, you're trying to add the element into the existing array. An array is a collection of fixed size, so you will receive an error because it can't be extended.
$array += $element creates a new array with the same elements as old one + the new item, and this new larger array replaces the old one in the $array-variable
You can use the += operator to add an element to an array. When you use it, Windows PowerShell actually creates a new array with the values of the original array and the added value. For example, to add an element with a value of 200 to the array in the $a variable, type:
Copy$a += 200
Source: about_Arrays
+= is an expensive operation, so when you need to add many items you should try to add them in as few operations as possible, ex:
Copy$arr = 1..3 #Array
$arr += (4..5) #Combine with another array in a single write-operation
$arr.Count
5
If that's not possible, consider using a more efficient collection like List or ArrayList (see the other answer).
When using the $array.Add()-method, you're trying to add the element into the existing array. An array is a collection of fixed size, so you will receive an error because it can't be extended.
$array += $element creates a new array with the same elements as old one + the new item, and this new larger array replaces the old one in the $array-variable
You can use the += operator to add an element to an array. When you use it, Windows PowerShell actually creates a new array with the values of the original array and the added value. For example, to add an element with a value of 200 to the array in the $a variable, type:
Copy$a += 200
Source: about_Arrays
+= is an expensive operation, so when you need to add many items you should try to add them in as few operations as possible, ex:
Copy$arr = 1..3 #Array
$arr += (4..5) #Combine with another array in a single write-operation
$arr.Count
5
If that's not possible, consider using a more efficient collection like List or ArrayList (see the other answer).
If you want a dynamically sized array, then you should make a list. Not only will you get the .Add() functionality, but as @frode-f explains, dynamic arrays are more memory efficient and a better practice anyway.
And it's so easy to use.
Instead of your array declaration, try this:
Copy$outItems = New-Object System.Collections.Generic.List[System.Object]
Adding items is simple.
Copy$outItems.Add(1)
$outItems.Add("hi")
And if you really want an array when you're done, there's a function for that too.
Copy$outItems.ToArray()
How do I add to this Collection in Powershell? - Stack Overflow
Adding items to a custom object?
It is important to note that what you are doing is creating a new object, $stuff, with 2 properties: data1 and data2.
What you are showing in your example output is actually what you would be getting from a collection of objects. So, first we will create a collection object. For simplicity's sake, we will just make a standard empty array object to hold the objects in the collection:
$collection = @()
Now, we will add the items one at a time into the collection:
$collection += new-object psobject -property @{data1="foo1";data2="bar1"}
$collection += new-object psobject -property @{data1="foo2";data2="bar2"}
$collection += new-object psobject -property @{data1="foo3";data2="foo3"}Showing the contents of collection will give us:
$collection data2 data1 ----- ----- bar1 foo1 bar2 foo2 bar3 foo3
There are ways to make this faster, for instance create the collection as an arraylist and use the .add() method to add objects into the collection: [edit for clarity: By 'faster', I mean in instances where you are working with a large amount of data, not necessarily faster to create the script. For most uses that I'm aware of / have tried, the standard empty array @() will work just fine.]
$collection = new-object system.collections.arraylist
$collection.add(new-object psobject -property @{data1="foo";data2="bar"})The only downside to using an arraylist is that the .add() method returns the current index that the item is being added at, so adding 5 objects into the collection would show the following in the console:
0 1 2 3 4
To circumvent this, pipe the $collection.add() method to out-null, so that it eats the output:
$collection.add(new-object pscustomobject -property @{data1="foo";data2="bar"}) | out-nullHope this helps!
More on reddit.compowershell - Add items into a collection array dynamically - Stack Overflow
Two ways of creating a new System.Collections.ArrayList object, what's the difference?
Videos
I know not a lot about custom objects. I want to do something easy. At this point I'm just making a hash table, adding content to it, then making a new custom object that reflects the data in that hash table. I want to be able to keep adding data to this custom object moving forward. Something like this...
$things=@{}
$things.data1="foo"
$things.data2="bar"
$stuff=new-object psobject -property $things
$stuff
data2 data1
----- -----
bar foo OK so far. Now I want to add more. How do I get to this?
$stuff data2 data1 ----- ----- bar foo morebar fooALLTHETIME
It is important to note that what you are doing is creating a new object, $stuff, with 2 properties: data1 and data2.
What you are showing in your example output is actually what you would be getting from a collection of objects. So, first we will create a collection object. For simplicity's sake, we will just make a standard empty array object to hold the objects in the collection:
$collection = @()
Now, we will add the items one at a time into the collection:
$collection += new-object psobject -property @{data1="foo1";data2="bar1"}
$collection += new-object psobject -property @{data1="foo2";data2="bar2"}
$collection += new-object psobject -property @{data1="foo3";data2="foo3"}
Showing the contents of collection will give us:
$collection
data2 data1
----- -----
bar1 foo1
bar2 foo2
bar3 foo3
There are ways to make this faster, for instance create the collection as an arraylist and use the .add() method to add objects into the collection: [edit for clarity: By 'faster', I mean in instances where you are working with a large amount of data, not necessarily faster to create the script. For most uses that I'm aware of / have tried, the standard empty array @() will work just fine.]
$collection = new-object system.collections.arraylist
$collection.add(new-object psobject -property @{data1="foo";data2="bar"})
The only downside to using an arraylist is that the .add() method returns the current index that the item is being added at, so adding 5 objects into the collection would show the following in the console:
0
1
2
3
4
To circumvent this, pipe the $collection.add() method to out-null, so that it eats the output:
$collection.add(new-object pscustomobject -property @{data1="foo";data2="bar"}) | out-null
Hope this helps!
$stuff = @()
$stuff += New-Object psobject -prop @{
data1 = 'foo'
data2 = 'bar'
}
$stuff += New-Object psobject -prop @{
data1 = 'morebar'
data2 = 'fooALLTHETHINGS'
}
# and if you want to add a new property, these both achieve the same result
$stuff | % {$_ | Add-Member -MemberType NoteProperty -Name data3 -Value 'new'}
$stuff = $stuff | % {$_ | select *, @{n='data4';e={'somethingelse'}}}
# but then when you want to add another object should specify all the properties
$stuff += New-Object psobject -prop @{
data1 = 'test1'
data2 = 'test2'
data3 = 'test3'
data4 = 'test4'
}
$stuff
*edited
The problem is that you're updating the very same object, $Table, over and over, and adding references to that same object to the output array, $ToWrite - all of whose elements therefore end up pointing to the one and only $Table object, whose property values at that point contain the ones that were assigned in the last iteration.
The problem is explained in detail in this answer, which shows a possible solution using custom classes, available in PowerShell v5 and above.
A solution without custom classes requires you to clone your custom $Table object in each iteration:
# Create a new instance with the same properties:
$Table = $Table.psobject.Copy()
Note: This cloning technique only works as expected with custom objects, i.e., instances of [System.Management.Automation.PSCustomObject], such as created by the Select-Object cmdlet and literal syntax [pscustomobject] @{ ... }
That said, since you're assigning to all properties of your custom object in your loop, there is no benefit to creating a template object up front - instead, simply use literal custom-object creation syntax [pscustomobject] @{ ... } (PSv3+) inside your loop, which implicitly creates a new instance in every iteration.
Additionally, your solution can be streamlined, because it is both simpler and more efficient to let PowerShell create arrays for you, simply by collecting the output from commands that output multiple objects in a variable.
Here's a simplified example that puts it all together:
# Loop over the input and instantiate a new custom object
# in each iteration, then let PowerShell collect the results
# in array variable $ToWrite
[array] $ToWrite = 1..3 | ForEach-Object {
# Instantiate and output a new custom object in each iteration.
[pscustomobject] @{
PropA = "ValueA-$_"
PropB = "ValueB-$_"
}
}
# Output the resulting array
$ToWrite
Note: The [array] type constraint is only needed if you need to ensure that $ToWrite is always an array; without it, if there happened to be just a single loop iteration and therefore output object, $ToWrite would store that output object as-is, not wrapped in an array (this behavior is fundamental to PowerShell's pipeline).
The above yields the following, showing that distinct objects were created:
PropA PropB
----- -----
ValueA-1 ValueB-1
ValueA-2 ValueB-2
ValueA-3 ValueB-3
To illustrate - big caveat here, I'm at home so can't test any of this but it should give you an idea:
$AllPOCs = Get-ADGroupMember 'ALL POC'
$Table = $AllPOCs | ForEach-Object {
$Name = $_.SamAccountName
$TestPOC = Invoke-Sqlcmd -Query "SELECT * FROM TABLE WHERE CLIENT = '$Name'" -ServerInstance "SERVER\INSTANCE"
If($TestPOC -eq $null) {
$POC = get-aduser $Name -Properties * | select -Property SamAccountName, GivenName, Surname, SID, EmailAddress
$SEQUENCE = Invoke-Sqlcmd -Query "Select TABLEFIELD FROM DATABASE WHERE NAME = 'FIELDID'" -ServerInstance "SERVER\INSTANCE"
$SEQUENCE = $SEQUENCE.RECNUM + 1
[pscustomobject]@{SEQUENCE = $SEQUENCE;
LASTUSER = 'SYSTEMACCOUNT';
GROUP = 1;
CLIENT = $_.ToUpper();
FNAME = $_.GivenName.ToString();
Name = $_.surname.ToString();
EmailID = 'SMTP:{' + $_.EmailAddress.ToString() + '}' + $_.EmailAddress.ToString();
USEDEPT = 0;
USELOCATION = 0;
CREATEDFROMSSD = 0;
DISPLAYCLIENTCOMMENTS = 0;
_INACTIVE_ = 0;
WINUSERID = '\DOMAIN' + $_.SamAccountName.ToString();
SELFSERVICEACCESS = 'TYPE';
SELFSERVICELICENSE = 1;
WIAENABLED = 1;
SID = $_.SID.ToString()}
$SEQUENCE += 1
}
}
The above can also be simplified, but I've tried to keep it similar to your exisitng code
I've come across two ways of creating a new System.Collections.ArrayList object:
$arrA = New-Object System.Collections.ArrayList $arrB = [System.Collections.ArrayList]@()
I have two questions:
-
for arrB, if I'm reading this right, @() is creating an empty array and then it's being cast into [System.Collections.ArrayList]?
-
Working with the created object is the same for me either way, but are there any differences I may be missing?
I made a quick test and casting was faster, but the difference is only noticeable when creating new arrays reaches the hundreds of thousands to millions (tested on an old A10-7870k). Doesn't really matter when I'm creating one array, but I thought it was mildly interesting.
$max = 100000
$ticksStart = (Get-Date).Ticks
for ($i = 0; $i -lt $max; $i++)
{
$arrA = New-Object System.Collections.ArrayList
}
$ticksEnd = (Get-Date).Ticks
Write-Host 'arrA (ticks) : ' ($ticksEnd - $ticksStart)
$ticksStart = (Get-Date).Ticks
for ($i = 0; $i -lt $max; $i++)
{
$arrB = [System.Collections.ArrayList]@()
}
$ticksEnd = (Get-Date).Ticks
Write-Host 'arrB (ticks) : ' ($ticksEnd - $ticksStart)
arrA (ticks) : 64310000
arrB (ticks) : 3170000Could it be because of the new version on powershell that when i'm trying to add a string to an array it doesn't work with the method of .add and .remove?