属性有值但无法选择它

时间:2018-01-26 19:57:54

标签: powershell powershell-v2.0 powershell-v5.0 type-accelerators

我有一个函数可以检查注册表中是否有名为Get-InstalledApps的卸载密钥

Function Get-InstalledApps {
    param (
        [Parameter(ValueFromPipeline=$true)]
        [string[]]$ComputerName = $env:COMPUTERNAME,
        [string]$NameRegex = ''
    )

    foreach ($comp in $ComputerName) {
        $keys = '','\Wow6432Node'
        foreach ($key in $keys) {
            try {
                $reg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine', $comp)
                $apps = $reg.OpenSubKey("SOFTWARE$key\Microsoft\Windows\CurrentVersion\Uninstall").GetSubKeyNames()
            } catch {
                continue
            }

            foreach ($app in $apps) {
                $program = $reg.OpenSubKey("SOFTWARE$key\Microsoft\Windows\CurrentVersion\Uninstall\$app")
                $name = $program.GetValue('DisplayName')
                if ($name -and $name -match $NameRegex) {
                    [pscustomobject]@{
                        ComputerName = $comp
                        DisplayName = $name
                        DisplayVersion = $program.GetValue('DisplayVersion')
                        Publisher = $program.GetValue('Publisher')
                        InstallDate = $program.GetValue('InstallDate')
                        UninstallString = $program.GetValue('UninstallString')
                        Bits = $(if ($key -eq '\Wow6432Node') {'64'} else {'32'})
                        Path = $program.name
                    }
                }
            }
        }
    }
}

然后我抓住DisplayName / Version以获得我需要的东西。我目前的问题是它似乎只适用于某些机器。例如:

Get-InstalledApps | Where-Object {$_.Displayname -like "*Citrix Receiver*"}

Name                           Value
----                           -----
InstallDate
ComputerName                   Computer
DisplayName                    Citrix Receiver 4.7
Bits                           64
UninstallString                C:\ProgramData\Citrix\Citrix Receiver 4.7\TrolleyExpress.exe /uninstall /cleanup
Path                           HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\CitrixOnlinePluginPackWeb
Publisher                      Citrix Systems, Inc.                                                              
DisplayVersion                 14.7.0.13011

所以这很棒,我得到了我想要的东西。现在我通常只是在| Select-Object Displayname -ExpandProperty Displayname中管道,它会像我想要的那样返回"Citrix Receiver 4.7"。我的问题是在某些机器上我得到了这个:

Get-InstalledApps | Where-Object {$_.Displayname -like "*Citrix Receiver*"} | Select-Object DisplayName

DisplayName
-----------

就是这样。为什么没有列出价值?如果我尝试expandproperty我会收到错误,因为它说没有任何内容,但显然有些内容或Where-Object在我的搜索中找不到它。同样,在很多情况下,这段代码工作得很好,我得到了我想要的价值,但在很多机器上,我得到的是你上面看到的。

从评论中编辑:

我在用户的机器上运行它,我得到了我发布的结果。如果我在我的机器上运行它,我每次都会得到“Citrix Receiver 4.7”的值。另外,在我的机器上,我没有获得Name和Value列。我运行此代码的机器中只有大约1/4实际上给了我预期的值。 Windows 7与Windows 10的关系?

1 个答案:

答案 0 :(得分:1)

在我看来,你的函数返回[hashtable],但你正在使用它,就像它是一个具有属性的对象。

这恰好适用于Where-Object,因为.Member语法适用于访问[hashtable]值,但它不适用于Select-Object,因为它在实际属性上运行

那你能做什么?

如果您希望将其保留为[hashtable],并坚持在管道中执行此操作,则可以使用ForEach-Object

Get-InstalledApps | 
    Where-Object {$_.Displayname -like "*Citrix Receiver*"} |
    ForEach-Object -Process { $_.DisplayName }

Get-InstalledApps | 
    Where-Object {$_.Displayname -like "*Citrix Receiver*"} |
    ForEach-Object -MemberName Item -ArgumentList DisplayName

您可以做的另一件事是更改函数以返回对象。

使用[hashtable]这很容易做到;所以说你的函数即将返回$hash,而是返回:

New-Object -TypeName PSObject -Property $hash

现在,您可以使用正常的cmdlet套件并让它们按预期工作。

看到你的代码后,

编辑,看起来你已经将哈希表转换为一个对象了,但你的输出却说不然。如果是这种情况,它不会显示为NameValue列,所以我仍然认为出现了错误,输出为[hashtable]

编辑2:,其中包含有关平台差异的评论信息,这似乎正在发生,因为对象转换是使用PowerShell v3中添加的[pscustomobject] type accelerator完成的。由于有问题的机器运行的是Windows 7,它可能正在运行v2(这是Win 7附带的)。

建议:

  1. 摆脱Windows 7。
  2. 如果您不能这样做,请在该计算机上升级PowerShell(Windows Management Framework)。
  3. 无论哪种方式,请使用上面发布的New-Object