Skip to content

Commit

Permalink
Merge pull request #405 from PowerShell/development
Browse files Browse the repository at this point in the history
Merge Branches
  • Loading branch information
raghushantha committed Dec 16, 2015
2 parents 71f7791 + 51f9d93 commit 4c3466c
Show file tree
Hide file tree
Showing 79 changed files with 3,218 additions and 710 deletions.
37 changes: 37 additions & 0 deletions CHANGELOG.MD
Original file line number Diff line number Diff line change
@@ -1,3 +1,40 @@
## Released v1.2.0 (Dec.17, 2015)
###Features:
- Support for consuming PowerShell content as streams (-ScriptDefinition)
- ScriptAnalyzer accepts configuration (settings) in the form of a hashtable (-Settings), added sample Settings
- Ability to run default ruleset along with custom ones in the same invocation (-IncludeDefaultRules)
- Recurse Custom Rule Paths (-RecurseCustomRulePath)
- Consistent Engine error handling when working with Settings, Default and Custom Rules

###Rules:
- Rule to detect the presence of default value for Mandatory parameters (AvoidDefaultValueForMandatoryParameter)

###Fixes:
####Engine:
- Engine update to prevent script based injection attacks
- CustomizedRulePath is now called CustomRulePath – Fixes to handle folder paths
- Fixes for RecurseCustomRulePath functionality
- Fix to binplace cmdlet help file as part of build process
- ScriptAnalyzer Profile is now called Settings
- Fix to emit filename in the diagnosticrecord when using Script based custom rules
- Fix to prevent Engine from calling Update-Help for script based custom rules
- Added additional pester tests to take care of test holes in Custom Rule feature
- Post-build error handling improvements, fixed typos in the project

####Rules:
- Fixed bug in Positional parameter rule to trigger only when used with > 3 positional parameters
- Updated keywords that trigger PSAvoidUsingPlainTextForPassword rule
- Updated ProvideDefaultParameterValue rule to AvoidDefaultValueForMandatoryParameter rule
- Deprecate Internal Url rule based on community feedback, identified additional rules to handle hardcoded paths etc
- Added localhost exceptions for HardCodedComputerName Rule
- Update to Credential based rules to validate the presence of CredentialAttribute and PSCredential type

###Documentation:
- Rule & Cmdlet documentation updates – Cmdlet help file addition


##

## Released v1.1.1 (Nov.3, 2015)
###Features:
- Support for PSDrives when using Invoke-ScriptAnalyzer
Expand Down
File renamed without changes.
25 changes: 20 additions & 5 deletions Engine/Commands/GetScriptAnalyzerRuleCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,25 @@ public class GetScriptAnalyzerRuleCommand : PSCmdlet, IOutputWriter
[Parameter(Mandatory = false)]
[ValidateNotNullOrEmpty]
[SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]
public string[] CustomizedRulePath
[Alias("CustomizedRulePath")]
public string[] CustomRulePath
{
get { return customizedRulePath; }
set { customizedRulePath = value; }
get { return customRulePath; }
set { customRulePath = value; }
}
private string[] customizedRulePath;
private string[] customRulePath;

/// <summary>
/// RecurseCustomRulePath: Find rules within subfolders under the path
/// </summary>
[Parameter(Mandatory = false)]
[SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]
public SwitchParameter RecurseCustomRulePath
{
get { return recurseCustomRulePath; }
set { recurseCustomRulePath = value; }
}
private bool recurseCustomRulePath;

/// <summary>
/// Name: The name of a specific rule to list.
Expand Down Expand Up @@ -76,7 +89,9 @@ public string[] Severity
/// </summary>
protected override void BeginProcessing()
{
ScriptAnalyzer.Instance.Initialize(this, customizedRulePath);
string[] rulePaths = Helper.ProcessCustomRulePaths(customRulePath,
this.SessionState, recurseCustomRulePath);
ScriptAnalyzer.Instance.Initialize(this, rulePaths, null, null, null, null == rulePaths ? true : false);
}

