PowerShell - 枚举集合并更改集合

11

如何修复这个脚本呢?

是的,我在foreach循环中修改了集合,这就是导致此错误的原因。

枚举集合时发生错误:已修改集合;可能无法执行枚举操作。 位于 C:\Users\user\Documents\PowerShell\ChangeAllListsV2.ps1:47 字符:20 + foreach <<<< ($list in $webLists) + CategoryInfo : InvalidOperation: (Microsoft.Share...on+SPEnumerator:SPEnumerator) [], RuntimeException + FullyQualifiedErrorId : BadEnumeration

#Script change in all lists the required field property "testfield" to false


#Part 0 - Configuration

$urlWebApp = "http://dev.sharepoint.com"
$countFound = 0
$countList = 0
$countFoundAndChange = 0

#Part 1 - PreScript  

$snapin = Get-PSSnapin | Where-Object {$_.Name -eq "Microsoft.SharePoint.Powershell"}

if ($snapin -eq $null)

{
    Write-Host “Loading SharePoint Powershell”
    Add-PSSnapin Microsoft.SharePoint.Powershell
}

#Part 2 - Script

$webApp = Get-SPWebApplication $urlWebApp

#$webApp | fl

    $webAppSites = $webApp.sites

    foreach($site in $webAppSites)
    {
        Write-Host "***********************************************************************"
        Write-Host "Found site: " $site -foreground blue

        $siteAllWebs = $site.AllWebs

        foreach($web in $siteAllWebs)
        {
            Write-Host "Found web: " $web -foreground blue
            #$web | fl

           $webLists = $web.Lists

            foreach($list in $webLists)
            {
             $countList ++

             Write-Host "Found list: " $list -foreground blue

                #Change list property

                $field = $Null
                $field = $list.Fields["testfield"]

                    if($field){
                    Write-Host "Field found: " $list -foreground green
                    #Write-Host "in web: " $web -foreground green
                    $countFound ++

                        try{

                            if($field.Required)
                            {

                            #######################################################
                            $field.Required = $False
                            $field.Update()
                            #######################################################

                            $field = $Null
                            Write-Host "Done!: Change list: " $list -foreground  green
                            $countFoundAndChange ++                    

                            }else{ 
                            Write-Host "Already!: Change list: " $list -foreground  green       

                            }

                        }
                        catch{
                            $field = $Null
                            Write-Host "Error!: Change list: " $list -foreground red
                            Write-Host "in web: " $web -foreground red
                            $_

                        }

                    }


            } 


        }


    }



Write-Host "Found lists: " $countList
Write-Host "Found lists with column [testfield]: " $countFound
Write-Host "Change lists with column [testfield]: " $countFoundAndChange
5个回答

22

SPListCollection在更新其属性(字段、事件接收器等)时往往会修改集合。您可以改用for循环:

for ($i = 0; $i -lt $webLists.Count; $i++)
{
  $list = $web.Lists[$i];
  # ...
}

7
我知道这是一个相当老的帖子。对于任何在这个页面上寻找答案的人来说,这是有用的。
像其他答案建议的那样,想法是使用“clone()”方法将集合复制到另一个集合,并迭代“another”,在循环内部修改原始变量,而无需使用“for”代替“foreach”:
一个ArrayList类型的集合:
[System.Collections.ArrayList]$collection1 = "Foo","bar","baz"
$($collection1.Clone()) | foreach {
$collection1.Remove("bar")
}

输出:

PS H:\> $collection1
Foo
baz

一种类型为 Hashtable 的集合:

[System.Collections.Hashtable]$collection2 = @{
        "Forum" = "Stackoverflow"
        "Topic" = "PowerShell"
        }

$($collection2.Clone())| foreach {
$collection2.Remove("Forum")
}

输出: PS H:> $collection2

Name                           Value                                                              
----                           -----                                                              
Topic                          PowerShell                                                         

还有一个基本数组:

[System.Array]$collection3 = 1, 2, 3, 4
$($collection3.Clone()) | foreach {
$collection3[$collection3.IndexOf($_)] = 10
}

输出:

PS H:\> $collection3
10
10
10
10

只要你的集合大小不是固定的。

4

您可以尝试将当前正在迭代的集合复制到另一个集合(数组或列表)中,然后在该新集合上进行迭代。

像这样:

$collection = @(1, 2, 3, 4)
$copy = @($collection)
$collection[0] = 10
$collection -join " "
$copy -join " "

上面的代码会产生以下输出:
10 2 3 4
1 2 3 4

请注意,$copy 变量引用的是不同的集合。

你的意思是像这样 $webAppSites = $webApp.sites 吗?我复制每个集合,然后使用 foreach。 - LaPhi
@LaPhi:不,不是那样的。你说的只是一个赋值操作,而不是复制。我更新了我的答案,展示了如何复制一个数组。 - Gebb
1
整个网站的深度复制并不是最好的选择。使用常规的“for”循环是更好的方法。 - Servy
1
@Servy 我没有建议深度复制。 - Gebb

0

检查:http://soreddymanjunath.blogspot.in/2014/07/collection-was-modified-enumeration.html

这里是同样问题的另一个例子。

    if($web.IsMultilingual -eq $true  )
  {

    foreach($cul in $web.SupportedUICultures)
   {
     if($cul.LCID -ne  $webCul.LCID -and $cul.LCID -ne "1033")
     {    

       $web.RemoveSupportedUICulture($cul)


      }
    }
 $web.Update()
  }

第一次循环时,它将遍历foreach循环并删除首次支持的语言文化,当进行第二次迭代循环时,它将抛出异常“集合已修改;枚举操作可能无法执行”,

解决上述问题的方法是将要修改的值存储在一个ArrayList中,并尝试修改它,这将修复该问题,在这里我正在存储名为enumcul的ArrayList并向其中插入值并对其进行修改...

$enumcul=New-Object Collections.ArrayList
$i=0
if($web.IsMultilingual -eq $true  )
  {

    foreach($cul in $web.SupportedUICultures)
   {
     if($cul.LCID -ne  $webCul.LCID -and $cul.LCID -ne "1033")
     {

      $enumcul.Insert($i, $cul)
      $i=$i+1
      }

   }


 foreach( $k in $enumcul)
 {

    $web.RemoveSupportedUICulture($k)
    $web.Update()
 }

0
我发现对于少量物品来说,最快的方法是
$bar = @{ 
   one = "1"
   two = "2"
}
foreach($foo in $($bar.Keys){
    $bar[$foo] = Read-Host -Prompt "new value is"
}

将集合包装在 $($collection.Keys) 中。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接