如何在PowerShell中创建类似Pester的DSL?
Vester项目创建的pester测试遵循特定的模式,即描述、It、尝试、捕获、更新以测试,然后修复VMWare环境中的问题,例如 在半伪码中,算法的核心是:如何在PowerShell中创建类似Pester的DSL?,powershell,Powershell,Vester项目创建的pester测试遵循特定的模式,即描述、It、尝试、捕获、更新以测试,然后修复VMWare环境中的问题,例如 在半伪码中,算法的核心是: Param( [switch]$Remediate = $false ) Process { Describe -Name "Test Group Name" -Tag @("Tag") -Fixture { #Some code to load up state for the test group
Param(
[switch]$Remediate = $false
)
Process {
Describe -Name "Test Group Name" -Tag @("Tag") -Fixture {
#Some code to load up state for the test group
foreach ($Thing in $Things) {
It -name "Name of first test" -test {
#Some code to load up state for the test
try {
#Conditional tests using Pester syntax
} catch {
if ($Remediate) {
Write-Warning -Message $_
Write-Warning -Message "Remediation Message"
#Code to remediate issues
} else {
throw $_
}
}
}
}
}
}
我希望能够编写代码,以支持以下类似纠缠的DSL语法:
Param(
[switch]$Remediate = $false
)
CheckGroup "AD User Checks" {
ForEach($Aduser in (Get-aduser -Filter * -Properties HomeDirectory)) {
Check "Home directory path exists" {
Condition {
if ($Aduser.HomeDirectory) {
Test-path $Aduser.HomeDirectory | Should be $true
}
}
Remdiation "Create home directory that doesn't exist" {
New-Item -ItemType Directory -Path $Aduser.HomeDirectory
}
}
}
}
运行此操作将导致实际运行以下内容:
Describe -Name "AD User Checks" -Fixture {
ForEach($Aduser in (Get-aduser -Filter * -Properties HomeDirectory)) {
It -name "Home directory path exists" -test {
try {
if ($Aduser.HomeDirectory) {
Test-path $Aduser.HomeDirectory | Should be $true
}
} catch {
if ($Remediate) {
Write-Warning -Message $_
Write-Warning -Message "Create home directory that doesn't exist"
New-Item -ItemType Directory -Path $Aduser.HomeDirectory
} else {
throw $_
}
}
}
}
}
我如何实现这个专门为执行检查和修正而设计的DSL
以下是我为实现这一目标而编写的一些代码:
Function CheckGroup {
param (
[Parameter(Mandatory, Position = 0)][String]$Name,
[Parameter(Position = 1)]$CheckGroupScriptBlock
)
Describe $CheckGroupName -Fixture $CheckGroupScriptBlock
}
Function Check {
param (
[Parameter(Mandatory, Position = 0)][String]$Name,
$ConditionScriptBlock,
$RemediationScriptBlock
)
It -name $Name -test {
try {
& $ConditionScriptBlock
} catch {
& $RemediationScriptBlock
}
}
}
Function Condition {
[CmdletBinding()]
param (
[Parameter(Position = 1)]$ScriptBlock
)
& $ScriptBlock
}
Function Remediation {
[CmdletBinding()]
param (
$Name,
[Parameter(Position = 1)]$ScriptBlock,
[bool]$Remediate = $false
)
if ($Remediate) {
Write-Verbose $_
Write-Verbose $Name
& $ScriptBlock
} else {
throw $_
}
}
对于函数
Check
,我确实需要能够将单个脚本块作为参数,但不知何故,在传递的脚本块中找到条件
和修正
函数调用,并将它们从脚本块中分离出来,并将它们混合到Try{}Catch{}中的适当位置
在It
函数中的检查中。您发布的示例不是Pester的子集(也不是超集)-它只是另一个DSL-这里真正的问题是什么?@MathiasR.Jessen谢谢,我已将问题更改为删除对子集的任何引用,我在问如何在PowerShell中实现此DSL。我列出了使用Pester的PowerShell代码,但我希望代码更加枯燥,我尝试实现DSL的方法都有问题。您到底尝试了什么,遇到了什么问题?一种明显的方法是将CheckGroup
定义为descripe
的别名,然后将Check
定义为接受字符串和脚本块的函数。修改scriptblock AST并调用It
@MathiasR.Jessen“修改scriptblock AST”这是我一直坚持的部分,我不知道如何使用脚本块AST,尽管我看到它是脚本块对象的属性。不过我真的很想学这个。我会尽快发布我尝试过的代码,这会让这个问题变得太长,但这可能是错误的决定。感谢您发布的示例不是Pester的子集(也不是超集)-它只是另一个DSL-这里真正的问题是什么?@MathiasR.Jessen谢谢,我已经更改了问题以删除对子集的任何引用,我想问如何在PowerShell中实现此DSL。我列出了使用Pester的PowerShell代码,但我希望代码更加枯燥,我尝试实现DSL的方法都有问题。您到底尝试了什么,遇到了什么问题?一种明显的方法是将CheckGroup
定义为descripe
的别名,然后将Check
定义为接受字符串和脚本块的函数。修改scriptblock AST并调用It
@MathiasR.Jessen“修改scriptblock AST”这是我一直坚持的部分,我不知道如何使用脚本块AST,尽管我看到它是脚本块对象的属性。不过我真的很想学这个。我会尽快发布我尝试过的代码,这会让这个问题变得太长,但这可能是错误的决定。谢谢