我正在使用 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 返回单元素集合,或者确定返回的“事物”是否是对象而不是集合?
以两种方式之一将变量定义为数组...
将您的管道命令括在括号中,并在开头使用 @
:
$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> }
将结果强制为 Array,以便您可以拥有 Count 属性。单个对象(标量)没有 Count 属性。字符串具有长度属性,因此您可能会得到错误的结果,请使用 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'}
-is
检查数据类型吗?
@($serverIps).Count
是不必要的。使用 $serverIps.Count
即可。
您可以在返回列表之前添加一个逗号 (,
),例如 return ,$list
,或者在您倾向于使用该列表的位置添加 [Array]
或 [YourType[]]
。
,
(一元数组运算符)取得成功。
如果您提前将变量声明为数组,则可以向其中添加元素 - 即使它只是一个...
这应该工作...
$serverIps = @()
gwmi Win32_NetworkAdapterConfiguration
| Where { $_.IPAddress }
| Select -Expand IPAddress
| Where { $_ -like '*.*.*.*' }
| Sort | ForEach-Object{$serverIps += $_}
您可以使用 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
}
Measure-Object
是不必要的。使用 $serverIps.Count
即可。
Count
属性不可用。这是原始问题的全部要点。 Measure-Object
将保证具有多个、单个甚至 $null 对象的有效 Count
属性。
.Count
属性。 function Get1 { return @('Hello') }; (Get1).GetType(); (Get1).Count
。
.Count
。
作为引用对象返回,因此它在传递时永远不会转换。
return @{ Value = @("single data") }
我在将数组传递给 Azure 部署模板时遇到了这个问题。如果有一个对象,PowerShell 会将其“转换”为字符串。在下面的示例中,$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
传递给部署模板的参数(数组类型)。
作为参考,可爱的错误 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.."
有一种方法可以处理您的情况。让大部分代码保持原样,只需更改处理 $serverIps
对象的方式。这段代码可以处理$null
,只有一个项目,很多项目。
$serverIps = gwmi Win32_NetworkAdapterConfiguration
| Where { $_.IPAddress }
| Select -Expand IPAddress
| Where { $_ -like '*.*.*.*' }
| Sort
# Always use ".Count" instead of ".Length".
# This works on $null, only one item, or many items.
if ($serverIps.Count -le 1) {
Write-Host "You need at least 2 IP addresses for this to work!"
exit
}
# Always use foreach on a array-possible object, so that
# you don't have deal with this issue anymore.
$serverIps | foreach {
# The $serverIps could be $null. Even $null can loop once.
# So we need to skip the $null condition.
if ($_ -ne $null) {
# Get the index of the array.
# The @($serverIps) make sure it must be an array.
$idx = @($serverIps).IndexOf($item)
if ($idx -eq 0) { $primaryIp = $_ }
if ($idx -eq 1) { $secondaryIp = $_ }
}
}
在 PowerShell Core 中,每个对象都有一个 .Count 属性。在 Windows PowerShell 中,“几乎”每个对象都有一个 .Count 属性。
不定期副业成功案例分享
@(...)
中包装命令也会返回一个数组。而将结果分配给[Array]
类型的变量仍将返回 $null 如果有零个对象。@(...)
对于任何类型的对象都可以正常工作(产生我期望它应该产生的结果)。Return ,$out
解决了我最近的问题。如果我再次遇到问题,我会发布一个示例。