I'm attempting to use the builtin parallel processing capabilities of Invoke-Command
so I can quickly scan hundreds of machines for Office 365 installations (finding discrepancies in SCCM reporting). However, when Get-ItemProperty
can't find the registry key, I'm not sure how to capture the fact that the machine does not have O365.
For example;
<some list of machines>.txt contains
computer1
computer2
computer3
$Computers = Get-Content .\<some list of machines>.txt
Invoke-Command -ComputerName $Computer -ScriptBlock {(Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\O365ProPlusRetail*)} -ErrorAction SilentlyContinue -ErrorVariable Problem | select pscomputername, DisplayName, DisplayVersion
... works really fast and list every machine with O365 and the version. That's great. But missing is every machine that DOES NOT have O365 installed. I.E. if "computer2" in the list above does not have O365, the output shows;
PSComputerName DisplayName DisplayVersion
-------------- ----------- --------------
computer1 Microsoft Office 365 ProPlus - en-us 16.0.9226.2114
computer3 Microsoft Office 365 ProPlus - en-us 16.0.9226.2114
Any ideas on how I could retain parallel processing and get output similar to the following?
PSComputerName DisplayName DisplayVersion
-------------- ----------- --------------
computer1 Microsoft Office 365 ProPlus - en-us 16.0.9226.2114
computer2
computer3 Microsoft Office 365 ProPlus - en-us 16.0.9226.2114
Modify your script block to return a dummy object that signals when the information is not available:
Invoke-Command -ComputerName $Computer -ScriptBlock {
$result = Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\O365ProPlusRetail*
if (-not $result) { [pscustomobject] @{} } else { $result }
} -ErrorAction SilentlyContinue -ErrorVariable Problem |
Select-Object pscomputername, DisplayName, DisplayVersion
[pscustomobject] @{}
creates a custom object without properties, to which the remoting infrastructure automatically adds the .PSComputerName
property (among others) on local deserialization; Select-Object
will then implicitly add empty .DisplayName
and .DisplayVersion
properties.