LOGO OA教程 ERP教程 模切知识交流 PMS教程 CRM教程 开发文档 其他文档  
 
网站管理员

【C#】如何判断虚拟磁盘VHDX文件是否已经被挂载,挂载到了哪一个盘符,并且当前是挂载为只读模式还是可读写模式

admin
2025年5月16日 11:1 本文热度 1637

如何判断虚拟磁盘VHDX文件是否已经被挂载,挂载到了哪一个盘符,并且当前是挂载为只读模式还是可读写模式呢?以下是用于检测VHDX挂载状态和属性的完整C#实现方案:

using System;
using System.IO;
using System.Management;
using System.Diagnostics;
using System.Text;


class VhdxStatusChecker
{
    // 主检查方法(返回:是否挂载,盘符列表,是否只读)
    public static (bool isMounted, string drives, bool isReadOnly) CheckVhdxStatus(string vhdxPath)
    {
        var normalizedPath = Path.GetFullPath(vhdxPath).ToLower();


        using (var searcher = new ManagementObjectSearcher("SELECT * FROM Win32_DiskDrive"))
        {
            foreach (ManagementObject disk in searcher.Get())
            {
                // 检查磁盘是否为虚拟磁盘
                if (disk["MediaType"]?.ToString() != "Microsoft Virtual Disk")
                    continue;


                // 获取VHDX文件路径
                var diskPath = GetVhdxPathFromDisk(disk);
                if (diskPath == null) continue;


                // 路径匹配检测
                if (Path.GetFullPath(diskPath).ToLower() != normalizedPath)
                    continue;


                // 获取挂载信息
                var drives = GetMountedDrives(disk);
                var isReadOnly = CheckReadOnlyStatus(diskPath);


                return (true, drives, isReadOnly);
            }
        }
        return (false, null, false);
    }


    // 获取VHDX文件路径(兼容不同Windows版本)
    private static string GetVhdxPathFromDisk(ManagementObject disk)
    {
        // 方法1:通过FileName属性获取
        if (disk["FileName"] is string fileName && fileName.EndsWith(".vhdx", StringComparison.OrdinalIgnoreCase))
            return fileName;


        // 方法2:通过WMI扩展属性获取(需要Windows 8+)
        try
        {
            using (var p = new ManagementObject($"Win32_DiskDrive.DeviceID='{disk["DeviceID"]}'"))
            {
                p.Scope = new ManagementScope(@"\\.\root\Microsoft\Windows\Storage");
                return p["FileName"]?.ToString();
            }
        }
        catch { /* 忽略兼容性错误 */ }


        return null;
    }


    // 获取已挂载的盘符
    private static string GetMountedDrives(ManagementObject disk)
    {
        var sb = new StringBuilder();
        var query = $"ASSOCIATORS OF {{Win32_DiskDrive.DeviceID='{EscapeWmiPath(disk["DeviceID"].ToString())}'}} " +
                    "WHERE AssocClass = Win32_DiskDriveToDiskPartition";


        using (var partitions = new ManagementObjectSearcher(query).Get())
        {
            foreach (ManagementObject partition in partitions)
            {
                var driveQuery = $"ASSOCIATORS OF {{Win32_DiskPartition.DeviceID='{EscapeWmiPath(partition["DeviceID"].ToString())}'}} " +
                                "WHERE AssocClass = Win32_LogicalDiskToPartition";


                using (var drives = new ManagementObjectSearcher(driveQuery).Get())
                {
                    foreach (ManagementObject drive in drives)
                    {
                        if (drive["DeviceID"] != null)
                            sb.Append($"{drive["DeviceID"]} ");
                    }
                }
            }
        }
        return sb.ToString().Trim();
    }


