Get-WmiObject to combine to outputs - powershell

I was executing below script to obtain the server patch version of Skype for business servers.
I need the output as server patch name, version and computername.
$x = Get-Content "E:\temp\servers.txt"
foreach ($y in $x)
{
Invoke-Command -ComputerName $y -scriptblock {Get-WmiObject -query ‘select name, version from win32_product’ | where {$_.name -like “*Skype for Business server 2015, core*”}} | Select-object name, Version, #{Name='ComputerName';Expression={$y}} | ft -AutoSize
}
But I am receiving output as below
Name Version ComputerName
---- ------- ------------
Skype for Business Server 2015, Core Components 6.0.9319.598 D221412xxxxxx
Name Version ComputerName
---- ------- ------------
Skype for Business Server 2015, Core Components 6.0.9319.598 D221412xxxxxxxx
Name Version ComputerName
---- ------- ------------
Skype for Business Server 2015, Core Components 6.0.9319.598 D221412xxxxxx
Name Version ComputerName
---- ------- ------------
Skype for Business Server 2015, Core Components 6.0.9319.598 D221412xxxxxxx
Name Version ComputerName
---- ------- ------------
Skype for Business Server 2015, Core Components 6.0.9319.598 D221412xxxxxx
I don't need my header tiles in every line of output. Any suggestions?

You are getting headers for each computer because the select
statement is inside the foreach loop.
Invoke-command accepts multiple
computers so you dont need a foreach loop.
use server-side filtering
where possible.
$x = Get-Content "E:\temp\servers.txt"
Invoke-Command -ComputerName $x -scriptblock {Get-WmiObject -query "select name, version from win32_product where name like 'Skype for Business server 2015, Core%'"} |
Select-object PSComputerName,name, Version
For future:
Use Get-CimInstance because Get-wmiobject is deprecated.
Do not use win32_product because it can potentially lead to msi corruption. Use
the registry instead.
https://community.idera.com/database-tools/powershell/powertips/b/tips/posts/find-installed-software

Related

Invoke-command not returning any value when get-itemproperty return null

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.

Powershell Script to fetch netback client and SMTP relay

Is there anyway to fetch value for "netbackup client version" and "whether the server requires SMTP relay or not" using powershell script? Below script I used to get the citrix version in the windows server not sure how to get the other values.
powershell "$Citrix=(Get-WmiObject -Class Win32_Product | Sort-object Name | select Name, version | Where { $_.Name -match 'Citrix'}).version -join ',';Write-Host "Citrix = $Citrix";' '"
Dependent services can be looked up with Get-Service cmdlet. I don't have Netback, so let's use Sql Server as an example. The Agent depends on Sql Server like so,
Get-Service -Name 'SQLAgent$SQLI001' -RequiredServices
Status Name DisplayName
------ ---- -----------
Stopped MSSQL$SQLI001 SQL Server (SQLI001)
As for how to get the software version, see if the binary contains the version. This approach requires you to know the binary path. Like so,
(Get-ChildItem E:\MSSQL12.SQLI001\MSSQL\Binn\SQLAGENT.EXE).VersionInfo | Select-Object -Property ProductVersion,FileVersion
ProductVersion FileVersion
-------------- -----------
12.0.5207.0 2014.0120.5207.00 ((SQL14_PCU_main).170703-0132 )

Powershell get installed program script doesn't return computer name

I'm trying to get a list of installed programs off a group of remote servers. I'm able to get the program name but not return the system name. Below is my script.
$computerfile = get-content "D:\Users\Admin\Docs\PrimaryServers.txt"
ForEach ($computer in $computerfile) {
Get-WmiObject Win32_Product -ComputerName $computer |
Select-Object SystemName,Name,Version,PackageName,Installdate,Vendor |
Format-Table -AutoSize
}
Below is my output
First, -ComputerName can take an array of names so by looping you are going to increase the time because the loop will be in serial where utilizing the array for computername will be in parallel.
Second, it's best practice to use the CIM cmdlets in place of the WMI cmdlets. They operate over WSMAN by default and are easier to work with.
Third, Win32_Product forces a consistency check so reading the Uninstall registry keys is usually superior.
Lastly, SystemName isn't a property name that is returned by Get-WMIObject. PSComputerName is the property you are looking for and you can make a Calculated Property from it.
$computerfile = get-content "D:\Users\Admin\Docs\PrimaryServers.txt"
Get-CimInstance Win32_Product -ComputerName $Computerfile |
Select-Object #{n=SystemName;e={$_.PSComputerName}},Name,Version,PackageName,Installdate,Vendor |
Format-Table -AutoSize
Another approach is to use the Invoke-Command where it automatically extends the result with the PSComputerName column
First build up the script blocks to use as query
Block 1 is my approach for both x32 and x64 implementations. Consider this as an alternative because I has some issues with the proposed implementation.
$block1={
# Query x64 bit applications
$queryPath="HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*"
Get-ItemProperty $queryPath | Select-Object -Property DisplayName, Publisher, InstallDate, DisplayVersion
# Query x32 bit applications
$queryPath="HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*"
Get-ItemProperty $queryPath | Select-Object -Property DisplayName, Publisher, InstallDate, DisplayVersion
}
Block 2 is the proposed approach on this question
$block2={
Get-CimInstance Win32_Product | Select-Object Name,Version,PackageName,Installdate,Vendor
}
For either $block1 or $block2 execute remotely on a server list
Invoke-Command -ComputerName $computernames -ScriptBlock $block1
And one record looks like this
DisplayName : Microsoft Visual C++ 2013 x86 Additional Runtime - 12.0.21005
Publisher : Microsoft Corporation
InstallDate : 20161202
DisplayVersion : 12.0.21005
PSComputerName : MECDEVAPP01
RunspaceId : 4b8cc747-da25-4c6e-b108-0ca3138c0335

"Get-WmiObject Win32_QuickFixEngineering" returns "InstalledOn" with a future date

I want to check via PowerShell for the latest date when security updates were installed. Therefore I'd like to use something like this:
Get-WmiObject Win32_QuickFixEngineering | Where-Object {
$_.Description -eq "Security Update"
}
I tried using Get-CimInstance -Class, but that's not working on Windows 7.
Output is like this:
Source Description HotFixID InstalledBy InstalledOn
------ ----------- -------- ----------- -----------
VM10111 Security Update KB4014579 NT-AUTORITÄT\SYSTEM 05.11.2017 00:00:00
Is the date incorrectly formatted or incorrectly displayed? How to avoid this?
The date is being displayed in MM.DD.YYYY format. So the actual date that is being represented is 11th May 2017 and it is not 5th November 2017.
You Can also try the command
Get-HotFix | where {$_.Description -eq 'Security Update'}
to get the Installed security patches

Using Select-Object on two adjacent lines in a row outputs a "broken" list

Consider the following example:
if ([Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SMO") -eq $null) {return}
$server = New-Object Microsoft.SqlServer.Management.Smo.Server servername
$server | Select Name, Product, Edition, VersionString
$server.Databases | select name,CompatibilityLevel
If executed line per line on the command line, the output will somewhat resemble the following:
Name Product Edition VersionString
---- ------- ------- -------------
SERVERNAME Microsoft SQL Server Developer Edition (64-bit) 12.0.4213.0
Name CompatibilityLevel
---- ------------------
Database123456789 Version100
Database234567890 Version100
If executed as a script, the output looks like the following (note the missing "Version100"...):
Name Product Edition VersionString
---- ------- ------- -------------
SERVERNAME Microsoft SQL Server Developer Edition (64-bit) 12.0.4213.0
Database123456789
Database234567890
Even changing the script like this won't help with the output being messed up.
if ([Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SMO") -eq $null) {return}
$server = New-Object Microsoft.SqlServer.Management.Smo.Server servername
$server | Select Name, Product, Edition, VersionString
Write-Host "Databases on $($server.Name):"
$server.Databases | select name,CompatibilityLevel
Instead the output will look like this:
Name Product Edition VersionString
---- ------- ------- -------------
SERVERNAME Microsoft SQL Server Developer Edition (64-bit) 12.0.4213.0
Databases on SERVERNAME:
Database123456789
Database234567890
How can I force PowerShell to output the CompatibilityLevel member?
You could use the Format-Table cmdlet to force the output:
$server.Databases | select name,CompatibilityLevel | Format-Table