How to force ForceShell to return an array when a call returns only one object?

I am using Powershell to configure IIS bindings on a web server and have a problem with the following code:

$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] 

If the server has 2+ IP addresses, fine - Powershell returns an array, and I can query the length of the array and extract only the first and second addresses.

The problem is if there is only one IP, Powershell does not return a singleton array, it returns an IP address (like a string, for example, "192.168.0.100") - the string has the .length property .length it is greater than 1, so the test passes, and I get the first two characters per line, not the first two IP addresses in the collection.

How can I get Powershell to return a singleton collection or, conversely, determine if the returned β€œthing” is an object, not a collection?

+90
powershell
Jun 19 '12 at 18:49
source share
6 answers

Defining a variable as an array is one of two ways ...

Paste the copied commands into parentheses with @ at the beginning:

 $serverIps = @(gwmi Win32_NetworkAdapterConfiguration | Where { $_.IPAddress } | Select -Expand IPAddress | Where { $_ -like '*.*.*.*' } | Sort) 

Specify the data type of the variable as an array:

 [array]$serverIps = gwmi Win32_NetworkAdapterConfiguration | Where { $_.IPAddress } | Select -Expand IPAddress | Where { $_ -like '*.*.*.*' } | Sort 

Or check the data type of the variable ...

 IF ($ServerIps -isnot [array]) { <error message> } ELSE { <proceed> } 
+111
Jun 19 '12 at 18:52
source share

Force the result to an array to have the Count property. Individual objects (scalar) do not have the Count property. Strings have a length property, so you can get false results, use the Count property:

 if (@($serverIps).Count -le 1)... 

By the way, instead of using a wildcard that can also match strings, use the -as operator:

 [array]$serverIps = gwmi Win32_NetworkAdapterConfiguration -filter "IPEnabled=TRUE" | Select-Object -ExpandProperty IPAddress | Where-Object {($_ -as [ipaddress]).AddressFamily -eq 'InterNetwork'} 
+11
Jun 19 '12 at 18:51
source share

If you declare a variable as an array ahead of time, you can add elements to it - even if it's just one ...

This should work ...

 $serverIps = @() gwmi Win32_NetworkAdapterConfiguration | Where { $_.IPAddress } | Select -Expand IPAddress | Where { $_ -like '*.*.*.*' } | Sort | ForEach-Object{$serverIps += $_} 
+5
Jun 19 '12 at 18:53
source share

You can use Measure-Object to get the actual number of objects without resorting to the Count property of the object.

 $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 } 
+1
Jul 10 '18 at 12:27
source share

I'm having a problem passing an array to an Azure deployment template. If only one object existed, PowerShell "converted" it to a string. In the example below, $a returned from a function that receives a VM according to the tag value. I pass $a to the New-AzureRmResourceGroupDeployment , wrapping it in @() . For example:

 $TemplateParameterObject=@{ VMObject=@($a) } New-AzureRmResourceGroupDeployment -ResourceGroupName $RG -Name "TestVmByRole" -Mode Incremental -DeploymentDebugLogLevel All -TemplateFile $templatePath -TemplateParameterObject $TemplateParameterObject -verbose 

VMObject is one of the template options.

This may not be the most technical / reliable way to do this, but that's enough for Azure.




Update

Good thing worked above. I tried all of the above and some, but the only way I was able to pass $vmObject as an array compatible with the deployment template, with one element as follows (I expect MS to play again (this was a report and a bug fix in 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 is the output of Get-AzureRmVM.

I pass $DeserializedJson to the deployment pattern parameter (type array).

For reference, the perfect New-AzureRmResourceGroupDeployment throws

 "The template output '{output_name}' is not valid: The language expression property 'Microsoft.WindowsAzure.ResourceStack.Frontdoor.Expression.Expressions.JTokenExpression' can't be evaluated.." 
0
Nov 29 '17 at 20:38 on
source share

You can add a comma ( , ) before the return ,$list list return ,$list for example return ,$list or cast it to [Array] or [YourType[]] where you tend to use the list.

0
Jul 10 '19 at 19:05
source share



All Articles