호출이 하나의 개체 만 반환 할 때 Powershell에서 배열을 반환하도록하려면 어떻게해야합니까?


123

Powershell을 사용하여 웹 서버에서 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에서 단일 요소 컬렉션을 반환하도록 강제하거나 반환 된 "사물"이 컬렉션이 아닌 개체인지 여부를 어떻게 확인할 수 있습니까?


28
PowerShell의 가장 혼자서 성가신 / 버그가 많은 측면 ..
user2864740

나는 당신의 예가 너무 복잡하다고 생각합니다. 더 간단한 질문 : << $ x = echo Hello; $ x -is [Array] >>는 False를 생성합니다.
라울 살리나스 - Monteagudo

이 동작은 powershell 5에서 변경 되었습니까? 5 번에는 재현 할 수 없지만 4
번은

답변:


143

두 가지 방법 중 하나로 변수를 배열로 정의하십시오.

파이프 명령을 @시작 부분 에 괄호로 묶습니다 .

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

28
명령을 래핑하면 @(...)개체가 0 개라도 배열이 반환됩니다. 결과를 [Array]-typed 변수에 할당하면 개체가 0 개이면 $ null이 반환됩니다.
Nic 2011

1
반환되는 개체가 PSObject (다른 경우) 인 경우 이러한 솔루션 중 어느 것도 작동하지 않습니다.
Deadly-Bagel

2
@ Deadly-Bagel 이것의 예를 보여줄 수 있습니까? 나를 @(...)위해 모든 유형의 객체에 대해 제대로 작동합니다 (생성해야 할 결과를 생성합니다).
user4003407

1
똑같은 질문으로 돌아가는 방식이 재밌습니다. 나는 (그리고 다시) 약간 다른 문제가 있었다. 네, 질문에서와 같이 이것은 잘 작동하지만 함수에서 돌아올 때 그것은 다른 이야기입니다. 요소가 하나 있으면 배열이 무시되고 요소 만 반환됩니다. 변수 앞에 쉼표를 넣으면 배열에 강제 적용되지만 다중 요소 배열은 2 차원 배열을 반환합니다. 매우 지루합니다.
Deadly-Bagel

1
이건 지난번에도 일어난 일인데, 지금은 복제 할 수 없습니다. 어쨌든 나는 Return ,$out항상 작동하는 것처럼 보이는 사용하여 최근 문제를 해결 했습니다. 다시 문제가 발생하면 예제를 게시하겠습니다.
Deadly-Bagel

13

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?
JNK

문자열은 .length 속성이 있습니다 - 그것은 작동하고 그 이유는 ... :)
딜런 비티

8

변수를 미리 배열로 선언하면 하나라도 요소를 추가 할 수 있습니다.

이것은 작동합니다 ...

$serverIps = @()

gwmi Win32_NetworkAdapterConfiguration 
    | Where { $_.IPAddress } 
    | Select -Expand IPAddress 
    | Where { $_ -like '*.*.*.*' } 
    | Sort | ForEach-Object{$serverIps += $_}

실제로 이것이 가장 명확하고 안전한 옵션이라고 생각합니다. '컬렉션 또는'GE의 1의 Foreach '- 당신은 안정적 ".Count 사용할 수 있습니다
Jaigene 강

2

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
}

1

,반환 목록 앞에 쉼표 ( ) 를 추가 return ,$list하거나 목록을 캐스트 [Array]하거나 [YourType[]]목록을 사용하는 위치에 추가 할 수 있습니다.


0

배열을 Azure 배포 템플릿에 전달하는 데이 문제가 발생했습니다. 하나의 개체가있는 경우 PowerShell은이를 문자열로 "변환"했습니다. 아래 예에서는 $a태그 값에 따라 VM 객체를 가져 오는 함수에서 반환됩니다. 를 래핑 $a하여 New-AzureRmResourceGroupDeploymentcmdlet에 전달합니다 @(). 이렇게 :

$TemplateParameterObject=@{
     VMObject=@($a)
}

New-AzureRmResourceGroupDeployment -ResourceGroupName $RG -Name "TestVmByRole" -Mode Incremental -DeploymentDebugLogLevel All -TemplateFile $templatePath -TemplateParameterObject $TemplateParameterObject -verbose

VMObject 템플릿의 매개 변수 중 하나입니다.

이를 수행하는 가장 기술적이고 강력한 방법은 아니지만 Azure에는 충분합니다.


최신 정보

위의 내용이 작동했습니다. 위와 일부를 모두 시도했지만 $vmObject배포 템플릿과 호환되는 배열 로 전달 하고 하나의 요소를 사용 하는 유일한 방법 은 다음과 같습니다. 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의 출력입니다.

I 패스 $DeserializedJson(Array 형의) 배치 템플릿 '파라미터.

참고로 멋진 오류 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.."

0

참조 된 객체로 반환하므로 전달하는 동안 변환되지 않습니다.

return @{ Value = @("single data") }
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.