You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Delphi通过WMI设置Hyper-V虚拟机网络配置PUT操作无效求助

问题:Delphi通过WMI设置Hyper-V虚拟机静态IP,PUT操作返回成功但配置未生效

我正在用Delphi开发基于WMI的功能,目标是给Hyper-V虚拟机设置静态IP,但遇到异常:PUT操作返回成功,可虚拟机的网络配置根本没变化。已经用管理员身份连接本地Hyper-V主机,而且PowerShell方案能成功实现这个功能。

可正常运行的PowerShell代码

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))
}

我的Delphi实现代码

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;

当前现象

日志显示Msvm_GuestNetworkAdapterConfiguration对象已经被修改,PUT_方法返回了有效的ISWbemObjectPath,而且通过WMI-Activity追踪到PUTInstance操作已经在Hyper-V服务器上执行,但虚拟机的网络配置还是没更新。另外因为需求限制,不能用DHCP,必须给现有虚拟机动态指定静态IP和VLAN。


解决方案

问题出在你直接调用Msvm_GuestNetworkAdapterConfiguration的Put_方法,而Hyper-V的网络配置更新必须通过Msvm_VirtualSystemManagementService的SetGuestNetworkAdapterConfiguration方法来完成,这和你PowerShell里的逻辑一致,但Delphi代码里没这么做。

修改后的Delphi代码示例

procedure TForm2.SetNetworkAdapterConfiguration;
var
  FSWbemLocator: ISWbemLocator;
  FWMIService: ISWbemServices;
  FWbemObjectSet: ISWbemObjectSet;
  NetworkAdapterConfig: ISWbemObject;
  VMSvc: ISWbemObject;
  VM: ISWbemObject;
  InParams: ISWbemObject;
  OutParams: ISWbemObject;
  ObjText: WideString;
begin
  try
    FSWbemLocator := CoSWbemLocator.Create;
    FWMIService := FSWbemLocator.ConnectServer('', 'root\virtualization\v2', '', '', '', '', 0, nil);

    // 获取目标虚拟机的Msvm_ComputerSystem实例(替换成你的虚拟机名称)
    FWbemObjectSet := FWMIService.ExecQuery('SELECT * FROM Msvm_ComputerSystem WHERE ElementName = ''你的虚拟机名称''', 'WQL', 0, nil);
    if (FWbemObjectSet.Count = 0) then
    begin
      ShowMessage('虚拟机未找到');
      Exit;
    end;
    VM := FWbemObjectSet.ItemIndex(0) as ISWBemObject;

    // 获取Msvm_VirtualSystemManagementService实例
    FWbemObjectSet := FWMIService.ExecQuery('SELECT * FROM Msvm_VirtualSystemManagementService', 'WQL', 0, nil);
    if (FWbemObjectSet.Count = 0) then
    begin
      ShowMessage('无法获取虚拟机管理服务');
      Exit;
    end;
    VMSvc := FWbemObjectSet.ItemIndex(0) as ISWBemObject;

    // 获取目标GuestNetworkAdapterConfiguration
    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;

    // 修改配置属性
    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']));

    // 获取对象的CIM文本
    ObjText := NetworkAdapterConfig.GetObjectText_(1);

    // 获取SetGuestNetworkAdapterConfiguration的输入参数
    InParams := VMSvc.Methods_.Item('SetGuestNetworkAdapterConfiguration', 0).InParameters.SpawnInstance_();
    InParams.Properties_.Item('ComputerSystem', 0).Set_Value(VM.Path_); // 传入虚拟机路径
    InParams.Properties_.Item('ConfigurationData', 0).Set_Value(ObjText); // 传入修改后的配置文本

    // 调用方法
    OutParams := VMSvc.ExecMethod_('SetGuestNetworkAdapterConfiguration', InParams, 0, nil);

    // 检查返回值(0表示成功)
    if (OutParams.Properties_.Item('ReturnValue', 0).Value = 0) then
      ShowMessage('配置更新成功')
    else
      ShowMessage('配置更新失败,返回值: ' + IntToStr(OutParams.Properties_.Item('ReturnValue', 0).Value));
  except
    on E: Exception do
      ShowMessage('Error: ' + E.Message);
  end;
end;

关键说明

  • Hyper-V的Msvm_GuestNetworkAdapterConfiguration是一个关联类,直接PUT不会触发实际的虚拟机配置更新,必须通过管理服务的专用方法提交
  • 调用SetGuestNetworkAdapterConfiguration时,需要传入虚拟机的Msvm_ComputerSystem路径和修改后的配置对象文本(对应PowerShell里的$ipstuff.GetText(1))
  • 注意方法返回值的检查,不同的返回值对应不同的错误(比如32表示虚拟机未运行,需要虚拟机处于运行状态才能修改Guest网络配置)

内容的提问来源于stack exchange,提问作者Diego Carrilho

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 08:05:56