PowerShell模块不按预期进行点源/导入功能

时间:2017-07-07 12:38:32

标签: powershell azure-powershell

更新1: 最初,我发布了标题:“脚本忽略了PowerShell模块中的错误处理”,因为这是当前的问题,但它似乎更像是一个模块问题,所以我重命名了标题。

更新2: 在一条让我对Azure cmdlet提出疑问的评论之后,我已经测试了最基本的脚本(添加到模块中)并且结果是相同的,因为错误没有传递给调用脚本,但是,添加了{{ 1}} Get-Service确实返回了一些我可能在处理错误时可以利用的东西(<{1}}除外):

-errorVariable

返回:

WriteErrorException

但是,如果我在ISE中运行“Test-MyError”,那么调用该函数,我得到:

function Test-MyError($Variable)
{
    Try
    {
        Get-Service -Name $variable -ErrorAction Stop -ErrorVariable bar
        #Get-AzureRmSubscription -SubscriptionName $variable -ErrorAction Stop
    }
    Catch
    {
        Write-Error $error[0]
        $bar
    }
}

所以我不确定在ISE中运行“Test-MyError”并调用它时发生了什么,它是在PSM1文件中点源并然后调用它?

我现在必须使用Test-MyError "Foo" Test-MyError : Exception of type 'Microsoft.PowerShell.Commands.WriteErrorException' was thrown. At line:3 char:1 + Test-MyError "Foo" + ~~~~~~~~~~~~~~~~~~ + CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Test-MyError The running command stopped because the preference variable "ErrorActionPreference" or common parameter is set to Stop: Cannot find any service with service name 'foo'. 处理吗?

原始问题: 我在模块中有两个函数:Get-Subscription和Get-AllSubscriptions。每个函数都位于自己的PS1文件中,PSM1文件对它们进行点源。该模块似乎很好,因为模块脚本可以使用intelisense访问,并且模块加载没有问题。我在很多模块中都使用过这种结构,之前我没有遇到过这个问题。 (虽然我想知道MS是否已经改变了模块在PS 5.1中工作的方式,因为我注意到使用Test-MyError "Foo" Test-MyError : Cannot find any service with service name 'Foo'. At line:3 char:1 + Test-MyError "Foo" + ~~~~~~~~~~~~~~~~~~ + CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Test-MyError The running command stopped because the preference variable "ErrorActionPreference" or common parameter is set to Stop: Cannot find any service with service name 'Foo'. -ErrorVariable的行为似乎与以前不同。)

Get-AllSubscriptions调用Get-Subscription。

如果我没有登录Azure,则Get-Subscription会抛出一个错误,并且会提示我登录。如果我从Get-Subscription.ps1调用Get-Subscription,这将按预期工作。

但是,当我从新的PS1文件,Get-AllSubscriptions或从powershell控制台调用Get-Subscription时,它不起作用。它一直遍历do..until循环,而不像我期望的那样“处理”错误。在每次迭代中,它似乎抛出一般错误:

FunctionsToExport='x','y','Z'

但是,我确实看到了上一个错误Export-ModuleMember

如果我在ISE中执行Get-Subscription,然后在新的PS1文件或Get-AllSubscriptions中调用Get-Subscription,它会按预期工作,但是,一旦我重新导入模块(Get-Subscription : Exception of type 'Microsoft.PowerShell.Commands.WriteErrorException' was thrown. ),它回到了不正确的行为。

如果我在调用者脚本中点源Get-Subscription,它可以工作,但为什么呢?这是模块的PSM1应该发生的事情。

任何人都可以帮我解决我在这里做错的事吗?

(PS 5.1,Windows 7)

获取订阅:

Get-Subscription : Unable to find requested subscription after 3 login attempts.

获取-AllSubscriptions:

Import-Module AzureVnetTools -Force -Verbose

测试

function Get-Subscription
{
    [cmdletbinding()]
    Param
    (
        [string]$SubscriptionName,
        [string]$UserName,
        [string]$code
    )

    $c=1
    Write-Verbose "Checking access to '$SubscriptionName' with user '$UserName'..."
    Do
    {
        Write-Verbose "Attempt $c"
        Try
        {
            $oSubscription = Get-AzureRmSubscription -SubscriptionName $SubscriptionName -ErrorAction Stop -WarningAction SilentlyContinue

            Write-Verbose "Subscription found: $($oSubscription.SubscriptionName)."
        }
        Catch
        {
            if($error[0].Exception.Message -like "*Please verify that the subscription exists in this tenant*")
            {
                Write-Verbose "Cannot find subscription '$SubscriptionName' with provided credentials."
                $account = Login-AzureRmAccount -Credential (Get-Credential -UserName $Username -Message "Subscription '$SubscriptionName' user' password:")
            }
            elseif($error[0].Exception.Message -like "*Run Login-AzureRmAccount to login*")
            {
                Write-Verbose "No logged in session found. Please log in."
                $account = Login-AzureRmAccount -Credential (Get-Credential -UserName $Username -Message "Subscription '$SubscriptionName' user' password:")
            }
            else
            {
                Write-Error $error[0]
            }
        }
        $c++
    }
    until(($oSubscription) -or ($c -eq 4))

    if($c -eq 4)
    {
        Write-Error "Unable to find requested subscription after $($c-1) login attempts."
        break
    }
    $oSubscription | Add-Member -MemberType NoteProperty -Name Code -Value $code
    $oSubscription
}

