14

我有一个 PowerShell 模块,它封装了许多常用的业务功能。通常不会从控制台调用它;相反,它的功能由导入模块的自动部署和管理脚本调用。

该模块包含一个日志功能,可写入两个集中的日志位置。我还想加入Write-Verbose功能以写入控制台。

#'Start Script.ps1
#'----------------

Import-Module Corporate
Write-Logger 'Foo'

我的限制是 - 从 Corporate PowerShell 模块中 - 我需要确定是否使用-Verbose参数调用了 Script.ps1。理想情况下,我希望确定代码完全在模块本身内。

这是一个例子:

[CmdletBinding()]
Param ()

New-Module -Name TempModule -ScriptBlock {
    function Test-ModuleVerbose() {
        [CmdletBinding()]
        Param ()

        PROCESS {
            $vb = ($PSCmdlet.MyInvocation.BoundParameters['Verbose'] -eq $true)
            Write-Host ("1: Module verbose preference: " + ($PSCmdlet.MyInvocation.BoundParameters['Verbose'] -eq $true))
            Write-Host ("2: Module verbose preference: " + $Script:VerbosePreference)
            Write-Host ("3: Module verbose preference: " + $VerbosePreference)
        }
    }
} | Out-Null

function Test-Verbose() {
    [CmdletBinding()]
    Param ()

    PROCESS {
        Write-Host ("Verbose preference: $VerbosePreference")
        Test-ModuleVerbose
    }
}

Test-Verbose

将以上内容另存为test.ps1。从控制台调用时:

PS C:\temp> .\test.ps1
Verbose preference: SilentlyContinue
1: Module verbose preference: False
2: Module verbose preference:
3: Module verbose preference: SilentlyContinue

PS C:\temp> .\test.ps1 -Verbose
VERBOSE: Exporting function 'Test-ModuleVerbose'.
VERBOSE: Importing function 'Test-ModuleVerbose'.
Verbose preference: Continue
1: Module verbose preference: False
2: Module verbose preference:
3: Module verbose preference: SilentlyContinue

如您所见,$VerbosePreference 变量在模块中不可用。有没有办法从模块中获取调用脚本是否已使用-Verbose标志调用?

4

4 回答 4

12

可以使用匹配的首选项变量和类似这样的语法传递大多数常用参数-Parameter:$ParameterPreference。因此,对于详细的具体情况,语法是-Verbose:$VerbosePreference.

有几个例外:

  • Debug: 的值$DebugPreference是自动传递的,但指定 -Debug 开关强制 $DebugPreference Inquire.
  • WhatIf:自动传递。

我已将 OP 代码示例修改如下:

[CmdletBinding(SupportsShouldProcess=$true)]
param(
    [Switch]$FullPassThru
)

New-Module -Name TempModule -ScriptBlock {
        function Test-ModuleVerbose
        {
            [CmdletBinding(SupportsShouldProcess=$true)]
            param ()

            Write-Host "1: Module: verbose parameter is bound : $($PSCmdlet.MyInvocation.BoundParameters['Verbose'])"
            Write-Host "2: Module: verbose preference         : $VerbosePreference"

            # Write-Verbose will just work without any change
            Write-Verbose "Verbose"

            # Other commands need the $VerbosePreference passed in
            Set-Item -Path Env:\DEMONSTRATE_PASS_THRU `
                     -Value 'You can safely delete this variable' `
                     -Verbose:$VerbosePreference
        }

        function Test-ModulePreferencePassThru
        {
            [CmdletBinding(SupportsShouldProcess=$true)]
            param()

            Write-Debug   "DebugPreference: $DebugPreference"
            Write-Warning "WarningPreference: $WarningPreference"
            Write-Error   "ErrorActionPreference: $ErrorActionPreference"

            Set-Item -Path Env:\DEMONSTRATE_PASS_THRU `
                     -Value 'You can safely delete this variable' `
                     -Verbose:$VerbosePreference `
                     -WarningAction:$WarningPreference `
                     -ErrorAction:$ErrorActionPreference
        }
    } | Out-Null

function Test-Verbose
{
    [CmdletBinding(SupportsShouldProcess=$true)]
    param()

    Write-Host ("Verbose preference: $VerbosePreference")
    Test-ModuleVerbose -Verbose:$VerbosePreference
}

function Test-PreferencePassThru
{
    [CmdletBinding(SupportsShouldProcess=$true)]
    param()

    Test-ModulePreferencePassThru -Verbose:$VerbosePreference
}

try
{
    if ($FullPassThru -eq $false)
    {
        # just demonstrate -verbose pass-through
        Test-Verbose
    }
    else
    {
        # most of the preferences can be explicitly passed-through, however:
        #
        #  -Debug  : $DebugPreference is automatically passed-through
        #            and -Debug forces $DebugPreference to 'Inquire'
        #  -WhatIf : automatically passed-through
        Test-ModulePreferencePassThru -Verbose:$VerbosePreference `
                                        -WarningAction:$WarningPreference `
                                        -ErrorAction:$ErrorActionPreference | Out-Null
    }
}
finally
{
    # cleanup
    Remove-Item -Path Env:\DEMONSTRATE_PASS_THRU -Force | Out-Null
}

将以上内容另存为test.ps1。从控制台调用时:

PS C:\temp> .\test.ps1
Verbose preference: SilentlyContinue
1: Module: verbose parameter is bound : False
2: Module: verbose preference         : SilentlyContinue

