从PowerShell cmdlet返回错误的最佳做法是什么?

时间:2021-02-13 21:18:29

I am writing a PowerShell-based XML module for our application configuration needs. Following is the one of the functions.

我正在为我们的应用程序配置需求编写基于PowerShell的XML模块。以下是其中一项功能。

<#
.Synopsis
   To update an XML attribute value
.DESCRIPTION
   In the XML file for a particular attribute, if it contains valueToFind then replace it with valueToReplace
.EXAMPLE

-------------------------------Example 1 -------------------------------------------------------------------
   Update-XMLAttribute -Path "C:\web.Config" -xPath "/configuration/system.serviceModel/behaviors/serviceBehaviors/behavior/serviceMetadata" -attribute "externalMetadataLocation" -valueToFind "http:" -ValueToReplace "https:"

   Look for the XPath expression with the attribute mentioned and search whether the value contains "http:". If so, change that to "https":
.EXAMPLE

-------------------------------Example 2 -------------------------------------------------------------------
   Update-XMLAttribute -Path "C:\web.Config" -xPath "/configuration/system.serviceModel/behaviors/serviceBehaviors/behavior/serviceMetadata" -attribute "externalMetadataLocation" -valueToFind "http:" -ValueToReplace "https:"

   Same as Example 1 except that the attribute name is passed as part of the XPath expression

#>
function Update-XMLAttribute
{
    [CmdletBinding()]
    [OutputType([int])]
    Param
    (
        # Web configuration file full path
        [Parameter(Mandatory=$true,
                   ValueFromPipelineByPropertyName=$true,
                   Position=0)]
        [string]$Path,

        # XPath expression up to the parent node
        [string] $xPath,
        # This parameter is optional if you mentioned it in xPath itself
        [string] $attribute,

        [string] $valueToFind,

        [string] $ValueToReplace
    )

    Try
    {
        If (Test-path -Path $Path)
        {
                    $xml = New-Object XML
                    $xml.Load($Path)

                    # If the xPath expression itself contains an attribute name then the value of attribute will be processed and taken
                    If ($xPath.Contains("@")) {
                        $xPath, $attribute = $xPath -split '/@', 2
                    }

                    # Getting the node value using xPath
                    $Items  = Select-Xml -XML $xml -XPath $xPath
                    ForEach ($Item in $Items)
                    {

                        $attributeValue = $Item.node.$attribute
                        Write-Verbose "Attribute value is $attributeValue "

                        if ($attributeValue.contains($valueToFind)) {


                            Write-Verbose "In the attribute $attributeValue - $valueToFind is to be repalced with $ValueToReplace"
                            $Item.node.$attribute = $attributeValue.replace($valueToFind, $ValueToReplace)
                        }
                    }

                    $xml.Save($Path)
                    Write-Verbose " Update-XMLAttribute is completed successfully"
        }
        Else {
            Write-Error " The $path is not present"
        }

    }
    Catch {
        Write-Error "$_.Exception.Message"
        Write-Error "$_.Exception.ItemName"
        Write-Verbose " Update-XMLAttribute is failed"
    }
} # End Function Update-XMLAttribute

As this cmdlet will be consumed by many I don't think simply writing into console will be the right approach.

由于这个cmdlet将被许多人使用,我不认为简单地写入控制台将是正确的方法。

As of now in my script if no errors, I can assume that mine is successfully completed.

截至目前在我的脚本中如果没有错误,我可以认为我的成功完成了。

What is the standard practice to get the results from a PowerShell cmdlet so that the consumer knows whether it is successfully completed or not?

从PowerShell cmdlet获取结果以便消费者知道它是否成功完成的标准做法是什么?

3 个解决方案

#1


The standard practice is to throw exceptions. Each different type of error has a separate exception type which can be used to diagnose further.

标准做法是抛出异常。每种不同类型的错误都有一个单独的异常类型,可用于进一步诊断。

Say, file is not represented, you do this:

比如,文件没有表示,你这样做:

if (-not (Test-Path $file))
{
    throw [System.IO.FileNotFoundException] "$file not found."
}

Your cmdlet should document all the possible exceptions it will throw, and when.

您的cmdlet应记录它将抛出的所有可能的异常,以及何时。

#2


Your function should throw if it runs into an error. Leave it to the caller to decide how the error should be treated (ignore, log a message, terminate, whatever).

如果遇到错误,您的函数应该抛出。将它留给调用者来决定如何处理错误(忽略,记录消息,终止,等等)。

#3


While you can throw an exception, which PowerShell will catch and wrap in an ErrorRecord, you have more flexibility using the ThrowTerminatingError method. This is the typical approach for a C# based cmdlet.

虽然您可以抛出一个异常,PowerShell将捕获并包装在ErrorRecord中,但您可以使用ThrowTerminatingError方法获得更大的灵活性。这是基于C#的cmdlet的典型方法。

ThrowTerminatingError(new ErrorRecord(_exception, _exception.GetType().Name, ErrorCategory.NotSpecified, null));

This allows you to pick an error category and provide the target object. BTW what you have above isn't what I'd call a cmdlet. Cmdlets are compiled C# (typically). What you have is an advanced function. :-)

这允许您选择错误类别并提供目标对象。顺便说一下,你所拥有的不是我称之为cmdlet的东西。 Cmdlet编译为C#(通常)。你拥有的是一项先进的功能。 :-)

From an advanced function you can access this method like so:

从高级功能,您可以像这样访问此方法:

$pscmdlet.ThrowTerminatingError(...)

#1


The standard practice is to throw exceptions. Each different type of error has a separate exception type which can be used to diagnose further.

标准做法是抛出异常。每种不同类型的错误都有一个单独的异常类型,可用于进一步诊断。

Say, file is not represented, you do this:

比如,文件没有表示,你这样做:

if (-not (Test-Path $file))
{
    throw [System.IO.FileNotFoundException] "$file not found."
}

Your cmdlet should document all the possible exceptions it will throw, and when.

您的cmdlet应记录它将抛出的所有可能的异常,以及何时。

#2


Your function should throw if it runs into an error. Leave it to the caller to decide how the error should be treated (ignore, log a message, terminate, whatever).

如果遇到错误,您的函数应该抛出。将它留给调用者来决定如何处理错误(忽略,记录消息,终止,等等)。

#3


While you can throw an exception, which PowerShell will catch and wrap in an ErrorRecord, you have more flexibility using the ThrowTerminatingError method. This is the typical approach for a C# based cmdlet.

虽然您可以抛出一个异常,PowerShell将捕获并包装在ErrorRecord中,但您可以使用ThrowTerminatingError方法获得更大的灵活性。这是基于C#的cmdlet的典型方法。

ThrowTerminatingError(new ErrorRecord(_exception, _exception.GetType().Name, ErrorCategory.NotSpecified, null));

This allows you to pick an error category and provide the target object. BTW what you have above isn't what I'd call a cmdlet. Cmdlets are compiled C# (typically). What you have is an advanced function. :-)

这允许您选择错误类别并提供目标对象。顺便说一下,你所拥有的不是我称之为cmdlet的东西。 Cmdlet编译为C#(通常)。你拥有的是一项先进的功能。 :-)

From an advanced function you can access this method like so:

从高级功能,您可以像这样访问此方法:

$pscmdlet.ThrowTerminatingError(...)