arrays - 如何将 cmdlet 的输出添加到数组中?
问题描述
我正在尝试确定我们的 Windows 服务器上是否安装了特定的 Windows 修补程序。我对 PowerShell 脚本很陌生,这就是我目前所拥有的:
$servers = Get-ADComputer -Filter {(OperatingSystem -like "Windows Server 2019*") -and (enabled -ne $false)} -Property *
$result = @()
ForEach ($item in $servers) {
$testhotfix = Get-HotFix -Id KB4534310,KB4534314,KB4534283,KB4534288,KB4534297,KB4534309,KB4534271,KB4534273 -ComputerName $item.Name | `
select $item.Name,$item.CanonicalName,$item.OperatingSystem
$result += $testhotfix
}
$result | Export-Csv -Path C:\Users\user1\Desktop\Servers.csv -NoTypeInformation
创建的 CSV 文件包含一行包含我要查找的信息,后跟几行逗号,如下所示:
"SERVER1","somedomain.com/Servers/Non-Prod/New_Server_Staging/SERVER1","Windows Server 2019 Standard" ,, ,, ,, ,, ,, ,, ,, ,, ,, ,, ,, ,, ,, ,, ,, ,, ,, ,, ,, ,, ,,
我们有几台服务器至少安装了一个修补程序。如何将每个服务器添加到$result数组?
谢谢
解决方案
通常来说,一般来说:
select $item.Name,$item.CanonicalName,$item.OperatingSystem
应该:
select Name, CanonicalName, OperatingSystem
也就是说,您需要将属性名称(例如Name
)而不是当前输入对象的属性值(例如$item.Name
)传递给select
(Select-Object
cmdlet)。
最终效果是Select-Object
创建自定义对象,其属性(错误地)以属性值命名,并且它们本身没有 value,因为输入对象没有这样的属性。这解释了您看到的输出。
然而,更大的问题是即使这样也行不通,因为属性名称与对象相关,而不是$item
与操作的对象输出的对象相关。Get-HotFix
select
事实证明,您真正需要的是使用Get-HotFix
调用作为条件,以便仅在安装了至少一个指定的修补程序时为手头的计算机编写一个 CSV 行:
$hotfixIds = 'KB4534310', 'KB4534314', 'KB4534283', 'KB4534288', 'KB4534297', 'KB4534309', 'KB4534271', 'KB4534273'
if (0 -ne (Get-HotFix -ErrorAction SilentlyContinue -Id $hotfixIds -ComputerName $item.Name).Count) {
$result += $item | select Name, CanonicalName, OperatingSystem
}
笔记:
请注意现在
$item
(手头的计算机)如何通过管道传输到select
,以确保提取其属性(以具有这些属性的自定义对象的形式)。您可以完全省略
0 -eq
并依赖 PowerShell 的隐式到布尔转换,其中任何非零数字的计算结果为(有关所有规则的摘要,请参阅此答案$true
的底部部分。- 相反,如果您想测试所有正在安装的指定修补程序,请替换
0 -ne
为$hotfixIds.Count -eq
.
- 相反,如果您想测试所有正在安装的指定修补程序,请替换
-ErrorAction SilentlyContinue
消除未安装任何指定修补程序的计算机的错误;$Error
您可以事后检查自动收集,或用于-ErrorVariable err
收集变量中的所有命令特定错误$err
。
此外,您的整体命令可以大大简化 - 请参阅底部。
针对不同场景的解决方案,也可能令人感兴趣:
如果您想将输出Get-HotFix
对象的属性与对象的属性($item
代表手头的计算机)结合起来:
以下命令:
- 从输出对象中选择所有属性 ( )
Get-HotFix
-Property *
$item
使用计算的属性从当前添加感兴趣的属性
# Additional 'KB...' values omitted for brevity.
Get-HotFix -Id KB4534310, KB4534314 -ComputerName $item.Name |
Select-Object -Exclude Name -Property *,
@{ n = 'Name'; e = { $item.Name } },
@{ n = 'CanonicalName'; e = { $item.CanonicalName } },
@{ n = 'OperatingSystem'; e = { $item.OperatingSystem } }
请注意,从输入对象(具有此类属性的输出对象,但它是空-Exclude Name
的)中排除该属性,因此可以将其添加为包含计算机名称的属性。Name
Get-HotFix
Name
至于你尝试了什么:
除了Select-Object
上面提到的属性名称问题之外,您的主要问题是您期望管道段作为条件,这不是管道的工作方式:
Get-HotFix ... | select ...
以上只是将Get-HotFix
的输出对象发送到select
( Select-Object
),然后它无条件地处理它们(并且,如前所述,在这些对象上查找具有给定名称的属性)。
现在,如果没有Get-HotFix
产生任何输出,那么条件逻辑就会隐式应用:那么select
命令就不会被调用。
相反,如果Get-HotFix
产生多个输出,select
将在每个.
也就是说,如果我们天真地尝试从以下位置更正您的命令:
Get-HotFix ... | select ...
至:
Get-HotFix ... | ForEach-Object { $item | select ... }
您可能会在每台计算机上创建多个输出对象,即每当给定计算机碰巧安装了多个给定修补程序时。
您的(更正的)命令的简化版本:
您的命令可以简化为仅使用单个管道,而无需 aux。变量:
Get-ADComputer -Filter '(OperatingSystem -like "Windows Server 2019*") -and (enabled -ne $false)' -Property * |
ForEach-Object {
if (0 -ne (Get-HotFix -ErrorAction SilentlyContinue -ComputerName $item.Name -Id KB4534310,KB4534314,KB4534283,KB4534288,KB4534297,KB4534309,KB4534271,KB4534273).Count) {
$item | select Name, CanonicalName, OperatingSystem
}
} | Export-Csv -Path C:\Users\user1\Desktop\Servers.csv -NoTypeInformation
笔记:
如果以结束一行
|
,则不需要尾随`
信号线延续。- PowerShell [Core] v7.0+ 现在还允许放置在下一行
|
的开头。
- PowerShell [Core] v7.0+ 现在还允许放置在下一行
使用单引号字符串 (
'...'
) 代替脚本块 ({ ... }
) 来传递-Filter
参数,因为最好避免使用脚本块 ({ ... }
) 作为-Filter
参数。使用创建的输出自定义对象实例
$item | select Name, CanonicalName, OperatingSystem
直接发送到管道。
推荐阅读
- c# - 我应该将 ToUpper() 方法放在代码中的什么位置才能生效?
- spring - Spring Cloud Contract - 混合 http 和消息传递
- python - 检查用户是否在模型中并在重新注册之前阻止的条件
- java - 正则表达式找不到匹配项 - .find() 和 .matches() 之间的区别有错吗?
- java - 如何从方法中完成并返回列表?
- python - 在 PyTorch 张量切片上广播操作的最有效方法是什么?
- c++ - 将 std::async 限制为某些 CPU 内核
- docker - 如何配置 docker-compose 以重新启动在设定的时间间隔内以代码 0 退出的容器
- python - Python:检查、比较时间、日期。验证日期
- javascript - 从 Jest 中的函数中清除值