Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Question about PSUseCompatibleSyntax #1384

Closed
LaurentDardenne opened this issue Dec 12, 2019 · 4 comments · Fixed by #1395
Closed

Question about PSUseCompatibleSyntax #1384

LaurentDardenne opened this issue Dec 12, 2019 · 4 comments · Fixed by #1395

Comments

@LaurentDardenne
Copy link

I use this script with Powershell v3 ( Citrix farm with W 2008)

$h=@{}
$h.Test='Ok'
$controlName='Test'

writeLog "$($psversiontable|out-string)"
writeLog "Test compatibility"

if ($h.$controlName -eq 'ok')
{ writeLog "Test= $($h.$controlName )"}
else
{ writeLog "dont works"}

$a = 10,20,30
$property = "Length"
writeLog "Array =$($a.$property)"

$typeExpression=[int]
$staticMember='MaxValue'
writeLog "Static=$($typeExpression::$staticMember)"

$method = 'Trim'
$sb= { writeLog "Method =$($Method.$method())" } #Avoid ParseError
&$sb

I run PSSA version 1.8.3 with this settings :

@{
    ExcludeRules = @('PSAvoidGlobalVars','PSAvoidUsingWMICmdlet')

     # Check if the scripts uses cmdlets that are compatible PS 3.0,
    Rules = @{
        PSUseCompatibleSyntax = @{
            # This turns the rule on (setting it to false will turn it off)
            Enable = $true
    
            # List the targeted versions of PowerShell here
            TargetVersions = @(
                '3.0'
            )
        }

        PSUseCompatibleCommands = @{
            # Turns the rule on
            Enable = $true
    
            # Lists the PowerShell platforms we want to check compatibility with
            TargetProfiles = @(
                #PowerShell Version 3.0 Operating System Windows Server 2012
                'win-8_x64_6.2.9200.0_3.0_x64_4.0.30319.42000_framework'
            )
        }
    }
}

When I run PSSA under PS 5.v0 I get this result :

Invoke-ScriptAnalyzer -path  .\pssa.ps1 -Settings .\ScriptAnalyzerSettings.psd1

# RuleName                            Severity     ScriptName Line  Message
# --------                            --------     ---------- ----  -------
# PSUseCompatibleSyntax               Warning      pssa.ps1   6     The dynamic member invocation syntax
#                                                                   '$h.$controlName' is not available by default in
#                                                                   PowerShell versions 3
# PSUseCompatibleSyntax               Warning      pssa.ps1   7     The dynamic member invocation syntax
#                                                                   '$h.$controlName' is not available by default in
#                                                                   PowerShell versions 3
# PSUseCompatibleSyntax               Warning      pssa.ps1   13    The dynamic member invocation syntax '$a.$property'
#                                                                   is not available by default in PowerShell versions 3
# PSUseCompatibleSyntax               Warning      pssa.ps1   16    The dynamic member invocation syntax
#                                                                   '$typeExpression::$staticMember' is not available by
#                                                                   default in PowerShell versions 3
# PSUseCompatibleSyntax               Warning      pssa.ps1   19    The dynamic member invocation syntax '$x.$member' is
#                                                                   not available by default in PowerShell versions 3
# PSUseCompatibleSyntax               Warning      pssa.ps1   22    The dynamic method invocation syntax
#                                                                   '$Method.$method()' is not available by default in
#                                                                   PowerShell versions 3
# PSUseCompatibleSyntax               Warning      pssa.ps1   26    The dynamic member invocation syntax
#                                                                   '[EnvironmentVariableTarget]::$enumVal' is not
#                                                                   available by default in PowerShell versions 3

But when I read my logs, the rule message 'The dynamic member invocation syntax' seems incorrect and do not match the specifications in the 'Windows PowerShell Language Specification Version 3.0' file, chapter 7.1.2 Member access :

Name                           Value                                                                                               
----                           -----                                                                                               
PSVersion                      3.0                                                                                                 
WSManStackVersion              3.0                                                                                                 
SerializationVersion           1.1.0.1                                                                                             
CLRVersion                     4.0.30319.42000                                                                                     
BuildVersion                   6.2.9200.22198                                                                                      
PSCompatibleVersions           {1.0, 2.0, 3.0}                                                                                     
PSRemotingProtocolVersion      2.2                                                                                                 


