使用 powershell 删除 windows 上的应用程序而不查询 win32

Delete an app on windows using powershell without querying win32

所以我想删除一个我不知道其产品 ID 的应用程序。我知道您可以使用 msiexec.exe /x 然后使用产品 ID 删除应用程序。我将如何在命令行中获取特定应用程序的产品 ID 并将值存储在变量中,以便我可以将变量放在删除命令中?

提前致谢!!

总是get-package。除了我,没有人知道这件事。这应该适用于 msi 安装。

get-package *software* | uninstall-package

如果您知道确切的名称,这应该可行。 Uninstall-package 不接受通配符。

uninstall-package 'Citrix HDX RealTime Media Engine 2.9.400'

有时,烦人的是,它会提示先安装 nuget:

install-packageprovider nuget -force

如果不是安装 msi,而是安装程序,则需要更多的字符串处理。您可能需要在末尾添加 '/S' 或其他内容以进行静默安装。

$prog,$myargs = -split (get-package 'Remote Support Jump Client *' | 
  % { $_.metadata['uninstallstring'] })
& $prog $myargs

也许在这种情况下 运行 它:

& "C:\Program Files (x86)\Citrix\Citrix WorkSpace 2202\TrolleyExpress.exe" /uninstall /cleanup /silent

$uninstall = get-package 'Citrix Workspace 2202' | 
  % { $_.metadata['uninstallstring'] }
$split = $uninstall -split '"'
$prog = $split[1]
$myargs = -split $split[2]
$myargs += '/silent'
& $prog $myargs

我想我有一种方法可以在有或没有 double-quotes 的情况下实现 non-msi 安装:

$uninstall = get-package whatever | % { $_.metadata['uninstallstring'] }
$prog, $myargs = $uninstall | select-string '("[^"]*"|\S)+' -AllMatches | 
  % matches | % value
$prog = $prog -replace '"',$null
$silentoption = '/S'
$myargs += $silentoption  # whatever silent uninstall option
& $prog $myargs

这是我使用的脚本。你必须知道包的显示名称是什么......就像你去删除程序一样,它的名称是什么。它适用于我使用 WiX 创建的 MSI 包,但不适用于所有包。如果您使用的是 Windows 10+,则可以考虑使用 winget 命令。 winget 有一个卸载选项。

param (
    [Parameter(Mandatory = $true)]
    [string] $ProductName,
    [switch] $Interactive = $false,
    [switch] $key = $false
)

$log_directory = "c:\users\public"
# $log_directory = "c:\erase\logs"

if ((-not $Interactive) -and (-not (New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent())).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)))
{
    $interactive = $true
#   echo "Not elevated, needs to be interactive"
}

$found = $null
$productsKeyName = "SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Products"

$rootKey = [Microsoft.Win32.Registry]::LocalMachine.OpenSubKey($productsKeyName)
foreach ($productKeyName in $rootKey.GetSubKeyNames())
{
    #$productKeyName

    try
    {
        $installPropertiesKey = $rootKey.OpenSubKey("$productKeyName\InstallProperties")

        if ($installPropertiesKey)
        {
            $displayName = [string] $installPropertiesKey.GetValue("DisplayName")
            if ( (! [string]::IsNullOrEmpty($displayName))  -and ($displayName -eq $ProductName))
            {
                $found = $productKeyName
                break
            }
        }
    }
    catch
    {
    }
    finally
    {
        if ($installPropertiesKey) { $installPropertiesKey.Close() }
    }
}
$rootKey.Close()

if (-not $found)
{
    return "First search could not find $ProductName"
}

$localPackage = $null
if (! [string]::IsNullOrEmpty($found))
{
    try
    {
        $regkey = [Microsoft.Win32.Registry]::LocalMachine.OpenSubKey("$productsKeyName$found\InstallProperties")
        $localPackage = $regkey.GetValue("LocalPackage")
    }
    catch
    {
    }
    finally
    {
        if ($regkey) { $regkey.Close() }
    }
}

if ($key)
{
    return "Found key: $found"
}

if (![string]::IsNullOrEmpty($localPackage) -and (Test-Path $localPackage))
{
    $logflags = "/lv*"
    $logname = (Join-Path $log_directory "$ProductName_uninstall.log")
    
    
    $args = @($logflags, $logname, "/X", $localPackage)
    if (!$Interactive) { $args += "/q" }
    &msiexec $args
}
else
{
    "Could not find uninstall package: $ProductName"
}