查找已安装软件的最常用建议方法是查询一个或三个注册表项。这将是我的第一个解决方案,除了我的公司尚未配置服务器接受PSRemoting。任何reg查询只返回Kerberos身份验证错误。我可以在各个服务器上启用PSRemoting,但我的团队支持30K系统。所以解决方案就出来了。
最重要的是,我们正在将Symantec Endpoint Protection从v.11升级到v.12,我想要一个简单的检查来查找服务器上安装的版本。有没有其他方法可以找到Win32_Product和注册表查询以外的版本?
答案 0 :(得分:4)
我远程使用注册表,没有PSRemoting。这是我编写的函数,每天用于查询软件。
Function Get-RemoteSoftware{
<#
.SYNOPSIS
Displays all software listed in the registry on a given computer.
.DESCRIPTION
Uses the SOFTWARE registry keys (both 32 and 64bit) to list the name, version, vendor, and uninstall string for each software entry on a given computer.
.EXAMPLE
C:\PS> Get-RemoteSoftware -ComputerName SERVER1
This shows the software installed on SERVER1.
#>
param (
[Parameter(mandatory=$true,ValueFromPipelineByPropertyName=$true)][string[]]
# Specifies the computer name to connect to
$ComputerName
)
Process {
foreach ($Computer in $ComputerName)
{
#Open Remote Base
$reg=[microsoft.win32.registrykey]::OpenRemoteBaseKey('LocalMachine',$Computer)
#Check if it's got 64bit regkeys
$keyRootSoftware = $reg.OpenSubKey("SOFTWARE")
[bool]$is64 = ($keyRootSoftware.GetSubKeyNames() | ? {$_ -eq 'WOW6432Node'} | Measure-Object).Count
$keyRootSoftware.Close()
#Get all of they keys into a list
$softwareKeys = @()
if ($is64){
$pathUninstall64 = "SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall"
$keyUninstall64 = $reg.OpenSubKey($pathUninstall64)
$keyUninstall64.GetSubKeyNames() | % {
$softwareKeys += $pathUninstall64 + "\\" + $_
}
$keyUninstall64.Close()
}
$pathUninstall32 = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall"
$keyUninstall32 = $reg.OpenSubKey($pathUninstall32)
$keyUninstall32.GetSubKeyNames() | % {
$softwareKeys += $pathUninstall32 + "\\" + $_
}
$keyUninstall32.Close()
#Get information from all the keys
$softwareKeys | % {
$subkey=$reg.OpenSubKey($_)
if ($subkey.GetValue("DisplayName")){
$installDate = $null
if ($subkey.GetValue("InstallDate") -match "/"){
$installDate = Get-Date $subkey.GetValue("InstallDate")
}
elseif ($subkey.GetValue("InstallDate").length -eq 8){
$installDate = Get-Date $subkey.GetValue("InstallDate").Insert(6,".").Insert(4,".")
}
New-Object PSObject -Property @{
ComputerName = $Computer
Name = $subkey.GetValue("DisplayName")
Version = $subKey.GetValue("DisplayVersion")
Vendor = $subkey.GetValue("Publisher")
UninstallString = $subkey.GetValue("UninstallString")
InstallDate = $installDate
}
}
$subkey.Close()
}
$reg.Close()
}
}
}
答案 1 :(得分:1)
Get-RemoteSoftware运行良好 - 假设远程系统上启动了远程注册表服务。如果不是,您将收到错误。我总是检查这是否已启动,如果没有则启动它,然后在完成后停止它。我想知道这是否是为什么其他伟大的功能收到了下来的选票。
这是一个稍微修改过的版本,它将检查并启动远程注册表服务,并在完成后停止。
Function Get-WmiCustom2([string]$computername,[string]$namespace,[string]$class,[int]$timeout=15,[string]$whereclause='')
{
#Function Get-WMICustom2 by MSFT's Daniele Muscetta
#This is a modified version to add where clause parameter, optional
#Original function: http://blogs.msdn.com/b/dmuscett/archive/2009/05/27/get_2d00_wmicustom.aspx
$ConnectionOptions = new-object System.Management.ConnectionOptions
$EnumerationOptions = new-object System.Management.EnumerationOptions
$timeoutseconds = new-timespan -seconds $timeout
$EnumerationOptions.set_timeout($timeoutseconds)
$assembledpath = "\\" + $computername + "\" + $namespace
$Scope = new-object System.Management.ManagementScope $assembledpath, $ConnectionOptions
try {
$Scope.Connect()
} catch {
$result="Error Connecting " + $_
return $Result
}
$querystring = "SELECT * FROM " + $class + " " + $whereclause
$query = new-object System.Management.ObjectQuery $querystring
$searcher = new-object System.Management.ManagementObjectSearcher
$searcher.set_options($EnumerationOptions)
$searcher.Query = $querystring
$searcher.Scope = $Scope
trap { $_ } $result = $searcher.get()
return $result
}
Function Get-RemoteSoftware{
<#
.SYNOPSIS
Displays all software listed in the registry on a given computer.
.DESCRIPTION
Uses the SOFTWARE registry keys (both 32 and 64bit) to list the name, version, vendor, and uninstall string for each software entry on a given computer.
.EXAMPLE
C:\PS> Get-RemoteSoftware -ComputerName SERVER1
This shows the software installed on SERVER1.
#>
param (
[Parameter(mandatory=$true,ValueFromPipelineByPropertyName=$true)][string[]]
# Specifies the computer name to connect to
$ComputerName
)
Process {
foreach ($Computer in $ComputerName)
{
$ChangeStateBack=$False
$RemoteRegistryObj=""
$ServiceWMIObj=@(get-wmicustom2 -class "win32_service" -namespace "root\cimv2" -whereclause "WHERE name='RemoteRegistry'" -computername $computername –timeout 60 -erroraction stop)
if ($ServiceWMIObj.Count -gt 0) {
$RemoteRegistryObj = $ServiceWMIObj[0]
if ($RemoteRegistryObj.State -ne 'Running') {
$ChangeStateBack=$true
$RemoteRegistryObj.InvokeMethod("StartService",$null) | Out-Null
Start-Sleep -m 1800
#give it a chance to actually start. 1.5 second delay
}
}
#Open Remote Base
$reg=[microsoft.win32.registrykey]::OpenRemoteBaseKey('LocalMachine',$Computer)
#Check if it's got 64bit regkeys
$keyRootSoftware = $reg.OpenSubKey("SOFTWARE")
[bool]$is64 = ($keyRootSoftware.GetSubKeyNames() | ? {$_ -eq 'WOW6432Node'} | Measure-Object).Count
$keyRootSoftware.Close()
#Get all of they keys into a list
$softwareKeys = @()
if ($is64){
$pathUninstall64 = "SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall"
$keyUninstall64 = $reg.OpenSubKey($pathUninstall64)
$keyUninstall64.GetSubKeyNames() | % {
$softwareKeys += $pathUninstall64 + "\\" + $_
}
$keyUninstall64.Close()
}
$pathUninstall32 = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall"
$keyUninstall32 = $reg.OpenSubKey($pathUninstall32)
$keyUninstall32.GetSubKeyNames() | % {
$softwareKeys += $pathUninstall32 + "\\" + $_
}
$keyUninstall32.Close()
#Get information from all the keys
$softwareKeys | % {
$subkey=$reg.OpenSubKey($_)
if ($subkey.GetValue("DisplayName")){
$installDate = $null
if ($subkey.GetValue("InstallDate") -match "/"){
$installDate = Get-Date $subkey.GetValue("InstallDate")
}
elseif ($subkey.GetValue("InstallDate").length -eq 8){
$installDate = Get-Date $subkey.GetValue("InstallDate").Insert(6,".").Insert(4,".")
}
New-Object PSObject -Property @{
ComputerName = $Computer
Name = $subkey.GetValue("DisplayName")
Version = $subKey.GetValue("DisplayVersion")
Vendor = $subkey.GetValue("Publisher")
UninstallString = $subkey.GetValue("UninstallString")
InstallDate = $installDate
}
}
$subkey.Close()
}
$reg.Close()
if ($ChangeStateBack){
$RemoteRegistryObj.InvokeMethod("StopService",$null) | Out-Null
}
}
}
}
这是使用MSFT编写的某个自定义WMI get包装器,因此如果完整地复制此代码段,它将按原样运行。您可以将其修改回标准的get-wmiobject函数,但是没有内置超时。在某些[并非所有罕见]情况下,远程WMI响应程序将无限期地挂起默认WMI,因此会增加超时。 -Dane
答案 2 :(得分:0)
我建议阅读this scripting guy article,了解为什么Win32_Product与其他选项一样糟糕。我通常使用Win32Reg_AddRemovePrograms,因为我们正在使用安装此类的SCCM。如果你没有使用像@Chris N那样的注册表查询SCCM棒。
PS:\>Measure-Command {gwmi win32reg_addremoveprograms}
Days : 0
Hours : 0
Minutes : 0
Seconds : 0
Milliseconds : 162
Ticks : 1623758
TotalDays : 1.87934953703704E-06
TotalHours : 4.51043888888889E-05
TotalMinutes : 0.00270626333333333
TotalSeconds : 0.1623758
TotalMilliseconds : 162.3758
答案 3 :(得分:-1)
实际上是后续行动嘿!脚本专家文章 Use PowerShell to Find Installed Software讨论了获取该信息的其他更有效方法。简而言之,使用以下两个命令之一:
Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\* | Select-Object DisplayName, DisplayVersion, Publisher, InstallDate | Format-Table –AutoSize
Get-ItemProperty HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\* | Select-Object DisplayName, DisplayVersion, Publisher, InstallDate | Format-Table –AutoSize