将开关附加到自定义卸载程序

Appending switch to a custom uninstaller

我有自己制作的自定义卸载程序脚本。它背后的想法是它是通用的,可以与卸载 msiexec 以及可执行卸载程序(从注册表中提取卸载字符串)一起使用。 现在要注意的是;我注意到几个 msi 安装有卸载字符串,这些字符串将 /I 显示为开关而不是 /X;这对我来说没有意义,我认为这是不正确的。

在我的脚本中,我检查参数是否有 /I 并将其替换为 /X。 同样,如果卸载没有静默卸载字符串,我会尝试将其附加到我的卸载程序中,这样它就不需要任何用户交互。当我尝试附加它时,我得到了所有开关随附的 msiexec window ;这告诉我传递开关的方式不正确。

这是我尝试卸载 Teams 时的示例。我打印出卸载程序的变量和传递的参数。

输出看起来像这样(这告诉我它应该有效):

MsiExec.exe 
/X{731F6BAA-A986-45A4-8936-7C3AAAAA760B} /qn /norestart

我希望有人能帮助我。这是我的脚本。

CLS

$Software = "Teams"
$Filter = "*" + $Software + "*"
$Program = $ProgUninstall = $NULL

try 
{
    if (Test-Path -Path "HKLM:\SOFTWARE\WOW6432Node") 
    {
        $programs = Get-ItemProperty -Path "HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*" -ErrorAction Stop
    }

    $programs += Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*" -ErrorAction Stop
    $programs += Get-ItemProperty -Path "Registry::\HKEY_USERS\*\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*" -ErrorAction SilentlyContinue
} 
catch
{
    Write-Error $_
    break
}

foreach($Program in $Programs)
{
    $ProgDisplayName = $Program.DisplayName
    $ProgUninstall = $Program.UninstallString

    if(($ProgDisplayName -like $Filter) -and ($NULL -ne $ProgUninstall))
    {

        $aux = $ProgUninstall -split @('\.exe'),2,[System.StringSplitOptions]::None
        $Uninstaller = (cmd /c echo $($aux[0].TrimStart('"').TrimStart("'") + '.exe')).Trim('"')
        $UninsParams = $aux[1].TrimStart('"').TrimStart("'").Trim().split(' ',[System.StringSplitOptions]::RemoveEmptyEntries)

        if($UninsParams -like "/I*")
        {
            $UninsParams = $UninsParams -replace("/I", "/X")
        }

        
        if($Uninstaller -like "MsiExec.exe")
        {
            $UninsParams = "$UninsParams /qn /norestart"
        }
        
        
        #Debug
        $Uninstaller
        $UninsParams

        try
        {
            . $Uninstaller $UninsParams | Where-Object { $_ -notlike "param 0 = *" }
        }
        Catch
        {
            write-host "Unable to uninstall: " $Uninstaller $UninsParams
        }
    }
}

您遇到的问题是您在这一行创建了一个字符串数组:

$aux = $ProgUninstall -split @('\.exe'),2,[System.StringSplitOptions]::None

$aux 是一个字符串数组,但您稍后尝试将其视为单个字符串。如果你想让它像一个字符串而不是一个数组,你需要在某个时候加入它。或者不使用 cmd 执行卸载并将其保存为数组(这就是我要做的)。如果您想将其保留为一个数组,您可以改用 Start-Process,然后将您的参数添加到正确的参数中。类似于:

foreach($Program in $Programs)
{
    $ProgDisplayName = $Program.DisplayName
    $ProgUninstall = $Program.UninstallString

    if(($ProgDisplayName -like $Filter) -and ($NULL -ne $ProgUninstall))
    {

        $aux = $ProgUninstall -split '(?<=\.exe[''"]?) ',2,[System.StringSplitOptions]::None
        $Uninstaller = $aux[0].trim('''"')
        $UninsParams = $aux[1].Trim() -split ' (?=/|-)',[System.StringSplitOptions]::RemoveEmptyEntries

        if($Uninstaller -eq "MsiExec.exe")
        {
            [string[]]$UninsParams = $UninsParams -replace "/I", "/X"
            [string[]]$UninsParams = $UninsParams|?{$_ -notin '/qn','/norestart'}
            [string[]]$UninsParams += '/qn'
            [string[]]$UninsParams += '/norestart'
        }
        
        
        #Debug
        $Uninstaller
        $UninsParams

        Try
        {
            Start-Process -FilePath $Uninstaller -ArgumentList $UninsParams
        }
        Catch
        {
            write-host "Unable to uninstall: $Uninstaller $UninsParams"
        }
    }
}

这会将您的参数拆分为 space,然后是 /-,这应该遵循大多数采用参数的内容。如果您只想在 space 上执行此操作,您可以将行更改为:

        $UninsParams = $aux[1].Trim() -split ' ',[System.StringSplitOptions]::RemoveEmptyEntries