直接从 msi 位置路径和 for 循环卸载时出现问题

问题描述

我尝试卸载 msi 文件,但是当我通过数组尝试此操作时出现错误(找不到安装包)

当我做同样的事情但不在数组中时 - 它有效

for ($i=0; $i -lt $msiArrayClean.length; $i++){
  
        Write-Host $msiArrayClean[$i]
        & msiexec.exe /x $msiArrayClean[$i]

}

here the output of Write Host

我是如何来到 $msiArrayClean

 $msiCache = get-wmiobject Win32_Product | Where-Object Name -like "*7-ZiP*"  | Format-Table LocalPackage -AutoSize -HideTableHeaders
    $msiString = $msiCache | Out-String
    $msiArrayWithEmptyLines = $msiString -split "`n"
    $msiArray = $msiArrayWithEmptyLines.Split('',[System.StringSplitOptions]::RemoveEmptyEntries)
    $msiArrayCleanString = $msiArray | Out-String
    $msiArrayClean = $msiArrayCleanString -split "`n"

解决方法

我不喜欢接触 WMI,因为它的性能是问题所在。我更喜欢通过注册表来做,它对我有用很多次。注释中的代码说明。

CreateMatrix = Matrix

编辑:在 Nehat 的评论之后添加了带有 msi 路径的解决方案,因为这对我有用(我试图最小化代码:))

$name = "7-zip"

#Get all items from registry
foreach ($obj in Get-ChildItem "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall") {
    #Get DisplayName property of registry
    $dname = $obj.GetValue("DisplayName")
    #Search for given name
    if ($dname -like "*$name*") {
        #Get uninstall string (it gets you msiexec /I{APPID})
        $uninstString = $obj.GetValue("UninstallString")
        foreach ($line in $uninstString) {
            #Getting GUID from "{" to "}""
            $found = $line -match '(\{.+\}).*'
            if ($found) {
                #If found - get GUID
                $appid = $matches[1]
                Write-Output "About to uninstall app $appid"
                #Start uninstallation
                Start-Process "msiexec.exe" -arg "/X $appid /qb" -Wait
            }
        }
    }
}
,

前面的一些警告:

  • Format-* cmdlet 输出对象,其唯一目的是向 PowerShell 的输出格式系统提供格式说明 - 参见 this answer。简而言之:只使用 Format-* cmdlet 来格式化数据用于显示,永远不要用于后续的程序化处理

  • CIM cmdlet(例如 Get-CimInstance)取代了 PowerShell v3(2012 年 9 月发布)中的 WMI cmdlet(例如 Get-WmiObject)。因此,应该避免使用 WMI cmdlet,尤其是因为 PowerShell (Core)(版本 6 及更高版本),未来所有的努力都将进行,甚至没有了。有关详细信息,请参阅 this answer

  • 不鼓励使用 Win32_Product WMI 类,出于性能原因和潜在的副作用 - 请参阅 this Microsoft article

    • 另一种选择 - 仅在 Windows PowerShell 中可用(不在 PowerShell (Core) 7+ 中) - 是使用以下命令来获取卸载命令行和通过 cmd /c 执行它们:

      Get-Package -ProviderName Programs -IncludeWindowsInstaller | 
        ForEach-Object { $_.meta.attributes['UninstallString'] }
      

如果您需要坚持使用 Win32_Product

# Get the MSI package paths of all installed products,where defined.
$msiCache = (Get-CimInstance Win32_Product).LocalPackage -ne $null

foreach ($msiPackagePath in $msiCache) {
  if (Test-Path -LiteralPath $msiPackagePath) {
    # Note that msiexec.exe runs *asynchronously*.
    # Use Start-Process -Wait to wait for each call to complete.
    & msiexec.exe /x $msiPackagePath
  } else {
    Write-Warning "Package not found: $msiPackagePath"
  }
}