Powershell Capture Invoke-Command Output



我遇到了一个我似乎弄不清楚的问题。我有这段代码,它能做我想要的。它搜索已安装并具有特定UpdateID的Windows更新。

param(
$updateId = $false,
$hostName = $false
)

if(($updateId -eq $false) -or ($hostName -eq $false))
{
Write-Host "checkUpdateInstalled.ps1 -updateId <updateIdValue> -hostName <Remote Host Name>"
exit
}

Invoke-Command -ComputerName $hostName -ScriptBlock {
$searcher = New-Object -ComObject Microsoft.Update.Searcher
$searcher.Search("IsInstalled=1 AND UpdateID='$Using:updateId'")
$tmp.Updates| ForEach-Object {
$i++
Write-Host "UpdateInfo Update No. $i"
Write-Host "Title: `t`t" $_.Title
Write-Host "Description: `t`t " $_.Description
Write-Host "UpdateID: `t`t " $_.Identity.UpdateID
Write-Host "RevisionNumber: `t`t " $_.Identity.RevisionNumber
Write-Host "KBArticleIDs: `t`t " $_.KBArticleIDs
Write-Host "==============================================="    
}
}

有了这个解决方案,我不能在Invoke-Command之外使用$tmp.Updates,但我试图用ForEach-Object循环收集的信息工作得很好。在这种情况下,打印$tmp.Updates可以提供有关特定更新的信息。

所以我尝试了以下方法来访问$tmp:

## Same top part

$tmp = Invoke-Command -ComputerName $hostName -ScriptBlock {
$searcher = New-Object -ComObject Microsoft.Update.Searcher
$searcher.Search("IsInstalled=1 AND UpdateID='$Using:updateId'")
}
$tmp.Updates| ForEach-Object {
$i++
Write-Host "UpdateInfo Update No. $i"
Write-Host "Title: `t`t" $_.Title
Write-Host "Description: `t`t " $_.Description
Write-Host "UpdateID: `t`t " $_.Identity.UpdateID
Write-Host "RevisionNumber: `t`t " $_.Identity.RevisionNumber
Write-Host "KBArticleIDs: `t`t " $_.KBArticleIDs
Write-Host "==============================================="    
}

在此尝试中,循环不打印信息。如果我想打印$tmp.Updates,我得到的是System.__ComObject

有人能理解吗?

这就是Invoke-Command的设计。

Invoke-Command不返回远程会话的对象。相反,它返回对象经过多个进程后的表示形式。

首先在远程环境上序列化,然后在本地环境上反序列化。

这是所有传播的东西。在序列化方面,有一些基本类型会被反序列化为"活"类型。对象,例如:

  • Byte, SByte, Byte[]
  • Int16, Int32, Int64, UInt16, UInt32, Uint64
  • 十进制,单,双
  • 时间跨度,日期时间,进度记录
  • Char, String, XmlDocument, SecureString
  • Boolean,Guid, Uri, Version

那么你就有了没有完全保真地反序列化的类型,但在大多数实际用途中表现为基本类型。

这包括enum,它被反序列化为底层整数。类似地,反序列化器将保留列表的内容,但可能会更改容器的实际类型。(例如:列表反序列化为数组列表,字典反序列化为哈希表,等等…)

最后,你也有一些物体被重新水合成它们的活体。例如,IP地址对象被序列化,然后被反序列化为Deserialized.System.Net.IPAddress,并通过"rehydration"再次转换为其原始类型,该过程规定了如何再次转换反序列化类型。

对于某些PowerShell类型,有一些内置的补水功能…:

  • PSPrimitiveDictionary
  • SwitchParameter
  • PSListModifier
  • PSCredential

以及基类库中的某些类型:

  • IPAddress, MailAddress
  • CultureInfo
  • X509Certificate2, X500DistinguishedName
  • 目录安全、文件安全、注册安全

因此,要执行您所查找的操作,您需要返回可序列化的对象。您需要深入COM对象并返回所需的属性值。您可以使用Get-Member来确定可用的属性,并从那里返回您想要的内容。

您也可以在远程对象上使用ConvertTo-Json来返回它的json表示,并在本地将其转换回PSObject。在类型方面,您也不会得到准确的表示,但您可能会得到更好的属性/值视图。如果需要,不要忘记将-Depth参数设置为更高的数字,因为默认是4层深度。

参考

Microsoft Dev-blogs - object是如何从远程地址发送和发送的

返回的序列化对象的深度似乎有限制(没有方法)。这对我来说是有效的,直接返回updates子属性。否则"updates"变成字符串数组。虽然我会使用"get-ciminstance win32_quickfixengineing& quot;相反。

$tmp = Invoke-Command localhost {  # elevated
$searcher = New-Object -ComObject Microsoft.Update.Searcher
$searcher.Search('IsInstalled=1')
}
$tmp.Updates
System.__ComObject
System.__ComObject
System.__ComObject
...

$tmp.Updates[0].gettype()
IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     String                                   System.Object
$tmp = Invoke-Command localhost {  # elevated
$searcher = New-Object -ComObject Microsoft.Update.Searcher
$searcher.Search('IsInstalled=1').updates
}
$tmp | % title
MSXML 6.0 RTM Security Update  (925673)
Update for Microsoft Report Viewer Redistributable 2010 Service Pack 1 (KB2549864)
Security Update for Microsoft Visual C++ 2005 Service Pack 1 Redistributable Package (KB2538242)
...

返回你想要的属性…

Invoke-Command localhost {  # elevated
$searcher = New-Object -ComObject Microsoft.Update.Searcher
$searcher.Search('IsInstalled=1').updates | select title, description,
@{n='UpdateID'; e={$_.Identity.UpdateID}},
@{n='RevisionNumber';e={$_.Identity.RevisionNumber}}, KBArticleIDs
}
Title          : Update for Windows Defender Antivirus antimalware platform - KB4052623 (Version 4.18.2001.10)
Description    : This package will update Windows Defender Antivirus antimalware platform’s components on the user machine.
UpdateID       : c01629fc-64ea-45f3-b7cb-cabc7d566933
RevisionNumber : 200
KBArticleIDs   : {4052623}
PSComputerName : localhost
RunspaceId     : 57b3ae43-6ee6-4e0c-add1-d9d82aba3f61
invoke-command localhost { get-ciminstance win32_quickfixengineering }
Source        Description      HotFixID      InstalledBy          InstalledOn                PSComputerName
------        -----------      --------      -----------          -----------                --------------
Update           KB5013887     NT AUTHORITYSYSTEM  6/18/2022 12:00:00 AM      localhost
Update           KB4562830     NT AUTHORITYSYSTEM  2/1/2021 12:00:00 AM       localhost
Update           KB4577586     NT AUTHORITYSYSTEM  5/24/2021 12:00:00 AM      localhost

最新更新