@@ -34,6 +34,7 @@ public class Helper
34
34
private CommandInvocationIntrinsics invokeCommand ;
35
35
private IOutputWriter outputWriter ;
36
36
private Object getCommandLock = new object ( ) ;
37
+ private readonly static Version minSupportedPSVersion = new Version ( 3 , 0 ) ;
37
38
38
39
#endregion
39
40
@@ -1602,6 +1603,182 @@ public bool GetNamedArgumentAttributeValue(NamedAttributeArgumentAst namedAttrib
1602
1603
return false ;
1603
1604
}
1604
1605
1606
+ /// <summary>
1607
+ /// Gets valid keys of a PowerShell module manifest file for a given PowerShell version
1608
+ /// </summary>
1609
+ /// <param name="powershellVersion">Version parameter; valid if >= 3.0</param>
1610
+ /// <returns>Returns an enumerator over valid keys</returns>
1611
+ public static IEnumerable < string > GetModuleManifestKeys ( Version powershellVersion )
1612
+ {
1613
+ if ( powershellVersion == null )
1614
+ {
1615
+ throw new ArgumentNullException ( "powershellVersion" ) ;
1616
+ }
1617
+ if ( ! IsPowerShellVersionSupported ( powershellVersion ) )
1618
+ {
1619
+ throw new ArgumentException ( "Invalid PowerShell version. Choose from version greater than or equal to 3.0" ) ;
1620
+ }
1621
+ var keys = new List < string > ( ) ;
1622
+ var keysCommon = new List < string > {
1623
+ "RootModule" ,
1624
+ "ModuleVersion" ,
1625
+ "GUID" ,
1626
+ "Author" ,
1627
+ "CompanyName" ,
1628
+ "Copyright" ,
1629
+ "Description" ,
1630
+ "PowerShellVersion" ,
1631
+ "PowerShellHostName" ,
1632
+ "PowerShellHostVersion" ,
1633
+ "DotNetFrameworkVersion" ,
1634
+ "CLRVersion" ,
1635
+ "ProcessorArchitecture" ,
1636
+ "RequiredModules" ,
1637
+ "RequiredAssemblies" ,
1638
+ "ScriptsToProcess" ,
1639
+ "TypesToProcess" ,
1640
+ "FormatsToProcess" ,
1641
+ "NestedModules" ,
1642
+ "FunctionsToExport" ,
1643
+ "CmdletsToExport" ,
1644
+ "VariablesToExport" ,
1645
+ "AliasesToExport" ,
1646
+ "ModuleList" ,
1647
+ "FileList" ,
1648
+ "PrivateData" ,
1649
+ "HelpInfoURI" ,
1650
+ "DefaultCommandPrefix" } ;
1651
+ keys . AddRange ( keysCommon ) ;
1652
+ if ( powershellVersion . Major >= 5 )
1653
+ {
1654
+ keys . Add ( "DscResourcesToExport" ) ;
1655
+ }
1656
+ if ( powershellVersion >= new Version ( 5 , 1 ) )
1657
+ {
1658
+ keys . Add ( "CompatiblePSEditions" ) ;
1659
+ }
1660
+ return keys ;
1661
+ }
1662
+
1663
+ /// <summary>
1664
+ /// Gets deprecated keys of PowerShell module manifest
1665
+ /// </summary>
1666
+ /// <returns>Returns an enumerator over deprecated keys</returns>
1667
+ public static IEnumerable < string > GetDeprecatedModuleManifestKeys ( )
1668
+ {
1669
+ return new List < string > { "ModuleToProcess" } ;
1670
+ }
1671
+
1672
+ /// <summary>
1673
+ /// Get a mapping between string type keys and StatementAsts from module manifest hashtable ast
1674
+ ///
1675
+ /// This is a workaround as SafeGetValue is not supported on PS v5 and below.
1676
+ /// </summary>
1677
+ /// <param name="hast">Hashtable Ast obtained from module manifest</param>
1678
+ /// <returns>A dictionary that maps string keys to values of StatementAst type</returns>
1679
+ private static Dictionary < string , StatementAst > GetMapFromHashtableAst ( HashtableAst hast )
1680
+ {
1681
+ var map = new Dictionary < string , StatementAst > ( StringComparer . OrdinalIgnoreCase ) ;
1682
+ foreach ( var pair in hast . KeyValuePairs )
1683
+ {
1684
+ var key = pair . Item1 as StringConstantExpressionAst ;
1685
+ if ( key == null )
1686
+ {
1687
+ return null ;
1688
+ }
1689
+ map [ key . Value ] = pair . Item2 ;
1690
+ }
1691
+ return map ;
1692
+ }
1693
+
1694
+ /// <summary>
1695
+ /// Checks if the version is supported
1696
+ ///
1697
+ /// PowerShell versions with Major greater than 3 are supported
1698
+ /// </summary>
1699
+ /// <param name="version">PowerShell version</param>
1700
+ /// <returns>true if the given version is supported else false</returns>
1701
+ public static bool IsPowerShellVersionSupported ( Version version )
1702
+ {
1703
+ if ( version == null )
1704
+ {
1705
+ throw new ArgumentNullException ( "version" ) ;
1706
+ }
1707
+ return version >= minSupportedPSVersion ;
1708
+ }
1709
+
1710
+ /// <summary>
1711
+ /// Checks if a given file is a valid PowerShell module manifest
1712
+ /// </summary>
1713
+ /// <param name="filepath">Path to module manifest</param>
1714
+ /// <param name="powershellVersion">Version parameter; valid if >= 3.0</param>
1715
+ /// <returns>true if given filepath points to a module manifest, otherwise false</returns>
1716
+ public static bool IsModuleManifest ( string filepath , Version powershellVersion = null )
1717
+ {
1718
+ Token [ ] tokens ;
1719
+ ParseError [ ] errors ;
1720
+ if ( filepath == null )
1721
+ {
1722
+ throw new ArgumentNullException ( "filepath" ) ;
1723
+ }
1724
+ if ( powershellVersion != null
1725
+ && ! IsPowerShellVersionSupported ( powershellVersion ) )
1726
+ {
1727
+ return false ;
1728
+ }
1729
+ if ( ! Path . GetExtension ( filepath ) . Equals ( ".psd1" , StringComparison . OrdinalIgnoreCase ) )
1730
+ {
1731
+ return false ;
1732
+ }
1733
+
1734
+ //using parsefile causes the parser to crash!
1735
+ string fileContent = File . ReadAllText ( filepath ) ;
1736
+ var ast = Parser . ParseInput ( fileContent , out tokens , out errors ) ;
1737
+ var hast = ast . Find ( x => x is HashtableAst , false ) as HashtableAst ;
1738
+ if ( hast == null )
1739
+ {
1740
+ return false ;
1741
+ }
1742
+ var map = GetMapFromHashtableAst ( hast ) ;
1743
+ var deprecatedKeys = GetDeprecatedModuleManifestKeys ( ) ;
1744
+ IEnumerable < string > allKeys ;
1745
+ if ( powershellVersion != null )
1746
+ {
1747
+ allKeys = GetModuleManifestKeys ( powershellVersion ) ;
1748
+ }
1749
+ else
1750
+ {
1751
+ Version version = null ;
1752
+ if ( map . ContainsKey ( "PowerShellVersion" ) )
1753
+ {
1754
+ var versionStrAst = map [ "PowerShellVersion" ] . Find ( x => x is StringConstantExpressionAst , false ) ;
1755
+ if ( versionStrAst != null )
1756
+ {
1757
+ try
1758
+ {
1759
+ version = new Version ( ( versionStrAst as StringConstantExpressionAst ) . Value ) ;
1760
+ }
1761
+ catch
1762
+ {
1763
+ // we just ignore if the value is not a valid version
1764
+ }
1765
+ }
1766
+ }
1767
+ if ( version != null
1768
+ && IsPowerShellVersionSupported ( version ) )
1769
+ {
1770
+ allKeys = GetModuleManifestKeys ( version ) ;
1771
+ }
1772
+ else
1773
+ {
1774
+ // default to version 5.1
1775
+ allKeys = GetModuleManifestKeys ( new Version ( "5.1" ) ) ;
1776
+ }
1777
+ }
1778
+
1779
+ // check if the keys given in module manifest are a proper subset of Keys
1780
+ return map . Keys . All ( x => allKeys . Concat ( deprecatedKeys ) . Contains ( x , StringComparer . OrdinalIgnoreCase ) ) ;
1781
+ }
1605
1782
#endregion Methods
1606
1783
}
1607
1784
0 commit comments