Powershell Item-属性 在使用 Get-ChildItem 存储到数组时未扩展

Powershell Item-Property not expanded when stored to an array with Get-ChildItem

编写符合 Posh 2.0 的脚本(要求),我需要使用注册表库获取服务的详细信息。

然而,当我使用确切的名称(并因此使用 -eq 或 -like)搜索特定服务时,结果不正确,而 -like 使用通配符,这按预期工作。我们该如何解释?

PS > [array]$services=Get-ChildItem HKLM:\SYSTEM\CurrentControlSet\Services | Where-Object {$_.PsChildName -like "*OpenVpnService*" }
PS > $services[0]


    Hive: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services


SKC  VC Name                           Property
---  -- ----                           --------
  0   8 OpenVpnService                 {Type, Start, ErrorControl, ImagePath...}

PS > "'$($services[0].PsChildName)'"
'OpenVpnService'

PS > [array]$services=Get-ChildItem HKLM:\SYSTEM\CurrentControlSet\Services | Where-Object {$_.PsChildName -eq "OpenVpnService" }
PS > $services[0]

SKC  VC Name                           Property
---  -- ----                           --------
  0   8

PS > "'$($services[0].PsChildName)'"
''

PS > [array]$services=Get-ChildItem HKLM:\SYSTEM\CurrentControlSet\Services | Where-Object {$_.PsChildName -like "OpenVpnService" }
PS > $services[0]

    SKC  VC Name                           Property
    ---  -- ----                           --------
      0   8

PS > "'$($services[0].PsChildName)'"
''

更新: 因为我需要一台完全兼容 Posh 2.0 的机器,所以我有一个全新的虚拟机,安装了 Windows 7 SP1 Ultimate,没有任何更新。为什么没有任何更新?因为通过更新机器,我会得到更新的 .NET 版本和 Posh 补丁。我在完全最新的 Windows 10 机器上进行了测试,它运行得非常完美,只要不将输出存储到数组,Windows 7 测试机器也会成功。

在尝试调试情况并缩小问题范围几个小时后,我已经能够确定导致问题的原因。

数组 initialization/casting 失败。简单地包围 the array subexpression operator @( ) 需要投射的内容就解决了这个问题。

最近的 PowerShell 版本(Windows 10 上的 5.1,未更新的 Windows 7 上的 PowerShell 2.0)似乎处理数组的方式发生了变化,尤其是 PowerShell 3.0介绍changes in collections and dictionaries

PS > [array]$services=@(Get-ChildItem HKLM:\SYSTEM\CurrentControlSet\Services | Where-Object {$_.PsChildName -like "*OpenVpnService*" })
PS > $services[0]


    Hive: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services


SKC  VC Name                           Property
---  -- ----                           --------
  0   8 OpenVpnService                 {Type, Start, ErrorControl, ImagePath...}

PS > "'$($services[0].PsChildName)'"
'OpenVpnService'

PS > [array]$services=@(Get-ChildItem HKLM:\SYSTEM\CurrentControlSet\Services | Where-Object {$_.PsChildName -eq "OpenVpnService" })
PS > $services[0]


    Hive: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services


SKC  VC Name                           Property
---  -- ----                           --------
  0   8 OpenVpnService                 {Type, Start, ErrorControl, ImagePath...}

PS > "'$($services[0].PsChildName)'"
'OpenVpnService'

PS > [array]$services=@(Get-ChildItem HKLM:\SYSTEM\CurrentControlSet\Services | Where-Object {$_.PsChildName -like "OpenVpnService" })
PS > $services[0]


    Hive: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services


SKC  VC Name                           Property
---  -- ----                           --------
  0   8 OpenVpnService                 {Type, Start, ErrorControl, ImagePath...}

PS > "'$($services[0].PsChildName)'"
'OpenVpnService'

如果您已经知道服务名称,您可以这样做:

$serviceName = "WinRM"

# registry
$regPath = "HKLM:\SYSTEM\CurrentControlSet\Services$serviceName"
[bool](Get-ItemProperty -Path $regPath -Name DelayedAutoStart -ErrorAction 0)

# WMI
(Get-WmiObject Win32_Service |
    Where-Object { $_.Name -eq $serviceName }).DelayedAutoStart

# result = True

$serviceName = "spooler"

# registry
$regPath = "HKLM:\SYSTEM\CurrentControlSet\Services$serviceName"
[bool](Get-ItemProperty -Path $regPath -Name DelayedAutoStart -ErrorAction 0)

# WMI
(Get-WmiObject Win32_Service |
    Where-Object { $_.Name -eq $serviceName }).DelayedAutoStart

# result = False