/// <summary>
Expand Down
132 changes: 111 additions & 21 deletions Engine/Commands/InvokeScriptAnalyzerCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,19 @@ namespace Microsoft.Windows.PowerShell.ScriptAnalyzer.Commands
/// <summary>
/// InvokeScriptAnalyzerCommand: Cmdlet to statically check PowerShell scripts.
/// </summary>
[Cmdlet(VerbsLifecycle.Invoke, "ScriptAnalyzer", HelpUri = "http://go.microsoft.com/fwlink/?LinkId=525914")]
[Cmdlet(VerbsLifecycle.Invoke,
"ScriptAnalyzer",
DefaultParameterSetName="File",
HelpUri = "http://go.microsoft.com/fwlink/?LinkId=525914")]
public class InvokeScriptAnalyzerCommand : PSCmdlet, IOutputWriter
{
#region Parameters
/// <summary>
/// Path: The path to the file or folder to invoke PSScriptAnalyzer on.
/// </summary>
[Parameter(Position = 0, Mandatory = true)]
[Parameter(Position = 0,
ParameterSetName = "File",
Mandatory = true)]
[ValidateNotNull]
[Alias("PSPath")]
public string Path
Expand All @@ -48,18 +53,57 @@ public string Path
}
private string path;

/// <summary>
/// ScriptDefinition: a script definition in the form of a string to run rules on.
/// </summary>
[Parameter(Position = 0,
ParameterSetName = "ScriptDefinition",
Mandatory = true)]
[ValidateNotNull]
public string ScriptDefinition
{
get { return scriptDefinition; }
set { scriptDefinition = value; }
}
private string scriptDefinition;

/// <summary>
/// CustomRulePath: The path to the file containing custom rules to run.
/// </summary>
[Parameter(Mandatory = false)]
[ValidateNotNull]
[SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]
public string[] CustomizedRulePath
[Alias("CustomizedRulePath")]
public string[] CustomRulePath
{
get { return customRulePath; }
set { customRulePath = value; }
}
private string[] customRulePath;

/// <summary>
/// RecurseCustomRulePath: Find rules within subfolders under the path
/// </summary>
[Parameter(Mandatory = false)]
[SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]
public SwitchParameter RecurseCustomRulePath
{
get { return customizedRulePath; }
set { customizedRulePath = value; }
get { return recurseCustomRulePath; }
set { recurseCustomRulePath = value; }
}
private string[] customizedRulePath;
private bool recurseCustomRulePath;

/// <summary>
/// IncludeDefaultRules: Invoke default rules along with Custom rules
/// </summary>
[Parameter(Mandatory = false)]
[SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]
public SwitchParameter IncludeDefaultRules
{
get { return includeDefaultRules; }
set { includeDefaultRules = value; }
}
private bool includeDefaultRules;

/// <summary>
/// ExcludeRule: Array of names of rules to be disabled.
Expand Down Expand Up @@ -125,16 +169,20 @@ public SwitchParameter SuppressedOnly
private bool suppressedOnly;

/// <summary>
/// Returns path to the file that contains user profile for ScriptAnalyzer
/// Returns path to the file that contains user profile or hash table for ScriptAnalyzer
/// </summary>
[Alias("Profile")]
[Parameter(Mandatory = false)]
[ValidateNotNull]
public string Profile
public object Settings
{
get { return profile; }
set { profile = value; }
get { return settings; }
set { settings = value; }
}
private string profile;

private object settings;

private bool stopProcessing;

#endregion Parameters

Expand All @@ -145,37 +193,79 @@ public string Profile
/// </summary>
protected override void BeginProcessing()
{
string[] rulePaths = Helper.ProcessCustomRulePaths(customRulePath,
this.SessionState, recurseCustomRulePath);

if (!ScriptAnalyzer.Instance.ParseProfile(this.settings, this.SessionState.Path, this))
{
stopProcessing = true;
return;
}

ScriptAnalyzer.Instance.Initialize(
this,
customizedRulePath,
rulePaths,
this.includeRule,
this.excludeRule,
this.severity,
this.suppressedOnly,
this.profile);
null == rulePaths ? true : this.includeDefaultRules,
this.suppressedOnly);
}

