简体   繁体   English

验证 PowerShell 中的 function 已成功运行

[英]Verify a function in PowerShell has run succesfully

I'm writing a script to backup existing bit locker keys to the associated device in Azure AD, I've created a function which goes through the bit locker enabled volumes and backs up the key to Azure however would like to know how I can check that the function has completed successfully without any errors. I'm writing a script to backup existing bit locker keys to the associated device in Azure AD, I've created a function which goes through the bit locker enabled volumes and backs up the key to Azure however would like to know how I can check function 已成功完成,没有任何错误。 Here is my code.这是我的代码。 I've added a try and catch into the function to catch any errors in the function itself however how can I check that the Function has completed succesfully - currently I have an IF statement checking that the last command has run "$? - is this correct or how can I verify please?我在 function 中添加了一个 try and catch 来捕获 function 本身的任何错误但是我如何检查 Z86408593C34AF77FDD90DF932F8 是否已成功运行正确或我该如何验证?

    function Invoke-BackupBDEKeys {

        ##Get all current Bit Locker volumes - this will ensure keys are backed up for devices which may have additional data drives
        $BitLockerVolumes = Get-BitLockerVolume | select-object MountPoint
        foreach ($BDEMountPoint in $BitLockerVolumes.mountpoint) {

            try {
            #Get key protectors for each of the BDE mount points on the device
            $BDEKeyProtector = Get-BitLockerVolume -MountPoint $BDEMountPoint | select-object -ExpandProperty keyprotector
            #Get the Recovery Password protector - this will be what is backed up to AAD and used to recover access to the drive if needed
            $KeyId = $BDEKeyProtector | Where-Object {$_.KeyProtectorType -eq 'RecoveryPassword'}
            #Backup the recovery password to the device in AAD
            BackupToAAD-BitLockerKeyProtector -MountPoint $BDEMountPoint -KeyProtectorId $KeyId.KeyProtectorId
            }
             catch {
                 Write-Host "An error has occured" $Error[0] 
            }
        }
    }     

#Run function
    Invoke-BackupBDEKeys

if ($? -eq $true) {

    $ErrorActionPreference = "Continue"
    #No errors ocurred running the last command - reg key can be set as keys have been backed up succesfully
    $RegKeyPath = 'custom path'
    $Name = 'custom name'
    New-ItemProperty -Path $RegKeyPath -Name $Name -Value 1 -Force
    Exit
}
 else {
    Write-Host "The backup of BDE keys were not succesful"
    #Exit
}
  • Unfortunately, as of PowerShell 7.2.1, the automatic $?不幸的是,从 PowerShell 7.2.1 开始, 自动$? variable has no meaningful value after calling a written-in-PowerShell function (as opposed to a binary cmdlet ) - unless the function call is aborted by a terminating error .在调用写入 PowerShell function(与二进制 cmdlet相对)变量没有有意义的值-除非 function 调用因终止错误而中止 (More immediately, even inside the function, $? only reflects $false at the very start of the catch block, as Mathias notes). (更直接的是,即使function 内部, $?也仅在catch块的最开始反映$false ,正如 Mathias 所指出的)。

    • If PowerShell functions had feature parity with binary cmdlets, then emitting at least one non-terminating error with Write-Error would set $?如果 PowerShell 函数与二进制 cmdlet 具有功能奇偶性,则发出至少一个带有Write-Error的非终止错误将设置$? in the caller's scope to $false , but that is currently not the case.在调用者的 scope 到$false ,但目前情况并非如此。

    • You can work around this limitation by using $PSCmdlet.WriteError() from an advanced function or script, but that is quite cumbersome.您可以通过使用高级function或脚本中的$PSCmdlet.WriteError()来解决此限制,但这非常麻烦。 The same applies to $PSCmdlet.ThrowTerminatingError() , which is the only way to create a statement -terminating error from PowerShell code.这同样适用于$PSCmdlet.ThrowTerminatingError() ,这是从 PowerShell 代码创建语句终止错误的唯一方法。 (By contrast, the throw statement generates a script -terminating error, ie terminates the entire script and its callers). (相比之下, throw语句会产生一个脚本终止错误,即终止整个脚本及其调用者)。

    • See this answer for more information and links to relevant GitHub issues.有关更多信息和相关 GitHub 问题的链接,请参阅此答案

  • As a workaround , I suggest:作为一种解决方法,我建议:

    • Make your function relay caught errors via Write-Error .使您的 function 继电器通过Write-Error捕获错误。

    • Make your function an advanced one, so as to enable support for the common -ErrorVariable parameter - it allows you to collect all non-terminating errors emitted by the function in a self-chosen variable.使您的 function 成为高级的,以便支持常见的-ErrorVariable参数- 它允许您在自选变量中收集 function 发出的所有非终止错误。

      • You can combine this with the common -ErrorAction parameter to initially silence the errors ( -ErrorAction SilentlyContinue ), so you can emit them later on demand.您可以将其与常见的-ErrorAction参数结合使用,以最初使错误静音( -ErrorAction SilentlyContinue ),以便稍后根据需要发出它们。
    • After invocation, check if any errors were collected, to determine whether at least one key wasn't backed up successfully.调用后,检查是否收集到任何错误,以确定是否至少有一个密钥没有备份成功。

