powershell 如何使用卸载路径卸载MSI

bwitn5fc  于 2023-03-30  发布在  Shell
关注(0)|答案(2)|浏览(240)

我试图得到一组应用程序的卸载路径并卸载它们。到目前为止,我可以得到卸载路径的列表。但我很难真正卸载这些程序。
到目前为止,我的代码是。

$app = @("msi1", "msi2", "msi3", "msi4")
     $Regpath = @(
                    'HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*'
                    'HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*'
                )
                   
    foreach ($apps in $app){
    $UninstallPath = Get-ItemProperty $Regpath | where {$_.displayname -like "*$apps*"} | Select-Object -Property UninstallString
    
    $UninstallPath.UninstallString
    #Invoke-Expression UninstallPath.UninstallString
    #start-process "msiexec.exe" -arg "X $UnistallPath /qb" - wait
    }

这将返回以下结果:

MsiExec.exe /X{F17025FB-0401-47C9-9E34-267FBC619AAE}
    MsiExec.exe /X{20DC0ED0-EA01-44AB-A922-BD9932AC5F2C}
    MsiExec.exe /X{29376A2B-2D9A-43DB-A28D-EF5C02722AD9}
    MsiExec.exe /X{18C9B6D0-DCDC-44D8-9294-0ED24B080F0C}

我正在努力寻找执行这些卸载路径,并实际卸载MSI。
我试过使用Invoke-Expression $UninstallPath.UninstallString,但它只显示windows安装程序,并给我msiexec的选项。
我也试过使用start-process "msiexec.exe" -arg "X $UnistallPath /qb" - wait,但这给出了同样的问题。

abithluo

abithluo1#

注:

  • 这一答复回答了所提出的问题。
  • js2010's helpful answer显示了一个更方便的替代方案,通过PackageManagement模块的Get-Package和**Uninstall-Package**cmdlet避免了原来的问题。Uninstall-Package支持卸载MSI安装的软件(-ProviderName msi,但似乎 * 不 *“程序”(-ProviderName Programs);我不清楚是否支持卸载 Windows Update 软件包(-ProviderName msu)。

但是,请注意,这些提供程序仅(直接)在 Windows PowerShell[1]中可用-相比之下,PowerShell (Core)从v7.3.3开始完全缺少这些包提供程序,并且(对我来说)不清楚是否会添加它们。

问题:

  • 存储在UninstallString/QuietUninstallString注册表值[2]中的卸载命令行是为来自-* cmd.exe * 的 no-shell /调用而设计的。
  • 因此,如果您将它们传递给Invoke-Expression,则它们可以从PowerShell**失败 *,即如果它们包含 * 未加引号的 * 字符,这些字符在cmd.exe外部没有特殊含义,但在PowerShell中是 * 元字符 *,这适用于您的情况下的{}
    解决方案

您有两种选择:

*(a)只需将卸载字符串原样传递给cmd /c

  • 请注意,与直接从PowerShell或直接从cmd.exe调用msiexec.exe不同,通过cmd /c调用会导致msiexec的 * 同步 * 执行,这是理想的。
    ***(B)将卸载字符串拆分为可执行文件和参数列表,允许您通过Start-Process**调用命令,可以更好地控制调用。
  • 请确保使用-Wait开关,以确保安装在脚本继续之前完成。

注意:以下命令假定卸载字符串包含在变量$UninstallString(代码中的$UninstallPath.UninstallString的等价物)中:

执行(a):

# Simply pass the uninstallation string (command line) to cmd.exe
# via `cmd /c`. 
# Execution is synchronous (blocks until the command finishes).
cmd /c $UninstallString

$exitCode = $LASTEXITCODE

然后可以查询自动$LASTEXITCODE变量以获得命令行的 * 退出代码 *。

(B)的执行情况:

# Split the command line into executable and argument list.
# Account for the fact that the executable name may be double-quoted.
if ($UninstallString[0] -eq '"') {
    $unused, $exe, $argList = $UninstallString -split '"', 3
}
else {
    $exe, $argList = $UninstallString -split ' ', 2
}

# Use Start-Process with -Wait to wait for the command to finish.
# -PassThru returns an object representing the process launched,
# whose .ExitCode property can then be queried.
$ps = if ($argList) {
        Start-Process -Wait -PassThru $exe $argList
      } else {
        Start-Process -Wait -PassThru $exe 
      }
$exitCode = $ps.ExitCode

您还可以添加-NoNewWindow来防止 console 基于程序的卸载命令行在新的控制台窗口中运行,但请注意,通过Start-Process捕获其stdout / stderr输出的唯一方法是使用-RedirectStandardOutput/-RedirectStandardError参数将其重定向到 files

特定版本/未来改进:

基于Start-Process的方法很麻烦,原因有两个:

  • 您不能传递 * 整个命令行 *,而必须分别指定可执行文件和参数。
  • GitHub proposal #14347的目标是增加对传递整个命令行的支持。
  • Windows PowerShell(其最新和 * 最终 * 版本是5.1)中,您不能将 * 空 * 字符串或数组传递给(位置暗示)-ArgumentList参数(因此需要上面的两个单独调用)。
  • 此问题已在跨平台、按需安装的PowerShell (Core)版本(版本6及更高版本)中得到修复。

[1]如果你不介意额外的开销,你可以(暂时)从PowerShell(核心)导入Windows PowerShell PackageManagement模块,使用Windows PowerShell compatibility feature
Import-Module -UseWindowsPowerShell PackageManagement .
[2]如您的问题所示,它们存储在HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Uninstall(64位应用程序)和HKEY_LOCAL_MACHINE\Wow6432Node \Software\Microsoft\Windows\CurrentVersion\Uninstall(32位应用程序)注册表项中。

7uhlpewt

7uhlpewt2#

或者,例如:

get-package *chrome* | uninstall-package

相关问题