    // 检查只读状态(兼容多语言系统)
    private static bool CheckReadOnlyStatus(string vhdxPath)
    {
        var output = ExecuteDiskPartCommand($@"
            select vdisk file=""{vhdxPath}""
            detail vdisk
            exit
        ");


        // 多语言匹配模式
        var patterns = new[] {
            new { Key = "Read-only", Yes = "Yes", No = "No" },        // 英语
            new { Key = "只读", Yes = "是", No = "否" },              // 中文
            new { Key = "Schreibgeschützt", Yes = "Ja", No = "Nein" } // 德语
        };


        foreach (var pattern in patterns)
        {
            var start = output.IndexOf(pattern.Key);
            if (start == -1) continue;


            var valueStart = output.IndexOf(':', start) + 1;
            var valueEnd = output.IndexOf('\n', valueStart);
            var value = output.Substring(valueStart, valueEnd - valueStart).Trim();


            return value.Equals(pattern.Yes, StringComparison.OrdinalIgnoreCase);
        }


        return false; // 默认返回可写状态
    }


    // 执行diskpart命令并获取输出
    private static string ExecuteDiskPartCommand(string script)
    {
        var tempFile = Path.GetTempFileName();
        File.WriteAllText(tempFile, script, Encoding.Unicode); // 必须使用Unicode编码


        try
        {
            var psi = new ProcessStartInfo("diskpart")
            {
                Arguments = $"/s \"{tempFile}\"",
                RedirectStandardOutput = true,
                UseShellExecute = false,
                CreateNoWindow = true,
                StandardOutputEncoding = Encoding.Unicode // 正确解析多语言输出
            };


            using (var process = Process.Start(psi))
            {
                var output = process.StandardOutput.ReadToEnd();
                process.WaitForExit(5000);
                return output;
            }
        }
        finally
        {
            File.Delete(tempFile);
        }
    }


    // WMI路径转义工具方法
    private static string EscapeWmiPath(string path)
    {
        return path.Replace(@"\", @"\\").Replace("'", @"\'");
    }
}

使用示例:

var (isMounted, drives, isReadOnly) = VhdxStatusChecker.CheckVhdxStatus(@"D:\Backup.vhdx");
Console.WriteLine($"已挂载: {isMounted}");
Console.WriteLine($"盘符: {drives ?? "无"}");
Console.WriteLine($"只读模式: {isReadOnly}");

方案特性:

1、多语言兼容:

  • 支持检测英语、中文、德语系统的只读状态

  • 自动识别系统语言输出格式

  • 使用Unicode编码处理特殊字符

2、双重检测机制:

  • 通过WMI获取基础磁盘信息

  • 通过diskpart验证详细属性

3、兼容性处理:

  • 支持Windows 7及更高版本

  • 兼容传统Win32接口和新的Storage命名空间

4、错误防御:

  • 自动转义WMI查询路径

  • 处理磁盘分区的多种情况

  • 超时机制防止进程挂起

实现原理:

1、WMI查询:

  • 通过Win32_DiskDrive定位虚拟磁盘

  • 使用关联查询获取挂载盘符

2、diskpart检测:

  • 执行detail vdisk获取详细信息

  • 多语言关键字匹配检测只读状态

3、路径标准化:

  • 统一转换为全路径和小写格式

  • 处理不同来源的路径格式差异

注意事项:

1、运行权限:

// 需要以管理员身份运行程序
// 在项目文件中添加:
// <ApplicationManifest>app.manifest</ApplicationManifest>
// 并启用requireAdministrator

2、异常处理:

try {
    var result = VhdxStatusChecker.CheckVhdxStatus(path);
}
catch (Exception ex) {
    Console.WriteLine($"检测失败: {ex.Message}");
}

3、性能优化:

// 对于频繁检测的场景,可以缓存ManagementObjectSearcher实例
// 但需要注意及时释放资源

该方案通过结合WMI和diskpart的优势,实现了可靠的VHDX状态检测,适用于需要高可靠性保障的备份系统。


相关教程:

C#零成本实现云服务器上Windows系统数据库自动备份并防止备份文件被勒索病毒破坏[20]
  http://31161.oa22.cn


该文章在 2025/5/16 11:03:58 编辑过
关键字查询
相关文章
点晴ERP是一款针对中小制造业的专业生产管理软件系统,系统成熟度和易用性得到了国内大量中小企业的青睐。
点晴PMS码头管理系统主要针对港口码头集装箱与散货日常运作、调度、堆场、车队、财务费用、相关报表等业务管理,结合码头的业务特点,围绕调度、堆场作业而开发的。集技术的先进性、管理的有效性于一体,是物流码头及其他港口类企业的高效ERP管理信息系统。
点晴WMS仓储管理系统提供了货物产品管理,销售管理,采购管理,仓储管理,仓库管理,保质期管理,货位管理,库位管理,生产管理,WMS管理系统,标签打印,条形码,二维码管理,批号管理软件。
点晴免费OA是一款软件和通用服务都免费,不限功能、不限时间、不限用户的免费OA协同办公管理系统。
Copyright 2010-2025 ClickSun All Rights Reserved