@@ -38,6 +38,7 @@ public class Helper
38
38
private readonly static Version minSupportedPSVersion = new Version ( 3 , 0 ) ;
39
39
private Dictionary < string , Dictionary < string , object > > ruleArguments ;
40
40
private PSVersionTable psVersionTable ;
41
+ private Dictionary < string , CommandInfo > commandInfoCache ;
41
42
42
43
#endregion
43
44
@@ -146,6 +147,7 @@ public void Initialize()
146
147
KeywordBlockDictionary = new Dictionary < String , List < Tuple < int , int > > > ( StringComparer . OrdinalIgnoreCase ) ;
147
148
VariableAnalysisDictionary = new Dictionary < Ast , VariableAnalysis > ( ) ;
148
149
ruleArguments = new Dictionary < string , Dictionary < string , object > > ( StringComparer . OrdinalIgnoreCase ) ;
150
+ commandInfoCache = new Dictionary < string , CommandInfo > ( StringComparer . OrdinalIgnoreCase ) ;
149
151
150
152
IEnumerable < CommandInfo > aliases = this . invokeCommand . GetCommands ( "*" , CommandTypes . Alias , true ) ;
151
153
@@ -594,12 +596,13 @@ public string VariableNameWithoutScope(VariablePath variablePath)
594
596
/// <returns></returns>
595
597
public bool HasSplattedVariable ( CommandAst cmdAst )
596
598
{
597
- if ( cmdAst == null || cmdAst . CommandElements == null )
598
- {
599
- return false ;
600
- }
601
-
602
- return cmdAst . CommandElements . Any ( cmdElem => cmdElem is VariableExpressionAst && ( cmdElem as VariableExpressionAst ) . Splatted ) ;
599
+ return cmdAst != null
600
+ && cmdAst . CommandElements != null
601
+ && cmdAst . CommandElements . Any ( cmdElem =>
602
+ {
603
+ var varExprAst = cmdElem as VariableExpressionAst ;
604
+ return varExprAst != null && varExprAst . Splatted ;
605
+ } ) ;
603
606
}
604
607
605
608
/// <summary>
@@ -610,12 +613,16 @@ public bool HasSplattedVariable(CommandAst cmdAst)
610
613
/// <returns></returns>
611
614
public bool PositionalParameterUsed ( CommandAst cmdAst , bool moreThanThreePositional = false )
612
615
{
613
- if ( cmdAst == null || cmdAst . GetCommandName ( ) == null )
616
+ if ( cmdAst == null )
614
617
{
615
618
return false ;
616
619
}
617
620
618
- CommandInfo commandInfo = GetCommandInfo ( GetCmdletNameFromAlias ( cmdAst . GetCommandName ( ) ) ) ?? GetCommandInfo ( cmdAst . GetCommandName ( ) ) ;
621
+ var commandInfo = GetCommandInfo ( cmdAst . GetCommandName ( ) ) ;
622
+ if ( commandInfo == null || ( commandInfo . CommandType != System . Management . Automation . CommandTypes . Cmdlet ) )
623
+ {
624
+ return false ;
625
+ }
619
626
620
627
IEnumerable < ParameterMetadata > switchParams = null ;
621
628
@@ -642,29 +649,31 @@ public bool PositionalParameterUsed(CommandAst cmdAst, bool moreThanThreePositio
642
649
643
650
foreach ( CommandElementAst ceAst in cmdAst . CommandElements )
644
651
{
645
- if ( ceAst is CommandParameterAst )
652
+ var cmdParamAst = ceAst as CommandParameterAst ;
653
+ if ( cmdParamAst != null )
654
+ {
655
+ // Skip if it's a switch parameter
656
+ if ( switchParams != null &&
657
+ switchParams . Any (
658
+ pm => String . Equals (
659
+ pm . Name ,
660
+ cmdParamAst . ParameterName , StringComparison . OrdinalIgnoreCase ) ) )
646
661
{
647
- // Skip if it's a switch parameter
648
- if ( switchParams != null &&
649
- switchParams . Any ( pm => String . Equals ( pm . Name , ( ceAst as CommandParameterAst ) . ParameterName , StringComparison . OrdinalIgnoreCase ) ) )
650
- {
651
- continue ;
652
- }
653
-
662
+ continue ;
663
+ }
654
664
655
- parameters += 1 ;
665
+ parameters += 1 ;
656
666
657
- if ( ( ceAst as CommandParameterAst ) . Argument != null )
658
- {
659
- arguments += 1 ;
660
- }
661
-
662
- }
663
- else
667
+ if ( cmdParamAst . Argument != null )
664
668
{
665
669
arguments += 1 ;
666
670
}
667
671
672
+ }
673
+ else
674
+ {
675
+ arguments += 1 ;
676
+ }
668
677
}
669
678
670
679
// if not the first element in a pipeline, increase the number of arguments by 1
@@ -685,6 +694,23 @@ public bool PositionalParameterUsed(CommandAst cmdAst, bool moreThanThreePositio
685
694
}
686
695
687
696
697
+ /// <summary>
698
+ /// Get a CommandInfo object of the given command name
699
+ /// </summary>
700
+ /// <returns>Returns null if command does not exists</returns>
701
+ private CommandInfo GetCommandInfoInternal ( string cmdName , CommandTypes ? commandType = null )
702
+ {
703
+ using ( var ps = System . Management . Automation . PowerShell . Create ( ) )
704
+ {
705
+ var cmdInfo = ps . AddCommand ( "Get-Command" )
706
+ . AddArgument ( cmdName )
707
+ . AddParameter ( "ErrorAction" , "SilentlyContinue" )
708
+ . Invoke < CommandInfo > ( )
709
+ . FirstOrDefault ( ) ;
710
+ return cmdInfo ;
711
+ }
712
+ }
713
+
688
714
/// <summary>
689
715
/// Given a command's name, checks whether it exists
690
716
/// </summary>
@@ -693,19 +719,28 @@ public bool PositionalParameterUsed(CommandAst cmdAst, bool moreThanThreePositio
693
719
/// <returns></returns>
694
720
public CommandInfo GetCommandInfo ( string name , CommandTypes ? commandType = null )
695
721
{
696
- CommandTypes defaultCmdType = CommandTypes . Alias
697
- | CommandTypes . Cmdlet
698
- | CommandTypes . ExternalScript
699
- | CommandTypes . Filter
700
- | CommandTypes . Function
701
- | CommandTypes . Script
702
- | CommandTypes . Workflow ;
703
- #if ! PSV3
704
- defaultCmdType |= CommandTypes . Configuration ;
705
- #endif
722
+ if ( string . IsNullOrWhiteSpace ( name ) )
723
+ {
724
+ return null ;
725
+ }
726
+
727
+ // check if it is an alias
728
+ string cmdletName = Helper . Instance . GetCmdletNameFromAlias ( name ) ;
729
+ if ( string . IsNullOrWhiteSpace ( cmdletName ) )
730
+ {
731
+ cmdletName = name ;
732
+ }
733
+
706
734
lock ( getCommandLock )
707
735
{
708
- return this . invokeCommand . GetCommand ( name , commandType ?? defaultCmdType ) ;
736
+ if ( commandInfoCache . ContainsKey ( cmdletName ) )
737
+ {
738
+ return commandInfoCache [ cmdletName ] ;
739
+ }
740
+
741
+ var commandInfo = GetCommandInfoInternal ( cmdletName , commandType ) ;
742
+ commandInfoCache . Add ( cmdletName , commandInfo ) ;
743
+ return commandInfo ;
709
744
}
710
745
}
711
746
0 commit comments