12
12
// limitations under the License.
13
13
// ----------------------------------------------------------------------------------
14
14
15
+ using Microsoft . WindowsAzure . Commands . Common ;
15
16
using Microsoft . WindowsAzure . Commands . Utilities . Common ;
16
17
using System ;
17
18
using System . Collections ;
@@ -31,7 +32,7 @@ public class AzureLongRunningJob<T> : Job, ICommandRuntime where T : AzurePSCmdl
31
32
string _status = "Running" ;
32
33
T _cmdlet ;
33
34
ICommandRuntime _runtime ;
34
- ConcurrentQueue < PSStreamObject > _actions = new ConcurrentQueue < PSStreamObject > ( ) ;
35
+ ConcurrentQueue < ShouldMethodStreamItem > _actions = new ConcurrentQueue < ShouldMethodStreamItem > ( ) ;
35
36
bool _shouldConfirm = false ;
36
37
Action < T > _execute ;
37
38
@@ -95,7 +96,7 @@ public override string StatusMessage
95
96
/// <summary>
96
97
/// A queue of actions that must execute on the cmdlet thread
97
98
/// </summary>
98
- protected ConcurrentQueue < PSStreamObject > BlockedActions { get { return _actions ; } }
99
+ internal ConcurrentQueue < ShouldMethodStreamItem > BlockedActions { get { return _actions ; } }
99
100
100
101
/// <summary>
101
102
/// Factory method for creating jobs
@@ -106,6 +107,21 @@ public override string StatusMessage
106
107
/// <returns>A job tracking the background execution of the cmdlet</returns>
107
108
public static AzureLongRunningJob < U > Create < U > ( U cmdlet , string command , string name ) where U : AzurePSCmdlet
108
109
{
110
+ if ( cmdlet == null )
111
+ {
112
+ throw new ArgumentNullException ( nameof ( cmdlet ) ) ;
113
+ }
114
+
115
+ if ( string . IsNullOrWhiteSpace ( command ) )
116
+ {
117
+ command = cmdlet . GetType ( ) . Name ;
118
+ }
119
+
120
+ if ( string . IsNullOrWhiteSpace ( name ) )
121
+ {
122
+ name = "Azure Long-Running Job" ;
123
+ }
124
+
109
125
var job = new Common . AzureLongRunningJob < U > ( cmdlet , command , name ) ;
110
126
return job ;
111
127
}
@@ -121,6 +137,26 @@ public static AzureLongRunningJob<U> Create<U>(U cmdlet, string command, string
121
137
/// <returns>A job tracking the background execution of the cmdlet</returns>
122
138
public static AzureLongRunningJob < U > Create < U > ( U cmdlet , string command , string name , Action < U > executor ) where U : AzurePSCmdlet
123
139
{
140
+ if ( null == cmdlet )
141
+ {
142
+ throw new ArgumentNullException ( nameof ( cmdlet ) ) ;
143
+ }
144
+
145
+ if ( null == executor )
146
+ {
147
+ throw new ArgumentNullException ( nameof ( executor ) ) ;
148
+ }
149
+
150
+ if ( string . IsNullOrWhiteSpace ( command ) )
151
+ {
152
+ command = cmdlet . GetType ( ) . Name ;
153
+ }
154
+
155
+ if ( string . IsNullOrWhiteSpace ( name ) )
156
+ {
157
+ name = "Azure Long-Running Job" ;
158
+ }
159
+
124
160
var job = new Common . AzureLongRunningJob < U > ( cmdlet , command , name , executor ) ;
125
161
return job ;
126
162
}
@@ -133,18 +169,23 @@ public static AzureLongRunningJob<U> Create<U>(U cmdlet, string command, string
133
169
/// <returns>A deep copy fo the cmdlet</returns>
134
170
public static U CopyCmdlet < U > ( U cmdlet ) where U : AzurePSCmdlet
135
171
{
172
+ if ( cmdlet == null )
173
+ {
174
+ throw new ArgumentNullException ( nameof ( cmdlet ) ) ;
175
+ }
176
+
136
177
var returnType = cmdlet . GetType ( ) ;
137
178
var returnValue = Activator . CreateInstance ( cmdlet . GetType ( ) ) ;
138
179
foreach ( var property in returnType . GetProperties ( ) )
139
180
{
140
181
if ( property . CanWrite && property . CanRead )
141
182
{
142
- property . SetValue ( returnValue , property . GetValue ( cmdlet ) ) ;
183
+ property . SafeCopyValue ( source : cmdlet , target : returnValue ) ;
143
184
}
144
185
}
145
186
foreach ( var field in returnType . GetFields ( BindingFlags . Instance | BindingFlags . Public | BindingFlags . NonPublic | BindingFlags . DeclaredOnly ) )
146
187
{
147
- field . SetValue ( returnValue , field . GetValue ( cmdlet ) ) ;
188
+ field . SafeCopyValue ( source : cmdlet , target : returnValue ) ;
148
189
}
149
190
150
191
return returnValue as U ;
@@ -164,7 +205,8 @@ public virtual void RunJob(object state)
164
205
}
165
206
catch ( Exception ex )
166
207
{
167
- Error . Add ( new ErrorRecord ( ex , ex . Message , ErrorCategory . InvalidOperation , this ) ) ;
208
+ string message = string . Format ( "The cmdlet failed in background execution. The returned error was '{0}'. Please execute the cmdlet again. You may need to execute this cmdlet synchronously, by omitting the '-AsJob' parameter" , ex . Message ) ;
209
+ Error . Add ( new ErrorRecord ( ex , message , ErrorCategory . InvalidOperation , this ) ) ;
168
210
Fail ( ) ;
169
211
}
170
212
}
@@ -185,10 +227,10 @@ protected void UnblockJob()
185
227
{
186
228
var executor = CopyCmdlet ( _cmdlet ) ;
187
229
executor . CommandRuntime = _runtime ;
188
- PSStreamObject stream ;
230
+ ShouldMethodStreamItem stream ;
189
231
while ( _actions . TryDequeue ( out stream ) )
190
232
{
191
- stream . WriteStreamObject ( executor ) ;
233
+ stream . ExecuteShouldMethod ( executor ) ;
192
234
}
193
235
}
194
236
@@ -266,7 +308,7 @@ public PSHost Host
266
308
public bool ShouldContinue ( string query , string caption )
267
309
{
268
310
Exception thrownException ;
269
- return InvokeCmdletMethodAndWaitForResults ( cmdlet => cmdlet . ShouldContinue ( query , caption ) , out thrownException ) ;
311
+ return InvokeShouldMethodAndWaitForResults ( cmdlet => cmdlet . ShouldContinue ( query , caption ) , out thrownException ) ;
270
312
}
271
313
272
314
/// <summary>
@@ -282,7 +324,7 @@ public bool ShouldContinue(string query, string caption, ref bool yesToAll, ref
282
324
Exception thrownException ;
283
325
bool localYesToAll = yesToAll ;
284
326
bool localNoToAll = noToAll ;
285
- bool result = InvokeCmdletMethodAndWaitForResults ( cmdlet => cmdlet . ShouldContinue ( query , caption ,
327
+ bool result = InvokeShouldMethodAndWaitForResults ( cmdlet => cmdlet . ShouldContinue ( query , caption ,
286
328
ref localYesToAll , ref localNoToAll ) , out thrownException ) ;
287
329
yesToAll = localYesToAll ;
288
330
noToAll = localNoToAll ;
@@ -296,9 +338,9 @@ public bool ShouldContinue(string query, string caption, ref bool yesToAll, ref
296
338
/// <returns>True if ShouldProcess must be called on the cmdlet thread, otherwise false</returns>
297
339
static bool ShouldConfirm ( AzurePSCmdlet cmdlet )
298
340
{
299
- ConfirmImpact confirmPreference = ConfirmImpact . Medium ;
341
+ ConfirmImpact confirmPreference = ConfirmImpact . High ;
300
342
ConfirmImpact cmdletImpact = ConfirmImpact . Medium ;
301
- var confirmVar = SafeGetVariableValue ( cmdlet , "ConfirmPreference" , "Medium " ) ;
343
+ var confirmVar = SafeGetVariableValue ( cmdlet , "ConfirmPreference" , "High " ) ;
302
344
if ( ! string . IsNullOrEmpty ( confirmVar ) )
303
345
{
304
346
Enum . TryParse ( confirmVar , out confirmPreference ) ;
@@ -310,7 +352,7 @@ static bool ShouldConfirm(AzurePSCmdlet cmdlet)
310
352
cmdletImpact = attribute . ConfirmImpact ;
311
353
}
312
354
313
- return cmdletImpact > confirmPreference ;
355
+ return cmdletImpact >= confirmPreference ;
314
356
}
315
357
316
358
static string SafeGetVariableValue ( PSCmdlet cmdlet , string name , string defaultValue )
@@ -352,7 +394,7 @@ public bool ShouldProcess(string target)
352
394
}
353
395
354
396
Exception thrownException ;
355
- return InvokeCmdletMethodAndWaitForResults ( cmdlet => cmdlet . ShouldProcess ( target ) , out thrownException ) ;
397
+ return InvokeShouldMethodAndWaitForResults ( cmdlet => cmdlet . ShouldProcess ( target ) , out thrownException ) ;
356
398
}
357
399
358
400
/// <summary>
@@ -369,7 +411,7 @@ public bool ShouldProcess(string target, string action)
369
411
}
370
412
371
413
Exception thrownException ;
372
- return InvokeCmdletMethodAndWaitForResults ( cmdlet => cmdlet . ShouldProcess ( target , action ) , out thrownException ) ;
414
+ return InvokeShouldMethodAndWaitForResults ( cmdlet => cmdlet . ShouldProcess ( target , action ) , out thrownException ) ;
373
415
}
374
416
375
417
/// <summary>
@@ -387,7 +429,7 @@ public bool ShouldProcess(string verboseDescription, string verboseWarning, stri
387
429
}
388
430
389
431
Exception thrownException ;
390
- return InvokeCmdletMethodAndWaitForResults ( cmdlet => cmdlet . ShouldProcess ( verboseDescription , verboseWarning , caption ) ,
432
+ return InvokeShouldMethodAndWaitForResults ( cmdlet => cmdlet . ShouldProcess ( verboseDescription , verboseWarning , caption ) ,
391
433
out thrownException ) ;
392
434
}
393
435
@@ -409,7 +451,7 @@ public bool ShouldProcess(string verboseDescription, string verboseWarning, stri
409
451
410
452
ShouldProcessReason closureShouldProcessReason = ShouldProcessReason . None ;
411
453
Exception thrownException ;
412
- bool result = InvokeCmdletMethodAndWaitForResults ( cmdlet => cmdlet . ShouldProcess ( verboseDescription , verboseWarning , caption , out closureShouldProcessReason ) ,
454
+ bool result = InvokeShouldMethodAndWaitForResults ( cmdlet => cmdlet . ShouldProcess ( verboseDescription , verboseWarning , caption , out closureShouldProcessReason ) ,
413
455
out thrownException ) ;
414
456
shouldProcessReason = closureShouldProcessReason ;
415
457
return result ;
@@ -431,7 +473,7 @@ public void ThrowTerminatingError(ErrorRecord errorRecord)
431
473
public bool TransactionAvailable ( )
432
474
{
433
475
Exception thrownException ;
434
- return InvokeCmdletMethodAndWaitForResults ( cmdlet => cmdlet . TransactionAvailable ( ) ,
476
+ return InvokeShouldMethodAndWaitForResults ( cmdlet => cmdlet . TransactionAvailable ( ) ,
435
477
out thrownException ) ;
436
478
}
437
479
@@ -543,13 +585,13 @@ internal bool IsTerminalState(JobState state)
543
585
/// Queue actions that must occur on the cmdlet thread, and block the current thread until they are completed
544
586
/// </summary>
545
587
/// <typeparam name="V">The output type of the called cmdlet action</typeparam>
546
- /// <param name="invokeCmdletMethodAndReturnResult ">The action to invoke</param>
588
+ /// <param name="shouldMethod ">The action to invoke</param>
547
589
/// <param name="exceptionThrownOnCmdletThread">Any exception that results</param>
548
590
/// <returns>The result of executing the action on the cmdlet thread</returns>
549
- private V InvokeCmdletMethodAndWaitForResults < V > ( Func < Cmdlet , V > invokeCmdletMethodAndReturnResult , out Exception exceptionThrownOnCmdletThread )
591
+ private bool InvokeShouldMethodAndWaitForResults ( Func < Cmdlet , bool > shouldMethod , out Exception exceptionThrownOnCmdletThread )
550
592
{
551
593
552
- V methodResult = default ( V ) ;
594
+ bool methodResult = false ;
553
595
Exception closureSafeExceptionThrownOnCmdletThread = null ;
554
596
object resultsLock = new object ( ) ;
555
597
using ( var gotResultEvent = new ManualResetEventSlim ( false ) )
@@ -580,28 +622,23 @@ private V InvokeCmdletMethodAndWaitForResults<V>(Func<Cmdlet, V> invokeCmdletMet
580
622
if ( ! gotResultEvent . IsSet )
581
623
{
582
624
this . Block ( ) ;
583
- // addition to results column happens here
584
- CmdletMethodInvoker < V > methodInvoker = new CmdletMethodInvoker < V >
625
+
626
+ ShouldMethodInvoker methodInvoker = new ShouldMethodInvoker
585
627
{
586
- Action = invokeCmdletMethodAndReturnResult ,
628
+ ShouldMethod = shouldMethod ,
587
629
Finished = gotResultEvent ,
588
630
SyncObject = resultsLock
589
631
} ;
590
- PSStreamObjectType objectType = PSStreamObjectType . ShouldMethod ;
591
- if ( typeof ( V ) == typeof ( object ) )
592
- {
593
- objectType = PSStreamObjectType . BlockingError ;
594
- }
595
632
596
- BlockedActions . Enqueue ( new PSStreamObject ( objectType , methodInvoker ) ) ;
633
+ BlockedActions . Enqueue ( new ShouldMethodStreamItem ( methodInvoker ) ) ;
597
634
gotResultEvent . Wait ( ) ;
598
635
this . Start ( ) ;
599
636
600
637
lock ( resultsLock )
601
638
{
602
639
if ( closureSafeExceptionThrownOnCmdletThread == null ) // stateChangedEventHandler didn't set the results? = ok to clobber results?
603
640
{
604
- closureSafeExceptionThrownOnCmdletThread = methodInvoker . ExceptionThrownOnCmdletThread ;
641
+ closureSafeExceptionThrownOnCmdletThread = methodInvoker . ThrownException ;
605
642
methodResult = methodInvoker . MethodResult ;
606
643
}
607
644
}
@@ -622,7 +659,7 @@ private V InvokeCmdletMethodAndWaitForResults<V>(Func<Cmdlet, V> invokeCmdletMet
622
659
623
660
public override void StopJob ( )
624
661
{
625
- PSStreamObject stream ;
662
+ ShouldMethodStreamItem stream ;
626
663
while ( _actions . TryDequeue ( out stream ) ) ;
627
664
this . Cancel ( ) ;
628
665
}
0 commit comments