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

U盘只读状态检测与DISKPART权限修改问题排查

U盘只读状态检测与Diskpart权限/执行问题修复

问题概述

需要实现U盘只读状态检测逻辑:若U盘处于只读状态则先解除保护→更新文件→重新设置只读;若可写则直接更新文件→设置只读。当前代码存在两个核心问题:

  1. 设置StartInfo.Verb="runas"无法让Diskpart获取管理员权限;
  2. 以管理员身份启动程序后,Diskpart窗口无法自动关闭,且U盘状态未发生变更;同时检测只读状态的方法完全失效。

问题原因与修复方案

1. 管理员权限失效的原因

当UseShellExecute=false时,Verb属性不会生效——该属性仅在UseShellExecute=true的模式下才起作用。但UseShellExecute=true时无法直接重定向标准输入输出,因此需要换一种方式给Diskpart传递命令:将命令写入临时脚本文件,让Diskpart执行该脚本,既满足权限提升需求,又能传递命令。

2. Diskpart窗口不关闭、状态无变更的原因

  • 未等待Diskpart进程执行完成就继续后续操作,导致命令可能未被完整执行;
  • 命令逻辑错误:使用select volume后直接执行attributes disk,但attributes disk命令需要先选中对应的磁盘而非卷;
  • 未捕获Diskpart的执行输出,无法排查命令执行过程中的错误;
  • 只读状态检测逻辑错误:DirectoryInfo.Attributes读取的是U盘根文件夹的只读属性,而非磁盘硬件级的只读保护状态。

修正后的代码

1. 检测U盘只读状态的正确方法

通过执行Diskpart命令并解析输出来判断磁盘是否处于只读状态,同时通过WMI获取盘符对应的磁盘编号:

private bool CheckReadOnly(string driveLetter)
{
    // 先通过盘符获取对应的磁盘编号
    string diskNumber = GetDiskNumberFromDriveLetter(driveLetter);
    if (string.IsNullOrEmpty(diskNumber))
        return false;

    // 生成Diskpart检测脚本
    string scriptContent = $"select disk {diskNumber}\nattributes disk\n";
    string tempScriptPath = Path.Combine(Path.GetTempPath(), "diskpart_check.txt");
    File.WriteAllText(tempScriptPath, scriptContent);

    Process p = new Process();
    p.StartInfo.FileName = @"C:\Windows\System32\diskpart.exe";
    p.StartInfo.Arguments = $"/s {tempScriptPath}";
    p.StartInfo.UseShellExecute = false;
    p.StartInfo.RedirectStandardOutput = true;
    p.StartInfo.CreateNoWindow = true;
    p.Start();

    // 读取执行输出并判断状态
    string output = p.StandardOutput.ReadToEnd();
    p.WaitForExit();
    File.Delete(tempScriptPath);

    bool isReadOnly = output.Contains("Read-only : Yes");
    debugListView.Items.Add($"{DateTime.Now} {isReadOnly ? "U盘处于只读状态" : "U盘可写入"}");
    return isReadOnly;
}

// 辅助方法:通过盘符获取对应的磁盘编号
private string GetDiskNumberFromDriveLetter(string driveLetter)
{
    driveLetter = driveLetter.TrimEnd('\\');
    using (ManagementObjectSearcher searcher = new ManagementObjectSearcher(
        $"SELECT * FROM Win32_LogicalDiskToPartition"))
    {
        foreach (ManagementObject obj in searcher.Get())
        {
            string logicalDisk = obj["Dependent"].ToString().Split('=')[1].Replace("\"", "");
            if (logicalDisk.Equals(driveLetter, StringComparison.OrdinalIgnoreCase))
            {
                string partition = obj["Antecedent"].ToString().Split('=')[1].Replace("\"", "");
                using (ManagementObject partitionObj = new ManagementObject($"Win32_DiskPartition.DeviceID=\"{partition}\""))
                {
                    return partitionObj["DiskIndex"].ToString();
                }
            }
        }
    }
    return null;
}

2. 修正后的U盘保护/解除保护方法

使用临时脚本传递命令,确保权限提升,同时等待进程执行完成:

private void ProtectPendrive(string driveLetter)
{
    string diskNumber = GetDiskNumberFromDriveLetter(driveLetter);
    if (string.IsNullOrEmpty(diskNumber))
        return;

    string scriptContent = $"select disk {diskNumber}\nattributes disk set readonly\nexit\n";
    string tempScriptPath = Path.Combine(Path.GetTempPath(), "diskpart_protect.txt");
    File.WriteAllText(tempScriptPath, scriptContent);

    Process p = new Process();
    p.StartInfo.FileName = @"C:\Windows\System32\diskpart.exe";
    p.StartInfo.Arguments = $"/s {tempScriptPath}";
    p.StartInfo.UseShellExecute = true;
    p.StartInfo.Verb = "runas"; // 提升至管理员权限
    p.StartInfo.CreateNoWindow = true;
    p.Start();
    p.WaitForExit(); // 等待命令执行完成
    File.Delete(tempScriptPath);

    debugListView.Items.Add($"{DateTime.Now} U盘已设置为只读状态");
}

private void UnprotectPendrive(string driveLetter)
{
    string diskNumber = GetDiskNumberFromDriveLetter(driveLetter);
    if (string.IsNullOrEmpty(diskNumber))
        return;

    string scriptContent = $"select disk {diskNumber}\nattributes disk clear readonly\nexit\n";
    string tempScriptPath = Path.Combine(Path.GetTempPath(), "diskpart_unprotect.txt");
    File.WriteAllText(tempScriptPath, scriptContent);

    Process p = new Process();
    p.StartInfo.FileName = @"C:\Windows\System32\diskpart.exe";
    p.StartInfo.Arguments = $"/s {tempScriptPath}";
    p.StartInfo.UseShellExecute = true;
    p.StartInfo.Verb = "runas";
    p.StartInfo.CreateNoWindow = true;
    p.Start();
    p.WaitForExit();
    File.Delete(tempScriptPath);

    debugListView.Items.Add($"{DateTime.Now} U盘已解除只读保护");
}

额外注意事项

  • 需要添加System.Management程序集引用(用于WMI查询磁盘编号);
  • 临时脚本使用后及时删除,避免残留文件;
  • CreateNoWindow=true可以避免弹出Diskpart控制台窗口,提升用户体验。

内容的提问来源于stack exchange,提问作者James Collins

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 05:22:56