You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

VB.NET通过注册表卸载字符串无法卸载M365的问题求助

卸载Microsoft 365后仍显示在已安装应用列表的问题

我正在使用基于.NET Framework 9.0的VB.NET程序卸载Microsoft 365产品,程序提示卸载完成,但Windows已安装应用列表中仍能看到M365产品。以下是我的实现代码:

目标卸载产品列表

Dim officeProductIds As String() = {
    "O365ProPlusEEANoTeamsRetail",
    "O365ProPlusRetail",
    "O365BusinessEEANoTeamsRetail",
    "O365BusinessRetail"
}

注册表卸载路径

Dim uninstallPaths As String() = {
    "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall",
    "SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall"
}

核心卸载逻辑代码

Try
    Dim baseKey As RegistryKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64)

    For Each regPath In uninstallPaths
        Using uninstallKey As RegistryKey = baseKey.OpenSubKey(regPath)
            If uninstallKey Is Nothing Then Continue For

            For Each subKeyName As String In uninstallKey.GetSubKeyNames()
                If officeProductIds.Any(Function(id) subKeyName.Contains(id)) Then
                    Dim uninstallString As String = ReadRegistry.GetOfficeUninstallString(subKeyName)
                    If Not String.IsNullOrEmpty(uninstallString) Then
                        Console.WriteLine($"[FOUND] Uninstall string for {subKeyName}: {uninstallString}")


                        Dim installerPath As String = ""
                        Dim arguments As String = ""

                        If uninstallString.StartsWith(ChrW(34)) Then
                            Dim endQuoteIndex As Integer = uninstallString.IndexOf(ChrW(34), 1)
                            installerPath = uninstallString.Substring(1, endQuoteIndex - 1)
                            arguments = uninstallString.Substring(endQuoteIndex + 1).Trim()
                        Else
                            Dim firstSpace = uninstallString.IndexOf(" "c)
                            If firstSpace > 0 Then
                                installerPath = uninstallString.Substring(0, firstSpace)
                                arguments = uninstallString.Substring(firstSpace + 1).Trim()
                            Else
                                installerPath = uninstallString
                            End If
                        End If
                        Dim installerFolder As String = IO.Path.GetDirectoryName(installerPath)
                        Console.WriteLine()
                        Console.WriteLine($"Installer: {IO.Path.GetFileName(installerPath)}")
                        Console.WriteLine($"Install Folder: {installerFolder}")
                        Console.WriteLine($"Arguments: {arguments}")
                        Console.WriteLine()

                        ApplicationInstallerHelper.UninstallApplication(IO.Path.GetFileName(installerPath), installerFolder, True, arguments)
                    Else
                        Console.WriteLine($"[WARNING] No UninstallString for {subKeyName}")
                    End If
                End If
            Next
        End Using
    Next
Catch ex As Exception
    Console.WriteLine("[EXCEPTION] " & ex.Message)
End Try

卸载执行方法

Public Sub UninstallApplication(installerFileName As String, installerFolderPath As String, Optional silent As Boolean = False, Optional installerArguments As String = "")
    Dim fullPath As String = IO.Path.Combine(installerFolderPath, installerFileName)

    If Not IO.File.Exists(fullPath) Then
        StrBuilder.WrapMessage($"Installer not found at: {fullPath}", "ERR")
        Return
    End If

    If silent AndAlso Not installerArguments.Contains("/quiet") Then
        installerArguments &= " /quiet"
    End If
    If silent AndAlso Not installerArguments.Contains("/norestart") Then
        installerArguments &= " /norestart"
    End If

    Dim psCommand As String =
        $"Start-Process -FilePath '{fullPath}' -ArgumentList '{installerArguments}' -Wait -NoNewWindow; exit $LASTEXITCODE"

    Dim psi As New ProcessStartInfo("powershell.exe", $"-NoProfile -ExecutionPolicy Bypass -Command ""{psCommand}""")
    psi.UseShellExecute = False
    psi.RedirectStandardOutput = True
    psi.RedirectStandardError = True
    psi.CreateNoWindow = True

    Dim proc As Process = Process.Start(psi)
    proc.WaitForExit()

    Dim output As String = proc.StandardOutput.ReadToEnd()
    Dim errors As String = proc.StandardError.ReadToEnd()
    Dim code As Integer = proc.ExitCode

    If code = 0 Then
        StrBuilder.WrapMessage("Uninstall completed successfully.", "OK")
    Else
        StrBuilder.WrapMessage($"Uninstall failed with exit code {code}", "ERR")
        If Not String.IsNullOrWhiteSpace(errors) Then
            Console.WriteLine("[STDERR] " & errors)
        End If
    End If
End Sub

排查与解决方向

  1. 注册表残留清理
    Office卸载程序可能未完全删除Uninstall路径下的对应子键,导致系统误判产品状态。卸载完成后,检查对应注册表子键是否存在,若存在则通过代码(需管理员权限)删除该子键。
  2. 卸载参数补全
    当前自动添加的/quiet和/norestart可能不足以完成彻底卸载,可尝试添加/uninstall <ProductID>明确指定卸载产品,或加入/force参数强制卸载,确保参数匹配Office官方卸载要求。
  3. 注册表视图兼容
    代码仅使用RegistryView.Registry64,若系统为32位或Office是32位安装,需同时打开RegistryView.Registry32检查卸载信息,避免遗漏。
  4. 权限验证
    卸载Office必须以管理员身份运行程序,可在程序清单中设置requestedExecutionLevel为requireAdministrator,或在代码中添加权限检查逻辑。
  5. 扩展产品ID范围
    Microsoft 365包含多个关联组件,当前officeProductIds可能遗漏相关子键,可扩展数组加入MicrosoftTeamsRetail等其他Office相关ProductID。
  6. PowerShell命令转义修复
    当installerArguments包含特殊字符时,PowerShell命令可能解析错误,可改用脚本块方式执行:
    Dim psCommand As String = $"& ""{fullPath}"" {installerArguments}; exit $LASTEXITCODE"
    Dim psi As New ProcessStartInfo("powershell.exe", $"-NoProfile -ExecutionPolicy Bypass -Command ""{psCommand}""")
    

内容的提问来源于stack exchange,提问作者Fusion Oz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 04:52:14