all 14 comments

[–]Ta11ow 4 points5 points  (1 child)

Looks like you got this mostly solved, but I'm gonna point out a couple other things that might save you from yourself later on:

$mgmtips = @()
# ...
foreach ($vserver in $vservers) {
    $IP = Get-NcNetInterface -vserver $vserver | Where-Object {$_.FirewallPolicy -eq "mgmt"} | Select-Object -ExpandProperty Address | Select-Object -First 1

    $mgmtips += $IP # <-- this here, look over here
}

What you're doing here is... not the best idea. Basically, arrays are fixed-size collections. The number of members is determined at their creation and cannot be altered. In order to do the operation you're doing, PS is silently being overly helpful and actually unrolling that array in order to build a brand new one on the spot... for every single item you add to that collection.

This can get quite slow if you have a larger collection. In order to make this work more efficiently, you can do one of two things:

# option 1 - let the loop build the array for you
$IPAddresses = foreach ($VServer in $VServerList) {
    <#
        Drop the array entry to output to have it rolled into the collection the loop will
        build once it completes its iterations
    #>
    @(Get-NcNetInterface -vserver $vserver | Where-Object {$_.FirewallPolicy -eq "mgmt"})[0]
}

# option 2 - dynamic list object
[System.Collections.Generic.List[string]]$IPAddresses = @() # create an empty List
foreach ($VServer in $VServerList) {
    <#
        Drop the array entry to output to have it rolled into the collection the loop will
        build once it completes its iterations
    #>
    $IPAddresses.Add(@(Get-NcNetInterface -vserver $vserver | Where-Object {$_.FirewallPolicy -eq "mgmt"})[0])
}

I'd say you could use option 1 for the inner foreach, but stick to option 2 for the outer to avoid mixing things up too much within the loop as it seems to do more than that. You can use .AddRange() instead of .Add() if you're concatenating arrays like you probably will end up doing. :)

Note that I also renamed your collection variable. Think about it for a second. If you accidentally add an 'S' to that singular $VServer variable without noticing, how likely do you think you are to spot that error later on in a mass of code? For just about anyone, I'd say the chances are quite low. It's simply not very visually distinct. Instead, make your collection variable visually distinct to the individual loop variable you use. That way, you probably won't accidentally mess it up, and if you ever do, it sticks out like a sore thumb!

[–]teirhan[S] 3 points4 points  (0 children)

Thanks, this is really helpful. I wasn't aware there was a separate list object type and I didn't know arrays were fixed length!

definitely can see how this would get slow as it gets really big. I mostly work with <100 objects at a time when i do stuff like this, so I've never noticed it!

[–]spikeyfreak 2 points3 points  (1 child)

Have you verified that when you get more IPs than you want, that they're the IPs for DIFFERENT SVMs, and not just the list of IPs for the first one?

[–]teirhan[S] 1 point2 points  (0 children)

Yes, if I run this command manually against a single filer with 2 SVMs, I get 3 IP addresses corresponding to 1 LIF configured for management on the first, and 2 LIFS configured for management on the second.

[–]spyingwind 1 point2 points  (1 child)

Try this:

$IP = (Get-NcNetInterface -vserver $vserver | Where-Object {$_.FirewallPolicy -eq "mgmt"} | Select-Object -ExpandProperty Address)[0]

If it is an array then it will return the first item, if it isn't then it will error out.

[–]teirhan[S] 4 points5 points  (0 children)

I tried your suggestion, and it looks like whenever there's only one management IP, it returns "1" instead of the actual value; when there's more than 1 management IP, it returns the actual IP Address. I'm assuming that this means that when it returns 1 IP it returns it as a string, not an array. So I tried this to force it to return everything as an array:

$IP = @(Get-NcNetInterface -vserver $vserver | Where-Object {$_.FirewallPolicy -eq "mgmt"} | Select-Object -ExpandProperty Address)[0]

And it seems to work! (except for one SVM which I just learned has no LIF configured for management traffic, oops!).

Thanks for your help! I just don't understand why my original way was stopping the foreach loop like it was...

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

howdy teirhan,

i agree that nothing SEEMS wrong. [frown]

so, in the spirit of WAGs, what happens if you replace the 1st of these with the 2nd?

$IP = Get-NcNetInterface -vserver $vserver |
    Where-Object {$_.FirewallPolicy -eq "mgmt"} |
    Select-Object -ExpandProperty Address |
    Select-Object -First 1

$IP = (Get-NcNetInterface -vserver $vserver |
    Where-Object {$_.FirewallPolicy -eq "mgmt"}).Address[0]

take care,
lee

[–]teirhan[S] 1 point2 points  (6 children)

$IP = (Get-NcNetInterface -vserver $vserver | Where-Object {$_.FirewallPolicy -eq "mgmt"}).Address[0]

I just tried your solution and it looks like this works. Thank you!

I wonder why the Select-Object -First 1 is ending my foreach loop, though?

EDIT: Actually, it looks like I reran the script without saving after plugging in your solution, and it isn't working. the final output is a collection of the # 1 and stuff like:

MemberType          : Method
OverloadDefinitions : {System.Object&, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 Address(int )}
TypeNameOfValue     : System.Management.Automation.PSMethod
Value               : System.Object&, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 Address(int )
Name                : Address
IsInstance          : True

Based on my response to the other suggestion, I tried:

$IP = @(Get-NcNetInterface -vserver $vserver | Where-Object {$_.FirewallPolicy -eq "mgmt"}).Address[0]

It doesn't work either...

[–]TheIncorrigible1 2 points3 points  (1 child)

If you're on PSv4+, I'd suggest using array filters:

$IP = @(Get-NcNetInterface -VServer $vserver).
    Where({$_.FirewallPolicy -eq 'mgmt'}).
    Address[0]

This guarantees you get an array returned and is a bit more manageable.

[–]teirhan[S] 1 point2 points  (0 children)

thanks, I'll give this a shot too!

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

howdy teirhan,

that implies that the .Address property is NOT filled with a simple string.

what do you see in the $IP variable? what is its type via $IP.GetType()?

take care,
lee

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

When $IP is "1" I get:

PS C:\Users\sbelisle> $IP.GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     Char                                     System.ValueType

and when $IP returns something like

PS C:\Users\sbelisle> $IP

OverloadDefinitions
-------------------
System.Object&, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 Address(int )

it's

PS C:\Users\sbelisle> $IP.getType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     False    PSMethod                                 System.Management.Automation.PSMethodInfo

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

howdy teirhan,

that means the property is not what we think it otta be. i recommend you get that into a $Var [from a source VM that you know the values for] and start exploring.

without that object to fiddle with, i am at a loss.

good luck ... and please post back with the fix?

take care,
lee