Test compatibility
Test= Ok
 Array =3
Static=2147483647
Error:

The following Error (see $Method.$method() ), is saved by Export-CliXml:

$e=import-clixml "\\Server\Path\file.ps1xml"
$e
# invoke member w/ expression name
# Au caractère \\\\Server\Path\file.ps1:99 : 1
# + &$sb
# + ~~~~
#     + CategoryInfo          : OperationStopped: (:) [], NotImplementedException
#     + FullyQualifiedErrorId : System.NotImplementedException

$e.Exception|select *

# Message        : invoke member w/ expression name
# Data           : {System.Management.Automation.Interpreter.InterpretedFrameInfo}
# InnerException :
# TargetSite     : System.Object
#                  VisitInvokeMemberExpression(System.Management.Automation.Language.InvokeMemberExpressionAst)
# StackTrace     :    à
#                  System.Management.Automation.Language.Compiler.VisitInvokeMemberExpression(InvokeMemberExpressionAst
#                  invokeMemberExpressionAst)
#                     à System.Management.Automation.Language.Compiler.VisitCommandExpression(CommandExpressionAst
#                  commandExpressionAst)
#                     à System.Management.Automation.Language.Compiler.VisitPipeline(PipelineAst pipelineAst)
#                     à System.Management.Automation.Language.Compiler.CompileTrappableExpression(List`1 exprList,
#                  StatementAst stmt)
#                     à
#                  System.Management.Automation.Language.Compiler.CompileStatementListWithTraps(ReadOnlyCollection`1
#                  statements, ReadOnlyCollection`1 traps, List`1 exprs, List`1 temps)
#                     à System.Management.Automation.Language.Compiler.VisitStatementBlock(StatementBlockAst
#                  statementBlockAst)
#                     à System.Management.Automation.Language.Compiler.CaptureAstResults(Ast ast, CaptureAstContext
#                  context, MergeRedirectExprs generateRedirectExprs)
#                     à System.Management.Automation.Language.Compiler.<>c__DisplayClass5e.<VisitExpandableStringExpressi
#                  on>b__5d(ExpressionAst e)
#                     à System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
#                     à System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
#                     à System.Dynamic.Utils.CollectionExtensions.ToReadOnly[T](IEnumerable`1 enumerable)
#                     à System.Linq.Expressions.Expression.NewArrayInit(Type type, IEnumerable`1 initializers)
#                     à System.Management.Automation.Language.Compiler.VisitExpandableStringExpression(ExpandableStringEx
#                  pressionAst expandableStringExpressionAst)
#                     à System.Management.Automation.Language.Compiler.GetCommandArgumentExpression(CommandElementAst
#                  element)
#                     à System.Management.Automation.Language.Compiler.VisitCommand(CommandAst commandAst)
#                     à System.Management.Automation.Language.Compiler.VisitPipeline(PipelineAst pipelineAst)
#                     à System.Management.Automation.Language.Compiler.CompileTrappableExpression(List`1 exprList,
#                  StatementAst stmt)
#                     à
#                  System.Management.Automation.Language.Compiler.CompileStatementListWithTraps(ReadOnlyCollection`1
#                  statements, ReadOnlyCollection`1 traps, List`1 exprs, List`1 temps)
#                     à System.Management.Automation.Language.Compiler.CompileSingleLambda(ReadOnlyCollection`1
#                  statements, ReadOnlyCollection`1 traps, String funcName, IScriptExtent entryExtent, IScriptExtent
#                  exitExtent)
#                     à System.Management.Automation.Language.Compiler.CompileNamedBlock(NamedBlockAst namedBlockAst,
#                  String funcName)
#                     à System.Management.Automation.Language.Compiler.VisitScriptBlock(ScriptBlockAst scriptBlockAst)
#                     à System.Management.Automation.Language.Compiler.Compile(CompiledScriptBlockData scriptBlock,
#                  Boolean optimize)
#                     à System.Management.Automation.CompiledScriptBlockData.CompileUnoptimized()
#                     à System.Management.Automation.CompiledScriptBlockData.Compile(Boolean optimized)
#                     à System.Management.Automation.DlrScriptCommandProcessor.Init()
#                     à System.Management.Automation.CommandDiscovery.CreateCommandProcessorForScript(ScriptBlock
#                  scriptblock, ExecutionContext context, Boolean useNewScope, SessionStateInternal sessionState)
#                     à System.Management.Automation.PipelineOps.AddCommand(PipelineProcessor pipe,
#                  CommandParameterInternal[] commandElements, CommandBaseAst commandBaseAst, CommandRedirection[]
#                  redirections, ExecutionContext context)
#                     à System.Management.Automation.PipelineOps.InvokePipeline(Object input, Boolean ignoreInput,
#                  CommandParameterInternal[][] pipeElements, CommandBaseAst[] pipeElementAsts, CommandRedirection[][]
#                  commandRedirections, FunctionContext funcContext)
#                     à System.Management.Automation.Interpreter.ActionCallInstruction`6.Run(InterpretedFrame frame)
#                     à System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedFrame
#                  frame)
# HelpLink       :
# Source         : System.Management.Automation
# HResult        : -2147467263

