我正在使用Delphi开发WMI,目标是使用WMI设置VM IP。但 PUT 上出了点问题。
ConnectServer 功能正在以管理员身份连接到本地 Hyper-V 主机。
已经使用以下代码成功使用 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;
日志结果:
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 :
编辑:DHCP 不是一个选项,我必须在没有 dhcp 服务器的情况下动态指定现有计算机的 ip 和 vlan。
编辑2:https://learn.microsoft.com/en-us/windows/win32/wmisdk/swbemobject-put-
objObjectPath = .Put_( _
[ ByVal iFlags ], _
[ ByVal objwbemNamedValueSet ] _
)
查看文档,发现一些关于put_的参数:
wbemChangeFlagUpdateOnly(1(0x1))
objwbemNamedValueSet [输入,可选]
返回值objObjectPath 如果调用成功,则返回 SWbemObjectPath 对象。该对象包含已成功提交到 WMI 的实例或类的对象路径。
通过var dump put_返回的对象,他返回了一个完全限定的SWbemObjectPath,查看上面的Log3;
不幸的是仍然没有应用到虚拟机
编辑4
通过跟踪WMI-Activity,我可以看到Hyper-V服务器上正在执行put事件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>
解决方案是遵循 powershell 脚本的流程,并使用 ISWbemObjectEx 对象。
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);