3

I'm trying to figure out how to split some cmd output into multiple strings that I can use later to set labels.

The code i'm using is:

ProcessStartInfo diskdrive = new ProcessStartInfo("wmic", " diskdrive get index, model, interfacetype, size");
diskdrive.UseShellExecute = false;
diskdrive.RedirectStandardOutput = true;
diskdrive.CreateNoWindow = true;
var proc = Process.Start(diskdrive);

string s = proc.StandardOutput.ReadToEnd();

It gives an output like this:

Index  InterfaceType  Model                   Size           
2      IDE            WesternDigital    1000202273280  
1      IDE            Seagate             500105249280   
0      IDE            SAMSUNG SSD 830 Series  128034708480

Is it possible to put this in a list or an array so I can get for example the size of disk 2, or the interfacetype of disk 0. I can do some basic things in C# but this is over my head :I

BRAHIM Kamel
  • 13,492
  • 1
  • 36
  • 47
Zenkaipu
  • 53
  • 2
  • Di you try with [`String.Split`](https://msdn.microsoft.com/en-us/library/system.string.split(v=vs.110).aspx)? Or [`Regex`](https://msdn.microsoft.com/en-us/library/system.text.regularexpressions.regex(v=vs.110).aspx)? – Kryptos Jun 05 '15 at 14:05
  • `String.Split` will be problematic if some cells have spaces (as in "SAMSUNG SSD 830 Series". – adv12 Jun 05 '15 at 14:06
  • Split string won't do it here, it's because of the spaces I don't know how to tackle this. – Zenkaipu Jun 05 '15 at 15:44
  • 4
    Instead of shelling out to an external app to get your WMI information, you can query WMI directly in c#. Then you could access each data field directly without the need for splitting any strings. WMI queries in C# are SQL queries that gather information about the system. For example: `var allPDisks = Session.QueryInstances(@"root\microsoft\windows\storage", "WQL", "SELECT * FROM MSFT_PhysicalDisk")` The `MSFT_PhysicalDisk` class provides all of the fields you are trying to get. See [this link](https://msdn.microsoft.com/en-us/library/windows/desktop/hh830532(v=vs.85).aspx) – Chris Dunaway Jun 05 '15 at 15:57
  • You need to start with the facts: there will always be 4 columns, the first and last column will always be a numeric; try and work work backwards from that to get the remaining columns parsed and then you can build your list. – Paul Jun 08 '15 at 07:34
  • Is the output as given in the question correct? From what I can tell wmic outputs data in fixed width columns. This would suggest that the Size column is not aligned as it would be output by wmic. – Martin Brown Jun 08 '15 at 08:38

2 Answers2

1

Here is a working example. "result" will contain a list with the relevant parts you require. This is a first pass and i'm sure can be refactored somewhat:

using System;
using System.Collections.Generic;
using System.Linq;

namespace columnmatch
{
    internal class Program
    {

        private const string Ex1 = "2      IDE            WesternDigital    1000202273280";
        private const string Ex2 = "1      IDE            Seagate             500105249280 ";
        private const string Ex3 = "0      IDE            SAMSUNG SSD 830 Series  128034708480";

        private static void Main(string[] args)
        {
            var result = new List<MyModel>();
            result.Add(ParseItem(Ex1));
            result.Add(ParseItem(Ex2));
            result.Add(ParseItem(Ex3));
        }

        private static MyModel ParseItem(string example)
        {
            var columnSplit = example.Split((char[]) null, StringSplitOptions.RemoveEmptyEntries);

            int index = -1;
            string interfaceType = string.Empty;
            long size = -1;
            string model = string.Empty;

            if (columnSplit.Count() == 4)
            {
                //direct match (no spaces in input)
                index = Convert.ToInt32(columnSplit[0]);
                interfaceType = columnSplit[1];
                model = columnSplit[2];
                size = Convert.ToInt64(columnSplit[3]);
            }
            else
            {
                string modelDescription = string.Empty;

                for (int i = 0; i < columnSplit.Count(); i++)
                {
                    if (i == 0)
                    {
                        index = Convert.ToInt32(columnSplit[i]);
                    }
                    else if (i == 1)
                    {
                        interfaceType = columnSplit[i];
                    }
                    else if (i == columnSplit.Count() - 1) //last
                    {
                        size = Convert.ToInt64(columnSplit[i]);
                    }
                    else
                    {
                        //build the model
                        modelDescription += columnSplit[i] + ' ';
                    }
                }

                model = modelDescription.TrimEnd();
            }

            var myItem = BuildResultItem(index, interfaceType, model, size);
            return myItem;
        }

        private static MyModel BuildResultItem(int index, string interfaceType, string model, long size)
        {
            var myItem = new MyModel
            {
                Index = index,
                InterfaceType = interfaceType,
                Model = model,
                Size = size
            };

            return myItem;
        }

        private class MyModel
        {
            public int Index { get; set; }
            public string InterfaceType { get; set; }
            public string Model { get; set; }
            public long Size { get; set; }
        }
    }
}

This answer follows the facts from my comment: there will always be 4 columns, the first and last column will always be a numeric, and builds up from there.

Paul
  • 1,483
  • 14
  • 32
0

It appears that the command you run ensures a double-space between each column. It's then a matter of doing a string split on double strings only.

So, given your string s then this works for me:

var map =
    s
        .Split(Environment.NewLine.ToCharArray(), StringSplitOptions.RemoveEmptyEntries)
        .Skip(1)
        .Select(x => x.Split(new [] { "  " }, StringSplitOptions.RemoveEmptyEntries))
        .Select(x => x.Select(y => y.Trim()).ToArray())
        .ToDictionary(
            x => int.Parse(x[0]),
            x => new
            {
                InterfaceType = x[1],
                Model = x[2],
                Size = ulong.Parse(x[3]),
            });

I can then do:

string it = map[0].InterfaceType;
ulong size = map[2].Size;
Enigmativity
  • 113,464
  • 11
  • 89
  • 172