|
| 1 | +--- |
| 2 | +RFC: RFCnnnn |
| 3 | +Author: Kirk Munro |
| 4 | +Status: Draft |
| 5 | +SupercededBy: |
| 6 | +Version: 1.0 |
| 7 | +Area: Engine |
| 8 | +Comments Due: July 15, 2019 |
| 9 | +Plan to implement: Yes |
| 10 | +--- |
| 11 | + |
| 12 | +# Optional features in PowerShell |
| 13 | + |
| 14 | +There are several important issues in the PowerShell language that cannot be corrected without introducing breaking changes. At the same time, the number of breaking changes introduced in a new version of PowerShell needs to be as minimal as possible, so that there is a low barrier to adoption of new versions, allowing community members can transition scripts and modules across versions more easily. Given that those two statements are in conflict with one another, we need to consider how we can optionally introduce breaking changes into PowerShell over time. |
| 15 | + |
| 16 | +PowerShell has support for experimental features, which some may think covers this need; however, the intent of experimental features is to allow the community to try pre-release versions of PowerShell with breaking changes that are deemed necessary so that they can more accurately assess the impact of those breaking changes. For release versions of PowerShell, an experimental feature has one of three possible outcomes: |
| 17 | + |
| 18 | +1. The breaking change in the experimental feature is deemed necessary and accepted by the community as not harmful to adoption of new versions, in which case the experimental feature is no longer marked as experimental. |
| 19 | +1. The breaking change in the experimental feature is deemed necessary, but considered harmful to adoption of new versions, in which case the experimental feature is changed to an optional feature. |
| 20 | +1. The breaking change in the experimental feature is deemed not useful enough, in which case the experimental feature is deprecated. |
| 21 | + |
| 22 | +In some cases a breaking change may be implemented immediately as an optional feature, when it is known up front that such a breaking change would be considered harmful to adoption of new versions of PowerShell. |
| 23 | + |
| 24 | +Given all of that, we need to add support for optional features in PowerShell so that what is described above becomes a reality. |
| 25 | + |
| 26 | +As an example of a feature that will be optional if implemented, see RFCNNNN-Propagate-Execution-Preferences-Beyond-Module-Scope or RFCNNNN-Make-Terminating-Errors-Terminate. |
| 27 | + |
| 28 | +## Motivation |
| 29 | + |
| 30 | +As a script, function, or module author, |
| 31 | +I can enable optional features in my scripts or modules, |
| 32 | +so that I can leverage new functionality that could break existing scripts. |
| 33 | + |
| 34 | +## User experience |
| 35 | + |
| 36 | +```powershell |
| 37 | +# Create a module manifest, specifically enabling one or more optional features in the manifest |
| 38 | +New-ModuleManifest -Path ./test.psd1 -OptionalFeatures @('OptionalFeature1','OptionalFeature2') -PassThru | Get-Content |
| 39 | +
|
| 40 | +# Output: |
| 41 | +# |
| 42 | +# @{ |
| 43 | +# |
| 44 | +# <snip> |
| 45 | +# |
| 46 | +# # Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell. |
| 47 | +# PrivateData = @{ |
| 48 | +# |
| 49 | +# <snip> |
| 50 | +# |
| 51 | +# PSData = @{ |
| 52 | +# |
| 53 | +# # Optional features enabled in this module. |
| 54 | +# OptionalFeatures = @( |
| 55 | +# 'OptionalFeature1' |
| 56 | +# 'OptionalFeature2' |
| 57 | +# ) |
| 58 | +# |
| 59 | +# <snip> |
| 60 | +# |
| 61 | +# } # End of PSData hashtable |
| 62 | +# |
| 63 | +# <snip> |
| 64 | +# |
| 65 | +# } # End of PrivateData hashtable |
| 66 | +# |
| 67 | +# } |
| 68 | +
|
| 69 | +# Create a script file, enabling one or more optional features in the file |
| 70 | +@' |
| 71 | +#requires -OptionalFeature OptionalFeature1,OptionalFeature2 |
| 72 | +
|
| 73 | +<snip> |
| 74 | +'@ | Out-File -FilePath ./test.ps1 |
| 75 | +
|
| 76 | +# Get a list of optional features that are available |
| 77 | +Get-OptionalFeature |
| 78 | +
|
| 79 | +# Output: |
| 80 | +# |
| 81 | +# Name EnabledIn Source Description |
| 82 | +# ---- ------- ------ ----------- |
| 83 | +# OptionalFeature1 Manifest PSEngine Description of optional feature 1 |
| 84 | +# OptionalFeature2 Session PSEngine Description of optional feature 2 |
| 85 | +
|
| 86 | +# Enable an optional feature by default in PowerShell |
| 87 | +Enable-OptionalFeature -Name OptionalFeature1 |
| 88 | +
|
| 89 | +# Output: |
| 90 | +# This works just like Enable-ExperimentalFeature, turning the optional |
| 91 | +# feature on by default for all future sessions in PowerShell. |
| 92 | +
|
| 93 | +# Disable an optional feature by default in PowerShell |
| 94 | +Disable-OptionalFeature -Name OptionalFeature1 |
| 95 | +
|
| 96 | +# Output: |
| 97 | +# This works ust like Disable-ExperimentalFeature, turning the optional |
| 98 | +# feature off by default for all future sessions in PowerShell. |
| 99 | +
|
| 100 | +# Enable an optional feature by default in all new module manifests |
| 101 | +# created with New-ModuleManifest in all future sessions in PowerShell. |
| 102 | +Enable-OptionalFeature -Name OptionalFeature1 -NewModuleManifests |
| 103 | +
|
| 104 | +# Disable an optional feature by default in all new module manifests |
| 105 | +# created with New-ModuleManifest in all future sessions in PowerShell. |
| 106 | +Disable-OptionalFeature -Name OptionalFeature1 -NewModuleManifests |
| 107 | +``` |
| 108 | + |
| 109 | +## Specification |
| 110 | + |
| 111 | +Aside from closely (but not exactly, see below) mirroring what is already in place internally for experimental features in PowerShell, this RFC includes a few additional enhancements that will be useful for optional features, as follows: |
| 112 | + |
| 113 | +### Add parameter to New-ModuleManifest |
| 114 | + |
| 115 | +`[-OptionalFeatures <string[]>]` |
| 116 | + |
| 117 | +This new parameter would assign specific optional features to new modules. Note that these would be in addition to optional features that are enabled by default in manifests created with `New-ModuleManifest`. |
| 118 | + |
| 119 | +### Add parameter to #requires statement |
| 120 | + |
| 121 | +`#requires -OptionalFeatures <string[]>` |
| 122 | + |
| 123 | +This new parameter would enable optional features in the current script file. |
| 124 | + |
| 125 | +### New command: Get-OptionalFeature |
| 126 | + |
| 127 | +```none |
| 128 | +Get-OptionalFeature [[-Name] <string[]>] [<CommonParameters>] |
| 129 | +``` |
| 130 | + |
| 131 | +This command would return the optional features that are available in PowerShell. The default output format would be of type table with the properties `Name`, `Enabled`, `Source`, and `Description`. All of those properties would be of type string except for `Enabled`, which would be an enumeration with the possible values of `NotEnabled`, `Session`, `Manifest`, and `Script`. This differs from experimental features where `Enabled` is a boolean value. Given the locations in which an optional feature can be enabled, it would be more informative to identify where it is enabled than simply showing `$true` or `$false`. |
| 132 | + |
| 133 | +### New command: Enable-OptionalFeature |
| 134 | + |
| 135 | +```none |
| 136 | +Enable-OptionalFeature [-Name] <string[]> [-NewModuleManifests] [-WhatIf] [-Confirm] [<CommonParameters>] |
| 137 | +``` |
| 138 | + |
| 139 | +This command would enable an optional feature either globally (if the `-NewModuleManifests` switch is not used) or only in new module manifests created by `New-ModuleManifest`. |
| 140 | + |
| 141 | +### New command: Disable-OptionalFeature |
| 142 | + |
| 143 | +```none |
| 144 | +Disable-OptionalFeature [-Name] <string[]> [-NewModuleManifests] [-WhatIf] [-Confirm] [<CommonParameters>] |
| 145 | +``` |
| 146 | + |
| 147 | +This command would disable an optional feature either globally (if the `-NewModuleManifests` switch is not used) or only in new module manifests created by `New-ModuleManifest`. If the optional feature is not enabled that way in the first place, nothing would happen. |
| 148 | + |
| 149 | +### New command: Use-OptionalFeature |
| 150 | + |
| 151 | +```none |
| 152 | +Use-OptionalFeature [-Name] <string[]> [-ScriptBlock] <ScriptBlock> [-Confirm] [<CommonParameters>] |
| 153 | +``` |
| 154 | + |
| 155 | +This command would enable an optional feature for the duration of the `ScriptBlock` identified in the `-ScriptBlock` parameter, and return the feature to its previous state afterwards. This allows for easy use of an optional feature over a small section of code. |
| 156 | + |
| 157 | +## Alternate proposals and considerations |
| 158 | + |
| 159 | +### Extend experimental features to support the enhancements defined in this RFC |
| 160 | + |
| 161 | +Experimental features and optional features are very similar to one another, so much so that they really only differ in name. Given the model for how both of these types of features are used, it may make sense to have them both use the same functionality when it comes to enabling/disabling them in scripts and modules. The downside I see to this approach is that optional features are permanent features in PowerShell while experimental features are not, so it may not be a good idea to support more permanent ways to enable experimental features such as `#requires` or enabling an experimental feature in a new module manifest. |
| 162 | + |
| 163 | +### Supporting a `-Scope` parameter like the experimental feature cmdlets do |
| 164 | + |
| 165 | +The `Enable-OptionalFeature` and `Disable-OptionalFeature` cmdlets could support a `-Scope` parameter like their experimental feature cmdlet counterparts do. I felt it was better to remove this for optional features, because it may be risky to allow a command to enable an optional feature in a scope above the one in which it is invoked, influencing behaviour elsewhere. |
0 commit comments