PSScriptAnalyzer: PSUseToExportFieldsInManifest throw System.InvalidOperationException: Collection was modified; enumeration operation may not execute.

Steps to reproduce

1..30|% {$res=Invoke-ScriptAnalyzer -path 'C:\Program Files\WindowsPowerShell\Modules\PSScriptAnalyzer\1.16.1\PSScriptAnalyzer.psd1' -ExcludeRule PSMissingModuleManifestField }

Expected behavior

No error.

Actual behavior

Invoke-ScriptAnalyzer : La collection a été modifiée ; l'opération d'énumération peut ne pas s'exécuter.
At line:1 char:15
+ ... .30|% {$res=Invoke-ScriptAnalyzer -path 'C:\Program Files\WindowsPowe ...
+                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (C:\Program File...ptAnalyzer.psd1:String) [Invoke-ScriptAnalyzer], Cm
   dletInvocationException
    + FullyQualifiedErrorId : RULE_ERROR,Microsoft.Windows.PowerShell.ScriptAnalyzer.Commands.InvokeScriptAnalyzerComm
   and

Environment data

$psversiontable
Name                           Value
----                           -----
PSVersion                      5.1.14409.1012
PSEdition                      Desktop
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0, 5.0, 5.1.14409.1012}
BuildVersion                   10.0.14409.1012
CLRVersion                     4.0.30319.42000
WSManStackVersion              3.0
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1


 (Get-Module -ListAvailable PSScriptAnalyzer).Version | ForEach-Object { $_.ToString() }
1.16.1
1.16.0
1.15.0
1.12.0
1.11.1

See also the issue #900

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Comments: 19 (1 by maintainers)

Most upvoted comments

I was able to reproduce, but the error does not always occur.

Update: I can finally reproduce now with a Standard D2s v3 (2 vcpus, 8 GB memory) Azure VM (WinServer 2016). I get the error also for another ps.Invoke() call in AvoidUsingDeprecatedManifestFields in addition to the one that we found before in the Helper class. I get the issue also with PowerShell Core 6.0.2. Implementing the using pattern instead of the manual call to dispose does not fix it, therefore this rather looks like a problem of thread safety of the Invoke() method.

I no longer encounter this error.

The bug here involves ALIASES as far as I can tell.

At this point, I can reproduce this easily on my laptop with an empty psm1 and a three line .psd1:

@{
    ModuleVersion          = "1.0.0"
    RootModule             = "broken.psm1"
    AliasesToExport        = @("anything")
}

NOTE:

  • You must have a RootModule and the file must exist (i.e. broken.psm1)
  • The AliasesToExport cannot be an empty array

You can actually set AliasesToExport to "*" and then you’ll get failures of the rule mixed in with the exceptions – The rule still works

This reproduces too:

New-Item Aliaser -Type Directory
New-ModuleManifest Aliaser\Aliaser.psd1 -AliasesToExport anything -RootModule aliaser.psm1 -FunctionsToExport @() -CmdletsToExport @() -VariablesToExport @() 
Set-Content Aliaser\Aliaser.psm1 "" -Encoding UTF8
1..100 | %{ Invoke-ScriptAnalyzer .\Aliaser\Aliaser.psd1 }

It’s clearly a problem specific to aliases and this rule.

With Windows Seven sp1 Fr ( Microsoft Windows [version 6.1.7601] )

$Error[0]|select *

