我正在使用Powershell在Web服务器上设置IIS绑定,并且遇到以下代码的问题:
$serverIps = gwmi Win32_NetworkAdapterConfiguration
| Where { $_.IPAddress }
| Select -Expand IPAddress
| Where { $_ -like '*.*.*.*' }
| Sort
if ($serverIps.length -le 1) {
Write-Host "You need at least 2 IP addresses for this to work!"
exit
}
$primaryIp = $serverIps[0]
$secondaryIp = $serverIps[1]
如果服务器上有2个以上的IP,那么很好 - Powershell返回一个数组,我可以查询数组长度并提取第一个和第二个地址就好了。
问题是 - 如果只有一个IP,Powershell不返回单元素数组,它返回IP地址(作为字符串,如“192.168.0.100”) - 字符串有.length
属性,它大于1,所以测试通过,我最终得到字符串中的前两个字符,而不是集合中的前两个IP地址。
如何强制Powershell返回单元素集合,或者确定返回的“thing”是对象而不是集合?
答案 0 :(得分:108)
以两种方式之一将变量定义为数组......
将管道命令包含在括号中,并在开头添加@
:
$serverIps = @(gwmi Win32_NetworkAdapterConfiguration
| Where { $_.IPAddress }
| Select -Expand IPAddress
| Where { $_ -like '*.*.*.*' }
| Sort)
将变量的数据类型指定为数组:
[array]$serverIps = gwmi Win32_NetworkAdapterConfiguration
| Where { $_.IPAddress }
| Select -Expand IPAddress
| Where { $_ -like '*.*.*.*' }
| Sort
或者,检查变量的数据类型......
IF ($ServerIps -isnot [array])
{ <error message> }
ELSE
{ <proceed> }
答案 1 :(得分:11)
将结果强制为数组,以便您可以拥有Count属性。单个对象(标量)没有Count属性。字符串具有length属性,因此您可能会得到错误的结果,请使用Count属性:
if (@($serverIps).Count -le 1)...
顺便说一下,使用-as运算符:
,而不是使用也可以匹配字符串的通配符[array]$serverIps = gwmi Win32_NetworkAdapterConfiguration -filter "IPEnabled=TRUE" | Select-Object -ExpandProperty IPAddress | Where-Object {($_ -as [ipaddress]).AddressFamily -eq 'InterNetwork'}
答案 2 :(得分:5)
如果您提前将变量声明为数组,则可以向其中添加元素 - 即使它只是一个...
这应该有用......
$serverIps = @()
gwmi Win32_NetworkAdapterConfiguration
| Where { $_.IPAddress }
| Select -Expand IPAddress
| Where { $_ -like '*.*.*.*' }
| Sort | ForEach-Object{$serverIps += $_}
答案 3 :(得分:1)
您可以使用Measure-Object
来获取实际的对象计数,而无需求助于对象的Count
属性。
$serverIps = gwmi Win32_NetworkAdapterConfiguration
| Where { $_.IPAddress }
| Select -Expand IPAddress
| Where { $_ -like '*.*.*.*' }
| Sort
if (($serverIps | Measure).Count -le 1) {
Write-Host "You need at least 2 IP addresses for this to work!"
exit
}
答案 4 :(得分:0)
我将此数组传递给Azure部署模板时遇到此问题。如果有一个对象,PowerShell&#34;转换&#34;它到一个字符串。在下面的示例中,$a
从根据标记值获取VM的函数返回。我将$a
传递给New-AzureRmResourceGroupDeployment
cmdlet并将其包装在@()
中。像这样:
$TemplateParameterObject=@{
VMObject=@($a)
}
New-AzureRmResourceGroupDeployment -ResourceGroupName $RG -Name "TestVmByRole" -Mode Incremental -DeploymentDebugLogLevel All -TemplateFile $templatePath -TemplateParameterObject $TemplateParameterObject -verbose
VMObject
是模板的参数之一。
可能不是最技术/最强大的方法,但对Azure来说已经足够了。
以上确实有效。我已经尝试了以上所有和一些,但我设法传递$vmObject
作为数组的唯一方法,与部署模板兼容,有一个元素如下(我希望MS再次播放) (这是2015年的报告和修复错误)):
[void][System.Reflection.Assembly]::LoadWithPartialName("System.Web.Extensions")
foreach($vmObject in $vmObjects)
{
#$vmTemplateObject = $vmObject
$asJson = (ConvertTo-Json -InputObject $vmObject -Depth 10 -Verbose) #-replace '\s',''
$DeserializedJson = (New-Object -TypeName System.Web.Script.Serialization.JavaScriptSerializer -Property @{MaxJsonLength=67108864}).DeserializeObject($asJson)
}
$vmObjects
是Get-AzureRmVM的输出。
我将$DeserializedJson
传递给部署模板&#39;参数(类型数组)。
作为参考,可疑错误New-AzureRmResourceGroupDeployment
抛出
"The template output '{output_name}' is not valid: The language expression property 'Microsoft.WindowsAzure.ResourceStack.Frontdoor.Expression.Expressions.JTokenExpression'
can't be evaluated.."
答案 5 :(得分:0)
您可以在返回列表之类的,
之前添加逗号(return ,$list
),也可以将其转换为[Array]
或[YourType[]]
放在您倾向于使用列表的位置。
答案 6 :(得分:0)
返回为参考对象,因此传递时永远不会转换。
return @{ Value = @("single data") }