2014-02-19 3 views
2

열거되지 않는 개체를 수정할 때 :오류 나는 다음과 같은 스크립트를 한

$serverList = @{ 
    "Server1Name" = @{ "WindowsService1" = "Status"; "WindowsService2" = "Status" }; 
    "Server2Name" = @{ "WindowsService1" = "Status"; "WindowsService2" = "Status" }; 
    "Server3Name" = @{ "WindowsService1" = "Status" }; 
    "Server4Name" = @{ "WindowsService1" = "Status" }; 
    "Server5Name" = @{ "WindowsService1" = "Status" }; 
    "Server6Name" = @{ "WindowsService1" = "Status" } 
} 

$copy = $serverList.Clone() 

foreach ($server in $copy.Keys) { 
    foreach ($service in $copy[$server].Keys) { 
     $serviceInfo = Get-Service -ComputerName $server -Name $service 
     $serverList[$server][$service] = $serviceInfo.Status 
    } 
} 

은 내가 열거되고있는 해시 테이블을 수정하지 오전 확인했다,하지만 내가 실행할 때 아직 나는 아직도이 오류가 스크립트 :

Collection was modified; enumeration operation may not execute.At line:14 char:14 
+  foreach ($service in $copy[$server].Keys) { 
+    ~~~~~~~~ 
    + CategoryInfo   : OperationStopped: (:) [], InvalidOperationException 
    + FullyQualifiedErrorId : System.InvalidOperationException 

나는 여기에서 이것을 읽었다 : http://blog.matticus.net/2013/11/powershell-clearing-values-within.html. 코드 양식을 복사하면 오류없이 실행됩니다.

내 문제는 중첩 된 foreach 루프와 관련이 있습니까? 내 코드에 실수가 있습니까? 누구든지 이것에 대해 어떤 생각을 밝힐 수 있습니까?

답변

3

Powershell은 반복하는 컬렉션을 수정하는 것을 좋아하지 않습니다.

이 문제를 피하기 위해 처음에는 $ copy라는 복제본을 만들었습니다. clone()은 "얕은 복사본"이므로 각 키에 대해 참조되는 개체는 복사본에서 동일합니다. 이 라인에

는 : - 현재 이상 반복되는

$serverList[$server][$service] = $serviceInfo.Status 

당신은 내부 모음을 수정합니다.

사실 outter 컬렉션은 절대로 수정되지 않고 참조되기 때문에 outter clone() 호출은 불필요합니다. 대신 내부 컬렉션을 복제해야합니다. 이 (안된) 같은 뭔가 :

$serverList = @{ 
    "Server1Name" = @{ "WindowsService1" = "Status"; "WindowsService2" = "Status" }; 
    "Server2Name" = @{ "WindowsService1" = "Status"; "WindowsService2" = "Status" }; 
    "Server3Name" = @{ "WindowsService1" = "Status" }; 
    "Server4Name" = @{ "WindowsService1" = "Status" }; 
    "Server5Name" = @{ "WindowsService1" = "Status" }; 
    "Server6Name" = @{ "WindowsService1" = "Status" } 
} 



foreach ($server in $serverList.Keys) { 
    $copy = $serverList[$server].clone(); 
    foreach ($service in $copy.Keys) { 
     $serviceInfo = Get-Service -ComputerName $server -Name $service 
     $serverList[$server][$service] = $serviceInfo.Status 
    } 
} 
+0

와우, 멋진 대답 라인을

$copy = $serverList.Clone() 

를 교체해야합니다. 매력처럼 일했습니다. –

+0

해결 방법을 제공해 주셔서 감사합니다. 나만인가, 아니면 PowerShell의 나쁜 특징입니까? 나는 그것의 일부가 아닌 전체 객체를 복제하기를 원합니다 ... –

+0

아니요, 기본 프레임 워크가 콜렉션을 처리하는 방식에 내재되어 있습니다. 닷넷에서 똑같은 문제점을 겪을 것이다. (사실, 나는 C# 녀석이다. 그러나 powershell도 똑같이 작동한다는 것을 안다.) Naively, "Keys"속성을 변경하지 않으므로 괜찮을 것입니다. 그러나 .Keys는 아마도 KeyValue 객체에 대한 반복이며 KeyValueObject.Value를 변경하고 있으므로 프레임 워크는 반복되는 컬렉션을 수정 한 것으로 간주합니다. – Tewr

1

내가 .Clone() 메소드는 단지 같은 객체에 대한 새로운 참조를 생성하는 놀랐습니다, 그것은 같은 특성을 가진 새로운 객체를 생성하지 않습니다. 전체 해시 테이블을 복제하는 대신 실제로 복사하는 쉬운 방법을 찾을 수 없었습니다. 그래서 나는이 작업을 수행 할 수있는 기능 썼다 :

Function Copy-HashTable($HashTable) { 
    $newHash = @{} 
    $HashTable.GetEnumerator() | ForEach-Object { 
     if ($_.Value -is "Hashtable") { 
      $newHash[$_.Key] = Copy-HashTable $_.Value 
     } else { 
      $newHash[$_.Key] = $_.Value 
     } 
    } 
    $newHash 
} 

이 코드에 이것을 적용을, 당신은 단지

$copy = Copy-HashTable $ServerList 
+0

+1 재귀 사용 –