diff --git a/src/Makefile.am b/src/Makefile.am
index 3c7adae492bf6205bbe64e44ebc2033887305bbe..e2dc77e3d4e1899e21ee925b0a388a8be66bcacc 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -912,8 +912,6 @@ HYPERV_DRIVER_SOURCES =									\
 		hyperv/openwsman.h
 
 HYPERV_DRIVER_GENERATED =							\
-		hyperv/hyperv_wmi.generated.c					\
-		hyperv/hyperv_wmi.generated.h					\
 		hyperv/hyperv_wmi_classes.generated.c				\
 		hyperv/hyperv_wmi_classes.generated.h				\
 		hyperv/hyperv_wmi_classes.generated.typedef
diff --git a/src/hyperv/hyperv_driver.c b/src/hyperv/hyperv_driver.c
index b642a025d229a333c7cfc7c2186f8ffd08319b13..090ea243ba5d30d7ee7d2955d5fcd89980b95802 100644
--- a/src/hyperv/hyperv_driver.c
+++ b/src/hyperv/hyperv_driver.c
@@ -55,7 +55,67 @@ hypervFreePrivate(hypervPrivate **priv)
     VIR_FREE(*priv);
 }
 
+static int
+hypervInitConnection(virConnectPtr conn, hypervPrivate *priv,
+                     char *username, char *password)
+{
+    virBuffer query = VIR_BUFFER_INITIALIZER;
+    hypervWqlQuery wqlQuery = HYPERV_WQL_QUERY_INITIALIZER;
+    hypervObject *computerSystem = NULL;
+    int ret = -1;
+
+    /* Initialize the openwsman connection */
+    priv->client = wsmc_create(conn->uri->server, conn->uri->port, "/wsman",
+                               priv->parsedUri->transport, username, password);
+
+    if (priv->client == NULL) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("Could not create openwsman client"));
+        goto cleanup;
+    }
+
+    if (wsmc_transport_init(priv->client, NULL) != 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("Could not initialize openwsman transport"));
+        goto cleanup;
+    }
+
+    /* FIXME: Currently only basic authentication is supported  */
+    wsman_transport_set_auth_method(priv->client, "basic");
+
+    wqlQuery.info = Msvm_ComputerSystem_WmiInfo;
+    wqlQuery.query = &query;
+
+    virBufferAddLit(&query, MSVM_COMPUTERSYSTEM_WQL_SELECT);
+    virBufferAddLit(&query, "WHERE ");
+    virBufferAddLit(&query, MSVM_COMPUTERSYSTEM_WQL_PHYSICAL);
+
+    /* try query using V2 namespace (for Hyper-V 2012+) */
+    priv->wmiVersion = HYPERV_WMI_VERSION_V2;
+
+    if (hypervEnumAndPull(priv, &wqlQuery, &computerSystem) < 0) {
+        /* rebuild query because hypervEnumAndPull consumes it */
+        virBufferAddLit(&query, MSVM_COMPUTERSYSTEM_WQL_SELECT);
+        virBufferAddLit(&query, "WHERE ");
+        virBufferAddLit(&query, MSVM_COMPUTERSYSTEM_WQL_PHYSICAL);
+
+        /* fall back to V1 namespace (for Hyper-V 2008) */
+        priv->wmiVersion = HYPERV_WMI_VERSION_V1;
+
+        if (hypervEnumAndPull(priv, &wqlQuery, &computerSystem) < 0) {
+            virReportError(VIR_ERR_INTERNAL_ERROR,
+                           _("%s is not a Hyper-V server"), conn->uri->server);
+            goto cleanup;
+        }
+    }
+
+    ret = 0;
 
+ cleanup:
+    hypervFreeObject(priv, computerSystem);
+
+    return ret;
+}
 
 static virDrvOpenStatus
 hypervConnectOpen(virConnectPtr conn, virConnectAuthPtr auth,
@@ -67,8 +127,6 @@ hypervConnectOpen(virConnectPtr conn, virConnectAuthPtr auth,
     hypervPrivate *priv = NULL;
     char *username = NULL;
     char *password = NULL;
-    virBuffer query = VIR_BUFFER_INITIALIZER;
-    Msvm_ComputerSystem *computerSystem = NULL;
 
     virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);
 
@@ -147,41 +205,9 @@ hypervConnectOpen(virConnectPtr conn, virConnectAuthPtr auth,
         goto cleanup;
     }
 
-    /* Initialize the openwsman connection */
-    priv->client = wsmc_create(conn->uri->server, conn->uri->port, "/wsman",
-                               priv->parsedUri->transport, username, password);
 
-    if (priv->client == NULL) {
-        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                       _("Could not create openwsman client"));
+    if (hypervInitConnection(conn, priv, username, password) < 0)
         goto cleanup;
-    }
-
-    if (wsmc_transport_init(priv->client, NULL) != 0) {
-        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                       _("Could not initialize openwsman transport"));
-        goto cleanup;
-    }
-
-    /* FIXME: Currently only basic authentication is supported  */
-    wsman_transport_set_auth_method(priv->client, "basic");
-
-    /* Check if the connection can be established and if the server has the
-     * Hyper-V role installed. If the call to hypervGetMsvmComputerSystemList
-     * succeeds than the connection has been established. If the returned list
-     * is empty than the server isn't a Hyper-V server. */
-    virBufferAddLit(&query, MSVM_COMPUTERSYSTEM_WQL_SELECT);
-    virBufferAddLit(&query, "where ");
-    virBufferAddLit(&query, MSVM_COMPUTERSYSTEM_WQL_PHYSICAL);
-
-    if (hypervGetMsvmComputerSystemList(priv, &query, &computerSystem) < 0)
-        goto cleanup;
-
-    if (computerSystem == NULL) {
-        virReportError(VIR_ERR_INTERNAL_ERROR,
-                       _("%s is not a Hyper-V server"), conn->uri->server);
-        goto cleanup;
-    }
 
     conn->privateData = priv;
     priv = NULL;
@@ -191,7 +217,6 @@ hypervConnectOpen(virConnectPtr conn, virConnectAuthPtr auth,
     hypervFreePrivate(&priv);
     VIR_FREE(username);
     VIR_FREE(password);
-    hypervFreeObject(priv, (hypervObject *)computerSystem);
 
     return result;
 }
@@ -240,7 +265,7 @@ hypervConnectGetHostname(virConnectPtr conn)
         goto cleanup;
     }
 
-    ignore_value(VIR_STRDUP(hostname, computerSystem->data->DNSHostName));
+    ignore_value(VIR_STRDUP(hostname, computerSystem->data.common->DNSHostName));
 
  cleanup:
     hypervFreeObject(priv, (hypervObject *)computerSystem);
@@ -282,7 +307,7 @@ hypervNodeGetInfo(virConnectPtr conn, virNodeInfoPtr info)
                       "{Win32_ComputerSystem.Name=\"%s\"} "
                       "where AssocClass = Win32_ComputerSystemProcessor "
                       "ResultClass = Win32_Processor",
-                      computerSystem->data->Name);
+                      computerSystem->data.common->Name);
 
     if (hypervGetWin32ProcessorList(priv, &query, &processorList) < 0)
         goto cleanup;
@@ -295,7 +320,7 @@ hypervNodeGetInfo(virConnectPtr conn, virNodeInfoPtr info)
     }
 
     /* Strip the string to fit more relevant information in 32 chars */
-    tmp = processorList->data->Name;
+    tmp = processorList->data.common->Name;
 
     while (*tmp != '\0') {
         if (STRPREFIX(tmp, "  ")) {
@@ -313,16 +338,16 @@ hypervNodeGetInfo(virConnectPtr conn, virNodeInfoPtr info)
     }
 
     /* Fill struct */
-    if (virStrncpy(info->model, processorList->data->Name,
+    if (virStrncpy(info->model, processorList->data.common->Name,
                    sizeof(info->model) - 1, sizeof(info->model)) == NULL) {
         virReportError(VIR_ERR_INTERNAL_ERROR,
                        _("CPU model %s too long for destination"),
-                       processorList->data->Name);
+                       processorList->data.common->Name);
         goto cleanup;
     }
 
-    info->memory = computerSystem->data->TotalPhysicalMemory / 1024; /* byte to kilobyte */
-    info->mhz = processorList->data->MaxClockSpeed;
+    info->memory = computerSystem->data.common->TotalPhysicalMemory / 1024; /* byte to kilobyte */
+    info->mhz = processorList->data.common->MaxClockSpeed;
     info->nodes = 1;
     info->sockets = 0;
 
@@ -331,8 +356,8 @@ hypervNodeGetInfo(virConnectPtr conn, virNodeInfoPtr info)
         ++info->sockets;
     }
 
-    info->cores = processorList->data->NumberOfCores;
-    info->threads = info->cores / processorList->data->NumberOfLogicalProcessors;
+    info->cores = processorList->data.common->NumberOfCores;
+    info->threads = info->cores / processorList->data.common->NumberOfLogicalProcessors;
     info->cpus = info->sockets * info->cores;
 
     result = 0;
@@ -372,7 +397,7 @@ hypervConnectListDomains(virConnectPtr conn, int *ids, int maxids)
 
     for (computerSystem = computerSystemList; computerSystem != NULL;
          computerSystem = computerSystem->next) {
-        ids[count++] = computerSystem->data->ProcessID;
+        ids[count++] = computerSystem->data.common->ProcessID;
 
         if (count >= maxids)
             break;
@@ -532,7 +557,7 @@ hypervDomainSuspend(virDomainPtr domain)
     if (hypervMsvmComputerSystemFromDomain(domain, &computerSystem) < 0)
         goto cleanup;
 
-    if (computerSystem->data->EnabledState !=
+    if (computerSystem->data.common->EnabledState !=
         MSVM_COMPUTERSYSTEM_ENABLEDSTATE_ENABLED) {
         virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                        _("Domain is not active"));
@@ -560,7 +585,7 @@ hypervDomainResume(virDomainPtr domain)
     if (hypervMsvmComputerSystemFromDomain(domain, &computerSystem) < 0)
         goto cleanup;
 
-    if (computerSystem->data->EnabledState !=
+    if (computerSystem->data.common->EnabledState !=
         MSVM_COMPUTERSYSTEM_ENABLEDSTATE_PAUSED) {
         virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                        _("Domain is not paused"));
@@ -666,7 +691,7 @@ hypervDomainGetInfo(virDomainPtr domain, virDomainInfoPtr info)
         virReportError(VIR_ERR_INTERNAL_ERROR,
                        _("Could not lookup %s for domain %s"),
                        "Msvm_VirtualSystemSettingData",
-                       computerSystem->data->ElementName);
+                       computerSystem->data.common->ElementName);
         goto cleanup;
     }
 
@@ -676,7 +701,7 @@ hypervDomainGetInfo(virDomainPtr domain, virDomainInfoPtr info)
                       "{Msvm_VirtualSystemSettingData.InstanceID=\"%s\"} "
                       "where AssocClass = Msvm_VirtualSystemSettingDataComponent "
                       "ResultClass = Msvm_ProcessorSettingData",
-                      virtualSystemSettingData->data->InstanceID);
+                      virtualSystemSettingData->data.common->InstanceID);
 
     if (hypervGetMsvmProcessorSettingDataList(priv, &query,
                                               &processorSettingData) < 0) {
@@ -687,7 +712,7 @@ hypervDomainGetInfo(virDomainPtr domain, virDomainInfoPtr info)
         virReportError(VIR_ERR_INTERNAL_ERROR,
                        _("Could not lookup %s for domain %s"),
                        "Msvm_ProcessorSettingData",
-                       computerSystem->data->ElementName);
+                       computerSystem->data.common->ElementName);
         goto cleanup;
     }
 
@@ -697,7 +722,7 @@ hypervDomainGetInfo(virDomainPtr domain, virDomainInfoPtr info)
                       "{Msvm_VirtualSystemSettingData.InstanceID=\"%s\"} "
                       "where AssocClass = Msvm_VirtualSystemSettingDataComponent "
                       "ResultClass = Msvm_MemorySettingData",
-                      virtualSystemSettingData->data->InstanceID);
+                      virtualSystemSettingData->data.common->InstanceID);
 
     if (hypervGetMsvmMemorySettingDataList(priv, &query,
                                            &memorySettingData) < 0) {
@@ -709,15 +734,15 @@ hypervDomainGetInfo(virDomainPtr domain, virDomainInfoPtr info)
         virReportError(VIR_ERR_INTERNAL_ERROR,
                        _("Could not lookup %s for domain %s"),
                        "Msvm_MemorySettingData",
-                       computerSystem->data->ElementName);
+                       computerSystem->data.common->ElementName);
         goto cleanup;
     }
 
     /* Fill struct */
     info->state = hypervMsvmComputerSystemEnabledStateToDomainState(computerSystem);
-    info->maxMem = memorySettingData->data->Limit * 1024; /* megabyte to kilobyte */
-    info->memory = memorySettingData->data->VirtualQuantity * 1024; /* megabyte to kilobyte */
-    info->nrVirtCpu = processorSettingData->data->VirtualQuantity;
+    info->maxMem = memorySettingData->data.common->Limit * 1024; /* megabyte to kilobyte */
+    info->memory = memorySettingData->data.common->VirtualQuantity * 1024; /* megabyte to kilobyte */
+    info->nrVirtCpu = processorSettingData->data.common->VirtualQuantity;
     info->cpuTime = 0;
 
     result = 0;
@@ -803,7 +828,7 @@ hypervDomainGetXMLDesc(virDomainPtr domain, unsigned int flags)
         virReportError(VIR_ERR_INTERNAL_ERROR,
                        _("Could not lookup %s for domain %s"),
                        "Msvm_VirtualSystemSettingData",
-                       computerSystem->data->ElementName);
+                       computerSystem->data.common->ElementName);
         goto cleanup;
     }
 
@@ -813,7 +838,7 @@ hypervDomainGetXMLDesc(virDomainPtr domain, unsigned int flags)
                       "{Msvm_VirtualSystemSettingData.InstanceID=\"%s\"} "
                       "where AssocClass = Msvm_VirtualSystemSettingDataComponent "
                       "ResultClass = Msvm_ProcessorSettingData",
-                      virtualSystemSettingData->data->InstanceID);
+                      virtualSystemSettingData->data.common->InstanceID);
 
     if (hypervGetMsvmProcessorSettingDataList(priv, &query,
                                               &processorSettingData) < 0) {
@@ -824,7 +849,7 @@ hypervDomainGetXMLDesc(virDomainPtr domain, unsigned int flags)
         virReportError(VIR_ERR_INTERNAL_ERROR,
                        _("Could not lookup %s for domain %s"),
                        "Msvm_ProcessorSettingData",
-                       computerSystem->data->ElementName);
+                       computerSystem->data.common->ElementName);
         goto cleanup;
     }
 
@@ -834,7 +859,7 @@ hypervDomainGetXMLDesc(virDomainPtr domain, unsigned int flags)
                       "{Msvm_VirtualSystemSettingData.InstanceID=\"%s\"} "
                       "where AssocClass = Msvm_VirtualSystemSettingDataComponent "
                       "ResultClass = Msvm_MemorySettingData",
-                      virtualSystemSettingData->data->InstanceID);
+                      virtualSystemSettingData->data.common->InstanceID);
 
     if (hypervGetMsvmMemorySettingDataList(priv, &query,
                                            &memorySettingData) < 0) {
@@ -846,7 +871,7 @@ hypervDomainGetXMLDesc(virDomainPtr domain, unsigned int flags)
         virReportError(VIR_ERR_INTERNAL_ERROR,
                        _("Could not lookup %s for domain %s"),
                        "Msvm_MemorySettingData",
-                       computerSystem->data->ElementName);
+                       computerSystem->data.common->ElementName);
         goto cleanup;
     }
 
@@ -854,34 +879,34 @@ hypervDomainGetXMLDesc(virDomainPtr domain, unsigned int flags)
     def->virtType = VIR_DOMAIN_VIRT_HYPERV;
 
     if (hypervIsMsvmComputerSystemActive(computerSystem, NULL)) {
-        def->id = computerSystem->data->ProcessID;
+        def->id = computerSystem->data.common->ProcessID;
     } else {
         def->id = -1;
     }
 
-    if (virUUIDParse(computerSystem->data->Name, def->uuid) < 0) {
+    if (virUUIDParse(computerSystem->data.common->Name, def->uuid) < 0) {
         virReportError(VIR_ERR_INTERNAL_ERROR,
                        _("Could not parse UUID from string '%s'"),
-                       computerSystem->data->Name);
+                       computerSystem->data.common->Name);
         return NULL;
     }
 
-    if (VIR_STRDUP(def->name, computerSystem->data->ElementName) < 0)
+    if (VIR_STRDUP(def->name, computerSystem->data.common->ElementName) < 0)
         goto cleanup;
 
-    if (VIR_STRDUP(def->description, virtualSystemSettingData->data->Notes) < 0)
+    if (VIR_STRDUP(def->description, virtualSystemSettingData->data.common->Notes) < 0)
         goto cleanup;
 
-    virDomainDefSetMemoryTotal(def, memorySettingData->data->Limit * 1024); /* megabyte to kilobyte */
-    def->mem.cur_balloon = memorySettingData->data->VirtualQuantity * 1024; /* megabyte to kilobyte */
+    virDomainDefSetMemoryTotal(def, memorySettingData->data.common->Limit * 1024); /* megabyte to kilobyte */
+    def->mem.cur_balloon = memorySettingData->data.common->VirtualQuantity * 1024; /* megabyte to kilobyte */
 
     if (virDomainDefSetVcpusMax(def,
-                                processorSettingData->data->VirtualQuantity,
+                                processorSettingData->data.common->VirtualQuantity,
                                 NULL) < 0)
         goto cleanup;
 
     if (virDomainDefSetVcpus(def,
-                             processorSettingData->data->VirtualQuantity) < 0)
+                             processorSettingData->data.common->VirtualQuantity) < 0)
         goto cleanup;
 
     def->os.type = VIR_DOMAIN_OSTYPE_HVM;
