Error adding an array to an array

by dunagh at 2012-12-12 11:03:13

Hello. I am trying to add an array to another array but keep getting the following error message:

Method invocation failed because [System.Management.Automation.PSObject] doesn’t contain a method named ‘op_Addition’.
At E:\Get-MappedPrintersDrives.ps1:151 char:35
+ $mappingInfo = $mappingInfo + <<<< $(Get-MappedDrives $arrCompList[$i].Computer $arrCompList[$i].User $arrCompList[$i].SID)
+ CategoryInfo : InvalidOperation: (op_Addition:String) , RuntimeException
+ FullyQualifiedErrorId : MethodNotFound


All the code works up till this point. Can someone help point out what I am doing wrong? Following is the relevant code.

Thanks,

{
$mappingInfo = @()

if(!$noPrinter) {
$mappingInfo = Get-PrinterInfo $arrCompList[$i].Computer $arrCompList[$i].User $arrCompList[$i].SID
}

if(!$noDrive) {
$mappingInfo = $mappingInfo + $(Get-MappedDrives $arrCompList[$i].Computer $arrCompList[$i].User $arrCompList[$i].SID) # This is where the error is produced
}

}

Function Get-PrinterInfo {
Param($computerName, $userName, $userSID)


$arrMappedPrinters = @()

$reg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey(‘Users’, $computerName)

$regKey = $reg.OpenSubKey("$userSID\Printers\Connections") # Be aware that $userSID may be an object and not a string.

$subKeys = $regKey.GetSubkeyNames()

foreach($key in $subKeys)
{
$thisKey = $userSID + "\Printers\Connections&quot; + $key
#$arrPrinterKey = $printerKey.Split("&quot;)
$thisSubKey = $reg.OpenSubKey($thisKey)

# Because $key is in the format of ‘,<server name>, <printer name>’ we are gettin the fourth element of the array.
$printerName = $($key.Split(","))[3]

$obj = New-Object PSObject
$obj | Add-Member -MemberType NoteProperty -Name "ComputerName" -Value $computerName
$obj | Add-Member -MemberType NoteProperty -Name "UserName" -Value $userName
$obj | Add-Member -MemberType NoteProperty -Name "DeviceType" -Value "PRNTR"
$obj | Add-Member -MemberType NoteProperty -Name "DeviceID" -Value $printerName
$obj | Add-Member -MemberType NoteProperty -Name "TargetPath" -Value $thisSubKey.GetValue("Server")

$arrMappedPrinters += $obj
}

return $arrMappedPrinters

}


Function Get-MappedDrives {
Param($computerName, $userName, $userSID)

$arrMappedDrives = @()

$reg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey(‘Users’, $computerName)

$regKey = $reg.OpenSubKey("$userSID\Network") # Be aware that $userSID may be an object and not a string.

$subKeys = $regKey.GetSubkeyNames()

foreach($key in $subKeys)
{
$thisKey = $userSID + "\Network\" + $key

$thisSubKey = $reg.OpenSubKey($thisKey)

$obj = New-Object PSObject
$obj | Add-Member -MemberType NoteProperty -Name "ComputerName" -Value $computerName
$obj | Add-Member -MemberType NoteProperty -Name "UserName" -Value $userName
$obj | Add-Member -MemberType NoteProperty -Name "DeviceType" -Value "MAPPDDRV"
$obj | Add-Member -MemberType NoteProperty -Name "DeviceID" -Value $key
$obj | Add-Member -MemberType NoteProperty -Name "TargetPath" -Value $thisSubKey.GetValue("RemotePath")

$arrMappedDrives += $obj
}

return $arrMappedDrives

}
by ArtB0514 at 2012-12-12 12:31:11
Try this
$mappingInfo += @(Get-MappedDrives $arrCompList[$i].Computer $arrCompList[$i].User $arrCompList[$i].SID)

You’ll get that error if either the source doesn’t have an addition method or if the object added is of an improper type. I think you have a "$" instead of a "@". You shouln’t have any trouble joining two arrays.
by nohandle at 2012-12-13 04:23:24
[quote="dunagh"]Method invocation failed because [System.Management.Automation.PSObject] doesn’t contain a method named ‘op_Addition’.[/quote]Â
The exception shows that the $mappingInfo is [System.Management.Automation.PSObject] type,
you have to do $mappingInfo += every time you add an item to the array, otherwise the value get replaced and the $mappingInfo may no longer contain an array.
[quote="dunagh"] Â $arrMappedDrives += $obj
  }
return $arrMappedDrives[/quote]
This is totally unnecessary. You can output the objects one by one, Powershell will take care of making them in collection. In fact by your approach you may kill performance when piping because the pipe has to wait for you to finish one command until it gets any input for the next one.
[quote="ArtB0514"]You’ll get that error if either the source doesn’t have an addition method or if the object added is of an improper type.[/quote]
In the latter case you get cannot convert type to type exception, not the exception mentioned.
$int = 10
$int += "dog"

Cannot convert value "dog" to type "System.Int32". Error: "Input string was not in a correct format."

[quote="ArtB0514"]I think you have a "$" instead of a "@".[/quote]
If array is produced in the subexpression ($()) array is returned on the output. if not, only one object is returned on the output. If array or scalar is produced in the array subexpression (@()) array is returned on the output.
Either way you don’t care if you add an array or a scalar to the original array because the additon works in both cases.
$ar = @()
$ar += 10
$ar += 11, 12
$ar

10
11
12
by dunagh at 2012-12-13 21:59:04
[quote]Try this
$mappingInfo += @(Get-MappedDrives $arrCompList[$i].Computer $arrCompList[$i].User $arrCompList[$i].SID)


You’ll get that error if either the source doesn’t have an addition method or if the object added is of an improper type. I think you have a "$" instead of a "@". You shouln’t have any trouble joining two arrays.[/quote]

This worked, Thanks!

As for not using the += operator, two or three weeks of PowerShell does not leave me with an understanding of how this works without the operator. I attempted to omit it but I got and error. How does PowerShell automatically build a collection and return it? A pointer to a good tutorial would be great if you don’t have time or the desire to explain it. :slight_smile:
by nohandle at 2012-12-14 02:18:25
Hi,
no I don’t mind explaining it.
First I have to admit I maybe misled you a bit because I forgot to mention you should just output the objects instead of colleting them in a collection and outputting the whole collection on the end.
To see this on an example I call a function Foo that outputs four objects and save the output to a variable. If you call the new-object cmdlet, output of this cmdlet is the new object, I don’t capture output of the new-object command to any variable so it goes to the output of the function. Then it is saved to the collection and the collection is saved to the variable. All automatically without me caring about it.
In the output you can see the $collection variable has 4 items in it and is an array of objects.

function foo
{
1…4 | Foreach {
$hash = @{Value = $}
New-Object -TypeName PsObject -Property $hash
}
}



$collection = foo
$collection.Count
$collection.GetType().FullName
$collection | Format-Table -AutoSize


4
System.Object[]

Value
-----
1
2
3
4


Now if you change the functions a bit to make the difference more obvious.
function foo
{
[cmdletBinding()]
param()
Begin { Write-Verbose "Starting foo function"}
process {
1…4 | Foreach {
$hash = @{Value = $
}
#retrieving the object takes time
start-sleep -Seconds 3
Write-Verbose "outputting object $"
New-Object -TypeName PsObject -Property $hash
}
}
end {Write-Verbose "Ending foo function"}
}

function bar
{
[cmdletBinding()]
param()
Begin { Write-Verbose "Starting bar function"}
process {
$collection = @()
1…4 | Foreach {
$hash = @{Value = $
}
#retrieving the object takes time
start-sleep -Seconds 3
Write-Verbose "saving object $_"
$object = New-Object -TypeName PsObject -Property $hash
$collection += $object
}
Write-Verbose "outputting collection"
$collection
}
end {Write-Verbose "Ending bar function"}
}

Start one by one and see which command seems more responsive. To see how the commands are processed add -Verbose parameter to the call.
foo
bar