首页 > 解决方案 > 当脚本读取 XML 文件时,PowerCLI New-VM GuestOSCustomization 失败

问题描述

我有一个 Powershell (v5.1) 脚本(32 位模式),我一直在使用它来创建新的虚拟机(我们的 vRealize 编排似乎无法记录日志)。我正在运行 PowerCLI v5.5。

该脚本运行良好,唯一的问题是脚本中的大量数据是硬编码的。我编写了一个 XML 文件来包含我想要选择的所有可变数据,但是当我添加代码来读取 XML 文件时,VM 将无法在 OSGuestCustomization 期间更改 IP 地址(显然然后是管理员帐户凭据)和因此新的虚拟机对我来说毫无用处。

令人困惑的是为什么要添加这一行:

$script:CMDBInfo = [xml](gc c:\src\Enterprise\Enterprise\Systems\Scripts\Powershell-SCMDEV\Opsbrain\TMCMDB.xml)

到脚本会导致这一行失败:

$create_vm = New-VM -Template $script:json_data.opb_template -ResourcePool $script:json_data.opb_build_cluster -Name $script:json_data.host_name -Datastore $datastore -DiskStorageFormat Thin -OSCustomizationSpec $customization -Confirm:$false -RunAsync -ErrorAction Stop$create_vm = New-VM -Template $script:json_data.opb_template -ResourcePool $script:json_data.opb_build_cluster -Name $script:json_data.host_name -Datastore $datastore -DiskStorageFormat Thin -OSCustomizationSpec $customization -Confirm:$false -RunAsync -ErrorAction Stop

我终于尝试简单地注释掉 GC 并且 New-VM 工作。

一个简短的搜索出现了https://communities.vmware.com/thread/482488,我将磁盘安装在另一台服务器上以检查 VMware 临时文件和日志。

我看到了一些错误,但它们的原因并不是很明显。

c:\windows\setupact.log : dispci.dll:  DispCISkipClassInstaller: SetupDiGetSelectedDriver failed with error 0xe0000203.

c:\windows\setuperr.log 为空。

c:\windows\temp\vminst.log : 
2017-09-29 14:06:06| tools-build-3917699| INFO: Failed to fetch component state for '_driver_memctl.5C48FA9C_E001_43CB_B2B6_590CD422177E'.
2017-09-29 14:06:40| inst-build-3917699| E1: FILE: FileDeletionRetry: Non-retriable error encountered (C:\Windows\TEMP\vmware-SYSTEM\00007bf9\windows.iso): The system cannot find the file specified (2)

但看起来它完成了:

2017-09-29 14:06:40| inst-build-3917699| I1: Upgrader finished execution, now signalling event.
2017-09-29 14:06:40| inst-build-3917699| I1: Upgrader: returning [0]

我删除了很多注释和“无关”数据,以获得 XML 文件的代表性样本。

<?xml version="1.0" encoding="utf-8"?>
<CMDB>
    <IPTable>
        <Network Name="DevServerPrivate">
            <Range Subnet="192.168.1.0" RangeLow="192.168.1.21" RangeHigh="192.168.1.150" SubnetMask="255.255.255.0" DefGW="192.168.1.1" DNS="8.8.8.8,8.8.4.4" VMwareNetworkLabel="devserver" />
        </Network>
    </IPTable>
</CMDB>

以及脚本的摘录:

$script:CMDBInfo = [xml](gc D:\src\Enterprise\Enterprise\Systems\Scripts\Powershell-SCMDEV\Opsbrain\TMCMDB.xml)
$TargetNetwork = "$($json_data.environment)ServerPrivate"
$NetworkRanges = $script:CMDBInfo.CMDB.IPTable.Network | Where-Object {$_.Name -eq $TargetNetwork}
# Some ranges may be inactive, meaning we don't want to use them anymore
# Or some ranges may not have any available IP addresses, if multiple ranges are assigned to the environment then we'll want to try all of them to get a valid IP.
foreach($RangeInfo in $NetworkRanges.Range){
    if(-not ($RangeInfo.Active -eq 'false')){
        $IPAddress = GetIPFromIPAM -Subnet $RangeInfo.Subnet
        if([regex]::Matches($IPAddress,'([0-9]{1,3}\.){3}[0-9]').Success -eq 'True'){
            break
        }
    }
}
if([regex]::Matches($IPAddress,'([0-9]{1,3}\.){3}[0-9]').Success -eq 'True'){
    $script:json_data | Add-Member -Type NoteProperty -Name ip_address -Value $IPAddress
    $script:json_data | Add-Member -Type NoteProperty -Name opb_vm_port_group -Value $RangeInfo.VMwareNetworkLabel
    $script:json_data | Add-Member -Type NoteProperty -Name opb_netmask -Value $RangeInfo.SubnetMask
    $script:json_data | Add-Member -Type NoteProperty -Name opb_default_route -Value $RangeInfo.DefGW
    $script:json_data | Add-Member -Type NoteProperty -Name opb_name_server -Value $RangeInfo.DNS
} else {
    LLToLog -EventID $LLERROR -Text "Unable to get an IP address for $TargetNetwork"
    #Exit
}

$script:json_data

在最后转储 $script:json_data 后,所有数据都与我在脚本的前一个(工作)迭代中使用的硬编码值相同。

然后我使用数据填充 OSCustomization 对象:

$customization = Get-OSCustomizationSpec -Name "Spec_$host_name" | Get-OSCustomizationNicMapping | Set-OSCustomizationNicMapping  -IpMode UseStaticIP -IpAddress $script:json_data.ip_address -SubnetMask $script:json_data.opb_netmask -DefaultGateway $script:json_data.opb_default_route -Dns $script:json_data.opb_name_server[0],$script:json_data.opb_name_server[1]
$customization = Get-OSCustomizationSpec -Name "Spec_$host_name" | Set-OSCustomizationSpec -Domain $script:json_data.dns_domain -DomainUsername "service_account@domain.com" -DomainPassword $DomainAdminPwd

然后创建虚拟机:

$create_vm = New-VM -Template $script:json_data.opb_template -ResourcePool $script:json_data.opb_build_cluster -Name $script:json_data.host_name -Datastore $datastore -DiskStorageFormat Thin -OSCustomizationSpec $customization -Confirm:$false -RunAsync -ErrorAction Stop

现在,我有一个新旧剧本的科学怪人。我尝试通过从 XML 文件中提取信息来执行新脚本的工作,但随后我忽略了所有这些并将 json_data 值设置为旧脚本硬编码值。因此,无论我是否阅读 XML,我总是使用相同的值。

如果我注释掉 XML 的读取,OSGuestCustomization 在 New-VM 克隆完成后大约 2 分钟完成。如果我不加注释,OSGuestCustomization 永远不会完成。我认为有些部分可以:服务器认为它已加入域,但未设置 IP 地址(如 VMWare Tools 报告的那样),并且未设置本地管理员帐户凭据。

标签: powershellpowercli

解决方案


推荐阅读