2014-11-08 47 views
1

在Powershell的帮助下,我需要找到注册表项,其中值为'Cisco',并从Value name'Uninstallstring'中获取此关键数据。 我知道这听起来有点奇怪,但是这个应用程序在每台计算机上都有不同的卸载字符串。Pwershell.registry搜索项目值其中diplayname like“”

所以

ForEach-Object -InputObject (Get-ChildItem 'HKLM:\software\microsoft\windows\currentversion\uninstall') { 
    $single_item = $_ | Get-Item 
    $single_item_properties = $single_item | Get-ItemProperty | Select-Object -Property DisplayName,UninstallString | Where-Object {($_.DisplayName -like '*Cisco*TSP*')} 
    $uninstall_str = ($single_item_properties | Select UninstallString) 
    $str_to_execute=$uninstall_str.UninstallString -replace '" .*','"' 
    $str_to_execute 
    Start-Process -FilePath $str_to_execute -ArgumentList '-s','-f1"\\sandbox\Common.Installs\Utils\un.iss"' -Wait -PassThru 
} 

这个脚本给我们的错误

UninstallString


"C:\Program Files (x86)\InstallShield Installation Information{01A05F96-E34D-4308-965C-65DCA4AF114D}\setup.exe"

Start-Process : This command cannot be executed due to the error: The system cannot find the file specified.

的问题是,其结果是不字符串类型。

我无法将其转换为字符串。

+0

顺便说一句,在编辑我的问题注意到目前还不清楚你是否真的需要一个循环。是否有可能多个密钥可能匹配'* Cisco * TSP *',并且您希望为所有这些密钥执行卸载命令,或者每台计算机上只有一个密钥?在后一种情况下,我不认为需要使用** ForEach-Object **或** foreach **,因为您只是从注册表中检索单个字符串值的数据。 – 2014-11-09 06:28:20

+0

在我想运行此脚本的每台计算机上,只安装一个思科产品,因此搜索查询应该可以工作 – mnovak 2014-11-10 07:18:25

+0

再次考虑,您仍然需要迭代,因为您不知道密钥的名称并需要与**在哪里**过滤器。但是,请参阅我的更新答案。 – 2014-11-13 17:28:52

回答

0

这里有几个问题。

  1. 虽然的foreach对象确实-InputObject参数,它的设计主要采取管道输入。由于文件说,

    When you use the InputObject parameter with ForEach-Object, instead of piping command results to ForEach-Object, the InputObject value—even if the value is a collection that is the result of a command, such as –InputObject (Get-Process)—is treated as a single object. Because InputObject cannot return individual properties from an array or collection of objects, it is recommended that if you use ForEach-Object to perform operations on a collection of objects for those objects that have specific values in defined properties, you use ForEach-Object in the pipeline

    在你的代码中,脚本块被执行一次,并且$ single_item实际上是包含GET-ChildItem整个输出数组。为了对结果进行一个元素在时间迭代,你需要或者管道输出到的foreach对象 ...

    Get-ChildItem 'HKLM:\software\microsoft\...' | ForEach-Object { 
    

    ...或者更好的是,使用的foreach控制结构,其通常运行速度更快(尽管它使用更多的内存):

    foreach ($single_item in (Get-ChildItem 'HKLM:\software\microsoft\...')) { 
    
  2. 管道每个元素GET-项目是多余的。您可以直接输入Get-ItemProperty

  3. 您不需要选择一个属性以便通过过滤它Where-Object。因此,使用Select-Object -Property DisplayName,UninstallString是多余的,它会创建一个包含两个属性的PSCustomObject,然后稍后在代码中检索该PSCustomObject的该属性。只需使用先过滤对象,然后获得UninstallString| Select -ExpandProperty UninstallString的值。

    (关于使用-ExpandPropery开关原因的说明,请参见this answer

  4. 使用-ExpandProperty,你会得到错误,如果任何键返回不具有UninstallString属性,因此您可能需要将-ErrorAction SilentlyContinue添加到您的Select-Object声明中。

全部放在一起:

foreach ($single_item in (Get-ChildItem 'HKLM:\software\microsoft\windows\currentversion\uninstall')) { 
    $uninstall_str = $single_item ` 
    | Get-ItemProperty ` 
    | ?{$_.DisplayName -like '*Cisco*TSP*'} ` 
    | Select-Object -ExpandProperty UninstallString -ErrorAction SilentlyContinue 
    $str_to_execute = $uninstall_str -replace '" .*','"' 
    Start-Process -FilePath $str_to_execute -ArgumentList '-s','-f1"\\sandbox\Common.Installs\Utils\un.iss"' -Wait -PassThru } 
} 

如果有保证不超过一个匹配的物品,你可以做更简洁这样的:

$str_to_execute = (
    Get-ChildItem 'HKLM:\software\microsoft\windows\currentversion\uninstall' ` 
    | Get-ItemProperty ` 
    | ?{$_.DisplayName -like 'Microsoft*'} 
).uninstallstring $uninstall_str -replace '" .*','"' 

更紧凑版本将实际上工作,即使PowerShell v3 +中有多个匹配键,但在v2中,如果有多个键,它将返回null。

顺便说一句,Where-Object的缩写。同样,的foreach对象(只有当你使用它作为一个管道过滤器,但是这是你如何应该无论如何使用它。)的缩写

0

您显示的输出看起来与您提供的代码不匹配。当我执行你的代码时,我会根据自己的搜索得到uninstallstring。当我第一次看到输出时,我以为“哦......他忘记了他正在传递一个属性为UninstallString的对象以启动 - 处理”。但是当我看着你的代码时,我可以看到你通过做$uninstall_str.UninstallString来解释这一点。所以,我不知道究竟是什么错,但一个改进是使用-ExpandPropertySelect-Object

$uninstall_str = $single_item_properties | Select -ExpandProperty UninstallString 
$str_to_execute=$uninstall_str -replace '" .*','"' 

但我们可以做出一个衬垫,如果你喜欢。

$str_to_execute = ($single_item_properties).UninstallString -replace '" .*','"'