Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 74 additions & 0 deletions Engine/SafeDirectoryCatalog.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
//
// Copyright (c) Microsoft Corporation.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//

using System;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.IO;
using System.Linq;
using System.Reflection;

namespace Microsoft.Windows.PowerShell.ScriptAnalyzer
{
/// <summary>
/// Provides a simple DirectoryCatalog implementation that doesn't
/// fail assembly loading when it encounters a ReflectionTypeLoadException.
/// The default DirectoryCatalog implementation stops evaluating any
/// remaining assemblies in the directory if one of these exceptions
/// are encountered.
/// </summary>
internal class SafeDirectoryCatalog : AggregateCatalog
{
public SafeDirectoryCatalog(string folderLocation, IOutputWriter outputWriter)
{
if (outputWriter == null)
{
throw new ArgumentNullException("outputWriter");
}

// Make sure the directory actually exists
var directoryInfo = new DirectoryInfo(folderLocation);
if (directoryInfo.Exists == false)
{
throw new CompositionException(
"The specified folder does not exist: " + directoryInfo.FullName);
}

// Load each DLL found in the directory
foreach (var dllFile in directoryInfo.GetFileSystemInfos("*.dll"))
{
try
{
// Attempt to create an AssemblyCatalog for this DLL
var assemblyCatalog =
new AssemblyCatalog(
Assembly.LoadFile(
dllFile.FullName));

// We must call ToArray here to pre-initialize the Parts
// IEnumerable and cause it to be stored. The result is
// not used here because it will be accessed later once
// the composition container starts assembling parts.
assemblyCatalog.Parts.ToArray();

this.Catalogs.Add(assemblyCatalog);
}
catch (ReflectionTypeLoadException e)
{
// Write out the exception details and allow the
// loading process to continue
outputWriter.WriteWarning(e.ToString());
}
}
}
}
}
26 changes: 17 additions & 9 deletions Engine/ScriptAnalyzer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -357,13 +357,16 @@ private void Initialize(

#region Verify rules

// Safely get one non-duplicated list of rules
IEnumerable<IRule> rules =
this.ScriptRules.Union<IRule>(
this.TokenRules).Union<IRule>(
Enumerable.Union<IRule>(
Enumerable.Union<IRule>(
this.ScriptRules ?? Enumerable.Empty<IRule>(),
this.TokenRules ?? Enumerable.Empty<IRule>()),
this.ExternalRules ?? Enumerable.Empty<IExternalRule>());

// Ensure that rules were actually loaded
if (rules == null || rules.Count() == 0)
if (rules == null || rules.Any() == false)
{
this.outputWriter.ThrowTerminatingError(
new ErrorRecord(
Expand Down Expand Up @@ -411,22 +414,24 @@ private void LoadRules(Dictionary<string, List<string>> result, CommandInvocatio
{
List<string> paths = new List<string>();

// Clear external rules for each invoke.
ExternalRules = new List<ExternalRule>();

// Initialize helper
Helper.Instance = new Helper(invokeCommand, this.outputWriter);
Helper.Instance.Initialize();

// Clear external rules for each invoke.
ExternalRules = new List<ExternalRule>();
this.ScriptRules = null;
this.TokenRules = null;
this.ExternalRules = null;

// An aggregate catalog that combines multiple catalogs.
using (AggregateCatalog catalog = new AggregateCatalog())
{
// Adds all the parts found in the same directory.
string dirName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
catalog.Catalogs.Add(new DirectoryCatalog(dirName));
catalog.Catalogs.Add(
new SafeDirectoryCatalog(
dirName,
this.outputWriter));

// Adds user specified directory
paths = result.ContainsKey("ValidDllPaths") ? result["ValidDllPaths"] : result["ValidPaths"];
Expand All @@ -438,7 +443,10 @@ private void LoadRules(Dictionary<string, List<string>> result, CommandInvocatio
}
else
{
catalog.Catalogs.Add(new DirectoryCatalog(path));
catalog.Catalogs.Add(
new SafeDirectoryCatalog(
path,
this.outputWriter));
}
}

Expand Down
1 change: 1 addition & 0 deletions Engine/ScriptAnalyzerEngine.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@
<Compile Include="Helper.cs" />
<Compile Include="IOutputWriter.cs" />
<Compile Include="Loggers\WriteObjectsLogger.cs" />
<Compile Include="SafeDirectoryCatalog.cs" />
<Compile Include="ScriptAnalyzer.cs" />
<Compile Include="SpecialVars.cs" />
<Compile Include="Strings.Designer.cs">
Expand Down