【发布时间】:2021-09-14 00:04:10
【问题描述】:
我正在尝试创建一个具有多个属性的 PSCustomObject,这些属性是包含 PSCustomObjects 的 ArrayLists。我也将父对象添加到 ArrayList 中。这个想法是创建一种我可以轻松解析为 yml 或其他格式的关系。 例如,
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
我遇到的问题是,当我尝试将新对象添加到父对象的 ArrayList 属性之一时,我收到以下错误:
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
我正在使用这个函数来创建主机:
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
}
}
在脚本的主要部分,我正在创建父集合并使用以下内容向其中添加主机:
[System.Collections.ArrayList]$hosts= @()
$hosts.add((New-HostEntry -HostName $hostname -FQDN $fqdn -IP $ip -MAC $mac -RecordObj $RecordObj))
有时 IP、MAC 或 RecordObj 的值可能为 $null 或缺失。在最初创建新的 Host 对象并将其添加到集合时,这似乎并不重要。
稍后,现有的 Host 对象(在 $Hosts ArrayList 内)可能需要添加一个 $RecordObj:
Add-DNSRecordToHost $_.HostName $RecordObj
这是一个 RecordObj 的示例:
$RecordObj = [PSCustomObject]@{
Zone = $zonename
Source = $Source
TTL = $TTL
RRType = $RRType
Preference = $Preference
Target = $Target
Comment = $Comment
}
最后,这是失败的函数:
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 }
}
}
}
我已保留(但已注释掉)我的调试尝试。
注意:我也尝试过将 $host 对象传递给函数,但它也失败了:
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}
当我尝试将 $RecordObj 添加到 Host 对象的 DNSRecords 属性时出错。 我希望 DNSRecords 属性是一个 ArrayList,但根据上述错误消息,它已转换为 PSCustomObject。为什么要更改,如何正确添加?
【问题讨论】:
-
我没有看到
$host.DNSRecords被定义为ArrayList,这可能是错误的来源。 -
在函数 New-HostEntry 中,我正在创建
$DNSRecords = New-Object System.Collections.ArrayList,并将其作为属性DNSRecords = $DNSRecords添加到 PSCustomObject 中,您是否建议我最初将属性创建为空数组列表,将传入的记录添加到其中(如果存在),然后返回创建的 Host 对象? -
我尝试使用
$NewHost= [PSCustomObject]@{DNSRecords = New-Object System.Collections.ArrayList}将主机属性创建为一个空的ArrayList,然后使用if ($RecordObj){NewHost.DNSRecords.Add($RecordObj)}将$RecordObj 添加到其中,然后使用return $NewHost,但尝试时我仍然看到相同的行为向其中添加 $RecordObj。 -
错误很明显,
$host.DNSRecords不是ArrayList,或者你不应该遇到那个特定的错误。如果您有疑问,可以尝试$host.DNSRecords.GetType()并亲自查看。 -
我完全同意,我同意了。我在
$_.DNSRecords.Add($RecordObj)之后插入了$_.DNSRecords.GetType()(这会引发错误),GetType() 作为 PSCustomObject 返回。这正是我的问题 - 如果我在创建 $host 对象时将 DNSRecords 属性创建为空 ArrayList,为什么它会更改为 PSCustomObject?
标签: function powershell arraylist collections pscustomobject