@@ -133,6 +133,17 @@ public async Task<BreakpointDetails[]> SetLineBreakpoints(
133
133
{
134
134
ScriptBlock actionScriptBlock = ScriptBlock . Create ( breakpoint . Condition ) ;
135
135
136
+ // Check for simple, common errors that ScriptBlock parsing will not catch
137
+ // e.g. $i == 3 and $i > 3
138
+ string message ;
139
+ if ( ! ValidateBreakpointConditionAst ( actionScriptBlock . Ast , out message ) )
140
+ {
141
+ breakpoint . Verified = false ;
142
+ breakpoint . Message = message ;
143
+ resultBreakpointDetails . Add ( breakpoint ) ;
144
+ continue ;
145
+ }
146
+
136
147
// Check for "advanced" condition syntax i.e. if the user has specified
137
148
// a "break" or "continue" statement anywhere in their scriptblock,
138
149
// pass their scriptblock through to the Action parameter as-is.
@@ -156,7 +167,7 @@ public async Task<BreakpointDetails[]> SetLineBreakpoints(
156
167
// Failed to create conditional breakpoint likely because the user provided an
157
168
// invalid PowerShell expression. Let the user know why.
158
169
breakpoint . Verified = false ;
159
- breakpoint . Message = ex . Message ;
170
+ breakpoint . Message = ExtractAndScrubParseExceptionMessage ( ex , breakpoint . Condition ) ;
160
171
resultBreakpointDetails . Add ( breakpoint ) ;
161
172
continue ;
162
173
}
@@ -536,6 +547,85 @@ private async Task FetchStackFrames()
536
547
}
537
548
}
538
549
550
+ private bool ValidateBreakpointConditionAst ( Ast conditionAst , out string message )
551
+ {
552
+ message = string . Empty ;
553
+
554
+ // We are only inspecting a few simple scenarios in the EndBlock only.
555
+ ScriptBlockAst scriptBlockAst = conditionAst as ScriptBlockAst ;
556
+ if ( ( scriptBlockAst != null ) &&
557
+ ( scriptBlockAst . BeginBlock == null ) &&
558
+ ( scriptBlockAst . ProcessBlock == null ) &&
559
+ ( scriptBlockAst . EndBlock != null ) &&
560
+ ( scriptBlockAst . EndBlock . Statements . Count == 1 ) )
561
+ {
562
+ StatementAst statementAst = scriptBlockAst . EndBlock . Statements [ 0 ] ;
563
+ string condition = statementAst . Extent . Text ;
564
+
565
+ if ( statementAst is AssignmentStatementAst )
566
+ {
567
+ message = FormatInvalidBreakpointConditionMessage ( condition , "Use '-eq' instead of '=='." ) ;
568
+ return false ;
569
+ }
570
+
571
+ PipelineAst pipelineAst = statementAst as PipelineAst ;
572
+ if ( ( pipelineAst != null ) && ( pipelineAst . PipelineElements . Count == 1 ) &&
573
+ ( pipelineAst . PipelineElements [ 0 ] . Redirections . Count > 0 ) )
574
+ {
575
+ message = FormatInvalidBreakpointConditionMessage ( condition , "Use '-gt' instead of '>'." ) ;
576
+ return false ;
577
+ }
578
+ }
579
+
580
+ return true ;
581
+ }
582
+
583
+ private string ExtractAndScrubParseExceptionMessage ( ParseException parseException , string condition )
584
+ {
585
+ string [ ] messageLines = parseException . Message . Split ( '\n ' ) ;
586
+
587
+ // Skip first line - it is a location indicator "At line:1 char: 4"
588
+ for ( int i = 1 ; i < messageLines . Length ; i ++ )
589
+ {
590
+ string line = messageLines [ i ] ;
591
+ if ( line . StartsWith ( "+" ) )
592
+ {
593
+ continue ;
594
+ }
595
+
596
+ if ( ! string . IsNullOrWhiteSpace ( line ) )
597
+ {
598
+ // Note '==' and '>" do not generate parse errors
599
+ if ( line . Contains ( "'!='" ) )
600
+ {
601
+ line += " Use operator '-ne' instead of '!='." ;
602
+ }
603
+ else if ( line . Contains ( "'<'" ) && condition . Contains ( "<=" ) )
604
+ {
605
+ line += " Use operator '-le' instead of '<='." ;
606
+ }
607
+ else if ( line . Contains ( "'<'" ) )
608
+ {
609
+ line += " Use operator '-lt' instead of '<'." ;
610
+ }
611
+ else if ( condition . Contains ( ">=" ) )
612
+ {
613
+ line += " Use operator '-ge' instead of '>='." ;
614
+ }
615
+
616
+ return FormatInvalidBreakpointConditionMessage ( condition , line ) ;
617
+ }
618
+ }
619
+
620
+ // If the message format isn't in a form we expect, just return the whole message.
621
+ return FormatInvalidBreakpointConditionMessage ( condition , parseException . Message ) ;
622
+ }
623
+
624
+ private string FormatInvalidBreakpointConditionMessage ( string condition , string message )
625
+ {
626
+ return $ "'{ condition } ' is not a valid PowerShell expression. { message } ";
627
+ }
628
+
539
629
#endregion
540
630
541
631
#region Events
0 commit comments