writeErrorStream              : True
Exception                     : System.Management.Automation.CmdletInvocationException: La collection a été modifiée;
                                l'opération d'énumération peut ne pas s'exécuter. --->
                                System.InvalidOperationException: La collection a été modifiée; l'opération
                                d'énumération peut ne pas s'exécuter.
                                   à System.ThrowHelper.ThrowInvalidOperationException(ExceptionResource resource)
                                   à System.Collections.Generic.List`1.Enumerator.MoveNextRare()
                                   à
                                Microsoft.PowerShell.Commands.ModuleCmdletBase.UpdateCommandCollection(Collection`1
                                list, List`1 patterns)
                                   à Microsoft.PowerShell.Commands.ModuleCmdletBase.LoadModuleManifest(String
                                moduleManifestPath, ExternalScriptInfo scriptInfo, Hashtable data, Hashtable
                                localizedData, ManifestProcessingFlags manifestProcessingFlags, Version
                                minimumVersion, Version maximumVersion, Version requiredVersion, Nullable`1
                                requiredModuleGuid, ImportModuleOptions& options, Boolean& containedErrors)
                                   à Microsoft.PowerShell.Commands.TestModuleManifestCommand.ProcessRecord()
                                   à System.Management.Automation.CommandProcessor.ProcessRecord()
                                   --- Fin de la trace de la pile d'exception interne ---
                                   à System.Management.Automation.Runspaces.PipelineBase.Invoke(IEnumerable input)
                                   à
                                System.Management.Automation.PowerShell.Worker.ConstructPipelineAndDoWork(Runspace rs,
                                Boolean performSyncInvoke)
                                   à System.Management.Automation.PowerShell.Worker.CreateRunspaceIfNeededAndDoWork(Run
                                space rsToUse, Boolean isSync)
                                   à System.Management.Automation.PowerShell.CoreInvokeHelper[TInput,TOutput](PSDataCol
                                lection`1 input, PSDataCollection`1 output, PSInvocationSettings settings)
                                   à
                                System.Management.Automation.PowerShell.CoreInvoke[TInput,TOutput](PSDataCollection`1
                                input, PSDataCollection`1 output, PSInvocationSettings settings)
                                   à System.Management.Automation.PowerShell.Invoke(IEnumerable input,
                                PSInvocationSettings settings)
                                   à Microsoft.Windows.PowerShell.ScriptAnalyzer.Helper.GetModuleManifest(String
                                filePath, IEnumerable`1& errorRecord)
                                   à Microsoft.Windows.PowerShell.ScriptAnalyzer.BuiltinRules.UseToExportFieldsInManife
                                st.<AnalyzeScript>d__3.MoveNext()
                                   à System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
                                   à System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
                                   à Microsoft.Windows.PowerShell.ScriptAnalyzer.ScriptAnalyzer.<>c__DisplayClass78_0.<
                                AnalyzeSyntaxTree>b__1()
TargetObject                  : C:\Program
                                Files\WindowsPowerShell\Modules\PSScriptAnalyzer\1.16.1\PSScriptAnalyzer.psd1
FullyQualifiedErrorId         : RULE_ERROR,Microsoft.Windows.PowerShell.ScriptAnalyzer.Commands.InvokeScriptAnalyzerCom
                                mand
InvocationInfo                : System.Management.Automation.InvocationInfo
ErrorCategory_Category        : 7
ErrorCategory_Activity        : Invoke-ScriptAnalyzer
ErrorCategory_Reason          : CmdletInvocationException
ErrorCategory_TargetName      : C:\Program
                                Files\WindowsPowerShell\Modules\PSScriptAnalyzer\1.16.1\PSScriptAnalyzer.psd1
ErrorCategory_TargetType      : String
ErrorCategory_Message         : InvalidOperation: (C:\Program File...ptAnalyzer.psd1:String) [Invoke-ScriptAnalyzer],
                                CmdletInvocationException
SerializeExtendedInfo         : False
ErrorDetails_ScriptStackTrace : at <ScriptBlock>, <No file>: line 1
                                at <ScriptBlock>, <No file>: line 1
PSMessageDetails              :
CategoryInfo                  : InvalidOperation: (C:\Program File...ptAnalyzer.psd1:String) [Invoke-ScriptAnalyzer],
                                CmdletInvocationException
ErrorDetails                  :
ScriptStackTrace              : at <ScriptBlock>, <No file>: line 1
                                at <ScriptBlock>, <No file>: line 1
PipelineIterationInfo         : {0, 1}


Export-Clixml -InputObject $Error -Depth 5 -Path c:\temp\Issue902.txt

Issue902.txt