Diego Carrilho
Diego Carrilho

Reputation: 13

How to set network config to a Hyper-V VM with WMI?

I'm working on a WMI with Delphi, the goal is to set a VM IP with WMI. But something is going wrong on PUT.

The ConnectServer function is connecting to local Hyper-V Host as administrator.

Already had success working with powershell using the code:

    Invoke-Command -ComputerName $VMhost -ArgumentList $IPaddress, $Mask, $Gatew, $VMname  -ScriptBlock {

        [string]$VMname = $args[3]

        $VMManServ =  Get-WmiObject -Namespace root\virtualization\v2 -Class Msvm_VirtualSystemManagementService

        $vm = Get-WmiObject -Namespace 'root\virtualization\v2' -Class 'Msvm_ComputerSystem' | Where-Object { $_.ElementName -eq $VMname }

        $vmSettings = $vm.GetRelated('Msvm_VirtualSystemSettingData') | Where-Object { $_.VirtualSystemType -eq 'Microsoft:Hyper-V:System:Realized' } 

        $nwAdapters = $vmSettings.GetRelated('Msvm_SyntheticEthernetPortSettingData') 

        $ipstuff = $nwAdapters.getrelated('Msvm_GuestNetworkAdapterConfiguration')

        $ipstuff.DHCPEnabled = $false
        $ipstuff.DNSServers = $args[2]
        $ipstuff.IPAddresses = $args[0]
        $ipstuff.Subnets = $args[1]
        $ipstuff.DefaultGateways = $args[2]

        $VMManServ.SetGuestNetworkAdapterConfiguration($VM, $ipstuff.GetText(1))
    }

Now i'm working on a solution to integrate with a delphi application. After run, the app display success but nothing happens to the VM

procedure TForm2.SetNetworkAdapterConfiguration;
var
  FSWbemLocator: ISWbemLocator;
  FWMIService: ISWbemServices;
  FWbemObjectSet: ISWbemObjectSet;
  NetworkAdapterConfig: ISWbemObject;
  ReturnValue: ISWbemObjectPath;
begin
  try
    FSWbemLocator := CoSWbemLocator.Create;
    FWMIService := FSWbemLocator.ConnectServer('', 'root\virtualization\v2', '', '', '', '', 0, nil);

    FWbemObjectSet := FWMIService.ExecQuery('SELECT * FROM Msvm_GuestNetworkAdapterConfiguration WHERE InstanceID = "Microsoft:GuestNetwork\\CE89678D-73B0-4957-B7BF-73A42ABEDB52\\4FC2700C-A2F3-438A-80FB-078FDB33E67D"', 'WQL', 0, nil);

    if not Assigned(FWbemObjectSet) or (FWbemObjectSet.Count = 0) then
    begin
      ShowMessage('Config not found.');
      Exit;
    end;


    NetworkAdapterConfig := FWbemObjectSet.ItemIndex(0) as ISWBemObject;
     Log1(FWbemObjectSet.ItemIndex(0).GetObjectText_(1));

    NetworkAdapterConfig.Properties_.Item('DHCPEnabled', 0).Set_Value(OleVariant(False));
    NetworkAdapterConfig.Properties_.Item('DNSServers', 0).Set_Value(VarArrayOf(['8.8.8.8']));
    NetworkAdapterConfig.Properties_.Item('IPAddresses', 0).Set_Value(VarArrayOf(['192.168.0.199']));
    NetworkAdapterConfig.Properties_.Item('Subnets', 0).Set_Value(VarArrayOf(['255.255.255.0']));
    NetworkAdapterConfig.Properties_.Item('DefaultGateways', 0).Set_Value(VarArrayOf(['192.168.0.1']));

    Log2(NetworkAdapterConfig.GetObjectText_(1));

    ReturnValue := NetworkAdapterConfig.Put_(1, nil);
    ShowMessage('Success.');
    Log3(ISWbemObjectPathVarDump(ReturnValue));
  except
    on E: Exception do
      ShowMessage('Error: ' + E.Message);
  end;
end;

Result of the Logs:

Log1;

instance of Msvm_GuestNetworkAdapterConfiguration
{
    DefaultGateways = {"192.168.0.1"};
    DHCPEnabled = TRUE;
    DNSServers = {"192.168.0.15"};
    InstanceID = "Microsoft:GuestNetwork\\CE89678D-73B0-4957-B7BF-73A42ABEDB52\\4FC2700C-A2F3-438A-80FB-078FDB33E67D";
    IPAddresses = {"192.168.0.162"};
    IPAddressOrigins = {1};
    ProtocolIFType = 4096;
    Subnets = {"255.255.255.0"};
};


Log2;

instance of Msvm_GuestNetworkAdapterConfiguration
{
    DefaultGateways = {"192.168.0.1"};
    DHCPEnabled = FALSE;
    DNSServers = {"8.8.8.8"};
    InstanceID = "Microsoft:GuestNetwork\\CE89678D-73B0-4957-B7BF-73A42ABEDB52\\4FC2700C-A2F3-438A-80FB-078FDB33E67D";
    IPAddresses = {"192.168.0.199"};
    IPAddressOrigins = {1};
    ProtocolIFType = 4096;
    Subnets = {"255.255.255.0"};
};

Log3 Put_ result as ISWbemObjectPath;
\\.\root\virtualization\v2:Msvm_GuestNetworkAdapterConfiguration.InstanceID="Microsoft:GuestNetwork\\CE89678D-73B0-4957-B7BF-73A42ABEDB52\\4FC2700C-A2F3-438A-80FB-078FDB33E67D"
RelPath : Msvm_GuestNetworkAdapterConfiguration.InstanceID="Microsoft:GuestNetwork\\CE89678D-73B0-4957-B7BF-73A42ABEDB52\\4FC2700C-A2F3-438A-80FB-078FDB33E67D"
Server : .
Namespace : root\virtualization\v2
ParentNamespace : root\virtualization
DisplayName : WINMGMTS:{authenticationLevel=pktPrivacy,impersonationLevel=impersonate}!\\.\root\virtualization\v2:Msvm_GuestNetworkAdapterConfiguration.InstanceID="Microsoft:GuestNetwork\\CE89678D-73B0-4957-B7BF-73A42ABEDB52\\4FC2700C-A2F3-438A-80FB-078FDB33E67D"
Class_ : Msvm_GuestNetworkAdapterConfiguration
Locale : 
Authority : 

Edit: DHCP is not a option, i have to designate dynamically a already existing machine to a ip and vlan without dhcp server.

Edit2: https://learn.microsoft.com/en-us/windows/win32/wmisdk/swbemobject-put-

objObjectPath = .Put_( _
  [ ByVal iFlags ], _
  [ ByVal objwbemNamedValueSet ] _
)

Looking at docs, found something about the parameters of put_:

wbemChangeFlagUpdateOnly (1 (0x1))

objwbemNamedValueSet [in, optional]

Return value objObjectPath If the call is successful, an SWbemObjectPath object is returned. This object contains the object path of the instance or class that has been successfully committed to WMI.

by var dumping the object returned of put_, he returned a fully qualified SWbemObjectPath, check Log3 above;

Unfortunately still not applying to the Virtual Machine

Edit 4

By tracing WMI-Activity, i can see the put event being executed on Hyper-V Server Start IWbemServices::PutInstance

    - <Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