PS C:\temp> .\test.ps1 -Verbose
VERBOSE: Exporting function 'Test-ModuleVerbose'.
VERBOSE: Exporting function 'Test-ModulePreferencePassThru'.
VERBOSE: Importing function 'Test-ModulePreferencePassThru'.
VERBOSE: Importing function 'Test-ModuleVerbose'.
Verbose preference: Continue
1: Module: verbose parameter is bound : True
2: Module: verbose preference         : Continue
VERBOSE: Verbose
VERBOSE: Performing the operation "Set Item" on target "Item: DEMONSTRATE_PASS_THRU Value: You can safely delete this variable".

此外,传递$DebugPreference,$WarningPreference$ErrorActionPreference可以:

PS C:\temp> $VerbosePreference  = 'Continue'
PS C:\temp> $DebugPreference = 'Continue'
PS C:\temp> $WarningPreference = 'Continue'
PS C:\temp> $ErrorActionPreference = 'Continue'
PS C:\temp> .\test.ps1 -FullPassThru
VERBOSE: Exporting function 'Test-ModuleVerbose'.
VERBOSE: Exporting function 'Test-ModulePreferencePassThru'.
VERBOSE: Importing function 'Test-ModulePreferencePassThru'.
VERBOSE: Importing function 'Test-ModuleVerbose'.
DEBUG: DebugPreference: Continue
WARNING: WarningPreference: Continue
Test-ModulePreferencePassThru : ErrorActionPreference: Continue
At C:\OAASMain\Online\ContainerService\Tools\docker\test.ps1:72 char:9
+         Test-ModulePreferencePassThru -Verbose:$VerbosePreference `
+         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [Write-Error], WriteErrorException
    + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Test-ModulePreferencePassThru

VERBOSE: Performing the operation "Set Item" on target "Item: DEMONSTRATE_PASS_THRU Value: You can safely delete this variable".

-WhatIf自动通过:

PS C:\temp> .\test.ps1 -FullPassThru -WhatIf
What if: Performing the operation "Remove Item" on target "Item: DEMONSTRATE_PASS_THRU".

这也处理-WarningAction-ErrorAction

PS C:\temp> .\test.ps1 -FullPassThru -WarningAction Ignore -ErrorAction Stop
Test-ModulePreferencePassThru : ErrorActionPreference : Stop
At C:\OAASMain\Online\ContainerService\Tools\docker\test.ps1:72 char:9
+         Test-ModulePreferencePassThru -Verbose:$VerbosePreference `
+         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [Write-Error], WriteErrorException
    + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Test-ModulePreferencePassThru
于 2017-04-22T09:49:25.950 回答
10

有一个名为 $VerbosePreference 的变量,您可以检查以查看应如何处理 Verbose 输出。但是,加载到单独范围的脚本会给您带来问题。如果您阅读Get-Help about_scopes,您将看到:

脚本:
脚本文件运行时创建的范围。只有脚本中的命令在脚本范围内运行。对于脚本中的命令,脚本范围是本地范围。

您可以将脚本添加到当前范围,而不是使用点源表示法。在同一个帮助文件中,在使用带范围的点源表示法标题下方指出:

脚本和函数遵循所有范围规则。您在特定范围内创建它们,并且它们仅影响该范围,除非您使用 cmdlet 参数或范围修饰符来更改该范围。

但是,您可以使用点源表示法将脚本或函数添加到当前范围。然后,当脚本在当前范围内运行时,该脚本创建的任何函数、别名和变量都在当前范围内可用。

我建议在Get-Help about_scopes帮助章节中阅读更多关于范围的信息。

快速测试这是否有效:

[CmdletBinding()]
PARAM()

New-Module -Name TempModule -ScriptBlock {
    function Show-ModuleVerbosePreference
    {
        [CmdletBinding()]
        PARAM()

        Write-Host "Verbose preference in module function: $VerbosePreference"
    }
} | Out-Null

function Show-ScriptVerbosePreference
{
    [CmdletBinding()]
    PARAM()

    Write-Host "Verbose preference in script function: $VerbosePreference"
}

Show-ScriptVerbosePreference
Show-ModuleVerbosePreference</pre>

如果我们尝试使用不同的方法调用这个脚本文件,我们会得到以下输出:

PS C:\> .\verbosity.ps1
Verbose preference in script function: SilentlyContinue
Verbose preference in module function: SilentlyContinue

PS C:\> .\verbosity.ps1 -Verbose
VERBOSE: Exporting function 'Show-ModuleVerbosePreference'.
VERBOSE: Importing function 'Show-ModuleVerbosePreference'.
Verbose preference in script function: Continue
Verbose preference in module function: SilentlyContinue

PS C:\> . .\verbosity.ps1
Verbose preference in script function: SilentlyContinue
Verbose preference in module function: SilentlyContinue

PS C:\> . .\verbosity.ps1 -Verbose
VERBOSE: Exporting function 'Show-ModuleVerbosePreference'.
VERBOSE: Importing function 'Show-ModuleVerbosePreference'.
Verbose preference in script function: Continue
Verbose preference in module function: Continue

因此,通过使用点源符号,我们将脚本范围添加到当前范围中,这似乎使 VerbosePreference 设置在模块方法中也可见。

于 2014-01-06T23:37:30.443 回答
1

在我的 .psm1 中,我放置了一个类似于此的命令:

If ((Get-PSCallStack)[1].Arguments -like '\*Verbose=True\*') {
    Write-Host 'The .ps1 script importing this module is Verbose'
};

您可以使用脚本块来设置变量,例如模块范围内的 $VerbosePreference,或者为您自己的逻辑设置您自己的唯一变量。

于 2017-04-13T17:36:39.060 回答
0

尝试 ContainsKey 方法:

$PSCmdlet.MyInvocation.BoundParameters.ContainsKey('verbose')
于 2014-01-07T09:47:02.470 回答