错误时跳过脚本的一部分

Mit*_*own 2 powershell foreach if-statement try-catch active-directory

在这个问题上,我一直在撞墙一段时间.到目前为止,谷歌没有任何成功的结果.想知道是否有人可以帮助我?

# Load the PowerShell module for Active Directory
Import-Module ActiveDirectory

# For each computer in AD that is a member of the target group
Get-ADGroupMember -Identity "CN=RenameComputer,CN=Users,DC=int,DC=example,DC=com" | ForEach {

        # Define the new name as the old one, minus one letter at the end
        $NewComputerName = $_.Name -replace ".$"

        # Perform the rename operation
        Rename-Computer -ComputerName $_.Name -NewName $NewComputerName -Force -PassThru -Restart -WhatIf

        # Remove the computer from the target group
        # THIS SHOULD NOT OCCUR IF THE RENAME ABOVE FAILED!!!
        Remove-ADGroupMember -Identity "CN=RenameComputer,CN=Users,DC=int,DC=example,DC=com" -Members $NewComputerName -WhatIf

}
Run Code Online (Sandbox Code Playgroud)

TL; DR:此脚本查找指定组中的一组计算机,重命名它们,然后将其从组中删除.我需要帮助告诉脚本在重命名失败(机器脱机等)或抛出一些错误的情况下不要将它们从组中删除.

思考?

提前致谢!

Ben*_*est 5

有几种方法可以在Powershell中检查cmdlet的结果.

将cmdlet作为if语句条件运行

您可以使用cmdlet返回的对象作为if语句条件,只要它成功返回一个对象(这就是为什么我们需要-PassThruRename-Computer,因为通常它不会返回一个对象).所以以你的代码为例(并删除-WhatIf):

# If Rename-Computer succeeds...
if( Rename-Computer -ComputerName $_.Name `
  -NewName $NewComputerName -Force -PassThru -Restart ) {

  # then remove the Computer from group 
  Remove-ADGroupMember -Identity "CN=RenameComputer,CN=Users,DC=int,DC=example,DC=com" `
   -Members $NewComputerName

}
Run Code Online (Sandbox Code Playgroud)

这是有效的,因为Powershell中的对象是真实的.考虑大多数已定义的对象和除0(零)以外的任何数字$True,但是将值$null,""(空字符串)和0(零)等值评估为$False.因此,对于您的代码,如果成功,将返回一个对象($True),如果发生错误,则不会返回任何对象($ False).

显式检查cmdlet结果

或者,您可以Rename-Computer先运行,然后检查其成功:

Rename-Computer -ComputerName $_.Name -NewName $NewComputerName -Force

# Check success of last cmdlet
if( $? ) {
  Remove-ADGroupMember -Identity "CN=RenameComputer,CN=Users,DC=int,DC=example,DC=com" `
   -Members $NewComputerName
}
Run Code Online (Sandbox Code Playgroud)

$?评估最后一次cmdlet运行的成功(不要混淆它$LASTEXITCODE,用于检查上次运行的程序结果,而不是cmdlet结果).如果cmdlet成功,则返回$True(如果不是)$False.

捕获Try/Catch块中的错误

第三种方法是使用一个try/catch块,但是你必须确保任何错误都在终止(如果未被捕获将停止脚本)以捕获异常.你可以使用-ErrorAction Stopparemeter:

    try {

      Rename-Computer -ComputerName $_.Name -NewName $NewComputerName -Force `
        -PassThru -Restart -ErrorAction Stop

      Remove-ADGroupMember -Identity "CN=RenameComputer,CN=Users,DC=int,DC=example,DC=com" `
        -Members $NewComputerName

    } catch {
      # Do something on failure
      Write-Warning "An error occurred: $($_.Exception.Message)"
    }
Run Code Online (Sandbox Code Playgroud)

如果Rename-Computertry块中抛出错误,它将失败,执行跳转到catch块并将跳过Remove-ADGroupMember.如果使用a try/catch是您首选的错误处理方法,则可以考虑$ErrorActionPreference = 'Stop'在脚本中设置默认-ErrorAction行为Stop,并且不必在每个cmdlet上指定它.

附加信息

以下是Powershell 中的一些官方文档try/catch/finallyif声明.我没有在finally上面介绍,但这是try/catch声明的可选部分:

关于如果:https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_if?view=powershell-6

关于Try/Catch/Last:https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_try_catch_finally?view=powershell-6

以下是关于异常,错误以及在Powershell中处理它们的一些高级信息:https://kevinmarquette.github.io/2017-04-10-Powershell-exceptions-everything-you-ever-wanted-to-know/