属性 有值但不能 select

Property has a value but cannot select it

我有一个功能可以检查注册表中是否有名为 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 并且它会 return "Citrix Receiver 4.7" 就像我想要的那样。我的问题是在某些机器上我得到这个:

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

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

就是这样。为什么没有列出值?如果我尝试 expandproperty 我会得到一个错误,因为它说什么都没有,但显然那里有东西,否则 Where-Object 不会在我的搜索中找到它。同样,在很多情况下,这段代码工作得很好,我得到了我想要的值,但在很多机器上,我得到的是你在上面看到的。

根据评论编辑:

我 运行 在用户的机器上执行此操作,我得到了我发布的结果。如果我 运行 它在我的机器上,我每次都会得到值 "Citrix Receiver 4.7" 。此外,在我的机器上,我没有得到名称和值列。只有大约 1/4 的机器我 运行 这段代码实际上给了我预期的价值。 Windows 7 vs Windows 10 件事?

在我看来你的函数 return 是一个 [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

您可以做的另一件事是将函数更改为 return 一个对象。

这真的很容易做到 [hashtable];所以说你的函数即将 return $hash,而不是 return:

New-Object -TypeName PSObject -Property $hash

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


编辑: 看到您的代码后,您似乎已经将哈希表转换为对象,但您的输出却另有说明。如果是这种情况,它不会显示为 NameValue 列,所以我仍然认为有问题并且输出是 [hashtable].

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

建议:

  1. 干掉Windows7.
  2. 如果您不能这样做,请升级该机器上的 PowerShell(Windows 管理框架)。
  3. 无论哪种方式,请使用上面发布的 New-Object