1+ using System ;
2+ using System . IO ;
3+ using System . Threading ;
4+ using System . Management . Automation ;
5+
6+ using Microsoft . Build . Framework ;
7+ using Microsoft . Build . Utilities ;
8+
9+ public class InvokePowershellTask : Task , ICancelableTask
10+ {
11+ [ Required ] public string EntryPs1 { get ; set ; }
12+ [ Required ] public string SolutionRoot { get ; set ; }
13+ [ Required ] public string SdkInstallPath { get ; set ; }
14+ [ Required ] public string GameInstallPath { get ; set ; }
15+ [ Required ] public ITaskItem [ ] AdditionalArgs { get ; set ; }
16+
17+ private PowerShell _ps ;
18+
19+ private ManualResetEventSlim _startingMre = new ManualResetEventSlim ( false ) ;
20+
21+ public override bool Execute ( )
22+ {
23+ bool isSuccess = false ;
24+
25+ try
26+ {
27+ _ps = PowerShell . Create ( ) ;
28+
29+ _ps
30+ . AddCommand ( "Set-ExecutionPolicy" )
31+ . AddArgument ( "Unrestricted" )
32+ . AddParameter ( "Scope" , "CurrentUser" ) ;
33+
34+ _ps
35+ . AddStatement ( )
36+ . AddCommand ( EntryPs1 )
37+ . AddParameter ( "srcDirectory" , TrimEndingDirectorySeparator ( SolutionRoot ) )
38+ . AddParameter ( "sdkPath" , TrimEndingDirectorySeparator ( SdkInstallPath ) )
39+ . AddParameter ( "gamePath" , TrimEndingDirectorySeparator ( GameInstallPath ) ) ;
40+
41+ foreach ( ITaskItem Arg in AdditionalArgs )
42+ {
43+ string Val = Arg . GetMetadata ( "Value" ) ;
44+ if ( string . IsNullOrEmpty ( Val ) )
45+ {
46+ _ps . AddParameter ( Arg . ItemSpec ) ;
47+ }
48+ else
49+ {
50+ _ps . AddParameter ( Arg . ItemSpec , Val ) ;
51+ }
52+ }
53+
54+ BindStreamEntryCallback ( _ps . Streams . Debug , record => LogOutput ( record . ToString ( ) ) ) ;
55+ BindStreamEntryCallback ( _ps . Streams . Information , record => LogOutput ( record . ToString ( ) ) ) ;
56+ BindStreamEntryCallback ( _ps . Streams . Verbose , record => LogOutput ( record . ToString ( ) ) ) ;
57+ BindStreamEntryCallback ( _ps . Streams . Warning , record => LogOutput ( record . ToString ( ) ) ) ; // TODO: More flashy output?
58+
59+ BindStreamEntryCallback ( _ps . Streams . Error , record =>
60+ {
61+ // TODO: Less info than when from console
62+ // TODO: More flashy output?
63+ LogOutput ( record . ToString ( ) ) ;
64+ Log . LogError ( record . ToString ( ) ) ;
65+ isSuccess = false ;
66+ } ) ;
67+
68+ _ps . InvocationStateChanged += ( sender , args ) =>
69+ {
70+ if ( args . InvocationStateInfo . State == PSInvocationState . Running )
71+ {
72+ _startingMre . Set ( ) ;
73+ }
74+ } ;
75+
76+ isSuccess = true ;
77+ _ps . Invoke ( ) ;
78+ }
79+ catch ( System . Exception e )
80+ {
81+ Log . LogError ( e . Message ) ;
82+ isSuccess = false ;
83+ }
84+
85+ return isSuccess ;
86+ }
87+
88+ public void Cancel ( )
89+ {
90+ // Log.LogMessage(MessageImportance.High, "Got cancel");
91+
92+ // Do not call Stop() until we know that we've actually started
93+ // This could be more elaborate, but the time interval between Execute() and Invoke() being called is extremely small
94+
95+ _startingMre . Wait ( ) ;
96+ _ps . Stop ( ) ;
97+ }
98+
99+ private void LogOutput ( string output )
100+ {
101+ // This is required to keep the empty lines in the output
102+ if ( string . IsNullOrEmpty ( output ) ) output = " " ;
103+
104+ Log . LogMessage ( MessageImportance . High , output ) ;
105+ }
106+
107+ private static readonly char [ ] DirectorySeparatorsForTrimming = new char [ ]
108+ {
109+ Path . DirectorySeparatorChar ,
110+ Path . AltDirectorySeparatorChar
111+ } ;
112+
113+ private static string TrimEndingDirectorySeparator ( string path )
114+ {
115+ return path . TrimEnd ( DirectorySeparatorsForTrimming ) ;
116+ }
117+
118+ private static void BindStreamEntryCallback < T > ( PSDataCollection < T > stream , Action < T > handler )
119+ {
120+ stream . DataAdded += ( object sender , DataAddedEventArgs e ) => handler ( stream [ e . Index ] ) ;
121+ }
122+ }
0 commit comments