Cómo unirse a una consulta WMI (WQL)
Pregunta
Quiero obtener el número de serie del disco duro de arranque mediante una consulta WQL.
La partición de inicio se puede recuperar mediante la siguiente consulta:
SELECT * FROM Win32_DiskPartition where BootPartition=True
El número de serie está en Win32_DiskDrive:
SELECT DeviceID, SerialNumber FROM Win32_DiskDrive
Win32_DiskDriveToDiskPartition
tiene el mapeo de Win32_DiskDrive
a Win32_DiskPartition
.estan mapeados Win32_DiskDrive.DeviceID
a Win32_DiskPartition.DeviceID
en Win32_DiskDriveToDiskPartition
¿Cómo puedo crear una consulta WQL que se una internamente? Win32_DiskPartition
y Win32_DiskDrive
?¿Tengo que usar asociados o funciona con INNER JOIN?
Solución
WQL no soporta el JOIN
cláusula.Necesitas usar el ASSOCIATORS OF
declaración como lo adivinaste.Aquí hay un ejemplo en VBScript:
strComputer = "."
Set oWMI = GetObject("winmgmts:\\" & strComputer & "\root\CIMV2")
Set colPartitions = oWMI.ExecQuery( _
"SELECT * FROM Win32_DiskPartition WHERE BootPartition=True")
For Each oPartition in colPartitions
Set colDrives = oWMI.ExecQuery( _
"ASSOCIATORS OF {Win32_DiskPartition.DeviceID='" _
& oPartition.DeviceID & "'} WHERE ResultClass=Win32_DiskDrive")
For Each oDrive in colDrives
WScript.Echo oDrive.SerialNumber
Next
Next
Tenga en cuenta, sin embargo, que el Win32_DiskDrive.SerialNumber
La propiedad no está disponible antes de Windows Vista.Por lo tanto, si desea que su código funcione también en versiones anteriores de Windows (p. ej.Windows XP o Windows 2000) debería considerar el uso de API distintas a WMI.
Editar: (responder al comentario) Sí, puedes agregar un anidado. ASSOCIATORS OF
consulta para obtener el Win32_PhysicalMedia
instancias correspondientes a la Win32_DiskDrive
instancias;algo como esto:
...
For Each oDrive in colDrives
Set colMedia = oWMI.ExecQuery( _
"ASSOCIATORS OF {Win32_DiskDrive.DeviceID='" _
& oDrive.DeviceID & "'} WHERE ResultClass=Win32_PhysicalMedia")
For Each oMedia in colMedia
WScript.Echo oMedia.SerialNumber
Next
Next
No has dicho qué lenguaje estás usando. Supongo que en PowerShell o C# todo se puede hacer de manera más elegante, pero VBScript es bastante detallado.
Otros consejos
Aquí está el código C++ que hace lo mismo que el código VBScript publicado por Helen.
// Obtain the initial locator to WMI
// ...
// Connect to WMI through the IWbemLocator::ConnectServer method
// ...
// Set security levels on the proxy
// ...
wchar_t wmihddsn[256];
*wmihddsn=0;
hres = pSvc->ExecQuery(
bstr_t("WQL"),
bstr_t("SELECT * FROM Win32_DiskPartition WHERE BootPartition=True"),
WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
NULL,
&pEnumerator);
if(SUCCEEDED(hres) && pEnumerator)
{
// get the first Win32_DiskPartition
HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn);
if(SUCCEEDED(hr) && 0 != uReturn)
{
VARIANT vtProp;
wchar_t tmp[1024];
char query[1024];
// Get the value of the partition's DeviceID property
hr = pclsObj->Get(L"DeviceID", 0, &vtProp, 0, 0);
if(SUCCEEDED(hr))
{
if(vtProp.vt == VT_BSTR) {
// wcout << " SerialNumber : " << vtProp.bstrVal << endl;
wcscpy(tmp, vtProp.bstrVal);
}
VariantClear(&vtProp);
// "join" Win32_DiskPartition to Win32_DiskDrive
sprintf(query,
"ASSOCIATORS OF {Win32_DiskPartition.DeviceID='%s'} WHERE ResultClass=Win32_DiskDrive",
NarrowWcharString(tmp));
hres = pSvc->ExecQuery(
bstr_t("WQL"),
bstr_t(query),
WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
NULL,
&pEnumerator1);
if(SUCCEEDED(hres) && pEnumerator1)
{
// get the first Win32_DiskDrive
hr = pEnumerator1->Next(WBEM_INFINITE, 1, &pclsObj1, &uReturn);
if(SUCCEEDED(hr) && 0 != uReturn)
{
// Get the value of the disk-drive's DeviceID
hr = pclsObj1->Get(L"DeviceID", 0, &vtProp, 0, 0);
if(SUCCEEDED(hr))
{
if(vtProp.vt == VT_BSTR)
{
wcscpy(tmp, vtProp.bstrVal);
}
VariantClear(&vtProp);
// "join" Win32_DiskDrive to Win32_PhysicalMedia
sprintf(query,
"ASSOCIATORS OF {Win32_DiskDrive.DeviceID='%s'} WHERE ResultClass=Win32_PhysicalMedia",
NarrowWcharString(tmp));
hres = pSvc->ExecQuery(
bstr_t("WQL"),
bstr_t(query),
WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
NULL,
&pEnumerator2);
if(SUCCEEDED(hres) && pEnumerator2)
{
// get the first Win32_PhysicalMedia
hr = pEnumerator2->Next(WBEM_INFINITE, 1, &pclsObj2, &uReturn);
if(SUCCEEDED(hr) && 0 != uReturn)
{
// get the PhysicalMedia's SerialNumber
hr = pclsObj2->Get(L"SerialNumber", 0, &vtProp, 0, 0);
if(SUCCEEDED(hr))
{
if(vtProp.vt == VT_BSTR)
{
// wcout << " SerialNumber : " << vtProp.bstrVal << endl;
wcscpy(wmihddsn,vtProp.bstrVal);
}
VariantClear(&vtProp);
}
}
if(pclsObj2) pclsObj2->Release();
}
if(pEnumerator2) pEnumerator2->Release();
} // get disk-drive's DeviceID
}
if(pclsObj1) pclsObj1->Release();
}
if(pEnumerator1) pEnumerator1->Release();
} // get partition's DeviceID
}
if(pclsObj) pclsObj->Release();
} // if succeeded first query
if(pEnumerator) pEnumerator->Release();
// ...
// cleanup