【问题标题】:How can I uninstall an application using PowerShell?如何使用 PowerShell 卸载应用程序?
【发布时间】:2010-09-11 22:17:52
【问题描述】:

是否有一种简单的方法可以使用 PowerShell 连接到标准的“添加或删除程序”功能以卸载现有应用程序?或者检查应用程序是否已安装?

【问题讨论】:

    标签: windows powershell windows-installer uninstallation


    【解决方案1】:
    $app = Get-WmiObject -Class Win32_Product | Where-Object { 
        $_.Name -match "Software Name" 
    }
    
    $app.Uninstall()
    

    编辑: Rob 找到了另一种使用 Filter 参数的方法:

    $app = Get-WmiObject -Class Win32_Product `
                         -Filter "Name = 'Software Name'"
    

    【讨论】:

    • 差不多就是这样,我想说使用IdentifyingNumber而不是名称可能会更好,以防万一。
    • 经过一番研究还可以使用Get-WmiObject的-filter子句: $app = Get-WmiObject -Class Win32_Product -filter "select * from Win32_Product WHERE name = 'Software Name'"
    • 请注意,查看 WMI 仅适用于通过 MSI 安装的产品。
    • 这个 WMI 类需要 FOREVER 来枚举。我建议 Jeff 更新代码以包含 Rob 的提示。
    • (gwmi Win32_Product | ? Name -eq "Software").uninstall() 一点代码高尔夫。
    【解决方案2】:

    要修复 Jeff Hillman 帖子中的第二种方法,您可以这样做:

    $app = Get-WmiObject 
                -Query "SELECT * FROM Win32_Product WHERE Name = 'Software Name'"
    

    或者

    $app = Get-WmiObject -Class Win32_Product `
                         -Filter "Name = 'Software Name'"
    

    【讨论】:

    • 只是提醒...我发现使用“-Query”而不是“-Filter”选项不会返回 WmiObject,因此它没有“卸载”方法.
    • 此解决方案无法通过exe获取已安装的程序,但msi。因此,它仅适用于通过 microsoft installer(msi) 安装的程序
    【解决方案3】:

    为了在这篇文章中添加一点内容,我需要能够从多个服务器中删除软件。我用杰夫的回答引导我这样做:

    首先我得到了一个服务器列表,我使用了AD 查询,但是您可以根据需要提供计算机名称数组:

    $computers = @("computer1", "computer2", "computer3")
    

    然后我遍历它们,将 -computer 参数添加到 gwmi 查询中:

    foreach($server in $computers){
        $app = Get-WmiObject -Class Win32_Product -computer $server | Where-Object {
            $_.IdentifyingNumber -match "5A5F312145AE-0252130-432C34-9D89-1"
        }
        $app.Uninstall()
    }
    

    我使用 IdentificationNumber 属性而不是名称进行匹配,以确保我卸载了正确的应用程序。

    【讨论】:

    • 这个解决方案简直太可爱了
    【解决方案4】:

    我会做出自己的一点贡献。我需要从同一台计算机上删除一个包列表。这是我想出的脚本。

    $packages = @("package1", "package2", "package3")
    foreach($package in $packages){
      $app = Get-WmiObject -Class Win32_Product | Where-Object {
        $_.Name -match "$package"
      }
      $app.Uninstall()
    }
    

    我希望这被证明是有用的。

    请注意,我欠 David Stetler 的功劳,因为它是基于他的。

    【讨论】:

      【解决方案5】:

      用途:

      function remove-HSsoftware{
      [cmdletbinding()]
      param(
      [parameter(Mandatory=$true,
      ValuefromPipeline = $true,
      HelpMessage="IdentifyingNumber can be retrieved with `"get-wmiobject -class win32_product`"")]
      [ValidatePattern('{[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}}')]
      [string[]]$ids,
      [parameter(Mandatory=$false,
                  ValuefromPipeline=$true,
                  ValueFromPipelineByPropertyName=$true,
                  HelpMessage="Computer name or IP adress to query via WMI")]
      [Alias('hostname,CN,computername')]
      [string[]]$computers
      )
      begin {}
      process{
          if($computers -eq $null){
          $computers = Get-ADComputer -Filter * | Select dnshostname |%{$_.dnshostname}
          }
          foreach($computer in $computers){
              foreach($id in $ids){
                  write-host "Trying to uninstall sofware with ID ", "$id", "from computer ", "$computer"
                  $app = Get-WmiObject -class Win32_Product -Computername "$computer" -Filter "IdentifyingNumber = '$id'"
                  $app | Remove-WmiObject
      
              }
          }
      }
      end{}}
       remove-hssoftware -ids "{8C299CF3-E529-414E-AKD8-68C23BA4CBE8}","{5A9C53A5-FF48-497D-AB86-1F6418B569B9}","{62092246-CFA2-4452-BEDB-62AC4BCE6C26}"
      

      它没有经过全面测试,但它在 PowerShell 4 下运行。

      我已经运行了这里看到的 PS1 文件。让它从AD 中检索所有系统并尝试卸载所有系统上的多个应用程序。

      我使用 IdentificationNumber 来搜索 David Stetler 输入的软件原因。

      未测试:

      1. 不在脚本中的函数调用中添加 id,而是使用参数 ID 启动脚本
      2. 使用超过 1 个计算机名称调用脚本自动从函数中检索
      3. 从管道中检索数据
      4. 使用 IP 地址连接系统

      它没有什么:

      1. 如果在任何给定系统上确实找到了该软件,它不会提供任何信息。
      2. 它不提供有关卸载失败或成功的任何信息。

      我无法使用uninstall()。尝试我得到一个错误,告诉我为具有 NULL 值的表达式调用方法是不可能的。相反,我使用了 Remove-WmiObject,它似乎完成了相同的操作。

      注意:如果没有给出计算机名称,则会从 Active Directory 中的所有系统中删除该软件。

      【讨论】:

        【解决方案6】:

        我发现不推荐使用 Win32_Product 类,因为它会触发修复并且未对查询进行优化。 Source

        我从 Sitaram Pamarthi 找到了 this post,如果您知道应用程序 guid,则可以使用脚本进行卸载。他还提供了另一个脚本来非常快速地搜索应用程序here

        像这样使用:.\uninstall.ps1 -GUID {C9E7751E-88ED-36CF-B610-71A1D262E906}

        [cmdletbinding()]            
        
        param (            
        
         [parameter(ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
         [string]$ComputerName = $env:computername,
         [parameter(ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true,Mandatory=$true)]
         [string]$AppGUID
        )            
        
         try {
          $returnval = ([WMICLASS]"\\$computerName\ROOT\CIMV2:win32_process").Create("msiexec `/x$AppGUID `/norestart `/qn")
         } catch {
          write-error "Failed to trigger the uninstallation. Review the error message"
          $_
          exit
         }
         switch ($($returnval.returnvalue)){
          0 { "Uninstallation command triggered successfully" }
          2 { "You don't have sufficient permissions to trigger the command on $Computer" }
          3 { "You don't have sufficient permissions to trigger the command on $Computer" }
          8 { "An unknown error has occurred" }
          9 { "Path Not Found" }
          9 { "Invalid Parameter"}
         }
        

        【讨论】:

          【解决方案7】:

          编辑:多年来,这个答案得到了相当多的支持。我想添加一些cmets。从那以后我就没有使用过 PowerShell,但我记得观察到一些问题:

          1. 如果以下脚本的匹配项多于 1,则它不起作用,您必须附加将结果限制为 1 的 PowerShell 过滤器。我相信它是-First 1,但我不确定。随意编辑。
          2. 如果应用程序不是由 MSI 安装的,它就不能工作。之所以写成下面这样,是因为它修改了 MSI 以在不干预的情况下进行卸载,这在使用本机卸载字符串时并不总是默认情况。

          使用 WMI 对象需要很长时间。如果您只知道要卸载的程序的名称,这将非常快。

          $uninstall32 = gci "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall" | foreach { gp $_.PSPath } | ? { $_ -match "SOFTWARE NAME" } | select UninstallString
          $uninstall64 = gci "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall" | foreach { gp $_.PSPath } | ? { $_ -match "SOFTWARE NAME" } | select UninstallString
          
          if ($uninstall64) {
          $uninstall64 = $uninstall64.UninstallString -Replace "msiexec.exe","" -Replace "/I","" -Replace "/X",""
          $uninstall64 = $uninstall64.Trim()
          Write "Uninstalling..."
          start-process "msiexec.exe" -arg "/X $uninstall64 /qb" -Wait}
          if ($uninstall32) {
          $uninstall32 = $uninstall32.UninstallString -Replace "msiexec.exe","" -Replace "/I","" -Replace "/X",""
          $uninstall32 = $uninstall32.Trim()
          Write "Uninstalling..."
          start-process "msiexec.exe" -arg "/X $uninstall32 /qb" -Wait}
          

          【讨论】:

          • 谢谢!我正在尝试将它与-like "appNam*" 一起使用,因为版本在名称中并且它会更改,但它似乎没有找到该程序。有什么想法吗?
          • 查找 powershell 的 -like 函数,找出使用哪个过滤器以及如何使其正确匹配您的字符串。只需使用 shell 进行测试,一旦正确,请替换 -match :)
          • 这是黄金。就个人而言,我从“/qb”中删除了“b”,这样您就不必看到任何对话框。
          • 快得多:-)
          • 我把它变成了一个带有提示和“我要卸载的东西”信息的 .ps1 脚本。 gist.github.com/chrisfcarroll/e38b9ffcc52fa9d4eb9ab73b13915f5a
          【解决方案8】:

          根据 Jeff Hillman 的回答:

          这是一个您可以添加到 profile.ps1 或在当前 PowerShell 会话中定义的函数:

          # Uninstall a Windows program
          function uninstall($programName)
          {
              $app = Get-WmiObject -Class Win32_Product -Filter ("Name = '" + $programName + "'")
              if($app -ne $null)
              {
                  $app.Uninstall()
              }
              else {
                  echo ("Could not find program '" + $programName + "'")
              }
          }
          

          假设您想卸载Notepad++。只需在 PowerShell 中输入:

          > uninstall("notepad++")

          请注意Get-WmiObject 可能需要一些时间,所以请耐心等待!

          【讨论】:

            【解决方案9】:

            对于我的大多数程序,这篇文章中的脚本都可以完成这项工作。 但是我不得不面对一个无法使用 msiexec.exe 或 Win32_Product 类删除的遗留程序。 (由于某种原因,我得到了出口 0,但程序仍然存在)

            我的解决方案是使用 Win32_Process 类:

            nickdnk的帮助下,这个命令是获取卸载的exe文件路径:

            64位:

            [array]$unInstallPathReg= gci "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall" | foreach { gp $_.PSPath } | ? { $_ -match $programName } | select UninstallString
            

            32 位:

             [array]$unInstallPathReg= gci "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall" | foreach { gp $_.PSPath } | ? { $_ -match $programName } | select UninstallString
            

            你必须清理结果字符串:

            $uninstallPath = $unInstallPathReg[0].UninstallString
            $uninstallPath = $uninstallPath -Replace "msiexec.exe","" -Replace "/I","" -Replace "/X",""
            $uninstallPath = $uninstallPath .Trim()
            

            现在当你有了相关的程序卸载exe文件路径你就可以使用这个命令了:

            $uninstallResult = (Get-WMIObject -List -Verbose | Where-Object {$_.Name -eq "Win32_Process"}).InvokeMethod("Create","$unInstallPath")
            

            $uninstallResult - 将有退出代码。 0代表成功

            上面的命令也可以远程运行——我是使用调用命令完成的,但我相信添加参数 -computername 可以工作

            【讨论】:

              【解决方案10】:

              这是使用 msiexec 的 PowerShell 脚本:

              echo "Getting product code"
              $ProductCode = Get-WmiObject win32_product -Filter "Name='Name of my Software in Add Remove Program Window'" | Select-Object -Expand IdentifyingNumber
              echo "removing Product"
              # Out-Null argument is just for keeping the power shell command window waiting for msiexec command to finish else it moves to execute the next echo command
              & msiexec /x $ProductCode | Out-Null
              echo "uninstallation finished"
              

              【讨论】:

              • 我将这种方法与following flags 结合起来,出于某种原因,这对我来说比其他方法效果更好。
              【解决方案11】:
              function Uninstall-App {
                  Write-Output "Uninstalling $($args[0])"
                  foreach($obj in Get-ChildItem "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall") {
                      $dname = $obj.GetValue("DisplayName")
                      if ($dname -contains $args[0]) {
                          $uninstString = $obj.GetValue("UninstallString")
                          foreach ($line in $uninstString) {
                              $found = $line -match '(\{.+\}).*'
                              If ($found) {
                                  $appid = $matches[1]
                                  Write-Output $appid
                                  start-process "msiexec.exe" -arg "/X $appid /qb" -Wait
                              }
                          }
                      }
                  }
              }
              

              这样称呼:

              Uninstall-App "Autodesk Revit DB Link 2019"
              

              【讨论】:

                【解决方案12】:

                一行代码:

                get-package *notepad* |% { & $_.Meta.Attributes["UninstallString"]}
                

                【讨论】:

                  猜你喜欢
                  • 2011-03-25
                  • 1970-01-01
                  • 1970-01-01
                  • 2011-12-17
                  • 2018-08-11
                  • 1970-01-01
                  • 2020-07-01
                  • 2021-05-06
                  • 1970-01-01
                  相关资源
                  最近更新 更多