Here's the outline of this approach:以下是这种方法的概要:

function Invoke-BackupBDEKeys {
  # Make the function an *advanced* function, to enable
  # support for -ErrorVariable (and -ErrorAction)
  [CmdletBinding()]
  param()

  # ...
  foreach ($BDEMountPoint in $BitLockerVolumes.mountpoint) {

    try {
      # ... statements that may cause terminating errors.
      # Note: Non-terminating errors are NOT caught and are emitted
      #       to the error stream - unless $ErrorActionPreference = 'Stop'
      #       is in effect or -ErrorAction Stop was passed.
    }
    catch {
      # Convert the caught terminating error to a non-terminating one
      # and cotinue the loop.      
      $_ | Write-Error
    }
  }
}     

# Call the function and collect any
# non-terminating errors in variable $errs.
Invoke-BackupBDEKeys -ErrorAction SilentlyContinue -ErrorVariable errs

# If $errs is an empty collection, no errors occurred.
if (-not $errs) {

  "No errors occurred"
  # ... 
}
else {
  "At least one error occurred during the backup of BDE keys:`n$errs"
  # ...
}

As stated elsewhere, the try/catch you're using is what is preventing the relay of the error condition.如其他地方所述,您正在使用的 try/catch 是阻止错误条件中继的原因。 That is by design and the very intentional reason for using try/catch.这是设计使然,也是使用 try/catch 的有意原因。

What I would do in your case is either create a variable or a file to capture the error info.在您的情况下,我会做的是创建一个变量或一个文件来捕获错误信息。 My apologies to anyone named 'Bob'.我向任何名为“鲍勃”的人道歉。 It's the variable name that I always use for quick stuff.这是我总是用于快速处理的变量名。

Here is a basic sample that works:这是一个有效的基本示例:

$bob = (1,2,"blue",4,"notit",7)

$bobout = @{}                               #create a hashtable for errors

foreach ($tempbob in $bob) {
   $tempbob
   try {
      $tempbob - 2                          #this will fail for a string
   } catch {
      $bobout.Add($tempbob,"not a number")  #store a key/value pair (current,msg)
   }
}

$bobout                                     #output the errors

Here we created an array just to use a foreach.在这里,我们创建了一个数组只是为了使用 foreach。 Think of it like your $BDEMountPoint variable.把它想象成你的 $BDEMountPoint 变量。

Go through each one, do what you want. Go 通过每一个,做你想做的。 In the }catch{}, you just want to say "not a number" when it fails.在 }catch{} 中,您只想在失败时说“不是数字”。 Here's the output of that:这是 output :

-1
0
2
5

Name                           Value
----                           -----
notit                          not a number
blue                           not a number

All the numbers worked (you can obvious surpress output, this is just for demo).所有的数字都有效(你可以明显地忽略 output,这只是为了演示)。 More importantly, we stored custom text on failure.更重要的是,我们在失败时存储了自定义文本。

Now, you might want a more informative error.现在,您可能需要更多信息错误。 You can grab the actual error that happened like this:您可以抓住这样发生的实际错误:

$bob = (1,2,"blue",4,"notit",7)

$bobout = @{}                               #create a hashtable for errors

foreach ($tempbob in $bob) {
   $tempbob
   try {
      $tempbob - 2                          #this will fail for a string
   } catch {
      $bobout.Add($tempbob,$PSItem)         #store a key/value pair (current,error)
   }
}

$bobout

Here we used the current variable under inspection $PSItem, also commonly referenced as $_.这里我们使用了当前被检查的变量$PSItem,通常也被称为$_。

-1
0
2
5

Name                           Value
----                           -----
notit                          Cannot convert value "notit" to type "System.Int32". Error: "Input string was not in ...
blue                           Cannot convert value "blue" to type "System.Int32". Error: "Input string was not in a...

You can also parse the actual error and take action based on it or store custom messages.您还可以解析实际错误并根据它采取措施或存储自定义消息。 But that's outside the scope of this answer.但这不在此答案的 scope 范围内。 :) :)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 第一个 Powershell 函数和正则表达式来验证用户输入 - First Powershell Function and Regex to verify user input 从Python脚本运行PowerShell函数 - Run PowerShell function from Python script 在命令行中使用参数运行 PowerShell 脚本(函数) - Run PowerShell script(Function) with parameters in command line Powershell:每次从函数运行时添加数据的函数 - Powershell: Function that adds data every time it is run from a function Powershell功能-在一种情况下,参数必须是必需的,在另一种情况下,则必须是可选的 - Powershell function - parameter has to be mandatory in one case, optional in another 使用“使用PowerShell运行”执行时,在另一个脚本中调用函数 - Call a function in another script when executing using 'Run With PowerShell' 获取 PowerShell 函数以在运行期间将表格写入屏幕但不附加为返回 - Get PowerShell function to write a table to the screen during a run but not append as a return PowerShell 从 Windows 表单 add_click 运行“函数”(不是脚本) - PowerShell run a 'function' (not a script) from a Windows Form add_click 仅在上一个函数完成后才允许Javascript函数运行 - Only allowing a Javascript function to run when the previous function has finished 强制一个javascript函数等待运行,直到第一个函数完成 - forcing one javascript function to wait to run until the first has finished
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM