当一个调用只返回一个对象时,如何强制Powershell返回一个数组呢?

时间:2012-06-19 18:49:26

标签: powershell

我正在使用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”是对象而不是集合?

7 个答案:

答案 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") }