/// <summary>
/// Analyzes the given script/directory.
/// </summary>
protected override void ProcessRecord()
{
// throws Item Not Found Exception
Collection<PathInfo> paths = this.SessionState.Path.GetResolvedPSPathFromPSPath(path);
foreach (PathInfo p in paths)
if (stopProcessing)
{
stopProcessing = false;
return;
}

if (String.Equals(this.ParameterSetName, "File", StringComparison.OrdinalIgnoreCase))
{
// throws Item Not Found Exception
Collection<PathInfo> paths = this.SessionState.Path.GetResolvedPSPathFromPSPath(path);
foreach (PathInfo p in paths)
{
ProcessPathOrScriptDefinition(this.SessionState.Path.GetUnresolvedProviderPathFromPSPath(p.Path));
}
}
else if (String.Equals(this.ParameterSetName, "ScriptDefinition", StringComparison.OrdinalIgnoreCase))
{
ProcessPath(this.SessionState.Path.GetUnresolvedProviderPathFromPSPath(p.Path));
ProcessPathOrScriptDefinition(scriptDefinition);
}
}

protected override void EndProcessing()
{
ScriptAnalyzer.Instance.CleanUp();
base.EndProcessing();
}

protected override void StopProcessing()
{
ScriptAnalyzer.Instance.CleanUp();
base.StopProcessing();
}

#endregion

#region Methods

private void ProcessPath(string path)
private void ProcessPathOrScriptDefinition(string pathOrScriptDefinition)
{
IEnumerable<DiagnosticRecord> diagnosticsList =
ScriptAnalyzer.Instance.AnalyzePath(path, this.recurse);
IEnumerable<DiagnosticRecord> diagnosticsList = Enumerable.Empty<DiagnosticRecord>();

if (String.Equals(this.ParameterSetName, "File", StringComparison.OrdinalIgnoreCase))
{
diagnosticsList = ScriptAnalyzer.Instance.AnalyzePath(pathOrScriptDefinition, this.recurse);
}
else if (String.Equals(this.ParameterSetName, "ScriptDefinition", StringComparison.OrdinalIgnoreCase))
{
diagnosticsList = ScriptAnalyzer.Instance.AnalyzeScriptDefinition(pathOrScriptDefinition);
}

//Output through loggers
foreach (ILogger logger in ScriptAnalyzer.Instance.Loggers)
Expand Down
10 changes: 10 additions & 0 deletions Engine/Configurations/CmdletDesign.psd1
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
@{
IncludeRules=@('PSUseApprovedVerbs',
'PSReservedCmdletChar',
'PSReservedParams',
'PSShouldProcess',
'PSUseShouldProcessForStateChangingFunctions',
'PSUseSingularNouns',
'PSMissingModuleManifestField',
'PSAvoidDefaultValueSwitchParameter')
}
3 changes: 3 additions & 0 deletions Engine/Configurations/DSC.psd1
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
@{
IncludeRules=@('PSDSC*')
}
11 changes: 11 additions & 0 deletions Engine/Configurations/ScriptFunctions.psd1
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
@{
IncludeRules=@('PSAvoidUsingCmdletAliases',
'PSAvoidUsingWMICmdlet',
'PSAvoidUsingEmptyCatchBlock',
'PSUseCmdletCorrectly',
'PSUseShouldProcessForStateChangingFunctions',
'PSAvoidUsingPositionalParameters',
'PSAvoidGlobalVars',
'PSUseDeclaredVarsMoreThanAssignments',
'PSAvoidUsingInvokeExpression')
}
8 changes: 8 additions & 0 deletions Engine/Configurations/ScriptSecurity.psd1
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
@{
IncludeRules=@('PSAvoidUsingPlainTextForPassword',
'PSAvoidUsingComputerNameHardcoded',
'PSAvoidUsingConvertToSecureStringWithPlainText',
'PSUsePSCredentialType',
'PSAvoidUsingUserNameAndPasswordParams',
'PSAvoidUsingFilePath')
}
4 changes: 4 additions & 0 deletions Engine/Configurations/ScriptingStyle.psd1
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
@{
IncludeRules=@('PSProvideCommentHelp',
'PSAvoidUsingWriteHost')
}
4 changes: 2 additions & 2 deletions Engine/Generic/AvoidCmdletGeneric.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ namespace Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic
public abstract class AvoidCmdletGeneric : IScriptRule
{
/// <summary>
/// AnalyzeScript: Analyzes the given Ast and returns DiagnosticRecords based on the anaylsis.
/// AnalyzeScript: Analyzes the given Ast and returns DiagnosticRecords based on the analysis.
/// </summary>
/// <param name="ast">The script's ast</param>
/// <param name="fileName">The name of the script file being analyzed</param>
Expand All @@ -38,7 +38,7 @@ public IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string fileName)

List<String> cmdletNameAndAliases = Microsoft.Windows.PowerShell.ScriptAnalyzer.Helper.Instance.CmdletNameAndAliases(GetCmdletName());

// Iterrates all CommandAsts and check the command name.
// Iterates all CommandAsts and check the command name.
foreach (CommandAst cmdAst in commandAsts)
{
if (cmdAst.GetCommandName() == null) continue;
Expand Down
4 changes: 2 additions & 2 deletions Engine/Generic/AvoidParameterGeneric.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ namespace Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic
public abstract class AvoidParameterGeneric : IScriptRule
{
/// <summary>
/// AnalyzeScript: Analyzes the given Ast and returns DiagnosticRecords based on the anaylsis.
/// AnalyzeScript: Analyzes the given Ast and returns DiagnosticRecords based on the analysis.
/// </summary>
/// <param name="ast">The script's ast</param>
/// <param name="fileName">The name of the script file being analyzed</param>
Expand All @@ -35,7 +35,7 @@ public IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string fileName)
// Finds all CommandAsts.
IEnumerable<Ast> commandAsts = ast.FindAll(testAst => testAst is CommandAst, true);

// Iterrates all CommandAsts and check the condition.
// Iterates all CommandAsts and check the condition.
foreach (CommandAst cmdAst in commandAsts)
{
if (CommandCondition(cmdAst) && cmdAst.CommandElements != null)
Expand Down
11 changes: 10 additions & 1 deletion Engine/Generic/DiagnosticRecord.cs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,16 @@ public string ScriptName
{
get { return scriptName; }
//Trim down to the leaf element of the filePath and pass it to Diagnostic Record
set { scriptName = System.IO.Path.GetFileName(value); }
set {
if (!string.IsNullOrWhiteSpace(value))
{
scriptName = System.IO.Path.GetFileName(value);
}
else
{
scriptName = string.Empty;
}
}
}

/// <summary>
Expand Down
2 changes: 1 addition & 1 deletion Engine/Generic/ILogger.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public interface ILogger
string GetName();

/// <summary>
/// GetDescription: Retrives the description of the logger.
/// GetDescription: Retrieves the description of the logger.
/// </summary>
/// <returns>The description of the logger</returns>
string GetDescription();
Expand Down
2 changes: 1 addition & 1 deletion Engine/Generic/IScriptRule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ namespace Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic
public interface IScriptRule : IRule
{
/// <summary>
/// AnalyzeScript: Analyzes the given Ast and returns DiagnosticRecords based on the anaylsis.
/// AnalyzeScript: Analyzes the given Ast and returns DiagnosticRecords based on the analysis.
/// </summary>
/// <param name="ast">The script's ast</param>
/// <param name="fileName">The name of the script file being analyzed</param>
Expand Down
Loading

0 comments on commit 4c3466c

Please sign in to comment.