我正在使用一些PowerShell函数从一些REST API端点获取数据。遍历第一个查询的结果允许我使用id
字段来检索第二个查询中的匹配结果,但是,第二个查询返回的结果没有任何与原始结果集匹配的属性,因此我认为我不能执行JOIN或类似的操作。
例如,假设查询第一个REST端点的结果存储在$a
中。
$a =
ID Title Location Internal IP Address
-- ----- -------- -------------------
1 Endpoint 1 UK 10.0.0.1
2 Endpoint 2 US 10.1.0.1
3 Endpoint 3 AUS 10.2.0.1
并使用ID = 1
查询第二个REST端点,我们得到$b
中存储的以下内容:
$b =
NATed IP Address Last Provisioned Time
---------------- ---------------------
1.2.3.4 2022-02-10T04:09:31.988909+01:00
我想做的是结合两者的属性,一次一个记录,所以在我检索了$b
之后,我将创建$c
,它看起来像这样:
$c =
ID Title Location Internal IP Address NATed IP Address Last Provisioned Time
-- ----- -------- ------------------- ---------------- ---------------------
1 Endpoint 1 UK 10.0.0.1 1.2.3.4 2022-02-10T04:09:31.988909+01:00
当代码遍历$a
的结果时,因此我应该构建一个完整的合并对象,并且在$a
的三次迭代之后,我们应该以类似的内容结束:
$d =
ID Title Location Internal IP Address NATed IP Address Last Provisioned Time
-- ----- -------- ------------------- ---------------- ---------------------
1 Endpoint 1 UK 10.0.0.1 1.2.3.4 2022-02-10T04:09:31.988909+01:00
2 Endpoint 2 US 10.1.0.1 1.2.3.5 2022-02-10T04:09:31.988909+01:00
3 Endpoint 3 AUS 10.2.0.1 1.2.3.6 2022-02-10T04:09:31.988909+01:00
我觉得这将是相当简单的,然而,我看过许多不同的帖子和网站,但似乎没有一个能帮助我实现我想要的,或者更可能的是,我只是误解了Add-Member
等方法如何在多个管道循环中起作用,或者错过了盲目的明显
我最接近的是下面的代码,它实际上导致一个数组或哈希表(取决于我如何初始化$collection
变量),但结果是相似的:
$collection = @{}
foreach ($item in $a) {
$collection += @{
"Title" = $item.Title
"Location" = $item.Location
"Internal IP Address" = $item."Internal IP Address"
}
}
foreach ($item in $b) {
$collection += @{
"NATed IP Address" = $item."NATed IP Address"
"Last Provisioned Time" = $item."Last Provisioned Time"
}
}
生成如下键/值表:
Name Value
---- -----
ID 1
Title Endpoint 1
Internal IP Address 10.0.0.1
Location UK
NATed IP Address 1.2.3.4
Last Provisioned Time 2022-02-10T03:21:29.265257+01:00
这意味着我最终将得到一个数组的数组(或一个哈希表的哈希表)。虽然我认为我仍然可以使用这种类型的数据格式,但我很想知道我需要做些什么来实现我的初始目标。
获取$a
和$b
的代码如下:有一些函数封装了API调用:
$a = Get-Endpoints -Creds $Credentials -URI $FQDN
$a| ForEach-Object {
$b = Get-ProvisioningInfoEndpoint -Creds $Credentials -URI $FQDN -id $_.id |
Select-Object -Property @{Name="NATed IP Address";Expression={$_.ip}}, @{Name="Last Provisioned Time";Expression={$_.ts_created}}
}
更新2
下面是完整的代码,它可以工作,但有点冗长,可能真的效率低下,并导致hashtable的hashtable:
$a = Get-Endpoints -Creds $Credentials -URI $FQDN
$a| ForEach-Object {
$b = Get-ProvisioningInfoEndpoint -Creds $Credentials -URI $FQDN -id $_.id |
Select-Object -Property @{Name="NATed IP Address";Expression={$_.ip}}, @{Name="Last Provisioned Time";Expression={$_.ts_created}}
$EndpointSelectedData = $_ | Select-Object -Property ID, @{Name="Title";Expression={$_.title}}, @{Name="Location";Expression={$_.location}}, @{Name="Internal IP Address";Expression={$_.ip}}
$c = @{}
foreach ($EndpointData in $EndpointSelectedData) {
$c += @{
"ID" = $EndpointData.id
"Title" = $EndpointData.Title
"Location" = $EndpointData.Location
"Internal IP Address" = $EndpointData."Internal IP Address"
}
}
foreach ($ProvisionedD in $ProvisionedData) {
$collection += @{
"NATed IP Address" = $ProvisionedD."NATed IP Address"
"Last Provisioned Time" = $ProvisionedD."Last Provisioned Time"
}
}
$d = $d + @{"Node_$i" = $c}
$i = $i + 1
}
更新3
在@Santiago的建议答案和@iRon的指针之后,我现在有以下代码:
$Endpoints = Get-Endpoints -Creds $Credentials -URI $FQDN
foreach($i in $Endpoints) {
foreach($z in Get-ProvisioningInfoEndpoint -Creds $Credentials -URI $FQDN -Id $i.id) {
[pscustomobject]@{
'ID' = $i.Id
'Title' = $i.Title
'Location' = $i.Location
'Internal IP Address' = $i.Ip
'NATed IP Address' = $z.Ip
'Last Provisioned Time' = $z.Ts_Created
}
}
}
这将导致屏幕上的转储(我猜这是管道清理):
ID : 1
Title : Endpoint 1
Location : UK
Internal IP Address : 10.0.0.1
NATed IP Address : 1.2.3.4
Last Provisioned Time : 2022-02-10T04:09:32.126357+01:00
ID : 2
Title : Endpoint 2
Location : US
Internal IP Address : 10.1.0.1
NATed IP Address : 1.2.3.5
Last Provisioned Time : 2022-02-10T04:21:32.657364+01:00
ID : 3
Title : Endpoint 3
Location : Aus
Internal IP Address : 10.2.0.1
NATed IP Address : 1.2.3.6
Last Provisioned Time : 2022-02-10T04:09:31.990202+01:00
...
所以,我想这是接近我想要的,但仍然没有真正在那里。我现在需要弄清楚如何处理管道输出…这与思维方式的改变有很大关系,所以可能需要一些挠头。
更新4 -可能的解决方案
好,扩展上面的代码块,我创建了一些额外的逻辑来将pscustomobject
的输出管道到CSV文件。最终目的是根据前一天的配置检查各个端点的状态,以查看是否有任何更改(因为它经常在管理员不知情的情况下更改!)。
指定一个变量来存储嵌套的foreach
循环的结果。然后将其用于导出到CSV。我在脚本的开头添加了一些进一步的逻辑,以检查文件是否存在,如果存在,则删除今天的配置文件,以便脚本在每天意外运行多次时创建一个新的配置文件。
主循环完成后,将重新导入今天和昨天的文件,并使用Compare-Object
CmdLet查看是否有任何更改。如果两个文件之间有差异,我可能会添加一些发送电子邮件的代码。
$DateStamp = get-date -Format FileDate
if (Test-Path -Path ".endpoint-$($DateStamp).csv" -PathType Leaf) {
Remove-Item -Path ".endpoint-$($DateStamp).csv"
}
$Endpoints = Get-Endpoints -Creds $Credentials -ERMMgr $MgrFQDN
$result = foreach($i in $Endpoints) {
foreach($z in Get-ProvisioningInfoEndpoint -Creds $Credentials -URI $FQDN -Id $i.id) {
[pscustomobject]@{
'ID' = $i.Id
'Title' = $i.Title
'Location' = $i.Location
'Internal IP Address' = $i.Ip
'NATed IP Address' = $z.Ip
'Last Provisioned Time' = $z.Ts_Created
}
}
}
$result | Export-Csv ".endpoint-$DateStamp.csv"
if (Test-Path -Path ".endpoint-$($DateStamp-1).csv" -PathType Leaf) {
$InFile2 = Import-CSV -Path ".endpoint-$($DateStamp-1).csv"
Compare-Object -ReferenceObject $result -DifferenceObject $InFile2 -Property Title, "NATed IP Address" | Export-Csv ".endpoint_diff-$DateStamp.csv"
}
从它的外观来看,这可能会得到你想要的:
$result = foreach($i in Get-Endpoints -Creds $Credentials -URI $FQDN) {
foreach($z in Get-ProvisioningInfoEndpoint -Creds $Credentials -URI $FQDN -Id $id.id) {
[pscustomobject]@{
'ID' = $i.Id
'Title' = $i.Title
'Location' = $i.Location
'Internal IP Address' = $i.Ip
'NATed IP Address' = $z.Ip
'Last Provisioned Time' = $z.Ts_Created
}
}
}
基本上,对象可以在运行时创建,而不是同时收集$a
和$b
的结果,然后将它们连接/合并。