All posts tagged slmgr.vbs

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:


/// <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:


/// <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!