All posts tagged registry

Getting the Windows Key

Categories: .Net, C#, Console, WPF
Comments: No

In my last post I went over how to retrieve the Windows Product Activation information from Windows Vista / 7.0 / 2008. Today, we are going to do something on the same thread but very much more desirable. And that is retrieving the Windows Key information.

For as long as Windows has had a key, admins have been looking to be able to retrieve the Windows key information on the fly: especially when they need to do a re-install and lost their original media casing.

So, let’s get right to it with a console application.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
static void Main(string[] args)
{
    string computername = Environment.MachineName;
    const RegistryHive registryRoot = RegistryHive.LocalMachine;
    const string sSubKeyName = @"SOFTWAREMicrosoftWindows NTCurrentVersion";
    const string sValueName = "DigitalProductId";
    string windowsKey = "";
 
    // Get product Id
    RegistryKey regoutput = RegistryKey.OpenRemoteBaseKey(
        registryRoot, computername, RegistryView.Default).
        OpenSubKey(sSubKeyName);
 
    // Convert to byte array
    byte[] digitalProductId;
    if (regoutput != null)
    {
        digitalProductId = regoutput.GetValue(sValueName) as byte[];
 
        // Get Windows Product Key
        windowsKey = (digitalProductId != null)
            ? DecodeProductKey(digitalProductId)
            : "The product key was not accessible";
    }
 
    else
    {
        windowsKey = "The product key was not accessible";
    }
 
    // Output
    Console.WriteLine(windowsKey);
    Console.Read();
}

In this example, I am choosing my local machine as the target. The location of the value we want is located in the registry here:
HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindows NTCurrentVersionDigitalProductId.

We then get the byte array representing the key and decode it with the below method.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
/// <summary>
/// Decodes a Microsoft product key based on the provided digital product id.
/// </summary>
/// <param name="digitalProductId">The digital product id.</param>
/// <returns></returns>
private static string DecodeProductKey(byte[] digitalProductId)
{
    // Offset of first byte of encoded product key in
    //  'DigitalProductIdxxx" REG_BINARY value. Offset = 34H.
    const int keyStartIndex = 52;
 
    // Offset of last byte of encoded product key in
    //  'DigitalProductIdxxx" REG_BINARY value. Offset = 43H.
    const int keyEndIndex = keyStartIndex + 15;
 
    // Possible alpha-numeric characters in product key.
    var digits = new[]
            {
                'B', 'C', 'D', 'F', 'G', 'H', 'J', 'K', 'M', 'P', 'Q', 'R',
                'T', 'V', 'W', 'X', 'Y', '2', '3', '4', '6', '7', '8', '9'
            };
 
    // Length of decoded product key
    const int decodeLength = 29;
 
    // Length of decoded product key in byte-form.
    // Each byte represents 2 chars.
    const int decodeStringLength = 15;
 
    // Array of containing the decoded product key.
    var decodedChars = new char[decodeLength];
 
    // Extract byte 52 to 67 inclusive.
    var hexPid = new ArrayList();
    for (int i = keyStartIndex; i <= keyEndIndex; i++)
    {
        hexPid.Add(digitalProductId[i]);
    }
    for (int i = decodeLength - 1; i >= 0; i--)
    {
        // Every sixth char is a separator.
        if ((i + 1) % 6 == 0)
        {
            decodedChars[i] = '-';
        }
        else
        {
            // Do the actual decoding.
            int digitMapIndex = 0;
            for (int j = decodeStringLength - 1; j >= 0; j--)
            {
                int byteValue = (digitMapIndex << 8) | (byte)hexPid[j];
                hexPid[j] = (byte)(byteValue / 24);
                digitMapIndex = byteValue % 24;
                decodedChars[i] = digits[digitMapIndex];
            }
        }
    }
    return new string(decodedChars);
}

Now, if you are running 64-bit Windows (and most of us are), you may be running into problems getting your byte array. Why is that? Well, the short answer is that it has to do with your Configuration Manager settings. The default platform target is x86: which does not have access to several 64-bit spaces including certain registry values.