输出:

function Get-AllSubscriptions
{
    [cmdletbinding()]
    param
    (
        [string]$MasterSubscription,
        [string]$MasterSubscriptionCode,
        [string]$MasterSubscriptionUsername,
        [string]$ChildSubscription,
        [string]$ChildSubscriptionCode,
        [string]$ChildSubscriptionUsername
    )

    Write-Verbose "Getting all subscriptions..."

    $oAllSubscriptions = @()

    $oMasterSubscription = Get-Subscription -SubscriptionName $MasterSubscription -UserName $MasterSubscriptionUsername -code $MasterSubscriptionCode -Verbose

    $oChildSubscription = Get-Subscription -SubscriptionName $ChildSubscription -UserName $ChildSubscriptionUsername -code $ChildSubscriptionCode -Verbose

    $oAllSubscriptions = ($oMasterSubscription,$oChildSubscription)
    $oAllSubscriptions

}

AzureVnetTools.psm1

$splat2 = @{
    SubscriptionName = "SomeSubscription"
    Code = "S02"
    Username = "some.user@somewhere.com"
}

#Write-Output "Dot-source:"
#. "D:\Temp\PS.Modules\AzureVnetTools\functions\public\Get-Subscription.ps1"

Get-Subscription @splat2 -verbose

AzureVnetTools.psd1(相关部分):

Get-Subscription @splat2 -verbose
VERBOSE: Checking access to 'SomeSubscription' with user 'some.user@somewhere.com'...
VERBOSE: Attempt 1
Get-Subscription : Exception of type 'Microsoft.PowerShell.Commands.WriteErrorException' was thrown.
At line:7 char:1
+ Get-Subscription @splat2 -verbose
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [Write-Error], WriteErrorException
    + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Get-Subscription

VERBOSE: Attempt 2
Get-Subscription : Exception of type 'Microsoft.PowerShell.Commands.WriteErrorException' was thrown.
At line:7 char:1
+ Get-Subscription @splat2 -verbose
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [Write-Error], WriteErrorException
    + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Get-Subscription

VERBOSE: Attempt 3
Get-Subscription : Exception of type 'Microsoft.PowerShell.Commands.WriteErrorException' was thrown.
At line:7 char:1
+ Get-Subscription @splat2 -verbose
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [Write-Error], WriteErrorException
    + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Get-Subscription

Get-Subscription : Unable to find requested subscription after 3 login attempts.
At line:7 char:1
+ Get-Subscription @splat2 -verbose
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [Write-Error], WriteErrorException
    + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Get-Subscription

2 个答案:

答案 0 :(得分:0)

-ErrorAction Stop -WarningAction SilentlyContinue

这是一个被抛出而不是错误的警告吗?

答案 1 :(得分:0)

所以我的具体问题是我依赖于处理错误并根据它做一些事情。问题是由PowerShell的Write-Error工作(或不工作)的方式引起的,正如我从@Alek给出的回复here中学到的那样。

它根本没有将实际错误传递回调用脚本。正如@Alex建议的那样,我将Write-Error替换为$PSCmdlet.WriteError()。虽然这并没有完全奏效。

Catch{}块中,我随后将$error[0]更改为$_,并将完整错误返回给调用脚本/函数。

我进一步写了一个可重用的函数,添加到我的模块中:

function Write-PsError
{
    [cmdletbinding()]
    Param
    (
        [Exception]$Message,
        [Management.Automation.ErrorCategory]$ErrorCategory = "NotSpecified"
    )

    $arguments = @(
            $Message
            $null #errorid
            [Management.Automation.ErrorCategory]::$ErrorCategory
            $null

            )

    $ErrorRecord = New-Object -TypeName "Management.Automation.ErrorRecord" -ArgumentList $arguments
    $PSCmdlet.WriteError($ErrorRecord)

}

目前似乎运作良好。我特别喜欢intellisense获取所有ErrorCategories的方式。不确定ISE(PS 5.1 / Win 7)是做什么或如何做的。我以为我将不得不添加自己的动态参数。

HTH。