将开关附加到自定义卸载程序
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
我有自己制作的自定义卸载程序脚本。它背后的想法是它是通用的,可以与卸载 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