Using wmi to trigger query OIDs in NDIS driver - wmi

I would like to make wmi query in cs to trigger NDIS OIDs.
For example, to check hardware status (OID_GEN_HARDWARE_STATUS) I can use ManagementObjectSearcher("root\\WMI", "SELECT * FROM MSNDIS_HardwareStatus")
I need to make some other requests, but I cannot find any way to find wmi class name for given OID (let's say it's OID_802_3_RCV_OVERRUN, there is no any obvious relation like OID_GEN_HARDWARE_STATUS -> MSNDIS_HardwareStatus for it, at least I have not found one).
How do I find relations between wmi class name and NDIS OIDs? Is there any documentation for it?

The specific example you cite, OID_802_3_RCV_OVERRUN, does not have a corresponding WMI class. Here's one way to prove that, if you're comfortable using a kernel debugger.
Run the kernel debugger command !ndiskd.miniport -wmi <someHandle>
Search the text output for "OID_802_3_RCV_OVERRUN"
There's no matches, so the miniport does not expose that OID to WMI
If you'd rather not use a kernel debugger, or if you just want to see a few more examples, here's an article I wrote on how to inspect the relationship between WMI classes and OIDs.

Related

How do I get information about the Startup Type of a service in c++?

I'm looking for a way to get the Startup type of a service using c++. I am able to get the SERVICE_STATUS data from a ControlService() call, but the data does not include the startup type. I'm aware there is a way to get the Startup Type using windows power shell, maybe I should make a c++ method that makes that power shell call? Is that the best way to do it?
You need to open the service with OpenService() requesting SERVICE_QUERY_CONFIG access, and then you can use QueryServiceConfig(). dwStartType is one of the available fields of the returned QUERY_SERVICE_CONFIG structure data.

How does WMI get the ProcessorId?

I'd like to get the processor id without using WMI.
But if I try to get it using CPUID with EAX=3, I get an empty result.
How does WMI get the ProcessorId? And is there a way to get it without using WMI?
I found it out by myself, after looking at a cpuid dump.
It looks like WMI is creating the processor id by just combining EDX+EAX from the results of CPUID with EAX=1.
I thought that id from WMI was a unique serial number, but apparently it is not!

WMI methods for Hyper-V network management is failing on Windows 2012

I have been trying to use WMI classes (using C++) to manage Virtual Switches in Hyperv like Creation,Deletion, Attach a Virtual Network to a VM etc. I was able to do everything perfectly on Windows 2008 R2. But none of them are working fine on Windows 2012.
For example when I create an externalnetwork I call a method called CreateSwitchPort on the object of the class Msvm_VirtualSwitchManagementService. It's working on 2k8R2 but fails with out parameter return value as 32768 which means failure. Can anyone point out why does the method return an error? How to debug the issue? Are there any permissions I should be giving. Any help in the regard is highly appreciated.
--Ramakrishna.
Hyper-V 2012 supports the previous WMI API, and I have successfully used it. Hyper-V 2012 introduces a v2 API, but this is irrelevant to you.
CreateSwitchPort is a very straightforward call. Here is an example in Python that is quite readable. The Python call returns a tuple that the [out] parameters are added to.
#Create a port on the vswitch.
(new_port, ret_val) = switch_svc.CreateSwitchPort(
Name=str(uuid.uuid4()),
FriendlyName=vm_name,
ScopeOfResidence="",
VirtualSwitch=extswitch.path_())
Check that the VirtualSwitch parameter is valid. I use a WMI query shown below to get this object. It fails if the VirtualSwitch is not connected to an external NIC. Is your query successful?
return self._conn.Msvm_ExternalEthernetPort(IsBound='TRUE')[0]\
.associators(wmi_result_class='Msvm_SwitchLANEndpoint')[0]\
.associators(wmi_result_class='Msvm_SwitchPort')[0]\
.associators(wmi_result_class='Msvm_VirtualSwitch')[0]
Next, look to see if the name Name parameter needs to be unique. If you use a static name, the call might fail because of a naming conflict.
If none of this helps, then start inspecting the Hyper-V WMI objects in realtime. You can use Python and the WMI bindings for Python by Tim Golden.

Remote WMI method permissions

We have an application that we have instrumented with WMI, and have added a WMI method which is a ManagementTask. When we try to invoke this management task from another application the method is getting called just fine, however within that thread of execution we are trying to write to a file, send a command to the SCM, and perform debug logging. None of these three items will execute because they seem to be running into permissions problems.
When we try to write to a file we get the error
Either a required impersonation level was not provided, or the provided impersonation level is invalid.
How do we resolve this?
Al, I feel your pain. Any attempt to write to a file using native WMI methods will fail since WMI is not capable of doing it. However, there is a workaround created by Frank White using C#, which was fleshed out in VBS. Here's the line he created that does the magic:
InputParameters("CommandLine") = "cmd /c echo myFTPCommands > c:\ftpscript.txt"
Please refer to the VBS method for full description, and post back here if you have questions about it. And yes, you will need to set impersonationLevel, as shown in the VBS page.
For sending a command to the SCM, that shouldn't be a problem, so try it separately to ensure there's no issues. For debug logging, if you're writing a file to the remote system, then you'll have to use the workaround mentioned above.

Is MsiOpenProduct the correct way to read properties from an installed product?

