Loops 修改未枚举的对象时出错
我有以下脚本:Loops 修改未枚举的对象时出错,loops,powershell,foreach,hashtable,Loops,Powershell,Foreach,Hashtable,我有以下脚本: $serverList = @{ "Server1Name" = @{ "WindowsService1" = "Status"; "WindowsService2" = "Status" }; "Server2Name" = @{ "WindowsService1" = "Status"; "WindowsService2" = "Status" }; "Server3Name" = @{ "WindowsService1" = "Status" };
$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
我在这里读到了:。如果我将代码表单复制到那里,它将在没有错误的情况下执行
我的问题可能与嵌套的foreach循环有关吗?我的密码有错误吗?有人能解释一下吗?Powershell不喜欢您修改正在迭代的集合 开始时,为了避免此问题,您制作了一个名为$copy的克隆。克隆是一个浅拷贝,因此每个键引用的对象在副本中都是相同的 在这一行:
$serverList[$server][$service] = $serviceInfo.Status
您可以修改当前正在迭代的内部集合
事实上,outter集合从不被修改,只被引用,因此outter克隆调用是不必要的。相反,您应该克隆内部集合。
类似这样的未经测试:
$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
}
}
Powershell不希望您修改正在迭代的集合 开始时,为了避免此问题,您制作了一个名为$copy的克隆。克隆是一个浅拷贝,因此每个键引用的对象在副本中都是相同的 在这一行:
$serverList[$server][$service] = $serviceInfo.Status
您可以修改当前正在迭代的内部集合
事实上,outter集合从不被修改,只被引用,因此outter克隆调用是不必要的。相反,您应该克隆内部集合。
类似这样的未经测试:
$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
}
}
我很惊讶.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 = $serverList.Clone()
与
我很惊讶.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 = $serverList.Clone()
与
哇,回答得好。工作很有魅力。谢谢你的解决办法。只是我,还是这是PowerShell的一个糟糕功能?我希望它克隆整个对象,而不仅仅是它的一部分……不,这是底层框架处理集合的固有方式。事实上,在.Net中你也会遇到同样的问题,我更喜欢c语言,但我知道powershell的工作原理是一样的。天真地说,您没有更改Keys属性,因此应该可以。但是,.Keys可能是对KeyValue对象的迭代,您正在更改KeyValueObject.Value-因此框架认为您已经修改了您正在迭代的集合。哇,回答不错。工作很有魅力。谢谢你的解决办法。只是我,还是这是PowerShell的一个糟糕功能?我希望它克隆整个对象,而不仅仅是它的一部分……不,这是底层框架处理集合的固有方式。事实上,在.Net中你也会遇到同样的问题,我更喜欢c语言,但我知道powershell的工作原理是一样的。天真地说,您没有更改Keys属性,因此应该可以。但是,.Keys可能是对KeyValue对象的迭代,您正在更改KeyValueObject.Value,因此框架认为您已经修改了正在迭代的集合。