在Powershell中不间断地检查多个条件

时间:2016-06-29 15:56:29

标签: powershell

我正在研究域控制器的验证脚本。我有一个帐户,有4件事我需要验证。我所使用的代码,但如果其中一个条件不满足,我不希望它破坏,这就是它现在正在做的事情。所以,基本上我需要检查所有4个标准,无论条件是否满足。

这是我的代码:

static int cmp_int(const void *ap, const void *bp)
{
  const int a = *(const int *) ap, b = *(const int *) bp;
  return a < b ? -1 : a > b;
}

static bool in_sprawling_set(int data)
{
  static const int values[] = { 125, 500, 750 };
  return bsearch(&data, values, sizeof values / sizeof *values, sizeof *values, cmp_int) != 0;
}

如果不满足任何条件,它会破坏else语句,但我需要它继续检查每个条件。

我知道我可以打破这个并单独检查每个条件,但我更喜欢尽可能压缩它,因为它已经超过一千行。

我想真正的问题是,如果可以在不制作4个独立的IF / ELSE语句的情况下完成。

我不确定它是否存在结构问题(嵌套IF)或命令问题(当我应该使用IF和ELSEIF时使用IF和ELSE)。

有人能指出我正确的方向吗?提前谢谢。

2 个答案:

答案 0 :(得分:4)

未经测试,但这可能是一个起点,尽管您可以选择多个if语句的简单性。

$user = 'user.dadm'

$info = [ordered]@{
    created = "[X] $user was not created"
    neverexp = "[X] Password for $user has been set to expire"
    admin = "[X] $user was not added to Domain Admins"
    delegation = "[X] Account Delegation for $user was not removed"
}

switch ($true) {
    {net user $user} {
        $info.created = "[√] $user was created successfully"
    }

    {((uACADA $user) -band 65536) -ne 0} {
        $info.neverexp = "[√] Password for $user is set to never expire"
    }

    {(Get-ADGroupMember -Identity 'Domain Admins').Name -contains $user} {
        $info.admin = "[√] $user was added to Domain Admins"
    }

    {((uACADA $user) -band 1048576) -ne 0} {
        $info.delegation = "[√] Account Delegation Authority for $user was removed"
    }

    default {Write-Host 'all are false'}
}

$info.Keys | % {
    if ($info.$_.startswith('[X]')) {
        Write-Host $($info.$_) -ForegroundColor Red
    } else {
        Write-Host $($info.$_) -ForegroundColor Green
    }
}

答案 1 :(得分:3)

是的,您可以在没有if测试的情况下编写它,例如

$colors = @('Red', 'Green')
$messages = @('[X] Failed -', '[√] Succeeded -')

$username = "user.adm"

$result = [bool](net user "$username")
Write-Host "$($messages[$result]) Check user account exists" -ForegroundColor $colors[$result]

$result = [bool]((uACADA "$username") -band 65536)
Write-Host "$($messages[$result]) Check password never expires" -ForegroundColor $colors[$result]

$result = [bool]((Get-ADGroupMember -Identity "Domain Admins").Name -contains "$username")
Write-Host "$($messages[$result]) Check account is a domain admin" -ForegroundColor $colors[$result]

$result = [bool]((uACADA "$username") -band 1048576)
Write-Host "$($messages[$result]) Check Delegation Authority removed" -ForegroundColor $colors[$result]

NB。如果你没有使用if/else,你需要一些其他方法来进行真/假测试。我将结果转换为[bool]并使用2元素数组。 $array[$false]投射$false -> 0并获取元素0,$array[$true]投射$true -> 1并获取元素1.这就是将结果转换为适当颜色和消息的方式。

写这个的另一个合理方法是将Write-Hosts移动到一个函数中。

Function Report-Result { 
    param($Result, $Text)
    if ($Result) {
        Write-Host "Success - $Text" -Fore Green
    } else {
        Write-Host "Failure - $text" -Fore Red
    }
}

$result = [bool](...)
report-result $result "Check password never expires"

... etc.

输出如下:

Screenshot of first example code's output

哪个是好的 - 它将你的20行代码降低到~10,并且没有嵌套,并运行所有测试。

但是真的感觉你正在重新发明PowerShell DSC(“我希望的状态是最终帐户的.adm将密码设置为永不过期”)或Pester - PowerShell的测试框架, (“测试所有.adm帐户的密码设置为永不过期”)。

我不确定你是否可以将Pester完全适合你的用例,但它让我觉得我会改变脚本的所有内容,从结构的方式到输出消息,使它看起来像Pester。特别是我希望明确区分测试定义和打印输出,例如:

1. Here are my tests, with self-explanatory names
2. Here is a loop which runs all tests, and reports on them

这给了我类似的东西:

Function Validate-DCUserAccountShouldExist {
    param($Username) [bool](net user "$UserName")
}

Function Validate-DCUserAccountPasswordNeverExpireShouldBeSet {
    param($Username) [bool]((uACADA "$username") -band 65536)
}

Function Validate-DCUserAccountShouldBeADomainAdmin {
    param($Username) [bool]((Get-ADGroupMember -Identity "Domain Admins").Name -contains "$username")
}

Function Validate-DCUserAccountShouldHaveDelegationAuthorityRemoved {
    param($Username) [bool]((uACADA "$Username") -band 1048576)
}

# Search for all Validation functions and run them
$tests = (gci function: |Where Name -Like 'Validate-DCUserAccount*').Name

foreach ($test in $tests) {
    $result = try {
            & $test "user.adm" 
         } catch { 
            $false 
         }

    if ($result) {
        Write-Host -ForegroundColor Green "[√] $test - succeeded"
    } else {
        Write-Host -ForegroundColor Red "[X] $test - Failed"
    }
}

其中输出如下:

Screenshot of second example code's output

我对第二个代码的看法是:

  • 时间更长
  • 更复杂,更不容易理解
  • 写入主机的重复次数少很多
  • 更有条理,分离测试定义和输出
  • 函数名称解释了应该的状态,这使输出消息成功/失败
  • 输出消息在代码中更整洁,但在输出中读取更难(但可以调整,例如在打印时添加空格)
  • 可以很好地扩展到更多测试,只需添加更多测试