Given an MSI product code I want to get the upgrade code (among other properties) from an already installed product. I have tried this by calling the MsiOpenProduct method, followed by MsiGetProductProperty(). An (abbreviated) example looks like this:
MSIHANDLE handle = NULL;
MsiOpenProduct(strProductCode,&handle);
CString strUpgradeCode;
MsiGetProductProperty(handle,_T("UpgradeCode"), strUpgradeCode.GetBuffer(GUID_LENGTH), &dwSize);
strUpgradeCode.ReleaseBuffer();
MsiCloseHandle(handle);
This gets me the desired value, and judging from the MSDN documentation this seems like a valid way to do this:
The MsiOpenProduct function opens a
product for use with the functions
that access the product database. The
MsiCloseHandle function must be called
with the handle when the handle is no
longer needed.
However the call to MsiOpenProduct() pops up the "Windows installer is preparing the installation..." dialog. The call to MsiCloseHandle() makes it disappear again.
This left me wondering:
What does the call to MsiOpenProduct() do under the hood? I do not want to trigger any actions, I just want to read properties.
I don't mind the dialog popping up, as this is only for unit test code as long as this has no side effects. And as there are many unit tests that do this, it must still work when opening and closing handles in rapid succession.
Although I stumbled over the MsiGetProductInfo method, there seems to be no way to get the upgrade code. Am I right?
Is MsiOpenProduct the correct way to read properties like the upgrade code?
MsiOpenProduct should be fine So long as you don't run any sequences or actions, it won't do anything. If you want to silence the dialog, you can with careful use of either MsiSetInternalUI() or MsiSetExternalUI().
Another approach you can take, as long as the ProductCode and UpgradeCode are safely static (i.e. as long as they aren't changed by transforms), is to locate the database using MsiGetProductInfo() and call MsiOpenDatabase() on that. The difference is that MsiOpenProduct() (or similarly MsiOpenPackage) applies the transforms that were used at installation time and prepares a session, whereas MsiOpenDatabase() does neither.
There is a comprehensive answer with information on how to get the UpgradeCode using Powershell or VBScript and WMI here: How can I find the Upgrade Code for an installed MSI file?
Below is a quick, basic example using VBScript / COM automation (MSI API, not WMI) and the approach discussed by OP (using the OpenProduct method - the COM equivalent to the Win32 installer function).
As discussed in my comment above, I will just add this little VBScript to do the same as OP does in C++. Note that Windows Installer can be accessed via WMI (Win32_Product object), COM automation and Win32 C++ installer functions.
For some reason the UpgradeCode for a package appears to not be available directly from the COM API or the Win32 API. Very strange indeed, especially since it is an input parameter to functions like Installer.RelatedProducts - it is not clear in the documentation that the actual call should be RelatedProducts(UpgradeCode), but looking in the msi.IDL you see: StringList* RelatedProducts([in] BSTR UpgradeCode);
The WMI option works, but so does this OpenProduct call demonstrated below (which is significantly faster and appears safe - WMI is completely read-only as far as I know though - but heaven knows what they are doing "under the hood". Are they spinning up a session object? Or are they reading from a WMI database? WMI does "feels" safer somehow).
The beauty of the below method is that it will apply all transforms that were applied to the product in question at installation time. If you want to write to disk instead of showing message boxes and can't be bothered looking up the docs, here is a similar VBScript that writes package info to a desktop text file: How can I find the product GUID of an installed MSI setup? - quite a bit down the page, just copy a couple of lines and you are message box free).
Note! The script below will create one log file per opened MSI if automatic logging is enabled on the system. As it stands the script will only open one MSI before it exists though (the Exit For construct).
On Error Resume Next ' This "tersified" script has no error handling
Const msiUILevelNone = 2
Set installer = CreateObject("WindowsInstaller.Installer")
Set products = installer.ProductsEx("", "", 7)
installer.UILevel = msiUILevelNone ' Suppress GUI (MSI progress dialog)
'Iterate over all MSI packages on the box
For Each product In products
' productcode = product.ProductCode
' name = product.InstallProperty("ProductName")
' version = product.InstallProperty("VersionString")
' pkgcode = product.InstallProperty("PackageCode")
Set session = installer.OpenProduct(product.ProductCode)
upgradecode = session.ProductProperty("UpgradeCode")
MsgBox upgradecode
Set session = Nothing ' Important, close the session (doesn't work in Javascript btw)
Exit For ' End after one iteration (so you don't get a million message boxes)
' Alternatively something like: If i > 4 Then Exit For
Next
Set installer = Nothing
MsgBox "Finished"
I have tried to look in the C++ Win32 installer functions for any other way to retrieve the UpgradeCode, but I can't see anything obvious. The session approach should work in C++ as well, but I am a little apprehensive about the release of handles and resources. I am not properly potty-trained with C++, but know more than enough to be dangerous. Fire In The Hole. Etc...
I wonder if the OP retrieved all packages on the box, or just a single one. I wonder if the timing issues and concurrent session object problems seen with Javascript would strike in C++ as well? I will give it a go I think - someday.
For the information you want, it sounds like you can just call ::MsiGetProductInfo(). ::MsiOpenDatabase() is a very slow operation while ::MsiGetProductInfo() is (IIRC) more on par with registry look ups.