@@ -212,21 +212,6 @@ private string GetTempModulePath(string symLinkPath)
212
212
return line ;
213
213
}
214
214
215
- private void SaveModule ( PSObject module )
216
- {
217
- ThrowIfNull ( module , "module" ) ;
218
-
219
- // TODO validate module
220
- using ( var ps = System . Management . Automation . PowerShell . Create ( ) )
221
- {
222
- ps . Runspace = runspace ;
223
- ps . AddCommand ( "Save-Module" )
224
- . AddParameter ( "Path" , tempModulePath )
225
- . AddParameter ( "InputObject" , module ) ;
226
- ps . Invoke ( ) ;
227
- }
228
- }
229
-
230
215
private void SetupPSModulePath ( )
231
216
{
232
217
oldPSModulePath = Environment . GetEnvironmentVariable ( "PSModulePath" ) ;
@@ -295,51 +280,17 @@ public ModuleDependencyHandler(
295
280
296
281
}
297
282
298
- /// <summary>
299
- /// Encapsulates Find-Module
300
- /// </summary>
301
- /// <param name="moduleName">Name of the module</param>
302
- /// <returns>A PSObject if it finds the modules otherwise returns null</returns>
303
- public PSObject FindModule ( string moduleName )
304
- {
305
- ThrowIfNull ( moduleName , "moduleName" ) ;
306
- moduleName = moduleName . ToLower ( ) ;
307
- if ( modulesFound . ContainsKey ( moduleName ) )
308
- {
309
- return modulesFound [ moduleName ] ;
310
- }
311
- Collection < PSObject > modules = null ;
312
- using ( var ps = System . Management . Automation . PowerShell . Create ( ) )
313
- {
314
- ps . Runspace = runspace ;
315
- ps . AddCommand ( "Find-Module" , true )
316
- . AddParameter ( "Name" , moduleName )
317
- . AddParameter ( "Repository" , moduleRepository ) ;
318
- modules = ps . Invoke < PSObject > ( ) ;
319
- }
320
- if ( modules == null )
321
- {
322
- return null ;
323
- }
324
- var module = modules . FirstOrDefault ( ) ;
325
- if ( module == null )
326
- {
327
- return null ;
328
- }
329
- modulesFound . Add ( moduleName , module ) ;
330
- return module ;
331
- }
332
-
333
283
/// <summary>
334
284
/// SaveModule version that doesn't throw
335
285
/// </summary>
336
286
/// <param name="moduleName">Name of the module</param>
287
+ /// <param name="moduleVersion">(Optional) version of the module</param>
337
288
/// <returns>True if it can save a module otherwise false.</returns>
338
- public bool TrySaveModule ( string moduleName )
289
+ public bool TrySaveModule ( string moduleName , Version moduleVersion )
339
290
{
340
291
try
341
292
{
342
- SaveModule ( moduleName ) ;
293
+ SaveModule ( moduleName , moduleVersion ) ;
343
294
return true ;
344
295
}
345
296
catch
@@ -353,7 +304,8 @@ public bool TrySaveModule(string moduleName)
353
304
/// Encapsulates Save-Module cmdlet
354
305
/// </summary>
355
306
/// <param name="moduleName">Name of the module</param>
356
- public void SaveModule ( string moduleName )
307
+ /// <param name="moduleVersion">(Optional) version of the module</param>
308
+ public void SaveModule ( string moduleName , Version moduleVersion )
357
309
{
358
310
ThrowIfNull ( moduleName , "moduleName" ) ;
359
311
if ( IsModulePresentInTempModulePath ( moduleName ) )
@@ -368,6 +320,10 @@ public void SaveModule(string moduleName)
368
320
. AddParameter ( "Name" , moduleName )
369
321
. AddParameter ( "Repository" , moduleRepository )
370
322
. AddParameter ( "Force" ) ;
323
+ if ( moduleVersion != null )
324
+ {
325
+ ps . AddParameter ( "RequiredVersion" , moduleVersion ) ;
326
+ }
371
327
ps . Invoke ( ) ;
372
328
}
373
329
}
@@ -376,18 +332,25 @@ public void SaveModule(string moduleName)
376
332
/// Encapsulates Get-Module to check the availability of the module on the system
377
333
/// </summary>
378
334
/// <param name="moduleName"></param>
335
+ /// <param name="moduleVersion"></param>
379
336
/// <returns>True indicating the presence of the module, otherwise false</returns>
380
- public bool IsModuleAvailable ( string moduleName )
337
+ public bool IsModuleAvailable ( string moduleName , Version moduleVersion )
381
338
{
382
339
ThrowIfNull ( moduleName , "moduleName" ) ;
383
340
IEnumerable < PSModuleInfo > availableModules ;
384
341
using ( var ps = System . Management . Automation . PowerShell . Create ( ) )
385
342
{
386
343
ps . Runspace = runspace ;
387
- availableModules = ps . AddCommand ( "Get-Module" )
344
+ ps . AddCommand ( "Get-Module" )
388
345
. AddParameter ( "Name" , moduleName )
389
- . AddParameter ( "ListAvailable" )
390
- . Invoke < PSModuleInfo > ( ) ;
346
+ . AddParameter ( "ListAvailable" ) ;
347
+ if ( moduleVersion != null )
348
+ {
349
+ ps . AddCommand ( "Where-Object" )
350
+ . AddParameter ( "Filterscript" , ScriptBlock . Create ( $ "$_.Version -eq '{ moduleVersion } '") ) ;
351
+ }
352
+ availableModules = ps . Invoke < PSModuleInfo > ( ) ;
353
+
391
354
}
392
355
return availableModules != null ? availableModules . Any ( ) : false ;
393
356
}
@@ -405,25 +368,26 @@ public bool IsModuleAvailable(string moduleName)
405
368
/// </summary>
406
369
/// <param name="error"></param>
407
370
/// <param name="ast"></param>
371
+ /// <param name="moduleVersion"></param>
408
372
/// <returns>An enumeration over the module names that are not available</returns>
409
- public IEnumerable < string > GetUnavailableModuleNameFromErrorExtent ( ParseError error , ScriptBlockAst ast )
373
+ public IEnumerable < string > GetUnavailableModuleNameFromErrorExtent ( ParseError error , ScriptBlockAst ast , out Version moduleVersion )
410
374
{
411
375
ThrowIfNull ( error , "error" ) ;
412
376
ThrowIfNull ( ast , "ast" ) ;
413
- var moduleNames = ModuleDependencyHandler . GetModuleNameFromErrorExtent ( error , ast ) ;
377
+ var moduleNames = ModuleDependencyHandler . GetModuleNameFromErrorExtent ( error , ast , out moduleVersion ) ;
414
378
if ( moduleNames == null )
415
379
{
416
380
return null ;
417
381
}
418
382
var unavailableModules = new List < string > ( ) ;
419
383
foreach ( var moduleName in moduleNames )
420
384
{
421
- if ( ! IsModuleAvailable ( moduleName ) )
385
+ if ( ! IsModuleAvailable ( moduleName , moduleVersion ) )
422
386
{
423
387
unavailableModules . Add ( moduleName ) ;
424
388
}
425
389
}
426
- //return moduleNames.Where(x => !IsModuleAvailable(x));
390
+
427
391
return unavailableModules ;
428
392
}
429
393
@@ -438,9 +402,11 @@ public IEnumerable<string> GetUnavailableModuleNameFromErrorExtent(ParseError er
438
402
/// </summary>
439
403
/// <param name="error">Parse error</param>
440
404
/// <param name="ast">AST of the script that contians the parse error</param>
405
+ /// <param name="moduleVersion">Specifc version of the required module</param>
441
406
/// <returns>The name of the module that caused the parser to throw the error. Returns null if it cannot extract the module name.</returns>
442
- public static IEnumerable < string > GetModuleNameFromErrorExtent ( ParseError error , ScriptBlockAst ast )
407
+ public static IEnumerable < string > GetModuleNameFromErrorExtent ( ParseError error , ScriptBlockAst ast , out Version moduleVersion )
443
408
{
409
+ moduleVersion = null ;
444
410
ThrowIfNull ( error , "error" ) ;
445
411
ThrowIfNull ( ast , "ast" ) ;
446
412
var statement = ast . Find ( x => x . Extent . Equals ( error . Extent ) , true ) ;
@@ -452,46 +418,61 @@ public static IEnumerable<string> GetModuleNameFromErrorExtent(ParseError error,
452
418
// check if the command name is import-dscmodule
453
419
// right now we handle only the following forms
454
420
// 1. Import-DSCResourceModule -ModuleName somemodule
455
- // 2. Import-DSCResourceModule -ModuleName somemodule1,somemodule2
456
- if ( dynamicKywdAst . CommandElements . Count < 3 )
457
- {
458
- return null ;
459
- }
460
-
421
+ // 2. Import-DSCResourceModule -ModuleName somemodule1 -ModuleVersion major.minor.patch.build
422
+ // 3. Import-DSCResourceModule -ModuleName somemodule1,somemodule2
461
423
var dscKeywordAst = dynamicKywdAst . CommandElements [ 0 ] as StringConstantExpressionAst ;
462
424
if ( dscKeywordAst == null || ! dscKeywordAst . Value . Equals ( "Import-DscResource" , StringComparison . OrdinalIgnoreCase ) )
463
425
{
464
426
return null ;
465
427
}
466
428
467
429
// find a parameter named modulename
468
- int k ;
469
- for ( k = 1 ; k < dynamicKywdAst . CommandElements . Count ; k ++ )
430
+ int positionOfModuleNameParamter = 0 ;
431
+ int positionOfModuleVersionParameter = 0 ;
432
+ for ( int i = 1 ; i < dynamicKywdAst . CommandElements . Count ; i ++ )
470
433
{
471
- var paramAst = dynamicKywdAst . CommandElements [ k ] as CommandParameterAst ;
434
+ var paramAst = dynamicKywdAst . CommandElements [ i ] as CommandParameterAst ;
472
435
// TODO match the initial letters only
473
- if ( paramAst == null || ! paramAst . ParameterName . Equals ( "ModuleName" , StringComparison . OrdinalIgnoreCase ) )
436
+ if ( paramAst != null && paramAst . ParameterName . Equals ( "ModuleName" , StringComparison . OrdinalIgnoreCase ) )
437
+ {
438
+ if ( i == dynamicKywdAst . CommandElements . Count )
439
+ {
440
+ // command was Save-DscDependency ... -ModuleName -> module name missing
441
+ return null ;
442
+ }
443
+ positionOfModuleNameParamter = i + 1 ;
444
+ continue ;
445
+ }
446
+
447
+ if ( paramAst != null && paramAst . ParameterName . Equals ( "ModuleVersion" , StringComparison . OrdinalIgnoreCase ) )
474
448
{
449
+ if ( i == dynamicKywdAst . CommandElements . Count )
450
+ {
451
+ // command was Save-DscDependency ... -ModuleVersion -> module version missing
452
+ return null ;
453
+ }
454
+ positionOfModuleVersionParameter = i + 1 ;
475
455
continue ;
476
456
}
477
- break ;
478
457
}
479
458
480
- if ( k == dynamicKywdAst . CommandElements . Count )
481
- {
482
- // cannot find modulename
483
- return null ;
484
- }
485
459
var modules = new List < string > ( ) ;
486
460
487
- // k < count - 1, because only -ModuleName throws parse error and hence not possible
488
- var paramValAst = dynamicKywdAst . CommandElements [ ++ k ] ;
461
+ var paramValAst = dynamicKywdAst . CommandElements [ positionOfModuleNameParamter ] ;
489
462
490
463
// import-dscresource -ModuleName module1
491
464
var paramValStrConstExprAst = paramValAst as StringConstantExpressionAst ;
492
465
if ( paramValStrConstExprAst != null )
493
466
{
494
467
modules . Add ( paramValStrConstExprAst . Value ) ;
468
+
469
+ // import-dscresource -ModuleName module1 -ModuleVersion major.minor.patch.build
470
+ var versionParameterAst = dynamicKywdAst . CommandElements [ positionOfModuleVersionParameter ] as StringConstantExpressionAst ;
471
+ if ( versionParameterAst != null )
472
+ {
473
+ Version . TryParse ( versionParameterAst . Value , out Version version ) ; // ignore return value since a module version of null means no version
474
+ moduleVersion = version ;
475
+ }
495
476
return modules ;
496
477
}
497
478
@@ -513,6 +494,7 @@ public static IEnumerable<string> GetModuleNameFromErrorExtent(ParseError error,
513
494
}
514
495
return modules ;
515
496
}
497
+
516
498
return null ;
517
499
}
518
500
0 commit comments