I am trying to create a PSCustomObject that has multiple properties that are ArrayLists containing PSCustomObjects. I Am adding the parent object to an ArrayList as well. The idea is to create a relationship that I can easily parse out to yml or another format. For example,
Hosts: # Parent ArrayList
- HostName: myhost # Start of Parent Object
FQDN: myhost.my.domain.com
IPs: # ArrayList of Objects, Property of Parent Object
- IP: 192.168.1.2 # Start of Child Object
MAC: 00:00:00:00:00:00
- IP: 10.10.1.1 # Start of Child Object
Records: # ArrayList of Objects, Property of Parent Object
- Zone: 192.168.1 # Start of Child Object
RRType: PTR
Source: 2
Target: myhost.my.domain.com
TTL: 2H
- Zone: my.domain.com # Start of Child Object
RRType: A
Source: myhost.my.domain.com
Target: 192.168.1.2
TTL: 2H
The problem I'm having is when I try to add a new object to one of the ArrayList properties of the Parent object, I'm receiving the following error:
Method invocation failed because [System.Management.Automation.PSCustomObject] does not contain a method named 'add'.
At C:\merge.ps1:96 char:13
+ ,$_.DNSRecords.Add($RecordObj)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (add:String) [], RuntimeException
+ FullyQualifiedErrorId : MethodNotFound
I am using this function to create hosts:
function New-HostEntry {
param (
[Parameter(ValueFromPipeline=$true,position=0)]$HostName,
[Parameter(ValueFromPipeline=$true,position=1)]$FQDN,
[Parameter(ValueFromPipeline=$true,position=2)]$IP,
[Parameter(ValueFromPipeline=$true,position=3)]$MAC,
[Parameter(ValueFromPipeline=$true,position=4)]$RecordObj
)
$IPS = New-Object System.Collections.ArrayList
if ($IP){
$IPEntry = [PSCustomObject]@{
IP = $IP
MAC = $MAC
}
$IPS.Add($IPEntry)
}
$DNSRecords = New-Object System.Collections.ArrayList
if ($RecordObj){
$DNSRecords.Add($RecordObj)
}
[PSCustomObject]@{
HostName = $HostName
FQDN = $FQDN
IPs = $IPS
DNSRecords = $DNSRecords
}
}
In the main part of the script, I am creating the parent collection & adding hosts to it with the following:
[System.Collections.ArrayList]$hosts= @()
$hosts.add((New-HostEntry -HostName $hostname -FQDN $fqdn -IP $ip -MAC $mac -RecordObj $RecordObj))
Sometimes The values for IP, MAC, or RecordObj may be $null or missing. That does not seem to matter when initially creating the new Host object & adding it to the collection.
Later, an existing Host object (Inside the $Hosts ArrayList) may need to have a $RecordObj added to it:
Add-DNSRecordToHost $_.HostName $RecordObj
This is an example of a RecordObj:
$RecordObj = [PSCustomObject]@{
Zone = $zonename
Source = $Source
TTL = $TTL
RRType = $RRType
Preference = $Preference
Target = $Target
Comment = $Comment
}
Finally, this is the function that is failing:
function Add-DNSRecordToHost{
param (
[Parameter(ValueFromPipeline=$true,position=0)]$HostName,
[Parameter(ValueFromPipeline=$true,position=1)]$RecordObj
)
$found = $false
#Get the host with matching HostName
$hosts | Where-Object {$_.HostName -eq $HostName} | ForEach-Object {
#Compare each record already on the host to the new record
Write-host "Checking" $_.HostName "for" $RecordObj.Zone $RecordObj.RRType "record ..."
foreach ($DNSRecord in $_.DNSRecords){
if ( -not (Compare-Object $DNSRecord.PSObject.Properties $RecordObj.PSObject.Properties) ) {
#objects match
Write-Host "ERROR: Zone Record" $RecordObj.Zone "already exists on " $HostObj.Host -ForegroundColor Yellow
$found = $true
}
}
#If none of the records match add the new record to the host
if (!$found){
Write-Host "ACTION: Adding Zone Record" $RecordObj.Zone "to" $_.HostName -ForegroundColor Cyan
#Write-Host $DNSRecords.toString()
$_.DNSRecords.Add($RecordObj)
#,$_.DNSRecords.Add($RecordObj)
#$DNSRecords = $_.DNSRecords; $DNSRecords.add($RecordObj); $_.DNSRecords = $DNSRecords
#$_.DNSRecords | %{ Write-Host $_.Zone $_.Source $_.TTL $_.RRType $_.Preference $_.Target $_.Comment -ForegroundColor Yellow }
}
}
}
I have left in (but commented out) my attempts at debugging.
Note: I had also tried passing the function a $host object, but it failed also:
function Add-DNSRecordToHost{
param (
[Parameter(ValueFromPipeline=$true,position=0)]$Host,
[Parameter(ValueFromPipeline=$true,position=1)]$RecordObj
)
$found = $false
foreach ($DNSRecord in $Host.DNSRecords){
if ( -not (Compare-Object $DNSRecord.PSObject.Properties $RecordObj.PSObject.Properties) ) {
$found = $true
}
}
if (!$found){
$Host.DNSRecords.Add($RecordObj)
}
}
$hosts | % {Add-DNSRecordToHost $_ $RecordObj}
It errors out when I try to add a $RecordObj to the DNSRecords property of a Host object. I Expect the DNSRecords property to be an ArrayList, but the according to the above error message, it has converted to a PSCustomObject. Why is it being changed, and how can I correctly add to it?