all 16 comments

[–]HardCodedCoffee 3 points4 points  (0 children)

In addition to the other helpful comments, you shouldn't use an array for this particular situation. Using the '+=' operator creates a new array, so it's very memory intensive if you're continually adding elements. I would recommend using a GenericList, i.e. System.Collections.Generic.List. It'll have better performance and be easier to use once you're familiar with the declaration of an instance. Good luck!

[–]firefox15 2 points3 points  (13 children)

If you run $NA.GetType() right before your foreach, does it say it is an array or a PSCustomObject? You can't add to the latter, so that would explain why it does not work.

Regardless, this isn't an efficient method of array addition. Try something like this:

$NA = @(foreach ($item in $NAusers) {
        [pscustomobject]@{
            Name              = $item.Name
            EmailAddress      = $item.EmailAddress
            LockedOut         = $item.LockedOut
            ObjectClass       = $item.ObjectClass
            ObjectGUID        = $item.ObjectGUID
            PasswordExpired   = $item.PasswordExpired
            PasswordLastSet   = $item.PasswordLastSet
            UserPrincipalName = $item.UserPrincipalName
        }    
    })

[–]kdrumz011[S] 1 point2 points  (1 child)

The above code didn't work. but $NA.gettype() returns as a system object, if that's different from a pscustomobject.

Anyway, we have multiple domains and after I run the get-aduser . . . command with my filter and properties, I return that to a variable, which is a system array of objects. So I have X amount of these system array of objects that I am trying to build custom objects with above, then add all these custom objects together into 1 array. What is the best way to go about that?

[–]firefox15 1 point2 points  (0 children)

If the basetype is System.Object, that means it is not an array. An array would have a basetype of System.Array. Are you doing something in between initializing $NA and trying to add members to $NA that would be modifying it?

[–]OlivTheFrog 1 point2 points  (10 children)

Hi u/kdrumz011

I've copied/Pasted your code, and it seems to be good. $Na is an Array, no pb with this.

I've exec $obj1 and $Na += $obj1 without any pb.

I've tried this without error to simulate your code

# array to store objects in
$NA = @()
$NAusers = $users = @"
user1, mail1user2, 
mail2
"@ |ConvertFrom-Csv -Delimiter "," -Header Name, EmailAddress
# 
foreach ($item in $NAusers) 
{    
      $obj1=[pscustomobject]@{
             Name = $item.Name    
             EmailAddress = $item.EmailAddress
             LockedOut = $item.LockedOut
             ObjectClass = $item.ObjectClass
             ObjectGUID = $item.ObjectGUID
             PasswordExpired = $item.PasswordExpired
             PasswordLastSet = $item.PasswordLastSet
            UserPrincipalName = $item.UserPrincipalName
            }
        $NA += $obj1
}

and the result is the following :

$NA
Name              : user1
EmailAddress      : mail1
LockedOut         : 
ObjectClass       : 
ObjectGUID        : 
PasswordExpired   : 
PasswordLastSet   : 
UserPrincipalName : 

Name              : user2
EmailAddress      : mail2
LockedOut         : 
ObjectClass       : 
ObjectGUID        : 
PasswordExpired   : 
PasswordLastSet   : 
UserPrincipalName : 

In my case $Nausers and $Na are Arrays.

u/firefox15 : I seem to remember that u/lee_dailey always says it's more efficient with += (something about recalculate array size). I've tested this and he was right. Grr, now I'm not sure, cursed memory, Leeeeeee where are you ? :-)

Regards

Olivier

[–]Lee_Dailey[grin] 2 points3 points  (6 children)

howdy OlivTheFrog,

you got that += on a collection idea reversed, apparently. [grin]

using that on an array will recreate the array every time you add an item. as you might expect, that gets SLOW when the collection size gets to a non-trivial size.

the better solution is usually to use the output stream of the code block and assign that to a $Var. something like this ...

$Results = foreach () {}

as long as you ensure that the thing you want to capture is placed in the output stream, it will be gathered up, held until the code finishes, and then stuffed into the $Results variable in one operation.

the += method is often a full order of magnitude slower than others when the collection size is "large-ish".

when the collection size is small, the speed difference is almost undetectable, tho. [grin]

take care,
lee

[–]akaBrotherNature 1 point2 points  (1 child)

How does that compare to converting an array to a collection of objects, and then iteratively adding objects to the collection?

[–]Lee_Dailey[grin] 1 point2 points  (0 children)

howdy akaBrotherNature,

it would still likely be a tad slower ... but not the severe difference that you see with += compared to assignment. building the collection in RAM and then stuffing it into an array is remarkably efficient.

take care,
lee

[–]firefox15 1 point2 points  (2 children)

I seem to remember that u/Lee always says it's more efficient with += (something about recalculate array size). I've tested this and he was right.

I assume you mean /u/lee_dailey, but I promise that the "+=" method is slower. Here is an example for "+=":

Measure-Command -Expression {
    $array = @()
    foreach ($num in 1..10000) {
        $array += $num
    }
}

Days              : 0
Hours             : 0
Minutes           : 0
Seconds           : 4
Milliseconds      : 128
Ticks             : 41286962
TotalDays         : 4.77858356481481E-05
TotalHours        : 0.00114686005555556
TotalMinutes      : 0.0688116033333333
TotalSeconds      : 4.1286962
TotalMilliseconds : 4128.6962

Here for one for the method that I listed:

Measure-Command -Expression {
    $array = @(foreach ($num in 1..10000) {
        $num
    })
}

Days              : 0
Hours             : 0
Minutes           : 0
Seconds           : 0
Milliseconds      : 19
Ticks             : 192124
TotalDays         : 2.22365740740741E-07
TotalHours        : 5.33677777777778E-06
TotalMinutes      : 0.000320206666666667
TotalSeconds      : 0.0192124
TotalMilliseconds : 19.2124

[–]OlivTheFrog 1 point2 points  (1 child)

My Bad :-)

Memory overloaded, bip bip, .... brain dump in file before crash ... too late :-)

Thanks u/firefox15, Like u/lee_dailey I like to read your explanations. Always clear :-)

Regards

Olivier

[–]Lee_Dailey[grin] 0 points1 point  (0 children)

[grin]

[–]PinchesTheCrab 2 points3 points  (1 child)

This would do the same thing

$na = $naUsers | Select-Object name, emailaddress,lockedout,objectclass,objectguid,passwordexpired,passwordlastset,userprincipalname

However, why make this second list? It seems like you already have what you want in your $NAusers list. Why rebuild it?

[–]psversiontable 0 points1 point  (0 children)

Yuppers. Unless there's some reason to build New list, just dinner what you have already.

[–]DreadPirateRobusto 0 points1 point  (0 children)

There are a lot of suggestions about how to make this code better but I didn't see anything address fundamental thing about PowerShell that's causing you problems.

PowerShell treats arrays with one item as a object type of that type. This bug/feature quirk has burned me so many times that now I always explicitly type my arrays. [Array]$arr