1
+ //
2
+ // Copyright (c) Microsoft. All rights reserved.
3
+ // Licensed under the MIT license. See LICENSE file in the project root for full license information.
4
+ //
5
+
6
+ using System . Linq ;
7
+ using System . Threading . Tasks ;
8
+
9
+ namespace Microsoft . PowerShell . EditorServices . Session . Capabilities
10
+ {
11
+ using Microsoft . PowerShell . EditorServices . Utility ;
12
+ using System ;
13
+ using System . Collections . Generic ;
14
+ using System . Collections . ObjectModel ;
15
+ using System . Management . Automation ;
16
+
17
+ internal class DscBreakpointCapability : IRunspaceCapability
18
+ {
19
+ private string [ ] dscResourceRootPaths = new string [ 0 ] ;
20
+
21
+ private Dictionary < string , int [ ] > breakpointsPerFile =
22
+ new Dictionary < string , int [ ] > ( ) ;
23
+
24
+ public async Task < List < BreakpointDetails > > SetLineBreakpoints (
25
+ PowerShellContext powerShellContext ,
26
+ string scriptPath ,
27
+ BreakpointDetails [ ] breakpoints )
28
+ {
29
+ List < BreakpointDetails > resultBreakpointDetails =
30
+ new List < BreakpointDetails > ( ) ;
31
+
32
+ // We always get the latest array of breakpoint line numbers
33
+ // so store that for future use
34
+ if ( breakpoints . Length > 0 )
35
+ {
36
+ // Set the breakpoints for this scriptPath
37
+ this . breakpointsPerFile [ scriptPath ] =
38
+ breakpoints . Select ( b => b . LineNumber ) . ToArray ( ) ;
39
+ }
40
+ else
41
+ {
42
+ // No more breakpoints for this scriptPath, remove it
43
+ this . breakpointsPerFile . Remove ( scriptPath ) ;
44
+ }
45
+
46
+ string hashtableString =
47
+ string . Join (
48
+ ", " ,
49
+ this . breakpointsPerFile
50
+ . Select ( file => $ "@{{Path=\" { file . Key } \" ;Line=@({ string . Join ( "," , file . Value ) } )}}") ) ;
51
+
52
+ // Run Enable-DscDebug as a script because running it as a PSCommand
53
+ // causes an error which states that the Breakpoints parameter has not
54
+ // been passed.
55
+ await powerShellContext . ExecuteScriptString (
56
+ hashtableString . Length > 0
57
+ ? $ "Enable-DscDebug -Breakpoints { hashtableString } "
58
+ : "Disable-DscDebug" ,
59
+ false ,
60
+ false ) ;
61
+
62
+ // Verify all the breakpoints and return them
63
+ foreach ( var breakpoint in breakpoints )
64
+ {
65
+ breakpoint . Verified = true ;
66
+ }
67
+
68
+ return breakpoints . ToList ( ) ;
69
+ }
70
+
71
+ public bool IsDscResourcePath ( string scriptPath )
72
+ {
73
+ return dscResourceRootPaths . Any (
74
+ dscResourceRootPath =>
75
+ scriptPath . StartsWith (
76
+ dscResourceRootPath ,
77
+ StringComparison . CurrentCultureIgnoreCase ) ) ;
78
+ }
79
+
80
+ public static DscBreakpointCapability CheckForCapability (
81
+ RunspaceDetails runspaceDetails ,
82
+ PowerShellContext powerShellContext )
83
+ {
84
+ DscBreakpointCapability capability = null ;
85
+
86
+ if ( runspaceDetails . Context != RunspaceContext . DebuggedRunspace )
87
+ {
88
+ using ( PowerShell powerShell = PowerShell . Create ( ) )
89
+ {
90
+ powerShell . Runspace = runspaceDetails . Runspace ;
91
+
92
+ // Attempt to import the updated DSC module
93
+ powerShell . AddCommand ( "Import-Module" ) ;
94
+ powerShell . AddArgument ( @"C:\Program Files\DesiredStateConfiguration\1.0.0.0\Modules\PSDesiredStateConfiguration\PSDesiredStateConfiguration.psd1" ) ;
95
+ powerShell . AddParameter ( "PassThru" ) ;
96
+ powerShell . AddParameter ( "ErrorAction" , "SilentlyContinue" ) ;
97
+
98
+ PSObject moduleInfo = null ;
99
+
100
+ try
101
+ {
102
+ moduleInfo = powerShell . Invoke ( ) . FirstOrDefault ( ) ;
103
+ }
104
+ catch ( CmdletInvocationException e )
105
+ {
106
+ Logger . WriteException ( "Could not load the DSC module!" , e ) ;
107
+ }
108
+
109
+ if ( moduleInfo != null )
110
+ {
111
+ Logger . Write ( LogLevel . Verbose , "Side-by-side DSC module found, gathering DSC resource paths..." ) ;
112
+
113
+ // The module was loaded, add the breakpoint capability
114
+ capability = new DscBreakpointCapability ( ) ;
115
+ runspaceDetails . AddCapability ( capability ) ;
116
+
117
+ powerShell . Commands . Clear ( ) ;
118
+ powerShell . AddScript ( "Write-Host \" Gathering DSC resource paths, this may take a while...\" " ) ;
119
+ powerShell . Invoke ( ) ;
120
+
121
+ // Get the list of DSC resource paths
122
+ powerShell . Commands . Clear ( ) ;
123
+ powerShell . AddCommand ( "Get-DscResource" ) ;
124
+ powerShell . AddCommand ( "Select-Object" ) ;
125
+ powerShell . AddParameter ( "ExpandProperty" , "ParentPath" ) ;
126
+
127
+ Collection < PSObject > resourcePaths = null ;
128
+
129
+ try
130
+ {
131
+ resourcePaths = powerShell . Invoke ( ) ;
132
+ }
133
+ catch ( CmdletInvocationException e )
134
+ {
135
+ Logger . WriteException ( "Get-DscResource failed!" , e ) ;
136
+ }
137
+
138
+ if ( resourcePaths != null )
139
+ {
140
+ capability . dscResourceRootPaths =
141
+ resourcePaths
142
+ . Select ( o => ( string ) o . BaseObject )
143
+ . ToArray ( ) ;
144
+
145
+ Logger . Write ( LogLevel . Verbose , $ "DSC resources found: { resourcePaths . Count } ") ;
146
+ }
147
+ else
148
+ {
149
+ Logger . Write ( LogLevel . Verbose , $ "No DSC resources found.") ;
150
+ }
151
+ }
152
+ else
153
+ {
154
+ Logger . Write ( LogLevel . Verbose , $ "Side-by-side DSC module was not found.") ;
155
+ }
156
+ }
157
+ }
158
+
159
+ return capability ;
160
+ }
161
+ }
162
+ }
0 commit comments