- <System>
  <Provider Name="Microsoft-Windows-WMI-Activity" Guid="{1418ef04-b0b4-4623-bf7e-d74ab47bbdaa}" /> 
  <EventID>11</EventID> 
  <Version>0</Version> 
  <Level>4</Level> 
  <Task>0</Task> 
  <Opcode>0</Opcode> 
  <Keywords>0x8000000000000000</Keywords> 
  <TimeCreated SystemTime="2024-05-02T23:35:42.7638600Z" /> 
  <EventRecordID>65</EventRecordID> 
  <Correlation ActivityID="{1420ec18-2615-476a-bf58-c7fae612f136}" /> 
  <Execution ProcessID="1748" ThreadID="3556" /> 
  <Channel>Microsoft-Windows-WMI-Activity/Trace</Channel> 
  <Computer>HP006-SRV.MY_FQDN.com</Computer> 
  <Security /> 
  </System>
- <UserData>
- <Operation_New xmlns="http://manifests.microsoft.com/win/2006/windows/WMI">
  <CorrelationId>{00000000-0000-0000-0000-000000000000}</CorrelationId> 
  <GroupOperationId>335934</GroupOperationId> 
  <OperationId>335952</OperationId> 
  <Operation>Start IWbemServices::PutInstance - root\virtualization\v2 : Msvm_GuestNetworkAdapterConfiguration.InstanceID="Microsoft:GuestNetwork\\CE89678D-73B0-4957-B7BF-73A42ABEDB52\\4FC2700C-A2F3-438A-80FB-078FDB33E67D"</Operation> 
  <ClientMachine>NOTEHP-SRV</ClientMachine> 
  <ClientMachineFQDN>HP006-SRV.MY_FQDN.com</ClientMachineFQDN> 
  <User>MYDOMAIN\MY_USERNAME</User> 
  <ClientProcessId>3852</ClientProcessId> 
  <ClientProcessCreationTime>133591663144112869</ClientProcessCreationTime> 
  <NamespaceName>\\.\root\virtualization\v2</NamespaceName> 
  <IsLocal>true</IsLocal> 
  </Operation_New>
  </UserData>
  </Event>

Upvotes: 0

Views: 162

Answers (1)

Diego Carrilho
Diego Carrilho

Reputation: 13

The solution was to follow the flow of the powershell script, and the ISWbemObjectEx object use.

FSWbemLocator := CoSWbemLocator.Create;
FWMIService := FSWbemLocator.ConnectServer('', nameSpace.text, '', '', '', '', 0, nil)   ;


FWbemObjectSet := FWMIService.ExecQuery('SELECT * FROM Msvm_VirtualSystemManagementService', 'WQL', 0, nil);
FWbemObjectSet2 := FWMIService.ExecQuery('SELECT * FROM Msvm_GuestNetworkAdapterConfiguration WHERE InstanceID LIKE "'+NetworkID.text+'"', 'WQL', 0, nil);
FWbemObjectSet3 := FWMIService.ExecQuery('SELECT * FROM Msvm_ComputerSystem WHERE ElementName LIKE "'+vmName.Text+'"', 'WQL', 0, nil);

VSMS        := FWbemObjectSet.ItemIndex(0)  as ISWbemObject;
NetAdapter  := FWbemObjectSet2.ItemIndex(0) as ISWbemObjectEx;
VM          := FWbemObjectSet3.ItemIndex(0) as ISWbemObject;

NetAdapter.Properties_.Item('IPAddresses', 0).Set_Value(VarArrayOf([IPAddress.Text]));

NetworkConfigurationArray := VarArrayCreate([0, 0], varOleStr);
NetworkConfigurationArray[0] := NetAdapter.GetText_(1,0,nil);

InParameters := VSMS.Methods_.Item('SetGuestNetworkAdapterConfiguration',0).InParameters.SpawnInstance_(0);
InParameters.Properties_.Item('ComputerSystem', 0).Set_Value(VM.Path_.Path);
InParameters.Properties_.Item('NetworkConfiguration',0).Set_Value(NetworkConfigurationArray);

VSMS.ExecMethod_('SetGuestNetworkAdapterConfiguration', InParameters, 0, nil);

Upvotes: 0

Related Questions