Skip to content

Need straightforward way to honor the caller's preference-variable values / inherited common parameters in functions defined in script modules #4568

@mklement0

Description

@mklement0

This is a longstanding issue that @dlwyatt explained in detail in this 2014 blog post, and he has even published module PreferenceVariables with advanced function Get-CallerPreference to ease the pain, via a hard-coded list of preference variable names.

In short: A script module's functions do not see the preference-variable values set in the caller's context (except if that context happens to be the global one), which means that the caller's preferences are not honored.

Update: Since implicitly setting preference variables is PowerShell's method for propagating (inheriting) common parameters such as -WhatIf, such parameters are ultimately not honored in calls to script-module functions when passed via an advanced function - see #3106, #6556, and #6342. In short: the common-parameter inheritance mechanism is fundamentally broken for advanced functions across module scopes, which also affects standard modules such as NetSecurity and Microsoft.PowerShell.Archive .

  • From a user's perspective this is (a) surprising and (b), once understood, inconvenient.
    Additionally, given that compiled cmdlets do not have the same problem, it is not easy to tell in advance which cmdlets / advanced functions are affected. In a similar vein, compiled cmdlets proxied via implicitly remoting modules also do not honor the caller's preferences.

  • From a developer's perspective, it is (a) not easy to keep the problem in mind, and (b) addressing the problem requires a workaround that is currently quite cumbersome, exacerbated by currently not having a programmatic way identify all preference variables in order to copy their values to the callee's namespace - see Improving the discoverability of PowerShell variables #4394.

A simple demonstration of the problem:

# Define an in-memory module with a single function Foo() that provokes
# a non-terminating error.
$null = New-Module {
  function Foo {
    [CmdletBinding()] param()
    # Provoke a non-terminating error.
    Get-Item /Nosuch
  }
}

# Set $ErrorActionPreference in the *script* context:
# Request that errors be silenced.
# (Note: Only if you defined this in the *global* context would the module see it.)
$ErrorActionPreference = 'SilentlyContinue'

# Because the module in which Foo() is defined doesn't see this script's
# variables, it cannot honor the $ErrorActionPreference setting, and 
# the error message still prints.
Foo

Desired behavior

No output.

Current behavior

Get-Item : Cannot find path '/Nosuch' because it does not exist.
...

Environment data

PowerShell Core v6.0.0-beta.5 on macOS 10.12.6
PowerShell Core v6.0.0-beta.5 on Ubuntu 16.04.3 LTS
PowerShell Core v6.0.0-beta.5 on Microsoft Windows 10 Pro (64-bit; v10.0.15063)
Windows PowerShell v5.1.15063.483 on Microsoft Windows 10 Pro (64-bit; v10.0.15063)

Metadata

Metadata

Assignees

No one assigned

    Labels

    Issue-Discussionthe issue may not have a clear classification yet. The issue may generate an RFC or may be reclassifIssue-Enhancementthe issue is more of a feature request than a bugWG-Enginecore PowerShell engine, interpreter, and runtime

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions