【问题标题】:Assign vlan to network adapter via wmi classes通过 wmi 类将 vlan 分配给网络适配器
【发布时间】:2019-04-13 18:37:21
【问题描述】:

问题:无法使用 Msvm_VirtualEthernetSwitchManagementService 和 AddFeatureSettings 方法将 vlan 分配给 hyper-v 虚拟机。

谁能指出我做错了什么?

我还注意到,如果我使用 WMI 类创建 vNIC,我不会获得 Msvm_EthernetPortAllocationSettingData 的实例,但如果我手动分配 vNIC,它会被创建。我也无法通过 WMI 创建 Msvm_EthernetPortAllocationSettingData。

从下面的代码中,我得到的 ReturnValue 为 4096,这意味着该方法已执行.. 但未分配 vlan。

            ManagementPath syntheticAdapterSettingDataC = new ManagementPath("Msvm_EthernetSwitchPortVlanSettingData");
            String syntheticVlanAdapterId = String.Format("{0}\\C\\952C5004-4465-451C-8CB8-FA9AB382B773\\{1}", adapter.GetPropertyValue("InstanceID"), Guid.NewGuid());

            ManagementClass syntheticAdapterClassC =
               new ManagementClass(scope, syntheticAdapterSettingDataC, objectOptions)
               {
                   ["AccessVlanId"] = 55,
                   ["Caption"] = "Ethernet Switch Port VLAN Settings",
                   ["Description"] = "Represents the vlan setting data.",
                   ["ElementName"] = "Ethernet Switch Port VLAN Settings",
                   ["InstanceID"] = syntheticVlanAdapterId,
                   ["NativeVlanId"] = 0,
                   ["OperationMode"] = 1,
                   ["PrimaryVlanId"] = 0,
                   ["PruneVlanIdArray"] = null,
                   ["PvlanMode"] = 0,
                   ["SecondaryVlanId"] = 0,
                   ["SecondaryVlanIdArray"] = null,
                   ["TrunkVlanIdArray"] = null,
               };
            var syntheticAdapterC = syntheticAdapterClassC.CreateInstance();

            ManagementPath VirtualEthernetSwitchManagementServicePath= new ManagementPath("Msvm_VirtualEthernetSwitchManagementService");
            ManagementClass VirtualEthernetSwitchManagementServiceClass = new ManagementClass(scope, VirtualEthernetSwitchManagementServicePath, objectOptions);

            ManagementBaseObject inParams = VirtualEthernetSwitchManagementServiceClass.GetMethodParameters("AddFeatureSettings");


            string queryFeature = string.Format("select * from Msvm_FeatureSettingData Where InstanceID = 'Microsoft:Definition\\\\952C5004-4465-451C-8CB8-FA9AB382B773\\\\Default'");

            ManagementObjectSearcher searcherFeature = new ManagementObjectSearcher(scope, new ObjectQuery(queryFeature));

            ManagementObjectCollection features = searcherFeature.Get();

            ManagementObject feature = null;

            foreach (ManagementObject instance in features)
            {
                feature = instance;
                break;
            }

            string[] syntheticAdapterSettingsC = new string[1];
            syntheticAdapterSettingsC[0] = syntheticAdapterC.GetText(TextFormat.CimDtd20);



            inParams["AffectedConfiguration"] = feature.GetText(TextFormat.CimDtd20);

            inParams["FeatureSettings"] = syntheticAdapterSettingsC;

            ManagementObject service = null;

            foreach (ManagementObject instance in VirtualEthernetSwitchManagementServiceClass.GetInstances())
            {
                service = instance;
            }

            ManagementBaseObject vlanOut = service.InvokeMethod("AddFeatureSettings", inParams, null);

【问题讨论】:

    标签: c# wmi hyper-v


    【解决方案1】:

    经过试验,我找到了答案。您需要做的是使用“AddResourceSettings”方法创建带有 Msvm_VirtualSystemManagementService 类的 Msvm_EthernetPortAllocationSettingData 实例(如果您已经有一个,则指向一个)。

    要使用“AddResourceSettings”方法,您需要定义:

    • AffectedConfiguration 属性,它是 Msvm_VirtualSystemSettingData 类的一个实例
    • ResourceSettings 属性,是 Msvm_EthernetPortAllocationSettingData 的一个实例,但需要将该实例放入数组中。

    现在您已准备好分配 vlan。您需要使用 Msvm_VirtualSystemManagementService 类和“AddFeatureSettings”方法创建 Msvm_EthernetSwitchPortVlanSettingData 的实例。

    要使用“AddFeatureSettings”方法,您需要定义:

    • AffectedConfiguration,它是 Msvm_EthernetPortAllocationSettingData 的一个实例
    • FeatureSettings,是Msvm_EthernetSwitchPortVlanSettingData的实例,也是数组

    就是这样..

    干杯!

    【讨论】:

      【解决方案2】:

      ya..know 它有点老了,但是让其他人尝试实现它来避免头痛。以下代码会将网络适配器分配给 VM 并设置 VLAN。请记住,我的 '_dataFields' 是带有虚拟机数据的结构,因此您必须在此处更改一些内容。

      添加新的网络适配器并设置 VLAN

          /// <summary>
          /// For the given virtual machine, this sample adds a new Network Adapter device and 
          /// connects it to the specified switch. Note that in order to add a new Network Adapter 
          /// device to the virtual machine, the virtual machine must be in the power off state.
          /// Also note that the maximum number of Network Adapter devices that may be configured
          /// on a virtual machine is 8.
          /// </summary>
          public void ConnectVmToSwitch()
          {
              using (ManagementObject managementService = WmiUtils.GetVirtualMachineManagementService(_dataFields._scope))
      
              //
              // Find the Ethernet switch we want to connect to.
              //
              using (ManagementObject ethernetSwitch = NetworkUtils.FindEthernetSwitch(_dataFields.SwitchName, _dataFields._scope))
      
              //
              // Find the virtual machine we want to connect.
              //
              using (ManagementObject virtualMachine = WmiUtils.GetVirtualMachine(_dataFields.VmName, _dataFields._scope))
      
              //
              // Get the virtual machine's settings object which is used to make configuration changes.
              //
              using (ManagementObject virtualMachineSettings = WmiUtils.GetVirtualMachineSettings(virtualMachine))
      
              //
              // Add a new synthetic Network Adapter device to the virtual machine.
              //
              using (ManagementObject syntheticAdapter = NetworkUtils.AddSyntheticAdapter(virtualMachine, _dataFields._scope))
      
              //
              // Now that we have added a network adapter to the virtual machine we can configure its
              // connection settings.
              //
              using (ManagementObject connectionSettingsToAdd = NetworkUtils.GetDefaultEthernetPortAllocationSettingData(_dataFields._scope))
              {
                  connectionSettingsToAdd["Parent"] = syntheticAdapter.Path.Path;
                  connectionSettingsToAdd["HostResource"] = new string[] { ethernetSwitch.Path.Path };
      
                  //
                  // Now add the connection settings.
                  //
                  using (ManagementBaseObject addConnectionInParams = managementService.GetMethodParameters("AddResourceSettings"))
                  {
                      addConnectionInParams["AffectedConfiguration"] = virtualMachineSettings.Path.Path;
                      addConnectionInParams["ResourceSettings"] = new string[] { connectionSettingsToAdd.GetText(TextFormat.WmiDtd20) };
      
                      using (ManagementBaseObject addConnectionOutParams = managementService.InvokeMethod("AddResourceSettings", addConnectionInParams, null))
                      {
                          WmiUtils.ValidateOutput(addConnectionOutParams, _dataFields._scope);
      
                          if (_dataFields.VlanID > 0)
                          {
                              string[] syntheticAdapterResult = (string[])addConnectionOutParams["ResultingResourceSettings"]; // Msvm_EthernetPortAllocationSettingData return object
                              string syntheticAdapterPath = syntheticAdapterResult[0]; // Msvm_EthernetPortAllocationSettingData path
      
                              using (ManagementClass vlanSettingsData = new ManagementClass("Msvm_EthernetSwitchPortVlanSettingData"))
                              {
                                  vlanSettingsData.Scope = _dataFields._scope;
                                  using (ManagementObject vlanData = vlanSettingsData.CreateInstance())
                                  {
                                      vlanData["AccessVlanId"] = _dataFields.VlanID;
                                      vlanData["OperationMode"] = (uint)_dataFields.VLANOperationalModes;
      
                                      // Modify the VM settings.
                                      using (ManagementBaseObject inParams = managementService.GetMethodParameters("AddFeatureSettings"))
                                      {
                                          inParams["AffectedConfiguration"] = syntheticAdapterPath;
                                          inParams["FeatureSettings"] = new string[] { vlanData.GetText(TextFormat.CimDtd20) };
      
                                          using (ManagementBaseObject outParams = managementService.InvokeMethod("AddFeatureSettings", inParams, null))
                                          {
                                              WmiUtils.ValidateOutput(outParams, _dataFields._scope);
                                          }
                                      }
                                  }
                              }
                          }
                      }
                  }
              }
          }
      

      将交换机分配给 VM 的原始代码来自 https://github.com/microsoft/Windows-classic-samples/blob/1d363ff4bd17d8e20415b92e2ee989d615cc0d91/Samples/Hyper-V/Networking/cs/ConnectVmToSwitch.cs,我刚刚对其进行了扩展以支持 VLAN 使用。我在调用中没有任何参数,因为所有数据都在结构中。

      在 VM 上的现有网络适配器上添加/修改 VLAN

          /// <summary>
          /// Gets any virtual machine's management object
          /// </summary>
          /// <param name="managementObject">Any management object</param>
          /// <returns>Any virtual machine's management object.</returns>
          public static ManagementObject
          GetVirtualMachineManagementObject(ManagementObject managementObject, string className)
          {
              using (ManagementObjectCollection settingsCollection = managementObject.GetRelated(className))
              {
                  ManagementObject virtualMachineSettings = GetFirstObjectFromCollection(settingsCollection);
                  return virtualMachineSettings;
              }
          }
      
          /// <summary>
          /// For the given virtual machine, this sample will add / modfiy VLAN on existing network adapter
          /// </summary>
          public void SetVLANToVMNetworkAdapter()
          {
              ManagementObject syntheticAdapter = null;
              bool vlanAlreadySet = false;
      
              using (ManagementObject managementService = WmiUtils.GetVirtualMachineManagementService(_dataFields._scope))
      
              //
              // Find the virtual machine we want to connect.
              //
              using (ManagementObject virtualMachine = WmiUtils.GetVirtualMachine(_dataFields.VmName, _dataFields._scope))
      
              //
              // Now that we have added a network adapter to the virtual machine we can configure its
              // connection settings.
              //
              using (ManagementObjectCollection findConnections = NetworkUtils.FindConnections(virtualMachine, _dataFields._scope))
              {
                  if (findConnections.Count > 0)
                  {
                      foreach (ManagementObject connection in findConnections)
                      {
                          using (ManagementObjectCollection vmSwitches = connection.GetRelated("Msvm_SyntheticEthernetPortSettingData"))
                          {
                              if (vmSwitches.Count > 0)
                              {
                                  foreach (ManagementObject vmSwitch in vmSwitches)
                                  {
                                      if (vmSwitch["ElementName"].ToString() == _dataFields.NetworkAdapterName)
                                      {
                                          //
                                          // Got adapter on VM, lock it to connection object since we need connection path
                                          // for vlan modifications
                                          //
                                          syntheticAdapter = connection;
      
                                          //
                                          // Got VLAN defiinition based on connection lock for vlan modifications
                                          //
                                          using (ManagementObjectCollection vmSwitcheVLANs = syntheticAdapter.GetRelated("Msvm_EthernetSwitchPortVlanSettingData"))
                                          {
                                              if (vmSwitcheVLANs.Count > 0)
                                                  vlanAlreadySet = true;
                                          }
                                          break;
                                      }
                                  }
                              }
                          }
                      }
                  }
      
                  if (syntheticAdapter != null && _dataFields.VlanID > 0)
                  {
                      string syntheticAdapterPath = syntheticAdapter.Path.Path;
                      if (vlanAlreadySet)
                      {
                          // VLAN is already set on adapter, change operation
                          // Modify the VM settings.
                          using (ManagementObject vlanData = WmiUtils.GetVirtualMachineManagementObject(syntheticAdapter, "Msvm_EthernetSwitchPortVlanSettingData"))
                          {
                              vlanData["AccessVlanId"] = _dataFields.VlanID;
                              vlanData["OperationMode"] = (uint)_dataFields.VLANOperationalModes;
                              using (ManagementBaseObject inParams = managementService.GetMethodParameters("ModifyFeatureSettings"))
                              {
                                  inParams["FeatureSettings"] = new string[] { vlanData.GetText(TextFormat.CimDtd20) };
                                  using (ManagementBaseObject outParams = managementService.InvokeMethod("ModifyFeatureSettings", inParams, null))
                                  {
                                      WmiUtils.ValidateOutput(outParams, _dataFields._scope);
                                  }
                              }
                          }
                      }
                      else
                      {
                          using (ManagementClass vlanSettingsData = new ManagementClass("Msvm_EthernetSwitchPortVlanSettingData"))
                          {
                              vlanSettingsData.Scope = _dataFields._scope;
                              using (ManagementObject vlanData = vlanSettingsData.CreateInstance())
                              {
                                  vlanData["AccessVlanId"] = _dataFields.VlanID;
                                  vlanData["OperationMode"] = (uint)_dataFields.VLANOperationalModes;
      
                                  using (ManagementBaseObject inParams = managementService.GetMethodParameters("AddFeatureSettings"))
                                  {
                                      inParams["AffectedConfiguration"] = syntheticAdapterPath;
                                      inParams["FeatureSettings"] = new string[] { vlanData.GetText(TextFormat.CimDtd20) };
      
                                      using (ManagementBaseObject outParams = managementService.InvokeMethod("AddFeatureSettings", inParams, null))
                                      {
                                          WmiUtils.ValidateOutput(outParams, _dataFields._scope);
                                      }
                                  }
                              }
                          }
                      }
                  }
              }
          }
      

      从虚拟机上的网络适配器中删除 VLAN

          /// <summary>
          /// For the given virtual machine, this sample will delete VLAN on existing network adapter 
          /// </summary>
          public void RemoveVLANFromVMNetworkAdapter()
          {
              using (ManagementObject managementService = WmiUtils.GetVirtualMachineManagementService(_dataFields._scope))
      
              //
              // Find the virtual machine we want to connect.
              //
              using (ManagementObject virtualMachine = WmiUtils.GetVirtualMachine(_dataFields.VmName, _dataFields._scope))
      
              //
              // Now that we have added a network adapter to the virtual machine we can configure its
              // connection settings.
              //
              using (ManagementObjectCollection findConnections = NetworkUtils.FindConnections(virtualMachine, _dataFields._scope))
              {
                  if (findConnections.Count > 0)
                  {
                      foreach (ManagementObject connection in findConnections)
                      {
                          // Get network adapter on virtual machine
                          using (ManagementObjectCollection vmSwitches = connection.GetRelated("Msvm_SyntheticEthernetPortSettingData"))
                          {
                              if (vmSwitches.Count > 0)
                              {
                                  foreach (ManagementObject vmSwitch in vmSwitches)
                                  {
                                      if (vmSwitch["ElementName"].ToString() == _dataFields.NetworkAdapterName)
                                      {
                                          // Get vlan settings data from network adapter
                                          using (ManagementObjectCollection vmSwitcheVLANs = connection.GetRelated("Msvm_EthernetSwitchPortVlanSettingData"))
                                          {
                                              if (vmSwitcheVLANs.Count > 0)
                                              {
                                                  // Get first objecz
                                                  using (ManagementObject vlanData = WmiUtils.GetFirstObjectFromCollection(vmSwitcheVLANs))
                                                  {
                                                      using (ManagementBaseObject inParams = managementService.GetMethodParameters("RemoveFeatureSettings"))
                                                      {
                                                          // Remove it
                                                          inParams["FeatureSettings"] = new string[] { vlanData.Path.Path };
                                                          using (ManagementBaseObject outParams = managementService.InvokeMethod("RemoveFeatureSettings", inParams, null))
                                                          {
                                                              WmiUtils.ValidateOutput(outParams, _dataFields._scope);
                                                          }
                                                      }
                                                  }
                                              }
                                          }
                                      }
                                  }
                              }
                          }
                      }
                  }
              }
          }
      

      请记住,我不使用通用网络适配器名称,我在创建 VM 时使用个性化的名称。这样我可以在需要时轻松获取适配器数据。

      想要为适配器添加个性化名称的人可以编辑 AddSyntheticAdapter(ManagementObject virtualMachine, ManagementScope scope) 函数,并在 adapterToAdd["ElementName"] 对象中包含不同的名称。

      希望这对通过 WMI 进行开发的勇敢者有所帮助! :)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-10-06
        • 2011-03-05
        • 1970-01-01
        • 1970-01-01
        • 2015-05-30
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多