@@ -158,7 +158,7 @@ private void SetupPSSAAppData()
158158 SetupTempDir ( ) ;
159159 }
160160
161- private bool IsModulePresent ( string moduleName )
161+ private bool IsModulePresentInTempModulePath ( string moduleName )
162162 {
163163 foreach ( var dir in Directory . EnumerateDirectories ( TempModulePath ) )
164164 {
@@ -335,7 +335,7 @@ public bool TrySaveModule(string moduleName)
335335 public void SaveModule ( string moduleName )
336336 {
337337 ThrowIfNull ( moduleName , "moduleName" ) ;
338- if ( IsModulePresent ( moduleName ) )
338+ if ( IsModulePresentInTempModulePath ( moduleName ) )
339339 {
340340 return ;
341341 }
@@ -350,6 +350,60 @@ public void SaveModule(string moduleName)
350350 }
351351 }
352352
353+ /// <summary>
354+ /// Encapsulates Get-Module to check the availability of the module on the system
355+ /// </summary>
356+ /// <param name="moduleName"></param>
357+ /// <returns>True indicating the presence of the module, otherwise false</returns>
358+ public bool IsModuleAvailable ( string moduleName )
359+ {
360+ ThrowIfNull ( moduleName , "moduleName" ) ;
361+ IEnumerable < PSModuleInfo > availableModules ;
362+ using ( var ps = System . Management . Automation . PowerShell . Create ( ) )
363+ {
364+ ps . Runspace = runspace ;
365+ availableModules = ps . AddCommand ( "Get-Module" )
366+ . AddParameter ( "Name" , moduleName )
367+ . AddParameter ( "ListAvailable" )
368+ . Invoke < PSModuleInfo > ( ) ;
369+ }
370+ return availableModules != null ? availableModules . Any ( ) : false ;
371+ }
372+
373+ /// <summary>
374+ /// Extracts out the module names from the error extent that are not available
375+ ///
376+ /// This handles the following case.
377+ /// Import-DSCResourceModule -ModuleName ModulePresent,ModuleAbsent
378+ ///
379+ /// ModulePresent is present in PSModulePath whereas ModuleAbsent is not.
380+ /// But the error exent coverts the entire extent and hence we need to check
381+ /// which module is actually not present so as to be downloaded
382+ /// </summary>
383+ /// <param name="error"></param>
384+ /// <param name="ast"></param>
385+ /// <returns>An enumeration over the module names that are not available</returns>
386+ public IEnumerable < string > GetUnavailableModuleNameFromErrorExtent ( ParseError error , ScriptBlockAst ast )
387+ {
388+ ThrowIfNull ( error , "error" ) ;
389+ ThrowIfNull ( ast , "ast" ) ;
390+ var moduleNames = ModuleDependencyHandler . GetModuleNameFromErrorExtent ( error , ast ) ;
391+ if ( moduleNames == null )
392+ {
393+ return null ;
394+ }
395+ var unavailableModules = new List < string > ( ) ;
396+ foreach ( var moduleName in moduleNames )
397+ {
398+ if ( ! IsModuleAvailable ( moduleName ) )
399+ {
400+ unavailableModules . Add ( moduleName ) ;
401+ }
402+ }
403+ //return moduleNames.Where(x => !IsModuleAvailable(x));
404+ return unavailableModules ;
405+ }
406+
353407 /// <summary>
354408 /// Get the module name from the error extent
355409 ///
@@ -362,7 +416,7 @@ public void SaveModule(string moduleName)
362416 /// <param name="error">Parse error</param>
363417 /// <param name="ast">AST of the script that contians the parse error</param>
364418 /// <returns>The name of the module that caused the parser to throw the error. Returns null if it cannot extract the module name.</returns>
365- public static string GetModuleNameFromErrorExtent ( ParseError error , ScriptBlockAst ast )
419+ public static IEnumerable < string > GetModuleNameFromErrorExtent ( ParseError error , ScriptBlockAst ast )
366420 {
367421 ThrowIfNull ( error , "error" ) ;
368422 ThrowIfNull ( ast , "ast" ) ;
@@ -373,9 +427,10 @@ public static string GetModuleNameFromErrorExtent(ParseError error, ScriptBlockA
373427 return null ;
374428 }
375429 // check if the command name is import-dscmodule
376- // right now we handle only the following form
377- // Import-DSCResource -ModuleName xActiveDirectory
378- if ( dynamicKywdAst . CommandElements . Count != 3 )
430+ // right now we handle only the following forms
431+ // 1. Import-DSCResourceModule -ModuleName somemodule
432+ // 2. Import-DSCResourceModule -ModuleName somemodule1,somemodule2
433+ if ( dynamicKywdAst . CommandElements . Count < 3 )
379434 {
380435 return null ;
381436 }
@@ -386,19 +441,56 @@ public static string GetModuleNameFromErrorExtent(ParseError error, ScriptBlockA
386441 return null ;
387442 }
388443
389- var paramAst = dynamicKywdAst . CommandElements [ 1 ] as CommandParameterAst ;
390- if ( paramAst == null || ! paramAst . ParameterName . Equals ( "ModuleName" , StringComparison . OrdinalIgnoreCase ) )
444+ // find a parameter named modulename
445+ int k ;
446+ for ( k = 1 ; k < dynamicKywdAst . CommandElements . Count ; k ++ )
391447 {
392- return null ;
448+ var paramAst = dynamicKywdAst . CommandElements [ 1 ] as CommandParameterAst ;
449+ // TODO match the initial letters only
450+ if ( paramAst == null || ! paramAst . ParameterName . Equals ( "ModuleName" , StringComparison . OrdinalIgnoreCase ) )
451+ {
452+ continue ;
453+ }
454+ break ;
393455 }
394-
395- var paramValAst = dynamicKywdAst . CommandElements [ 2 ] as StringConstantExpressionAst ;
396- if ( paramValAst == null )
456+
457+ if ( k == dynamicKywdAst . CommandElements . Count )
397458 {
459+ // cannot find modulename
398460 return null ;
399461 }
462+ var modules = new List < string > ( ) ;
463+
464+ // k < count - 1, because only -ModuleName throws parse error and hence not possible
465+ var paramValAst = dynamicKywdAst . CommandElements [ ++ k ] ;
400466
401- return paramValAst . Value ;
467+ // import-dscresource -ModuleName module1
468+ var paramValStrConstExprAst = paramValAst as StringConstantExpressionAst ;
469+ if ( paramValStrConstExprAst != null )
470+ {
471+ modules . Add ( paramValStrConstExprAst . Value ) ;
472+ return modules ;
473+ }
474+
475+ // import-dscresource -ModuleName module1,module2
476+ var paramValArrLtrlAst = paramValAst as ArrayLiteralAst ;
477+ if ( paramValArrLtrlAst != null )
478+ {
479+ foreach ( var elem in paramValArrLtrlAst . Elements )
480+ {
481+ var elemStrConstExprAst = elem as StringConstantExpressionAst ;
482+ if ( elemStrConstExprAst != null )
483+ {
484+ modules . Add ( elemStrConstExprAst . Value ) ;
485+ }
486+ }
487+ if ( modules . Count == 0 )
488+ {
489+ return null ;
490+ }
491+ return modules ;
492+ }
493+ return null ;
402494 }
403495
404496 /// <summary>
0 commit comments