You can change that by doing the following in Visual Studio:

  1. Open your Project Properties.
  2. Go to the Build tab.
  3. For each Configuration set the Platorm target to Any CPU.
  4. For Visual Studio 2012, make sure to uncheck Prefer 32-bit.

That’s all there is to it.

Until next time.

In today’s blog I am going to give you the method I use to obtain the Windows Product Activation information in Astronomy.

Q: So, where does this information come from?
A: Well, as you may know, you can obtain this information from the following script:
C:\Windows\System32\slmgr.vbs

I always felt this needed to be modified for use in .Net, so I refactored this a bit and created my own replacement method:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
/// <summary>
/// Retrieves licensing information.
/// </summary>
/// <param name="managementScope">The management scope.</param>
/// <returns></returns>
public static string GetLicensingInfo(ManagementScope managementScope)
{
    // Output
    string result = "Information Unavailable";
    const string windowsAppId = "55c92734-d682-4d71-983e-d6ec3f16059f";
 
    // Default values
    const uint HR_SL_E_GRACE_TIME_EXPIRED = 0xC004F009;
    const uint HR_SL_E_NOT_GENUINE = 0xC004F200;
 
    // Set WMI query
    var query =
        new WqlObjectQuery(
            "SELECT LicenseStatus, GracePeriodRemaining " +
            "FROM SoftwareLicensingProduct " +
            "WHERE (PartialProductKey <> NULL) AND " +
            "(ApplicationId='" + windowsAppId + "')");
 
    // Get items
    using (var searcher = new ManagementObjectSearcher(managementScope, query))
     
    // Get data
    using (var colItems = searcher.Get())
    {
        foreach (ManagementBaseObject obj in colItems)
        {
            string subline;
 
            // License Status
            int licenseStatus = Convert.ToInt32(obj.GetPropertyValue("LicenseStatus"));
 
            // Time remaining: minutes / days
            int gpMin = Convert.ToInt32(obj.GetPropertyValue("GracePeriodRemaining"));
            int gpDay = gpMin / (24 * 60);
 
            // Evaluate
            switch (licenseStatus)
            {
                case 0:
                    result = "Unlicensed";
                    break;
 
                case 1:
                    result = "Licensed";
                    if (gpMin > 0)
                    {
                        subline =
                            String.Format(
                                "Activation expiration: " +
                                "{0} minute(s) ({1} day(s))", gpMin, gpDay);
                        result += "\n" + subline;
                    }
                    break;
 
                case 2:
                    result = "Initial grace period";
                    subline =
                        String.Format("Time remaining: {0} minute(s) " +
                                        "({1} day(s))", gpMin, gpDay);
                    result += "\n" + subline;
                    break;
 
                case 3:
                    result =
                        "Additional grace period (KMS license expired or " +
                        "hardware out of tolerance)";
                    subline =
                        String.Format("Time remaining: {0} minute(s) " +
                                        "({1} day(s))", gpMin, gpDay);
                    result += "\n" + subline;
                    break;
 
                case 4:
                    result = "Non-genuine grace period.";
                    subline =
                        String.Format("Time remaining: {0} minute(s) " +
                                        "({1} day(s))", gpMin, gpDay);
                    result += "\n" + subline;
                    break;
 
                case 5:
                    result = "Notification";
 
                    uint licenseStatusReason;
                    uint.TryParse(obj.GetPropertyValue("GracePeriodRemaining").ToString(),
                        out licenseStatusReason);
                         
                    // Evaluate
                    switch (licenseStatusReason)
                    {
                        case HR_SL_E_NOT_GENUINE:
                            subline =
                                String.Format(
                                    "Notification Reason: 0x{0} " +
                                    "(non-genuine).", licenseStatusReason);
                            break;
 
                        case HR_SL_E_GRACE_TIME_EXPIRED:
                            subline =
                                String.Format(
                                    "Notification Reason: 0x{0} " +
                                    "(grace time expired).", licenseStatusReason);
                            break;
 
                        default:
                            subline =
                                String.Format("Notification Reason: 0x{0}.",
                                                licenseStatusReason);
                            break;
                    }
                    result += "\n" + subline;
                    break;
 
                case 6:
                    result = "Extended grace period";
                    subline =
                        String.Format("Time remaining: {0} minute(s) " +
                                        "({1} day(s))", gpMin, gpDay);
                    result += "\n" + subline;
                    break;
 
                default:
                    result = "Unknown";
                    break;
            }
        }
    }
     
    // return
    return result;
}