Moreover the rule should be of severity 'Error' when I try to know if my code is compatible with Powershell v3, unless I did not understand the use and the behavior of this rule.

Why indicate that some syntax is problematic when it is not?

@rjmholt
Copy link
Contributor

rjmholt commented Dec 12, 2019

Why indicate that some syntax is problematic when it is not?

It could be wrong. I was under the impression that that feature was added later, but if testing shows it works in PS 3, we should correct that.

It should be fairly simple to take out if you'd like to open a PR:

public override AstVisitAction VisitInvokeMemberExpression(InvokeMemberExpressionAst methodCallAst)
{
// Look for [typename]::new(...) and [typename]::$dynamicMethodName syntax
if (!_targetVersions.Contains(s_v3) && !_targetVersions.Contains(s_v4))
{
return AstVisitAction.Continue;
}
if (_targetVersions.Contains(s_v3) && methodCallAst.Member is VariableExpressionAst)
{
string message = string.Format(
CultureInfo.CurrentCulture,
Strings.UseCompatibleSyntaxError,
"dynamic method invocation",
methodCallAst.Extent.Text,
"3");
_diagnosticAccumulator.Add(new DiagnosticRecord(
message,
methodCallAst.Extent,
_rule.GetName(),
_rule.Severity,
_analyzedFilePath
));
}
if (!(methodCallAst.Expression is TypeExpressionAst typeExpressionAst))
{
return AstVisitAction.Continue;
}
if (!(methodCallAst.Member is StringConstantExpressionAst stringConstantAst))
{
return AstVisitAction.Continue;
}
if (stringConstantAst.Value.Equals("new", StringComparison.OrdinalIgnoreCase))
{
string typeName = typeExpressionAst.TypeName.FullName;
CorrectionExtent suggestedCorrection = CreateNewObjectCorrection(
_analyzedFilePath,
methodCallAst.Extent,
typeName,
methodCallAst.Arguments);
string message = string.Format(
CultureInfo.CurrentCulture,
Strings.UseCompatibleSyntaxError,
"constructor",
methodCallAst.Extent.Text,
"3,4");
_diagnosticAccumulator.Add(new DiagnosticRecord(
message,
methodCallAst.Extent,
_rule.GetName(),
_rule.Severity,
_analyzedFilePath,
ruleId: null,
suggestedCorrections: new [] { suggestedCorrection }
));
return AstVisitAction.Continue;
}
return AstVisitAction.Continue;
}

@LaurentDardenne
Copy link
Author

Thanks.

@rjmholt
Copy link
Contributor

rjmholt commented Dec 15, 2019

@LaurentDardenne is the rule incorrect? If so, we should keep this issue open to track the need to fix it

@LaurentDardenne
Copy link
Author

is the rule incorrect?

Almost incorrect ;-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants