C# and diskpart: how to select by disk label and n

2019-07-08 10:58发布

问题:

I have a C# application that install Windows image. I have to choose the disk where the system will copied (C: or D: or ...) on the user interface. For that, it's ok.

Then i have to format the disk. I have to select with diskpart.exe the good physical disk associed to C:. But with diskpart, we choose the disk with number: select disk 0 or 1 or ...

How to make the connection between the good disk number and the letter choosen by users on the interface ?

I found Nothing on google. I tried to find an information with wmi Win32_DiskDrive but nothing in common with diskpart detail disk .

Thank's

回答1:

Another solution instead of using ManagementObjectSearcher is using DiskPart.exe programatically, but my code is rather a static solution (would be better with regex) but will work a long time.

It requires a manifest file with higher execution privileges (Add new element > Application Manifest File and change requestedExecutionLevel to <requestedExecutionLevel level="requireAdministrator" uiAccess="false" />. for further information: https://stackoverflow.com/a/43941461/5830773)

Then you can use following code to get the drive list with DiskPart.exe:

// execute DiskPart programatically
Process process = new Process();
process.StartInfo.FileName = "diskpart.exe";
process.StartInfo.UseShellExecute = false;
process.StartInfo.CreateNoWindow = true;
process.StartInfo.RedirectStandardInput = true;
process.StartInfo.RedirectStandardOutput = true;
process.Start();
process.StandardInput.WriteLine("list volume");
process.StandardInput.WriteLine("exit");
string output = process.StandardOutput.ReadToEnd();
process.WaitForExit();

// extract information from output
string table = output.Split(new string[] { "DISKPART>" }, StringSplitOptions.None)[1];
var rows = table.Split(new string[] { "\n" }, StringSplitOptions.None);
for (int i = 3; i < rows.Length; i++)
{
    if (rows[i].Contains("Volume"))
    {
        int index = Int32.Parse(rows[i].Split(new string[] { " " }, StringSplitOptions.None)[3]);
        string label = rows[i].Split(new string[] { " " }, StringSplitOptions.None)[8];
        Console.WriteLine($@"Volume {index} {label}:\");
    }
}

This gives following output like from DiskPart but you can customise it for your needs:

Volume 0 C:\
Volume 1 D:\
Volume 2 F:\
Volume 3 G:\
Volume 4 I:\
Volume 5 H:\

Now searching by drive letter is obvious:

public int GetIndexOfDrive(string drive)
{
    drive = drive.Replace(":", "").Replace(@"\", "");

    // execute DiskPart programatically
    Process process = new Process();
    process.StartInfo.FileName = "diskpart.exe";
    process.StartInfo.UseShellExecute = false;
    process.StartInfo.CreateNoWindow = true;
    process.StartInfo.RedirectStandardInput = true;
    process.StartInfo.RedirectStandardOutput = true;
    process.Start();
    process.StandardInput.WriteLine("list volume");
    process.StandardInput.WriteLine("exit");
    string output = process.StandardOutput.ReadToEnd();
    process.WaitForExit();

    // extract information from output
    string table = output.Split(new string[] { "DISKPART>" }, StringSplitOptions.None)[1];
    var rows = table.Split(new string[] { "\n" }, StringSplitOptions.None);
    for (int i = 3; i < rows.Length; i++)
    {
        if (rows[i].Contains("Volume"))
        {
            int index = Int32.Parse(rows[i].Split(new string[] { " " }, StringSplitOptions.None)[3]);
            string label = rows[i].Split(new string[] { " " }, StringSplitOptions.None)[8];

            if (label.Equals(drive))
            {
                return index;
            }
        }
    }

    return -1;
}

Usage:

Console.WriteLine(GetIndexOfDrive(@"D:\")); // returns 1 on my computer


回答2:

To map between disk and logical drive(C:, D:, etc), you have to get the information from:

Win32_LogicalDisk
Win32_LogicalDiskToPartition
Win32_DiskPartition

in any order. These tables will have all information. It can be easily used using System.Management in c# .