An overboard implementation:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
/// <summary>
/// Connects to a target computer through Kerberos authentication.
/// </summary>
/// <param name="computername">The computername.</param>
/// <param name="user">The user.</param>
/// <param name="securePass">The secure pass.</param>
/// <returns>
/// A ManagementScope context for the current connection.
/// </returns>
public static ManagementScope Connect(string computername, string user,
    SecureString securePass)
{
    // Build an options object for the remote connection
    var options = new ConnectionOptions
        {
            Impersonation = ImpersonationLevel.Impersonate,
            EnablePrivileges = true
        };
 
    // Set properties
    // Check name
    if (String.IsNullOrEmpty(computername))
    {
        computername = ".";
    }
 
    // Check credentials
    // Cannot pass a blank user and password.
    if (!String.IsNullOrEmpty(user))
    {
        options.Username = user;
        options.SecurePassword = securePass;
    }
     
    // Make a connection to a remote computer.
    var managementScope =
        new ManagementScope($@"\{computername}\root\cimv2", options);
 
    try
    {
        // Connect
        managementScope.Connect();
    }
    catch (Exception ex)
    {
        throw ex;
    }
     
    // return
    return managementScope;
}
 
/// <summary>
/// Gets the license you so desperately want.
/// </summary>
public void GetMyLicense()
{
    // Get the management scope
    var myManagementScope = Connect(".", "XCALIBUR\jarzt", {my secure password});
 
    // Get the licensing
    string licensing = GetLicensingInfo(myManagementScope);
 
    // Report to client
    MessageBox.Show("My current licensing status: " + licensing);
}

So, really that’s all there is to it.

Happy coding!

This is a bit dated, but the question is about how you get (near) accurate processor information in Windows 2003 with WMI and no external executables.

I wrote this a long time ago for VBS and translated it into C# for my upcoming application: Astronomy. I added some snazzy XAML in there to pimp it out a bit. There is a lot of code here, but that is because a lot needs to be done to format the data into something we want to see.

The desired result:

So, let’s see all that code:

The XAML:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
<Window x:Class="GetProcessCountLegacy.MainWindow"
        Title="MainWindow" Height="200" Width="525">
 
    <Window.Resources>
 
        <!-- Text Styles -->
        <Style x:Key="ListHeader" TargetType="{x:Type TextBlock}">
            <Setter Property="FontWeight" Value="Bold" />
        </Style>
        <Style x:Key="ListLabel" TargetType="{x:Type TextBlock}">
            <Setter Property="FontWeight" Value="Normal" />
        </Style>
        <Style x:Key="ListValue" TargetType="{x:Type TextBlock}">
            <Setter Property="FontWeight" Value="DemiBold" />
        </Style>
 
        <!-- Border -->
        <Style x:Key="BorderStyle" TargetType="Border">
            <Setter Property="BorderBrush" Value="#999" />
            <Setter Property="BorderThickness" Value="1" />
            <Setter Property="CornerRadius" Value="6" />
            <Setter Property="Padding" Value="16,14,16,16" />
            <Setter Property="Margin" Value="12,6,12,6" />
            <Setter Property="Background">
                <Setter.Value>
                    <LinearGradientBrush StartPoint="0.5, 0" EndPoint="0.5, 1" Opacity="1.0">
                        <GradientStop Color="#FFFFFF" Offset="0" />
                        <GradientStop Color="#FFFFFF" Offset="0.5" />
                        <GradientStop Color="#EDEDED" Offset="1" />
                    </LinearGradientBrush>
                </Setter.Value>
            </Setter>
        </Style>
    </Window.Resources>
 
    <Grid>
        <!-- Processor Information -->
        <Border Style="{StaticResource BorderStyle}">
            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition Height="28"/>
                    <RowDefinition Height="22"/>
                    <RowDefinition Height="22"/>
                    <RowDefinition Height="22"/>
                    <RowDefinition Height="22"/>
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="120"/>
                    <ColumnDefinition Width="600"/>
                </Grid.ColumnDefinitions>
 
                <TextBlock Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2"
                                       VerticalAlignment="Top"
                                       Text="Processor Information"
                                       Style="{StaticResource ListHeader}" />
 
                <TextBlock Grid.Row="1" Grid.Column="0"
                                       Text="Description:"
                                       Style="{StaticResource ListLabel}" />
                <TextBlock Grid.Row="1" Grid.Column="1"
                                       x:Name="txtDescription"
                                       Style="{StaticResource ListValue}" />
 
                <TextBlock Grid.Row="2" Grid.Column="0"
                                       Text="Core Speed:"
                                       Style="{StaticResource ListLabel}" />
                <TextBlock Grid.Row="2" Grid.Column="1"
                                       x:Name="txtSpeed"
                                       Style="{StaticResource ListValue}" />
 
                <TextBlock Grid.Row="3" Grid.Column="0"
                                       Text="Count:"
                                       Style="{StaticResource ListLabel}" />
                <TextBlock Grid.Row="3" Grid.Column="1"
                                       x:Name="txtCount"
                                       Style="{StaticResource ListValue}" />
 
                <TextBlock Grid.Row="4" Grid.Column="0"
                                       Text="Width:"
                                       Style="{StaticResource ListLabel}" />
                <TextBlock Grid.Row="4" Grid.Column="1"
                                       x:Name="txtWidth"
                                       Style="{StaticResource ListValue}" />
            </Grid>
        </Border>
    </Grid>
</Window>

C#

[Main Code]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
    #region Contructors
 
    /// <summary>
    /// Main constructor.
    /// </summary>
    public MainWindow()
    {
        // Initialize UI
        InitializeComponent();
 
        // Get processor information
        GetProcessorInformation();
    }
 
    #endregion
 
    /// <summary>
    /// Retrieve the processor information and add to UI.
    /// </summary>
    private void GetProcessorInformation()
    {
        // Build an options object for the remote connection
        var options = new ConnectionOptions
            {
                Impersonation = ImpersonationLevel.Impersonate,
                EnablePrivileges = true
            };
 
        // Make a connection to a remote computer.
        var ms = new ManagementScope(@"" + "." + @"rootcimv2", options);
 
        // Query
        string query = "SELECT Manufacturer, MaxClockSpeed, AddressWidth, Name, " +
                       "SocketDesignation, ProcessorID, UniqueID FROM Win32_Processor";
 
        // Searcher
        var searcher =
            new ManagementObjectSearcher(ms, new WqlObjectQuery(query));
 
        // Get legacy info
        var processor = GetProcessorInfoLegacy(searcher);
 
        // Processor information
        // Description
        txtDescription.Text = RemoveExcessSpaces(processor.Name);
        if (String.IsNullOrEmpty(txtDescription.Text))
        {
            txtDescription.Text = "{Unknown}";
        }
 
        // Speed
        txtSpeed.Text = GetProcessorSpeed(processor.Speed);
        if (String.IsNullOrEmpty(txtSpeed.Text))
        {
            txtSpeed.Text = "{Unknown}";
        }
 
        // Count
        txtCount.Text = GetProcessorCount(5.2, processor);
        if (String.IsNullOrEmpty(txtCount.Text))
        {
            txtCount.Text = "{Unknown}";
        }
 
        // Width
        txtWidth.Text = "x86-" + processor.Architecture;
        if (String.IsNullOrEmpty(txtWidth.Text))
        {
            txtWidth.Text = "{Unknown}";
        }
    }
 
    /// <summary>
    /// Gets processor information for Windows version 5.x.
    /// </summary>
    /// <param name="searcher"></param>
    /// <returns></returns>
    private static ProcessorInfo GetProcessorInfoLegacy(
        ManagementObjectSearcher searcher)
    {
        // Processor object
        var processor = new ProcessorInfo();
 
        // Descriptors
        var socket = new List<string>();
        var procId = new List<string>();
        var uniqueId = new List<string>();
 
        // Get data
        ManagementObjectCollection colItems = searcher.Get();
 
        try
        {
            // Evaluate data
            foreach (ManagementBaseObject objItem in colItems)
            {
                // Manufacturer
                if (objItem["Manufacturer"] != null)
                {
                    processor.Manufacturer = objItem["Manufacturer"].ToString();
                }
 
                // Speed
                if (objItem["MaxClockSpeed"] != null)
                {
                    processor.Speed = Convert.ToInt32(objItem["MaxClockSpeed"]);
                }
 
                // Architecture
                if (objItem["AddressWidth"] != null)
                {
                    processor.Architecture = objItem["AddressWidth"].ToString();
                }
 
                // Socket Designation
                if (objItem["SocketDesignation"] != null)
                {
                    processor.SocketDesignation =
                        objItem["SocketDesignation"].ToString();
                    socket.Add(processor.SocketDesignation);
                }
 
                // Name
                if (objItem["Name"] != null)
                {
                    processor.Name = objItem["Name"].ToString();
                }
 
                // ProcessorID
                if (objItem["ProcessorID"] != null)
                {
                    processor.ProcessorID = objItem["ProcessorID"].ToString();
                    procId.Add(processor.ProcessorID);
                }
                else
                {
                    procId.Add("");
                }
 
                // UniqueID
                if (objItem["UniqueID"] != null)
                {
                    processor.UniqueID = objItem["UniqueID"].ToString();
                    uniqueId.Add(processor.UniqueID);
                }
                else
                {
                    uniqueId.Add("");
                }
            }
 
            // Logical count
            int totalProcCount = colItems.Count;
            processor.LogicalProcessors = totalProcCount;
 
            // Cores
            GetLegacyCoreCount(socket, procId, uniqueId, ref processor);
 
            // Get #of possible sockets
            if ((processor.Cores > 0) && (processor.LogicalProcessors > 0))
            {
                int result = (processor.LogicalProcessors / processor.Cores);
                processor.Count = result;
            }
        }
        catch
        {
        }
        finally
        {
            colItems.Dispose();
        }
 
        // return
        return processor;
    }
 
    /// <summary>
    /// Gets the number of processor cores for Windows version 5.x.
    /// </summary>
    /// <param name="socket"></param>
    /// <param name="procId"></param>
    /// <param name="uniqueId"></param>
    /// <param name="processor"></param>
    private static void GetLegacyCoreCount(List<string> socket, List<string> procId,
                                           List<string> uniqueId, ref ProcessorInfo processor)
    {
        int totalProcessors = 0;
 
        // Processor marker
 
        // Check Socket Designation
        for (int i = 0; i < socket.Count; i++)
        {
            // Start with the assumption this is unique.
            bool isUnique = true;
 
            // Check for Redundancies
            for (int j = i + 1; j < socket.Count; j++)
            {
                if (socket[i] == socket[j])
                {
                    isUnique = false;
                    break;
                }
            }
 
            // If Redundant Unique ID's Exist
            for (int j = i + 1; j < socket.Count; j++)
            {
                if ((uniqueId[i] != "") && (uniqueId[j] != "") &&
                    (uniqueId[i] != uniqueId[j]))
                {
                    isUnique = true;
                    break;
                }
            }
 
            // Check for NULL ProcessorID
            if (procId[i].Trim() == "0000000000000000")
            {
                isUnique = false;
            }
 
            // Calculate Total
            if (isUnique)
            {
                totalProcessors++;
            }
        }
 
        // Get Cores
        int result = (processor.LogicalProcessors / totalProcessors);
        processor.Cores = result;
    }
 
    /// <summary>
    /// Retrieves the Processor speed in human-readable format.
    /// </summary>
    /// <param name="speed"></param>
    /// <returns></returns>
    public static string GetProcessorSpeed(int speed)
    {
        string result = string.Empty;
 
        if (speed.ToString().Length >= 4)
        {
            double dSpeed = Convert.ToDouble(speed) / 1000;
            result = dSpeed.ToString("0.00") + " GHz";
        }
        else
        {
            result = speed.ToString() + " MHz";
        }
 
        // Return
        return result;
    }
 
    /// <summary>
    /// Returns the processor count in a human-readable format.
    /// </summary>
    /// <param name="oSver"></param>
    /// <param name="proc"></param>
    /// <returns></returns>
    public static string GetProcessorCount(double oSver, ProcessorInfo proc)
    {
        string result = "";
 
        int physical = proc.Count;
        int cores = proc.Cores;
 
        // Manufacturer
        string hyper = "HyperThreading";
        if (proc.Manufacturer.ToLower().IndexOf("intel") == -1)
        {
            hyper = "HyperTransport";
        }
 
        // Processor count
        string physDesc = physical.ToString() + " processor(s)";
 
        // Cores
        string coreDesc = string.Empty;
 
        // Current
        if (oSver >= 6)
        {
            coreDesc = cores.ToString() + " core(s)";
            if (proc.IsHyperThreaded)
            {
                coreDesc += " w/ HyperThreading";
            }
        }
 
            // Legacy
        else
        {
            coreDesc = cores.ToString() + " core(s)";
 
            if ((cores / physical) == 2)
            {
                // Intel
                if (proc.Manufacturer.ToLower().IndexOf("intel") != -1)
                {
                    coreDesc += " (or " + physical + " core(s) w/ " + hyper + ")";
                }
            }
        }
 
        result = physDesc + " (" + coreDesc + ")";
 
        // Return
        return result;
    }
 
    /// <summary>
    /// Removes extra spaces between words.
    /// </summary>
    /// <param name="procDesc"></param>
    /// <returns></returns>
    public static string RemoveExcessSpaces(string procDesc)
    {
        string result = "";
 
        // Evaluate
        string[] desc = procDesc.Split((char)32);
 
        // Name
        for (int i = 0; i < desc.Length; i++)
        {
            if (desc[i].Trim() != "")
            {
                result += desc[i] + " ";
            }
        }
 
        // Return
        return result;
    }
}

[ProcessorInfo class]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
/// <summary>
/// Information relevant to the physical processors.
/// </summary>
public class ProcessorInfo
{
    #region Properties
 
    /// <summary>
    /// Win32_Processor: AddressWidth: On a 32-bit operating system, the value is 32
    /// and on a 64-bit operating system it is 64.
    /// </summary>
    public string Architecture { get; set; }
 
    /// <summary>
    /// Win32_Processor: NumberOfCores: Number of cores for the current instance of
    /// the processor.
    /// </summary>
    public int Cores { get; set; }
 
    /// <summary>
    /// Total processor count.
    /// </summary>
    public int Count { get; set; }
 
    /// <summary>
    /// Determines whether processors support Hyper-Threading or Hyper-Transport.
    /// </summary>
    public bool IsHyperThreaded { get; set; }
 
    /// <summary>
    /// Win32_Processor: NumberOfLogicalProcessors: Number of logical processors for
    /// the current instance of the processor.
    /// </summary>
    public int LogicalProcessors { get; set; }
 
    /// <summary>
    /// Win32_Processor: Manufacturer: Name of the processor manufacturer.
    /// </summary>
    public string Manufacturer { get; set; }
 
    /// <summary>
    /// Win32_Processor: Name: Label by which the object is known.
    /// </summary>
    public string Name { get; set; }
 
    /// <summary>
    /// Win32_Processor: ProcessorID: Processor information that describes the
    /// processor features.
    /// </summary>
    public string ProcessorID { get; set; }
 
    /// <summary>
    /// Win32_Processor: SocketDesignation: Type of chip socket used on the circuit.
    /// </summary>
    public string SocketDesignation { get; set; }
 
    /// <summary>
    /// Win32_Processor: MaxClockSpeed: Detected processor speed.
    /// </summary>
    public int Speed { get; set; }
 
    /// <summary>
    /// Win32_Processor: UniqueID: Globally unique identifier for the processor.
    /// </summary>
    public string UniqueID { get; set; }
 
    #endregion
 
    #region Constructors
 
    public ProcessorInfo()
    {
        Architecture = "x86";
    }
 
    #endregion
}