@@ -930,7 +955,7 @@ hypervConnectListDefinedDomains(virConnectPtr conn, char **const names, int maxn
 
     for (computerSystem = computerSystemList; computerSystem != NULL;
          computerSystem = computerSystem->next) {
-        if (VIR_STRDUP(names[count], computerSystem->data->ElementName) < 0)
+        if (VIR_STRDUP(names[count], computerSystem->data.common->ElementName) < 0)
             goto cleanup;
 
         ++count;
@@ -1154,7 +1179,7 @@ hypervDomainHasManagedSaveImage(virDomainPtr domain, unsigned int flags)
     if (hypervMsvmComputerSystemFromDomain(domain, &computerSystem) < 0)
         goto cleanup;
 
-    result = computerSystem->data->EnabledState ==
+    result = computerSystem->data.common->EnabledState ==
              MSVM_COMPUTERSYSTEM_ENABLEDSTATE_SUSPENDED ? 1 : 0;
 
  cleanup:
@@ -1177,7 +1202,7 @@ hypervDomainManagedSaveRemove(virDomainPtr domain, unsigned int flags)
     if (hypervMsvmComputerSystemFromDomain(domain, &computerSystem) < 0)
         goto cleanup;
 
-    if (computerSystem->data->EnabledState !=
+    if (computerSystem->data.common->EnabledState !=
         MSVM_COMPUTERSYSTEM_ENABLEDSTATE_SUSPENDED) {
         virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                        _("Domain has no managed save image"));
@@ -1280,7 +1305,7 @@ hypervConnectListAllDomains(virConnectPtr conn,
 
         /* managed save filter */
         if (MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_MANAGEDSAVE)) {
-            bool mansave = computerSystem->data->EnabledState ==
+            bool mansave = computerSystem->data.common->EnabledState ==
                            MSVM_COMPUTERSYSTEM_ENABLEDSTATE_SUSPENDED;
 
             if (!((MATCH(VIR_CONNECT_LIST_DOMAINS_MANAGEDSAVE) && mansave) ||
diff --git a/src/hyperv/hyperv_wmi.c b/src/hyperv/hyperv_wmi.c
index b2b52435c70d58e7b3d3a0623139ab845fb74623..a3c7dc0750423d0d546e30cb1d793fd71476b157 100644
--- a/src/hyperv/hyperv_wmi.c
+++ b/src/hyperv/hyperv_wmi.c
@@ -36,15 +36,56 @@
 
 #define WS_SERIALIZER_FREE_MEM_WORKS 0
 
-#define ROOT_CIMV2 \
-    "http://schemas.microsoft.com/wbem/wsman/1/wmi/root/cimv2/*"
+#define VIR_FROM_THIS VIR_FROM_HYPERV
 
-#define ROOT_VIRTUALIZATION \
-    "http://schemas.microsoft.com/wbem/wsman/1/wmi/root/virtualization/*"
 
-#define VIR_FROM_THIS VIR_FROM_HYPERV
+static int
+hypervGetWmiClassInfo(hypervPrivate *priv, hypervWmiClassInfoListPtr list,
+                      hypervWmiClassInfoPtr *info)
+{
+    const char *version = "v2";
+    size_t i;
+
+    if (list->count == 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("The WMI class info list is empty"));
+        return -1;
+    }
 
+    /* if there's just one WMI class and isn't versioned, assume "shared" */
+    if (list->count == 1 && list->objs[0]->version == NULL) {
+        *info = list->objs[0];
+        return 0;
+    }
 
+    if (priv->wmiVersion == HYPERV_WMI_VERSION_V1)
+        version = "v1";
+
+    for (i = 0; i < list->count; i++) {
+       if (STRCASEEQ(list->objs[i]->version, version)) {
+           *info = list->objs[i];
+           return 0;
+       }
+    }
+
+    virReportError(VIR_ERR_INTERNAL_ERROR,
+                   _("Could not match WMI class info for version %s"),
+                   version);
+
+    return -1;
+}
+
+static int
+hypervGetWmiClassList(hypervPrivate *priv, hypervWmiClassInfoListPtr wmiInfo,
+                      virBufferPtr query, hypervObject **wmiClass)
+{
+    hypervWqlQuery wqlQuery = HYPERV_WQL_QUERY_INITIALIZER;
+
+    wqlQuery.info = wmiInfo;
+    wqlQuery.query = query;
+
+    return hypervEnumAndPull(priv, &wqlQuery, wmiClass);
+}
 
 int
 hypervVerifyResponse(WsManClient *client, WsXmlDocH response,
@@ -106,16 +147,16 @@ hypervVerifyResponse(WsManClient *client, WsXmlDocH response,
  * Object
  */
 
-/* This function guarantees that query is freed, even on failure */
+/* This function guarantees that wqlQuery->query is reset, even on failure */
 int
-hypervEnumAndPull(hypervPrivate *priv, virBufferPtr query, const char *root,
-                  XmlSerializerInfo *serializerInfo, const char *resourceUri,
-                  const char *className, hypervObject **list)
+hypervEnumAndPull(hypervPrivate *priv, hypervWqlQueryPtr wqlQuery,
+                  hypervObject **list)
 {
     int result = -1;
     WsSerializerContextH serializerContext;
     client_opt_t *options = NULL;
     char *query_string = NULL;
+    hypervWmiClassInfoPtr wmiInfo = NULL;
     filter_t *filter = NULL;
     WsXmlDocH response = NULL;
     char *enumContext = NULL;
@@ -125,11 +166,12 @@ hypervEnumAndPull(hypervPrivate *priv, virBufferPtr query, const char *root,
     XML_TYPE_PTR data = NULL;
     hypervObject *object;
 
-    if (virBufferCheckError(query) < 0) {
-        virBufferFreeAndReset(query);
+    if (virBufferCheckError(wqlQuery->query) < 0) {
+        virBufferFreeAndReset(wqlQuery->query);
         return -1;
     }
-    query_string = virBufferContentAndReset(query);
+
+    query_string = virBufferContentAndReset(wqlQuery->query);
 
     if (list == NULL || *list != NULL) {
         virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
@@ -137,6 +179,9 @@ hypervEnumAndPull(hypervPrivate *priv, virBufferPtr query, const char *root,
         return -1;
     }
 
+    if (hypervGetWmiClassInfo(priv, wqlQuery->info, &wmiInfo) < 0)
+        goto cleanup;
+
     serializerContext = wsmc_get_serialization_context(priv->client);
 
     options = wsmc_options_init();
@@ -155,7 +200,8 @@ hypervEnumAndPull(hypervPrivate *priv, virBufferPtr query, const char *root,
         goto cleanup;
     }
 
-    response = wsmc_action_enumerate(priv->client, root, options, filter);
+    response = wsmc_action_enumerate(priv->client, wmiInfo->rootUri, options,
+                                     filter);
 
     if (hypervVerifyResponse(priv->client, response, "enumeration") < 0)
         goto cleanup;
@@ -166,7 +212,7 @@ hypervEnumAndPull(hypervPrivate *priv, virBufferPtr query, const char *root,
     response = NULL;
 
     while (enumContext != NULL && *enumContext != '\0') {
-        response = wsmc_action_pull(priv->client, resourceUri, options,
+        response = wsmc_action_pull(priv->client, wmiInfo->resourceUri, options,
                                     filter, enumContext);
 
         if (hypervVerifyResponse(priv->client, response, "pull") < 0)
@@ -196,11 +242,12 @@ hypervEnumAndPull(hypervPrivate *priv, virBufferPtr query, const char *root,
             goto cleanup;
         }
 
-        if (ws_xml_get_child(node, 0, resourceUri, className) == NULL)
+        if (ws_xml_get_child(node, 0, wmiInfo->resourceUri,
+                             wmiInfo->name) == NULL)
             break;
 
-        data = ws_deserialize(serializerContext, node, serializerInfo,
-                              className, resourceUri, NULL, 0, 0);
+        data = ws_deserialize(serializerContext, node, wmiInfo->serializerInfo,
+                              wmiInfo->name, wmiInfo->resourceUri, NULL, 0, 0);
 
         if (data == NULL) {
             virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
@@ -211,8 +258,8 @@ hypervEnumAndPull(hypervPrivate *priv, virBufferPtr query, const char *root,
         if (VIR_ALLOC(object) < 0)
             goto cleanup;
 
-        object->serializerInfo = serializerInfo;
-        object->data = data;
+        object->info = wmiInfo;
+        object->data.common = data;
 
         data = NULL;
 
@@ -248,7 +295,7 @@ hypervEnumAndPull(hypervPrivate *priv, virBufferPtr query, const char *root,
         /* FIXME: ws_serializer_free_mem is broken in openwsman <= 2.2.6,
          *        see hypervFreeObject for a detailed explanation. */
         if (ws_serializer_free_mem(serializerContext, data,
-                                   serializerInfo) < 0) {
+                                   wmiInfo->serializerInfo) < 0) {
             VIR_ERROR(_("Could not free deserialized data"));
         }
 #endif
@@ -287,8 +334,8 @@ hypervFreeObject(hypervPrivate *priv ATTRIBUTE_UNUSED, hypervObject *object)
          *        them in wsmc_release. So this doesn't result in a real
          *        memory leak, but just in piling up unused memory until
          *        the connection is closed. */
-        if (ws_serializer_free_mem(serializerContext, object->data,
-                                   object->serializerInfo) < 0) {
+        if (ws_serializer_free_mem(serializerContext, object->data.common,
+                                   object->info->serializerInfo) < 0) {
             VIR_ERROR(_("Could not free deserialized data"));
         }
 #endif
@@ -381,6 +428,70 @@ hypervReturnCodeToString(int returnCode)
 
 
 
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Generic "Get WMI class list" helpers
+ */
+
+int
+hypervGetMsvmComputerSystemList(hypervPrivate *priv, virBufferPtr query,
+                                Msvm_ComputerSystem **list)
+{
+    return hypervGetWmiClassList(priv, Msvm_ComputerSystem_WmiInfo, query,
+                                 (hypervObject **) list);
+}
+
+int
+hypervGetMsvmConcreteJobList(hypervPrivate *priv, virBufferPtr query,
+                             Msvm_ConcreteJob **list)
+{
+    return hypervGetWmiClassList(priv, Msvm_ConcreteJob_WmiInfo, query,
+                                 (hypervObject **) list);
+}
+
+int
+hypervGetWin32ComputerSystemList(hypervPrivate *priv, virBufferPtr query,
+                                 Win32_ComputerSystem **list)
+{
+    return hypervGetWmiClassList(priv, Win32_ComputerSystem_WmiInfo, query,
+                                 (hypervObject **) list);
+}
+
+int
+hypervGetWin32ProcessorList(hypervPrivate *priv, virBufferPtr query,
+                            Win32_Processor **list)
+{
+    return hypervGetWmiClassList(priv, Win32_Processor_WmiInfo, query,
+                                 (hypervObject **) list);
+}
+
+int
+hypervGetMsvmVirtualSystemSettingDataList(hypervPrivate *priv,
+                                          virBufferPtr query,
+                                          Msvm_VirtualSystemSettingData **list)
+{
+    return hypervGetWmiClassList(priv, Msvm_VirtualSystemSettingData_WmiInfo, query,
+                                 (hypervObject **) list);
+}
+
+int
+hypervGetMsvmProcessorSettingDataList(hypervPrivate *priv,
+                                      virBufferPtr query,
+                                      Msvm_ProcessorSettingData **list)
+{
+    return hypervGetWmiClassList(priv, Msvm_ProcessorSettingData_WmiInfo, query,
+                                 (hypervObject **) list);
+}
+
+int
+hypervGetMsvmMemorySettingDataList(hypervPrivate *priv, virBufferPtr query,
+                                   Msvm_MemorySettingData **list)
+{
+    return hypervGetWmiClassList(priv, Msvm_MemorySettingData_WmiInfo, query,
+                                 (hypervObject **) list);
+}
+
+
+
 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  * Msvm_ComputerSystem
  */
@@ -402,6 +513,7 @@ hypervInvokeMsvmComputerSystemRequestStateChange(virDomainPtr domain,
     virBuffer query = VIR_BUFFER_INITIALIZER;
     Msvm_ConcreteJob *concreteJob = NULL;
     bool completed = false;
+    const char *resourceUri = MSVM_COMPUTERSYSTEM_V2_RESOURCE_URI;
 
     virUUIDFormat(domain->uuid, uuid_string);
 
@@ -410,6 +522,9 @@ hypervInvokeMsvmComputerSystemRequestStateChange(virDomainPtr domain,
         virAsprintf(&properties, "RequestedState=%d", requestedState) < 0)
         goto cleanup;
 
+    if (priv->wmiVersion == HYPERV_WMI_VERSION_V1)
+        resourceUri = MSVM_COMPUTERSYSTEM_V1_RESOURCE_URI;
+
     options = wsmc_options_init();
 
     if (options == NULL) {
@@ -422,7 +537,7 @@ hypervInvokeMsvmComputerSystemRequestStateChange(virDomainPtr domain,
     wsmc_add_prop_from_str(options, properties);
 
     /* Invoke method */
-    response = wsmc_action_invoke(priv->client, MSVM_COMPUTERSYSTEM_RESOURCE_URI,
+    response = wsmc_action_invoke(priv->client, resourceUri,
                                   options, "RequestStateChange", NULL);
 
     if (hypervVerifyResponse(priv->client, response, "invocation") < 0)
@@ -471,7 +586,7 @@ hypervInvokeMsvmComputerSystemRequestStateChange(virDomainPtr domain,
                 goto cleanup;
             }
 
-            switch (concreteJob->data->JobState) {
+            switch (concreteJob->data.common->JobState) {
               case MSVM_CONCRETEJOB_JOBSTATE_NEW:
               case MSVM_CONCRETEJOB_JOBSTATE_STARTING:
               case MSVM_CONCRETEJOB_JOBSTATE_RUNNING:
@@ -530,7 +645,7 @@ int
 hypervMsvmComputerSystemEnabledStateToDomainState
   (Msvm_ComputerSystem *computerSystem)
 {
-    switch (computerSystem->data->EnabledState) {
+    switch (computerSystem->data.common->EnabledState) {
       case MSVM_COMPUTERSYSTEM_ENABLEDSTATE_UNKNOWN:
         return VIR_DOMAIN_NOSTATE;
 
@@ -570,7 +685,7 @@ hypervIsMsvmComputerSystemActive(Msvm_ComputerSystem *computerSystem,
     if (in_transition != NULL)
         *in_transition = false;
 
-    switch (computerSystem->data->EnabledState) {
+    switch (computerSystem->data.common->EnabledState) {
       case MSVM_COMPUTERSYSTEM_ENABLEDSTATE_UNKNOWN:
         return false;
 
@@ -615,17 +730,17 @@ hypervMsvmComputerSystemToDomain(virConnectPtr conn,
         return -1;
     }
 
-    if (virUUIDParse(computerSystem->data->Name, uuid) < 0) {
+    if (virUUIDParse(computerSystem->data.common->Name, uuid) < 0) {
         virReportError(VIR_ERR_INTERNAL_ERROR,
                        _("Could not parse UUID from string '%s'"),
-                       computerSystem->data->Name);
+                       computerSystem->data.common->Name);
         return -1;
     }
 
     if (hypervIsMsvmComputerSystemActive(computerSystem, NULL))
-        id = computerSystem->data->ProcessID;
+        id = computerSystem->data.common->ProcessID;
 
-    *domain = virGetDomain(conn, computerSystem->data->ElementName, uuid, id);
+    *domain = virGetDomain(conn, computerSystem->data.common->ElementName, uuid, id);
 
     return *domain ? 0 : -1;
 }
@@ -661,7 +776,3 @@ hypervMsvmComputerSystemFromDomain(virDomainPtr domain,
 
     return 0;
 }
-
-
-
-#include "hyperv_wmi.generated.c"
diff --git a/src/hyperv/hyperv_wmi.h b/src/hyperv/hyperv_wmi.h
index 563475c65c75f18ae7b37702b1af8346a3301219..edb8efa3d24a92ea6af0effb6269413ed5c1ca61 100644
--- a/src/hyperv/hyperv_wmi.h
+++ b/src/hyperv/hyperv_wmi.h
@@ -31,7 +31,7 @@
 
 
 
-typedef struct _hypervObject hypervObject;
+# define HYPERV_WQL_QUERY_INITIALIZER { NULL, NULL }
 
 int hypervVerifyResponse(WsManClient *client, WsXmlDocH response,
                          const char *detail);
@@ -41,8 +41,9 @@ int hypervVerifyResponse(WsManClient *client, WsXmlDocH response,
 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  * Object
  */
-typedef struct _hypervObjectUnified hypervObjectUnified;
-struct _hypervObjectUnified {
+
+typedef struct _hypervObject hypervObject;
+struct _hypervObject {
     /* Unserialized data from wsman response. The member called "common" has
      * properties that are the same type and name for all "versions" of given
      * WMI class. This means that calling code does not have to make any
@@ -57,18 +58,17 @@ struct _hypervObjectUnified {
     } data;
     /* The info used to make wsman request */
     hypervWmiClassInfoPtr info;
-    hypervObjectUnified *next;
+    hypervObject *next;
 };
 
-struct _hypervObject {
-    XmlSerializerInfo *serializerInfo;
-    XML_TYPE_PTR data;
-    hypervObject *next;
+typedef struct _hypervWqlQuery hypervWqlQuery;
+typedef hypervWqlQuery *hypervWqlQueryPtr;
+struct _hypervWqlQuery {
+    virBufferPtr query;
+    hypervWmiClassInfoListPtr info;
 };
 
-int hypervEnumAndPull(hypervPrivate *priv, virBufferPtr query,
-                      const char *root, XmlSerializerInfo *serializerInfo,
-                      const char *resourceUri, const char *className,
+int hypervEnumAndPull(hypervPrivate *priv, hypervWqlQueryPtr wqlQuery,
                       hypervObject **list);
 
 void hypervFreeObject(hypervPrivate *priv, hypervObject *object);
@@ -111,6 +111,35 @@ const char *hypervReturnCodeToString(int returnCode);
 
 
 
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Generic "Get WMI class list" helpers
+ */
+
+int hypervGetMsvmComputerSystemList(hypervPrivate *priv, virBufferPtr query,
+                                    Msvm_ComputerSystem **list);
+
+int hypervGetMsvmConcreteJobList(hypervPrivate *priv, virBufferPtr query,
+                                 Msvm_ConcreteJob **list);
+
+int hypervGetWin32ComputerSystemList(hypervPrivate *priv, virBufferPtr query,
+                                     Win32_ComputerSystem **list);
+
+int hypervGetWin32ProcessorList(hypervPrivate *priv, virBufferPtr query,
+                                    Win32_Processor **list);
+
+int hypervGetMsvmVirtualSystemSettingDataList(hypervPrivate *priv,
+                                              virBufferPtr query,
+                                              Msvm_VirtualSystemSettingData **list);
+
+int hypervGetMsvmProcessorSettingDataList(hypervPrivate *priv,
+                                          virBufferPtr query,
+                                          Msvm_ProcessorSettingData **list);
+
+int hypervGetMsvmMemorySettingDataList(hypervPrivate *priv, virBufferPtr query,
+                                       Msvm_MemorySettingData **list);
+
+
+
 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  * Msvm_ComputerSystem
  */
@@ -131,8 +160,4 @@ int hypervMsvmComputerSystemToDomain(virConnectPtr conn,
 int hypervMsvmComputerSystemFromDomain(virDomainPtr domain,
                                        Msvm_ComputerSystem **computerSystem);
 
-
-
-# include "hyperv_wmi.generated.h"
-
 #endif /* __HYPERV_WMI_H__ */
diff --git a/src/hyperv/hyperv_wmi_classes.h b/src/hyperv/hyperv_wmi_classes.h
index b0f3e3c43a205b6a3a6297f8f3f9fe6826c9fd75..f7d596febf73018418b4060e4054a359a449e2ac 100644
--- a/src/hyperv/hyperv_wmi_classes.h
+++ b/src/hyperv/hyperv_wmi_classes.h
@@ -27,6 +27,15 @@
 
 # include "hyperv_wmi_classes.generated.typedef"
 
+# define ROOT_CIMV2 \
+    "http://schemas.microsoft.com/wbem/wsman/1/wmi/root/cimv2/*"
+
+# define ROOT_VIRTUALIZATION \
+    "http://schemas.microsoft.com/wbem/wsman/1/wmi/root/virtualization/*"
+
+# define ROOT_VIRTUALIZATION_V2 \
+    "http://schemas.microsoft.com/wbem/wsman/1/wmi/root/virtualization/v2/*"
+
 
 
 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
diff --git a/src/hyperv/hyperv_wmi_generator.input b/src/hyperv/hyperv_wmi_generator.input
index 209a9ff140539329540f27dc497ffc4b7d62b18a..d7f819edee3c47e8b85b84230496c7a64f244763 100644
--- a/src/hyperv/hyperv_wmi_generator.input
+++ b/src/hyperv/hyperv_wmi_generator.input
@@ -56,6 +56,55 @@ class Msvm_ComputerSystem
 end
 
 
+class v2/Msvm_ComputerSystem
+    string   InstanceID
+    string   Caption
+    string   Description
+    string   ElementName
+    datetime InstallDate
+    uint16   OperationalStatus[]
+    string   StatusDescriptions[]
+    string   Status
+    uint16   HealthState
+    uint16   CommunicationStatus
+    uint16   DetailedStatus
+    uint16   OperatingStatus
+    uint16   PrimaryStatus
+    uint16   EnabledState
+    string   OtherEnabledState
+    uint16   RequestedState
+    uint16   EnabledDefault
+    datetime TimeOfLastStateChange
+    uint16   AvailableRequestedStates[]
+    uint16   TransitioningToState
+    string   CreationClassName
+    string   Name
+    string   PrimaryOwnerName
+    string   PrimaryOwnerContact
+    string   Roles[]
+    string   NameFormat
+    string   OtherIdentifyingInfo[]
+    string   IdentifyingDescriptions[]
+    uint16   Dedicated[]
+    string   OtherDedicatedDescriptions[]
+    uint16   ResetCapability
+    uint16   PowerManagementCapabilities[]
+    uint64   OnTimeInMilliseconds
+    uint32   ProcessID
+    datetime TimeOfLastConfigurationChange
+    uint16   NumberOfNumaNodes
+    uint16   ReplicationState
+    uint16   ReplicationHealth
+    uint16   ReplicationMode
+    uint16   FailedOverReplicationType
+    uint16   LastReplicationType
+    datetime LastApplicationConsistentReplicationTime
+    datetime LastReplicationTime
+    datetime LastSuccessfulBackupTime
+    uint16   EnhancedSessionModeState
+end
+
+
 class Msvm_ConcreteJob
     string   Caption
     string   Description
@@ -96,6 +145,51 @@ class Msvm_ConcreteJob
 end
 
 
+class v2/Msvm_ConcreteJob
+    string   InstanceID
+    string   Caption
+    string   Description
+    string   ElementName
+    datetime InstallDate
+    string   Name
+    uint16   OperationalStatus[]
+    string   StatusDescriptions[]
+    string   Status
+    uint16   HealthState
+    uint16   CommunicationStatus
+    uint16   DetailedStatus
+    uint16   OperatingStatus
+    uint16   PrimaryStatus
+    string   JobStatus
+    datetime TimeSubmitted
+    datetime ScheduledStartTime
+    datetime StartTime
+    datetime ElapsedTime
+    uint32   JobRunTimes
+    uint8    RunMonth
+    sint8    RunDay
+    sint8    RunDayOfWeek
+    datetime RunStartInterval
+    uint16   LocalOrUtcTime
+    datetime UntilTime
+    string   Notify
+    string   Owner
+    uint32   Priority
+    uint16   PercentComplete
+    boolean  DeleteOnCompletion
+    uint16   ErrorCode
+    string   ErrorDescription
+    string   ErrorSummaryDescription
+    uint16   RecoveryAction
+    string   OtherRecoveryAction
+    uint16   JobState
+    datetime TimeOfLastStateChange
+    datetime TimeBeforeRemoval
+    boolean  Cancellable
+    uint16   JobType
+end
+
+
 class Msvm_MemorySettingData
     string   Caption
     string   Description
@@ -126,6 +220,38 @@ class Msvm_MemorySettingData
 end
 
 
+class v2/Msvm_MemorySettingData
+    string  InstanceID
+    string  Caption
+    string  Description
+    string  ElementName
+    uint16  ResourceType
+    string  OtherResourceType
+    string  ResourceSubType
+    string  PoolID
+    uint16  ConsumerVisibility
+    string  HostResource[]
+    string  AllocationUnits
+    uint64  VirtualQuantity
+    uint64  Reservation
+    uint64  Limit
+    uint32  Weight
+    boolean AutomaticAllocation
+    boolean AutomaticDeallocation
+    string  Parent
+    string  Connection[]
+    string  Address
+    uint16  MappingBehavior
+    string  AddressOnParent
+    string  VirtualQuantityUnits
+    boolean DynamicMemoryEnabled
+    uint32  TargetMemoryBuffer
+    boolean IsVirtualized
+    boolean SwapFilesInUse
+    uint64  MaxMemoryBlocksPerNumaNode
+end
+
+
 class Msvm_ProcessorSettingData
     string   Caption
     string   Description
@@ -159,6 +285,37 @@ class Msvm_ProcessorSettingData
 end
 
 
+class v2/Msvm_ProcessorSettingData
+    string  InstanceID
+    string  Caption
+    string  Description
+    string  ElementName
+    uint16  ResourceType
+    string  OtherResourceType
+    string  ResourceSubType
+    string  PoolID
+    uint16  ConsumerVisibility
+    string  HostResource[]
+    string  AllocationUnits
+    uint64  VirtualQuantity
+    uint64  Reservation
+    uint64  Limit
+    uint32  Weight
+    boolean AutomaticAllocation
+    boolean AutomaticDeallocation
+    string  Parent
+    string  Connection[]
+    string  Address
+    uint16  MappingBehavior
+    string  AddressOnParent
+    string  VirtualQuantityUnits
+    boolean LimitCPUID
+    boolean LimitProcessorFeatures
+    uint64  MaxProcessorsPerNumaNode
+    uint64  MaxNumaNodesPerSocket
+end
+
+
 class Msvm_VirtualSystemSettingData
     string   Caption
     string   Description
@@ -184,6 +341,55 @@ class Msvm_VirtualSystemSettingData
 end
 
 
+class v2/Msvm_VirtualSystemSettingData
+    string   InstanceID
+    string   Caption
+    string   Description
+    string   ElementName
+    string   VirtualSystemIdentifier
+    string   VirtualSystemType
+    string   Notes[]
+    datetime CreationTime
+    string   ConfigurationID
+    string   ConfigurationDataRoot
+    string   ConfigurationFile
+    string   SnapshotDataRoot
+    string   SuspendDataRoot
+    string   SwapFileDataRoot
+    string   LogDataRoot
+    uint16   AutomaticStartupAction
+    datetime AutomaticStartupActionDelay
+    uint16   AutomaticStartupActionSequenceNumber
+    uint16   AutomaticShutdownAction
+    uint16   AutomaticRecoveryAction
+    string   RecoveryFile
+    string   BIOSGUID
+    string   BIOSSerialNumber
+    string   BaseBoardSerialNumber
+    string   ChassisSerialNumber
+    string   ChassisAssetTag
+    boolean  BIOSNumLock
+    uint16   BootOrder[]
+    string   Parent
+    boolean  IsSaved
+    string   AdditionalRecoveryInformation
+    boolean  AllowFullSCSICommandSet
+    uint32   DebugChannelId
+    uint16   DebugPortEnabled
+    uint32   DebugPort
+    string   Version
+    boolean  IncrementalBackupEnabled
+    boolean  VirtualNumaEnabled
+    boolean  AllowReducedFcRedundancy
+    string   VirtualSystemSubType
+    string   BootSourceOrder[]
+    boolean  PauseAfterBootFailure
+    uint16   NetworkBootPreferredProtocol
+    boolean  SecureBootEnabled
+    uint64   LowMmioGapSize
+end
+
+
 class Win32_ComputerSystem
     uint16   AdminPasswordStatus
     boolean  AutomaticManagedPagefile
@@ -607,39 +813,6 @@ class Msvm_VirtualSystemGlobalSettingData
 end
 
 
-class Msvm_VirtualSwitch
-    string   Caption
-    string   Description
-    string   ElementName
-    datetime InstallDate
-    uint16   OperationalStatus[]
-    string   StatusDescriptions[]
-    string   Status
-    uint16   HealthState
-    uint16   EnabledState
-    string   OtherEnabledState
-    uint16   RequestedState
-    uint16   EnabledDefault
-    datetime TimeOfLastStateChange
-    string   CreationClassName
-    string   Name
-    string   PrimaryOwnerContact
-    string   PrimaryOwnerName
-    string   Roles[]
-    string   NameFormat
-    string   OtherIdentifyingInfo[]
-    string   IdentifyingDescriptions[]
-    uint16   Dedicated[]
-    string   OtherDedicatedDescriptions[]
-    uint16   ResetCapability
-    uint16   PowerManagementCapabilities[]
-    string   ScopeOfResidence
-    uint32   NumLearnableAddresses
-    uint32   MaxVMQOffloads
-    uint32   MaxChimneyOffloads
-end
-
-
 class Msvm_ResourceAllocationSettingData
     string   Caption
     string   Description
diff --git a/src/hyperv/hyperv_wmi_generator.py b/src/hyperv/hyperv_wmi_generator.py
index 8c62882d61e7ce454c04ba6b262c393226063d2f..c15d97adc5b70be12f8db2240ac05268b5e869d5 100755
--- a/src/hyperv/hyperv_wmi_generator.py
+++ b/src/hyperv/hyperv_wmi_generator.py
@@ -24,130 +24,310 @@ import sys
 import os
 import os.path
 
+separator = "/*" + ("*" * 50) + "*\n"
+wmi_version_separator = "/"
+wmi_classes_by_name = {}
+
+class WmiClass:
+    """Represents WMI class and provides methods to generate C code.
+
+    This class holds one or more instances of WmiClassVersion because with the
+    Windows 2012 release, Microsoft introduced "v2" version of Msvm_* family of
+    classes that need different URI for making wsman requests and also have
+    some additional/changed properties (though many of the properies are the
+    same as in "v1". Therefore, this class makes sure that C code is generated
+    for each of them while avoiding name conflics, identifies common members,
+    and defined *_WmiInfo structs holding info about each version so the driver
+    code can make the right choices based on which Hyper-V host it's connected
+    to.
+    """
+
+    def __init__(self, name, versions = []):
+        self.name = name
+        self.versions = versions
+        self.common = None
 
 
-separator = "/* " + ("* " * 37) + "*\n"
+    def prepare(self):
+        """Prepares the class for code generation
 
+        Makes sure that "versioned" classes are sorted by version, identifies
+        common properies and ensures that they are aligned by name and
+        type in each version
+        """
+        # sort vesioned classes by version in case input file did not have them
+        # in order
+        self.versions = sorted(self.versions, key=lambda cls: cls.version)
 
+        # if there's more than one verion make sure first one has name suffixed
+        # because we'll generate "common" memeber and will be the "base" name
+        if len(self.versions) > 1:
+            first = self.versions[0]
+            if first.version == None:
+                first.version = "v1"
+            first.name = "%s_%s" % (first.name, first.version)
 
-class Class:
-    def __init__(self, name, properties):
-        self.name = name
-        self.properties = properties
+        # finally, identify common members in all versions and make sure they
+        # are in the same order - to ensure C struct member alignment
+        self._align_property_members()
 
 
-    def generate_header(self):
+    def generate_classes_header(self):
+        """Generate C header code and return it as string
+
+        Declares:
+          <class_name>_Data - used as one of hypervObject->data members
+          <class_name>_TypeInfo - used as wsman XmlSerializerInfo
+          <class_name> - "inherits" hypervObject struct
+        """
+
         name_upper = self.name.upper()
 
         header = separator
         header += " * %s\n" % self.name
         header += " */\n"
         header += "\n"
-        header += "int hypervGet%sList(hypervPrivate *priv, virBufferPtr query, %s **list);\n" \
-                  % (self.name.replace("_", ""), self.name)
-        header += "\n"
+        header += "#define %s_CLASSNAME \\\n" % name_upper
+        header += "    \"%s\"\n" % self.name
         header += "\n"
+        header += "#define %s_WQL_SELECT \\\n" % name_upper
+        header += "    \"SELECT * FROM %s \"\n" % self.name
         header += "\n"
+        header += "extern hypervWmiClassInfoListPtr %s_WmiInfo;\n\n" % self.name
+
+        header += self._declare_data_structs()
+        header += self._declare_hypervObject_struct()
 
         return header
 
 
+    def generate_classes_source(self):
+        """Returns a C code string defining wsman data structs
+
+        Defines:
+          <class_name>_Data structs
+          <class_name>_WmiInfo - list holding metadata (e.g. request URIs) for
+                                 each known version of WMI class.
+        """
+
+        source = separator
+        source += " * %s\n" % self.name
+        source += " */\n"
+
+        for cls in self.versions:
+            source += "SER_START_ITEMS(%s_Data)\n" % cls.name
+
+            for property in cls.properties:
+                source += property.generate_classes_source(cls.name)
+
+            source += "SER_END_ITEMS(%s_Data);\n\n" % cls.name
+
+
+        source += self._define_WmiInfo_struct()
+        source += "\n\n"
+
+        return source
+
+
     def generate_classes_typedef(self):
-        typedef = "typedef struct _%s_Data %s_Data;\n" % (self.name, self.name)
-        typedef += "typedef struct _%s %s;\n" % (self.name, self.name)
+        """Returns C string for typdefs"""
+
+        typedef = "typedef struct _%s %s;\n" % (self.name, self.name)
+
+        if self.common is not None:
+            typedef += "typedef struct _%s_Data %s_Data;\n" % (self.name, self.name)
+
+        for cls in self.versions:
+            typedef += "typedef struct _%s_Data %s_Data;\n" % (cls.name, cls.name)
 
         return typedef
 
 
-    def generate_classes_header(self):
-        name_upper = self.name.upper()
 
-        header = separator
-        header += " * %s\n" % self.name
-        header += " */\n"
-        header += "\n"
-        header += "#define %s_RESOURCE_URI \\\n" % name_upper
+    def _declare_data_structs(self):
+        """Returns string C code declaring data structs.
 
-        if self.name.startswith("Win32_") or self.name.startswith("CIM_"):
-            header += "    \"http://schemas.microsoft.com/wbem/wsman/1/wmi/root/cimv2/%s\"\n" % self.name
-        else:
-            header += "    \"http://schemas.microsoft.com/wbem/wsman/1/wmi/root/virtualization/%s\"\n" % self.name
+        The *_Data structs are members of hypervObject data union. Each one has
+        corresponding *_TypeInfo that is used for wsman unserialization of
+        response XML into the *_Data structs. If there's a "common" member, it
+        won't have corresponding *_TypeInfo becuase this is a special case only
+        used to provide a common "view" of v1, v2 etc members
+        """
 
-        header += "\n"
-        header += "#define %s_CLASSNAME \\\n" % name_upper
-        header += "    \"%s\"\n" % self.name
-        header += "\n"
-        header += "#define %s_WQL_SELECT \\\n" % name_upper
-        header += "    \"select * from %s \"\n" % self.name
-        header += "\n"
-        header += "struct _%s_Data {\n" % self.name
+        header = ""
+        if self.common is not None:
+            header += "struct _%s_Data {\n" % self.name
+            for property in self.common:
+                header += property.generate_classes_header()
+            header += "};\n\n"
 
-        for property in self.properties:
-            header += property.generate_classes_header()
+        # Declare actual data struct for each versions
+        for cls in self.versions:
+            header += "#define %s_RESOURCE_URI \\\n" % cls.name.upper()
+            header += "    \"%s\"\n" % cls.uri_info.resourceUri
+            header += "\n"
+            header += "struct _%s_Data {\n" % cls.name
+            for property in cls.properties:
+                header += property.generate_classes_header()
+            header += "};\n\n"
+            header += "SER_DECLARE_TYPE(%s_Data);\n" % cls.name
 
-        header += "};\n"
-        header += "\n"
-        header += "SER_DECLARE_TYPE(%s_Data);\n" % self.name
-        header += "\n"
+        return header
+
+
+    def _declare_hypervObject_struct(self):
+        """Return string for C code declaring hypervObject instance"""
+
+        header = "\n/* must match hypervObject */\n"
         header += "struct _%s {\n" % self.name
-        header += "    XmlSerializerInfo *serializerInfo;\n"
-        header += "    %s_Data *data;\n" % self.name
+        header += "    union {\n"
+
+        # if there's common use it as "common" else first and only version is
+        # the "common" member
+        if self.common is not None:
+            header += "        %s_Data *common;\n" % self.name
+        else:
+            header += "        %s_Data *common;\n" % self.versions[0].name
+
+        for cls in self.versions:
+            header += "        %s_Data *%s;\n" % (cls.name, cls.version)
+
+        header += "    } data;\n"
+        header += "    hypervWmiClassInfoPtr info;\n"
         header += "    %s *next;\n" % self.name
         header += "};\n"
-        header += "\n"
-        header += "\n"
-        header += "\n"
+
+        header += "\n\n\n"
 
         return header
 
 
-    def generate_source(self):
-        name_upper = self.name.upper()
+    def _define_WmiInfo_struct(self):
+        """Return string for C code defining *_WmiInfo struct
 
-        source = separator
-        source += " * %s\n" % self.name
-        source += " */\n"
-        source += "\n"
-        source += "int\n"
-        source += "hypervGet%sList(hypervPrivate *priv, virBufferPtr query, %s **list)\n" \
-                  % (self.name.replace("_", ""), self.name)
-        source += "{\n"
-
-        if self.name.startswith("Win32_") or self.name.startswith("CIM_"):
-            source += "    return hypervEnumAndPull(priv, query, ROOT_CIMV2,\n"
-        else:
-            source += "    return hypervEnumAndPull(priv, query, ROOT_VIRTUALIZATION,\n"
+        Those structs hold info with meta-data needed to make wsman requests for
+        each version of WMI class
+        """
+
+        source = "hypervWmiClassInfoListPtr %s_WmiInfo = &(hypervWmiClassInfoList) {\n" % self.name
+        source += "    .count = %d,\n" % len(self.versions)
+        source += "    .objs = (hypervWmiClassInfoPtr []) {\n"
+
+        for cls in self.versions:
+            source += "        &(hypervWmiClassInfo) {\n"
+            source += "            .name = %s_CLASSNAME,\n" % self.name.upper()
+            if cls.version is not None:
+                source += "            .version = \"%s\",\n" % cls.version
+            else:
+                source += "            .version = NULL,\n"
+            source += "            .rootUri = %s,\n" % cls.uri_info.rootUri
+            source += "            .resourceUri = %s_RESOURCE_URI,\n" % cls.name.upper()
+            source += "            .serializerInfo = %s_Data_TypeInfo\n" % cls.name
+            source += "        },\n"
 
-        source += "                             %s_Data_TypeInfo,\n" % self.name
-        source += "                             %s_RESOURCE_URI,\n" % name_upper
-        source += "                             %s_CLASSNAME,\n" % name_upper
-        source += "                             (hypervObject **)list);\n"
-        source += "}\n"
-        source += "\n"
-        source += "\n"
-        source += "\n"
+        source += "    }\n"
+        source += "};\n"
 
         return source
 
 
-    def generate_classes_source(self):
-        name_upper = self.name.upper()
+    def _align_property_members(self):
+        """Identifies common properties in all class versions.
 
-        source = separator
-        source += " * %s\n" % self.name
-        source += " */\n"
-        source += "\n"
-        source += "SER_START_ITEMS(%s_Data)\n" % self.name
+        Makes sure that properties in all versions are ordered with common
+        members first and that they are in the same order. This makes the
+        generated C structs memory aligned and safe to access via the "common"
+        struct that "shares" members with v1, v2 etc.
+        """
 
-        for property in self.properties:
-            source += property.generate_classes_source(self.name)
+        num_classes = len(self.versions)
+        common = {}
+        property_info = {}
 
-        source += "SER_END_ITEMS(%s_Data);\n" % self.name
-        source += "\n"
-        source += "\n"
-        source += "\n"
+        if num_classes < 2:
+            return
+
+        # count property occurences in all class versions
+        for cls in self.versions:
+            for prop in cls.properties:
+                # consdered same if matches by name AND type
+                key = "%s_%s" % (prop.name, prop.type)
+
+                if key in property_info:
+                    property_info[key][1] += 1
+                else:
+                    property_info[key] = [prop, 1]
+
+        # isolate those that are common for all and keep track of their postions
+        pos = 0
+        for key in property_info:
+            info = property_info[key]
+            # exists in all class versions
+            if info[1] == num_classes:
+                common[info[0].name] = [info[0], pos]
+                pos += 1
+
+        # alter each versions's property list so that common members are first
+        # and in the same order as in the common dictionary
+        total = len(common)
+        for cls in self.versions:
+            index = 0
+            count = len(cls.properties)
+
+            while index < count:
+                prop = cls.properties[index]
+
+                # it's a "common" property
+                if prop.name in common:
+                    pos = common[prop.name][1]
+
+                    # move to the same position as in "common" dictionary
+                    if index != pos:
+                        tmp = cls.properties[pos]
+                        cls.properties[pos] = prop
+                        cls.properties[index] = tmp
+                    else:
+                        index += 1
+                else:
+                    index += 1
+
+        # finally, get common properties as list sorted by position in dictionary
+        tmp = sorted(common.values(), key=lambda x: x[1])
+        self.common = []
+        for x in tmp:
+            self.common.append(x[0])
+
+
+
+class ClassUriInfo:
+    """Prepares URI information needed for wsman requests."""
+
+    def __init__(self, wmi_name, version):
+        self.rootUri = "ROOT_CIMV2"
+        self.resourceUri = None
+        baseUri = "http://schemas.microsoft.com/wbem/wsman/1/wmi/root/cimv2"
+
+        if wmi_name.startswith("Msvm_"):
+            baseUri = "http://schemas.microsoft.com/wbem/wsman/1/wmi/root/virtualization"
+            self.rootUri = "ROOT_VIRTUALIZATION"
+
+            if version == "v2":
+                baseUri += "/v2"
+                self.rootUri = "ROOT_VIRTUALIZATION_V2"
+
+        self.resourceUri = "%s/%s" % (baseUri, wmi_name)
+
+
+
+class WmiClassVersion:
+    """Represents specific version of WMI class."""
+
+    def __init__(self, name, version, properties, uri_info):
+        self.name = name
+        self.version = version
+        self.properties = properties
+        self.uri_info = uri_info
 
-        return source
 
 
 class Property:
@@ -155,9 +335,13 @@ class Property:
                "string"   : "STR",
                "datetime" : "STR",
                "int8"     : "INT8",
+               "sint8"    : "INT8",
                "int16"    : "INT16",
+               "sint16"   : "INT16",
                "int32"    : "INT32",
+               "sint32"   : "INT32",
                "int64"    : "INT64",
+               "sint64"   : "INT64",
                "uint8"    : "UINT8",
                "uint16"   : "UINT16",
                "uint32"   : "UINT32",
@@ -217,8 +401,15 @@ def parse_class(block):
     assert header_items[0] == "class"
 
     name = header_items[1]
-
     properties = []
+    version = None
+    wmi_name = name
+    ns_separator = name.find(wmi_version_separator)
+
+    if ns_separator != -1:
+        version = name[:ns_separator]
+        wmi_name = name[ns_separator + 1:]
+        name = "%s_%s" % (wmi_name, version)
 
     for line in block[1:]:
         # expected format: <type> <name>
@@ -236,7 +427,13 @@ def parse_class(block):
         properties.append(Property(type=items[0], name=items[1],
                                    is_array=is_array))
 
-    return Class(name=name, properties=properties)
+    cls = WmiClassVersion(name=name, version=version, properties=properties,
+                          uri_info=ClassUriInfo(wmi_name, version))
+
+    if wmi_name in wmi_classes_by_name:
+        wmi_classes_by_name[wmi_name].versions.append(cls)
+    else:
+        wmi_classes_by_name[wmi_name] = WmiClass(wmi_name, [cls])
 
 
 
@@ -248,15 +445,12 @@ def main():
         input_filename = os.path.join(os.getcwd(), "hyperv_wmi_generator.input")
         output_dirname = os.getcwd()
 
-    header = open_and_print(os.path.join(output_dirname, "hyperv_wmi.generated.h"))
-    source = open_and_print(os.path.join(output_dirname, "hyperv_wmi.generated.c"))
     classes_typedef = open_and_print(os.path.join(output_dirname, "hyperv_wmi_classes.generated.typedef"))
     classes_header = open_and_print(os.path.join(output_dirname, "hyperv_wmi_classes.generated.h"))
     classes_source = open_and_print(os.path.join(output_dirname, "hyperv_wmi_classes.generated.c"))
 
     # parse input file
     number = 0
-    classes_by_name = {}
     block = None
 
     for line in file(input_filename, "rb").readlines():
@@ -279,8 +473,7 @@ def main():
         if block is not None:
             if line == "end":
                 if block[0][1].startswith("class"):
-                    cls = parse_class(block)
-                    classes_by_name[cls.name] = cls
+                    parse_class(block)
 
                 block = None
             else:
@@ -289,21 +482,20 @@ def main():
     # write output files
     notice = "/* Generated by hyperv_wmi_generator.py */\n\n\n\n"
 
-    header.write(notice)
-    source.write(notice)
     classes_typedef.write(notice)
     classes_header.write(notice)
     classes_source.write(notice)
 
-    names = classes_by_name.keys()
+    names = wmi_classes_by_name.keys()
     names.sort()
 
     for name in names:
-        header.write(classes_by_name[name].generate_header())
-        source.write(classes_by_name[name].generate_source())
-        classes_typedef.write(classes_by_name[name].generate_classes_typedef())
-        classes_header.write(classes_by_name[name].generate_classes_header())
-        classes_source.write(classes_by_name[name].generate_classes_source())
+        cls = wmi_classes_by_name[name]
+        cls.prepare()
+
+        classes_typedef.write(cls.generate_classes_typedef())
+        classes_header.write(cls.generate_classes_header())
+        classes_source.write(cls.generate_classes_source())