确定 PowerShell 模块的 .NET 和 CLR 要求

Determine .NET and CLR requirements for your PowerShell modules

模块清单让我们指定 .NET 和 CLR 的要求,来自清单的示例 *.psd1

# Minimum version of Microsoft .NET Framework required by this module.
# This prerequisite is valid for the PowerShell Desktop edition only.
DotNetFrameworkVersion = "3.5"

# Minimum version of the common language runtime (CLR) required by this module.
# This prerequisite is valid for the PowerShell Desktop edition only.
CLRVersion = "2.0"

我有几个正在开发的模块,但我无法找到一些资源来帮助我指定我的模块所需的最低版本。

为了解决这个问题,我正在考虑编写一个正则表达式脚本,该脚本将扫描模块中使用的 .NET 类型,例如该脚本将收集以下类型:

[System.Net.IPAddress]
[System.Management.Automation.ValidateUserDriveAttribute]

根据使用的类型,我可以查看引入了哪些版本的 .NET 和 CLR。​​

然后我也可以 运行 使用旧版本的 PowerShell 进行测试,但仅限于“核心”版本,我不确定是否可以安装旧的 Windows PowerShell。

这需要大量工作,我什至不确定这是否能解决我的问题,您是否知道可用于学习需求的更好方法?

I'm thinking about writing a regex script that will scan modules for .NET types

它不会给你一个完整的画面,但它是一个好的开始!

不过我要强调一件事 - 不要将正则表达式用于此类静态分析!

PowerShell 公开了它的语言解析器,所以用它来生成一个抽象语法树,然后你可以用它来发现诸如类型文字名称之类的东西:

using namespace System.Management.Automation.Language

Get-ScriptTypeLiteral
{
  param([string]$LiteralPath)

  $filePath = Resolve-Path @PSBoundParameters

  # Step 1, parse the file to produce an AST
  $AST = [Parser]::ParseFile($filePath, [ref]$null, [ref]$null)

  # Step 2, find all type literals
  $TypeLiterals = $AST.FindAll({
    param($SubAST) 
    # Type literals come in two variants - expressions and attributes 
    # Expressions are things like the first half of `[type]::Member`
    # Attributes cover things like [ValidateLength()] as well as type constraints in param blocks
    $SubAST -is [TypeExpressionAst] -or $SubAST -is [AttributeAst]
  }, $true)

  # Step 3, return the type names
  return $TypeLiterals.TypeName
}

您可以进一步采用这种方法,并使用它来发现诸如 member access expressions 之类的东西,以将跨版本的 BCL 类型差异也考虑在内。

虽然我从未将它用于此特定目的,但我怀疑您可以利用 PSScriptAnalyzer 通过自定义规则简化此过程。

This is all together a lot of work and I'm not even sure if that answers my concern, do you know of better method that could be used to learn requirements?

我不确定我是否会考虑上述任何“最佳实践”,但可能值得在 the PowerShell GitHub repo

中提交问题寻求指导

在@Mathias 回答的帮助下,我进行了一些研究并找到了非常简单且准确率达到 90% 的解决方案。

第一步是为 PSScriptAnalyzer 定义规则,该规则应在文件 PSScriptAnalyzerSettings.psd1 中定义,并将其放入存储库的根目录中。

文件应包含此规则:

@{
    IncludeRules = @(
    
    'PSUseCompatibleCmdlets'
    'PSUseCompatibleSyntax'
    
     Rules = @{

        PSUseCompatibleSyntax = @{
            Enable = $true
            TargetVersions = @(
                "7.0",
                "5.1"
            )
        }

        PSUseCompatibleCmdlets = @{
            compatibility = @(
                "core-6.1.0-windows"
                "desktop-5.1.14393.206-windows"
            )
         }
      }
   )
}

然后从存储库的根目录调用分析器:

Invoke-ScriptAnalyzer .\ -Recurse -Settings .\PSScriptAnalyzerSettings.psd1

这会让您知道您的模块是否调用了与 Core 6.1 或 Desktop 5.1 不兼容的命令行开关

如果收到警告,则表明不支持这些版本,这意味着需要在更高的 PowerShell 版本上执行测试。

为什么这很重要?它是关于 PowerShell 版本的,而不是关于 .NET 或 CLR 的…… 另外,如果 5.1 是最新版本,您如何测试更高的 Windows PowerShell 版本?

上面的规则中还有一个版本号是14393,可能会报告问题,下一步是确定这个版本的Windows版本,这样做见:

Windows 10 release information

从这里我们看到内部版本号是 Windows v1607.

下一步是查看哪个版本的 .NET 包含在哪个 Windows 版本中,具体请参见:

.NET Framework versions and dependencies

从这里我们看到包含在 Windows 10 中的最低 .NET 版本是 .NET Framework 4.6,它取决于 CLR 4.0

至此,一切都归结为您的模块将部署在哪些系统上,如果您从 PSScriptAnalyzer 收到警告,那么最低限度是 .NET 4.6 和 CLR 4.0

下一步是确定您的模块失败的确切 OS 内部版本号,请参阅:

Determine which .NET Framework versions are installed

这应该有点帮助,但需要进行测试,所以我对大致结果很满意。