Strange method invocation issue using nested arrays...

Hi all,

I have the following powershell script I have put together to pull remote server adapter details, it is written using v2 as some of our servers are unfortunately still using Windows Sever 2008

I am receiving a 'Method invocation failed because [system.management.automation.psobject] does not contain a method named ‘op_addition’

I believe this may be due to trying to add the results of two psobject values to the same array variable but am not sure if this is true or how to work around the issue

$NicDetails = @()

$FinalList = @()

$lc = 1

Write-host ‘Getting list of servers from AD, this may take a few moments…’

$Servers = (Get-ADComputer -Filter ‘operatingsystem -like “server”-and enabled -eq “true”‘).Name

foreach ($Server in $Servers) {

if(Test-Connection -ComputerName $Server -Count 1 -ea 0) {

write-host ‘Getting NIC details from’$server $lc ‘of’ ($Servers.count)

$NetAdapter = $null

$NicConfig = $null

$NetAdapter = get-ciminstance -classname win32_networkadapter -computername $Server -filter “NetConnectionStatus = 2” | select netconnectionid,deviceid -ea silentlycontinue

$NicConfig = get-ciminstance -classname win32_networkadapterconfiguration -computername $Server -filter “ipenabled = true” | select ipaddress,ipsubnet,defaultipgateway,index

}

foreach ($Nic in $Netadapter){

$NicName = $null

$NicID = $null

$NicName = $Nic.netconnectionid

$NicID = $Nic.deviceid

$OutputObj = New-Object -Type PSObject

$OutputObj | Add-Member -MemberType NoteProperty -Name AdapterName -Value $NicName

$OutputObj | Add-Member -MemberType NoteProperty -Name AdapterID1 -Value $NicID

$NicDetails += $OutputObj}

foreach ($Nic in $NicConfig){

$NicIP = $null

$NicSubnet = $null

$NicGW = $Null

$NicIND = $null

$NicIP = $Nic.ipaddress

$NicSubnet = $Nic.ipsubnet

$NicGW = $Nic.defaultipgateway

$OutputObj = New-Object -Type PSObject

$OutputObj | Add-Member -MemberType NoteProperty -Name IP -Value $NicIP

$OutputObj | Add-Member -MemberType NoteProperty -Name SubnetAddresss -Value $NicSubnet

$OutputObj | Add-Member -MemberType NoteProperty -Name DefaultGateway -Value $NicGW

$OutputObj | Add-Member -MemberType NoteProperty -Name AdapterID2 -Value $NicIND

$NicDetails += $OutputObj}

write-host $NicDetails

$FinalList += $NicDetails

$NicDetails = $Null

$lc ++

}

$FinalList | export-csv NicDetails.csv

Many thanks for any help!

Apologies, there were errors in my script, corrected now but results still the same:

$NicDetails = @()
$FinalList = @()
$lc = 1
Write-host ‘Getting list of servers from AD, this may take a few moments…’
$Servers = (Get-ADComputer -Filter ‘operatingsystem -like “server”-and enabled -eq “true”’).Name
foreach ($Server in $Servers) {
if(Test-Connection -ComputerName $Server -Count 1 -ea 0) {
write-host ‘Getting NIC details from’$server $lc ‘of’ ($Servers.count)
$NetAdapter = $null
$NicConfig = $null
$NetAdapter = get-ciminstance -classname win32_networkadapter -computername $Server -filter “NetConnectionStatus = 2” | select netconnectionid,deviceid -ea silentlycontinue
$NicConfig = get-ciminstance -classname win32_networkadapterconfiguration -computername $Server -filter “ipenabled = true” | select ipaddress,ipsubnet,defaultipgateway,index
}
foreach ($Nic in $Netadapter){
$NicName = $null
$NicID = $null
$NicName = $Nic.netconnectionid
$NicID1 = $Nic.deviceid
$OutputObj = New-Object -Type PSObject
$OutputObj | Add-Member -MemberType NoteProperty -Name AdapterName -Value $NicName
$OutputObj | Add-Member -MemberType NoteProperty -Name AdapterID1 -Value $NicID1
$NicDetails += $OutputObj}
foreach ($Nic in $NicConfig){
$NicIP = $null
$NicSubnet = $null
$NicGW = $Null
$NicID2 = $null
$NicIP = $Nic.ipaddress
$NicSubnet = $Nic.ipsubnet
$NicGW = $Nic.defaultipgateway
$NicID2 = $Nic.index
$OutputObj = New-Object -Type PSObject
$OutputObj | Add-Member -MemberType NoteProperty -Name IP -Value $NicIP
$OutputObj | Add-Member -MemberType NoteProperty -Name SubnetAddresss -Value $NicSubnet
$OutputObj | Add-Member -MemberType NoteProperty -Name DefaultGateway -Value $NicGW
$OutputObj | Add-Member -MemberType NoteProperty -Name AdapterID2 -Value $NicID2
$NicDetails += $OutputObj}
write-host $NicDetails
$FinalList += $NicDetails
$NicDetails = $Null
$lc ++
}
$FinalList | export-csv NicDetails.csv

Thanks

Hi Martin,

The issue is you are trying to combine two lists with different types of objects with +=. Take this example

$obj1 = [pscustomobject]@{
    A = "A"
    B = "B"
}
$obj2 = [pscustomobject]@{
    C = "C"
    D = "D"
}

$obj1 += $obj2

You will see a familiar message

Method invocation failed because [System.Management.Automation.PSObject] does not contain a method named 'op_Addition'.
At line:1 char:1
+ $obj1 += $obj2
+ ~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (op_Addition:String) [], RuntimeException
    + FullyQualifiedErrorId : MethodNotFound

How would that CSV look anyways, with the different objects? Please clarify what you are trying to achieve, there is likely an easier approach/answer. Also you are using several outdated and slow practices with the array collection and Add-Member. Do you have PSremoting available? If so you could really improve the speed of this type of task.

Hi Doug,

Many thanks for your reply,

So basically I need to produce a list of remote machines active network adapters basic IP,subnet and gateway as well as the actual network name which contains the numerical value of the vlan used

Do to the additional annoyance of a small random portion of my company’s large infrastructure being Windows Server 2008 I need to use the two earlier objects ‘win32_networkadapter’ and ‘win32_networkadapterconfiguration’

I want to make a list of servername,netconnectionid,ipaddress,ipsubnet,defaultipgateway

however as I have two sets of objects my next hurdle would be to match the deviceid.index and then work out how to join the objects from both

 

Yeah its a mess and to be honest Doug, I could really do with your help

Thanks again

 

 

Here’s how I would handle it. The invoke-command cmdlet will run asynchronously against the servers, 32 at a time by default. You can raise or lower this amount by adding the parameter -ThrottleLimit and your desired maximum. You won’t get a play by play of “which server is processing” but even better you should almost instantly see the results on the console. This is achieved by using the parameter -OutVariable so that the results are captured to a variable and we can see them. We also don’t need to run a ping test, if the server is unreachable you’ll see a warning about it. If you need to log failures, simply add some logging to the catch block. If you’re unable to use PS remoting, you can still call the script block passing in the servers name to achieve the same result. A simple foreach loop could be used but for best performance/time - use PSRemoting like shown below.

$ea = $ErrorActionPreference
$ErrorActionPreference = 'stop'

$outfile = 'c:\temp\NicDetails.csv'

$scriptblock = {
    Param($server = $env:COMPUTERNAME)

    $adapterparams = @{
        Classname = 'win32_networkadapter'
        Server    = $server
        Filter    = “NetConnectionStatus = 2”
    }

    $NetAdapter = get-ciminstance @adapterparams | select netconnectionid,deviceid

    foreach($adapter in $NetAdapter)
    {
        $configparams = @{
            Classname = 'win32_networkadapterconfiguration'
            Server    = $server
            Filter    = "ipenabled = true AND index = $($Adapter.deviceid)"
        }

        Get-CimInstance @configparams | select ipaddress,ipsubnet,defaultipgateway,index | Foreach {
            $ipv6,$ipv4 = $_.ipaddress.where({$_ -match ':'},'split')
            [PSCustomObject]@{
                Servername       = $Server
                NetconnectionID  = $Adapter.netconnectionid
                IPv4Address      = $ipv4 -join ','
                IPv6Address      = $ipv6 -join ','
                IPSubnet         = $_.IPSubnet -join ','
                DefaultIPGateway = $_.DefaultIPGateway -join ','
            }
        }
    }
}

Write-host ‘Getting list of servers from AD, this may take a few moments…’
$Servers = (Get-ADComputer -Filter 'operatingsystem -like "*server*" -and enabled -eq "true"').Name

Try
{
    Invoke-Command -ComputerName $Servers -ScriptBlock $scriptblock |
        select -Property * -ExcludeProperty runspaceid,PSComputerName -OutVariable results
}
catch
{
    Write-Warning $_
}

$results | select -Property * -ExcludeProperty psshowcomputername | Export-CSV -Path $outfile -NoTypeInformation

$ErrorActionPreference = $ea

Frickin eck Doug!

May I say that you are in no doubt my PowerShell hero from hence forth lol

Worked exactly as I needed it bang on first time mate, although tbh it is still running as there are like I mentioned quite a few servers

I daren’t really ask for more however might I ask ;), there are a lot of retries going on still for what are probably some servers which are behind a firewall

Do the retries stop once reached the failed state and also can I pull the failure result into a log perhaps filtering the error result by ‘failed’

 

The whole exercise is to take this info and compare against some persistent route data I took a few days back which was a much surprisingly a much easier scripting exercise than this one, for my standards anyway.

Some poor so and so has to compare and remove the static routes which are no longer needed, not me fortunately but I’m sure ill get pulled back into it due to the scale of servers involved

 

Anyway, again thank you so much for your help, you guys are totally invaluable to us all!