2012-01-25 4 views
7

Come è possibile risolvere questo script?PowerShell - Enumerazione attraverso una raccolta e modifica della raccolta

Sì, sto cambiando la raccolta nel ciclo foreach e questo è il motivo di questo errore.

Si è verificato un errore durante l'enumerazione di una raccolta: la raccolta è stata modificata; l'operazione di enumerazione non può eseguire .. in C: \ Users \ utente \ Documenti \ PowerShell \ ChangeAllListsV2.ps1: 47 char: 20 + foreach < < < < (Lista $ a $ webLists) + CategoryInfo: InvalidOperation: (Microsoft .Share ... il + 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 

risposta

20

Il SPListCollection tende a modificare la raccolta quando si aggiornano le sue proprietà (campi, ricevitori di eventi, ecc.). È possibile utilizzare un ciclo for invece:

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

si può provare a copiare la collezione si sta iterazione su di un'altra raccolta (un array o una lista) e quindi scorrere su quella nuova collezione.

Qualcosa di simile:

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

Il codice precedente produce il seguente output:

10 2 3 4 
1 2 3 4 

nota che la variabile $copy indica un insieme differente.

+0

Vuoi dire come $ webAppSites = $ webApp.sites? Copio ogni collezione e dopo questo uso il foreach – LaPhi

+0

@LaPhi: No, non così. Quello di cui stai parlando è solo un compito, non una copia. Ho aggiornato la mia risposta per mostrare come viene copiata una matrice. – Gebb

+1

Una copia profonda di un intero sito non è la migliore delle idee. Un ciclo regolare "per" è la strada da percorrere. – Servy

0

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

Ecco anonther esempio per lo stesso problema

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() 
    } 

per la prima volta si passerà attraverso il foreach ciclo rimuoverà cultura supportata per la prima volta, quando si tratta di loop per la seconda iterazione, allora ti lancerà l'eccezione "La collezione è stata modificata; operazione di enumerazione potrebbe non essere eseguita ",

La soluzione al problema sopra è di memorizzare su valori da modificare in un arraylist e provare a modificare quale risolverà il problema, qui sto memorizzando l'arraylist chiamato enumcul e inserendo valori in esso e modificandolo ...

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