Skip to content

Commit cb42a87

Browse files
gaelcolasjoeyaiello
authored andcommitted
Accepted RFC0047 - Invoke-DscResource for PS7 (#214)
Merging with quorum and approval from @daxian-dbw, @JamesWTruher, @SteveL-MSFT, @joeyaiello, and @BrucePay * adding Invoke-DscResource RFC Draft * Update 1-Draft/RFCXXXX-RFC-Invoke-DscResource.md Co-Authored-By: Steve Lee <slee@microsoft.com> * cosmetic change - capitalization thanks Joey Co-Authored-By: Joey Aiello <joeyaiello@users.noreply.github.com> * updating RFC as per comments from Travis, Steve & Kevin * typ fix, spelled MVP * adding alternate proposals & consideration from template * updating RFC with updated discussion/comments (#3) * updating RFC with updated discussion/comments * Update 1-Draft/RFCXXXX-RFC-Invoke-DscResource.md Co-Authored-By: Travis Plunk <travis.plunk@microsoft.com> * Update 1-Draft/RFCXXXX-RFC-Invoke-DscResource.md * updating GET result as per Travis comment * Update 1-Draft/RFCXXXX-RFC-Invoke-DscResource.md properties to property Co-Authored-By: Travis Plunk <travis.plunk@microsoft.com> * Update 1-Draft/RFCXXXX-RFC-Invoke-DscResource.md properties to property Co-Authored-By: Travis Plunk <travis.plunk@microsoft.com> * Update 1-Draft/RFCXXXX-RFC-Invoke-DscResource.md properties to property Co-Authored-By: Travis Plunk <travis.plunk@microsoft.com> * updating according to comments - expanding LCM/WMI - reboot and $Global:DSCMachineStatus - superfluous text * Prepare Invoke-DscResource (RFC0047) for acceptance
1 parent 8033b77 commit cb42a87

File tree

1 file changed

+258
-0
lines changed

1 file changed

+258
-0
lines changed
Lines changed: 258 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,258 @@
1+
---
2+
RFC: RFC0047
3+
Author: Gael Colas
4+
Status: Experimental-Accepted
5+
SupersededBy: N/A
6+
Version: 0.9
7+
Area: Microsoft.PowerShell.DesiredStateConfiguration
8+
---
9+
10+
# Invoke-DscResource
11+
12+
Add cross-platform support for `Invoke-DscResource` in PowerShell 7+ without dependency
13+
on the [Local Configuration Manager](https://docs.microsoft.com/en-us/powershell/dsc/managing-nodes/metaconfig)
14+
(LCM), the
15+
[Common Information Model (CIM) or Windows Management Instrumentation (WMI)](https://devblogs.microsoft.com/scripting/should-i-use-cim-or-wmi-with-windows-powershell/).
16+
17+
This RFC addresses the need to leverage the DSC ecosystem of resources from newer
18+
versions of PowerShell, the way to decouple the execution of resources from the
19+
LCM and CIM/WMI, and the user experience from a consumer and solution vendor/integrator
20+
point of view.
21+
22+
## Motivation
23+
24+
1. DSC has been cited by users and solution partners as a blocker for moving from Windows PowerShell to PowerShell 7+.
25+
26+
2. As part of the latest survey on DSC usage started in June 2019, the top requested feature was support for Invoke-DscResource in PSCore without WMI dependency.
27+
28+
3. The DSC Ecosystem and Community would greatly benefit from enabling DSC resources to be used in imperative scripts, in current user context.
29+
30+
## Specification
31+
32+
### Invoke-DscResource in a module, decoupled from PowerShell
33+
34+
`Invoke-DscResource` is directly related to `Get-DscResource` in terms of user experience: Get provides the discoverability before the invocation.
35+
36+
`Invoke-DscResource` does not need to be part of the PowerShell engine (same as `Get-DscResource`), and we should aim to decouple PowerShell's engine from the DSC Ecosystem. While it's convenient for the `Configuration` keyword to have some of its implementation done in PowerShell's engine for parsing, `Invoke-DscResource` has no such requirements and should live in an independent module evolving in its own timeline, that will be bundled and shipped with PowerShell releases.
37+
38+
Open-sourcing this module should be a priority, but is out of scope for this RFC.
39+
40+
### Backward compatibility with Invoke-DscResource from PS 5.1
41+
42+
It is **not the intention to have feature parity** between the version found with Windows PowerShell 5.1 and the one described in this RFC.
43+
44+
While we attempt to maintain the same command syntax, the behavior will not be on par with `Invoke-DscResource` as found in PowerShell 5.1.
45+
46+
Specifically, we already know some features that **will not be supported** in this initial scope of work:
47+
48+
- Support for non-PowerShell resources (i.e. the native/binary or Python resources won't be supported)
49+
- Running as System by default ([Discussed later in this document](#Default-Execution-Scope:-Current-runspace))
50+
- Schema validation of invocation/results (It will only validate against the Resource's functions' signatures)
51+
52+
#### Syntax
53+
54+
As we don't plan on changing the usage much, plus the functions is currently not available outside of PowerShell, and there is currently no command for PowerShell 7+, so there is no need to change the Syntax found in Windows PowerShell 5.1.
55+
56+
The increment in PowerShell [MAJOR](https://semver.org/#spec-item-8)'s version field is enough to indicate the change of public API (as per [Semantic Versioning](https://semver.org/)).
57+
58+
```text
59+
Invoke-DscResource [-Name] <string> [-Method] <string> -ModuleName <ModuleSpecification> -Property <hashtable> [<CommonParameters>]
60+
```
61+
62+
#### Default Execution Scope: Current runspace
63+
64+
We aim at enabling existing scripts using `Invoke-DscResource`, written for Windows
65+
PowerShell 5.1, to "just work" in PowerShell 7+, but they will run resources
66+
**in the current user context**.
67+
68+
```PowerShell
69+
Invoke-DscResource -Name Script -ModuleName @{ModuleName='PSDscResources';ModuleVersion='2.12.0.0'} -Method 'Set' -Property @{
70+
GetScript = '<# My Get ScriptBlock #>'
71+
SetScript = '<# My Set ScriptBlock #>'
72+
TestScript = '<# My Test ScriptBlock #>'
73+
} -Verbose
74+
```
75+
76+
This should run in the current session state where the command is invoked.
77+
78+
#### PsDscRunAsCredential: throw exception if supplied
79+
80+
After more discussions (with @Jaykul & @TravisEz13) and thinking this through,
81+
it is **not** right to build the support for PsDscRunAsCredential in this command
82+
(more on why later in this RFC).
83+
84+
It's the user's responsibility to wrap the call in the required user context
85+
(such as using [Invoke-CommandAs](https://www.powershellgallery.com/packages/Invoke-CommandAs)
86+
by Mark Kellerman).
87+
88+
Although `PsDscRunAsCredential` is a recommended practice for DSC in WMF 5.1 to
89+
implement [least-privilege Administrative Models](https://docs.microsoft.com/en-us/windows-server/identity/ad-ds/plan/security-best-practices/implementing-least-privilege-administrative-models),
90+
it will **not** be supported as part of this implementation of `Invoke-DscResource`.
91+
92+
Instead, we'll aim at providing an example function in a script published
93+
on the PowerShell Gallery to proxy this command, so that it handles `PsDscRunAsCredential`
94+
to invoke the resource in a different user context, using PowerShell Jobs.
95+
96+
If the key `PsDscRunAsCredential` is to be found amongst the keys of the
97+
`-Property` parameter, then `Invoke-DscResource` will throw an exception,
98+
unless the `Invoke-DscResource` is invoked with the (new) switch parameter `-IgnorePsDscRunAsCredential`,
99+
in which case it will invoke the DSC Resource method after stripping
100+
the `PsDscRunAsCredential` key/value pair from the properties.
101+
102+
So calling:
103+
104+
```PowerShell
105+
Invoke-DscResource -Name Script -ModuleName @{ModuleName='PSDscResources';ModuleVersion='2.12.0.0'} -Method 'Set' -Property @{
106+
GetScript = '<# My Get ScriptBlock #>'
107+
SetScript = '<# My Set ScriptBlock #>'
108+
TestScript = '<# My Test ScriptBlock #>'
109+
PsDscRunAsCredential = $Credential
110+
} -Verbose
111+
112+
```
113+
114+
Will **throw an exception**, because of the `PsDscRunAsCredential` key.
115+
116+
> NOTES: We're avoiding to take dependencies on other technologies that would require extra configurations or permissions (such as remoting), or would not be available on other OSes.
117+
118+
#### Independent and isolated execution
119+
120+
`Invoke-DscResource` in PowerShell 7+ will not be aware of other instances being executed, and as such it will be possible to execute several instances in parallel when isolated in their own runspace, or run in parallel with the LCM.
121+
122+
This means that it enables concurrent execution, but also risks conflict if two conflicting resources are run simultaneously.
123+
124+
It is up to the user to sequence the execution safely, or to create appropriate resources.
125+
126+
#### Output & Types
127+
128+
##### Get
129+
130+
The `GET` function invoked via the LCM (WMF 5.1) returns a CIM representation of a hashtable,
131+
and will be a `hashtable` for `Invoke-DscResource` in PS7+.
132+
133+
##### Test
134+
135+
The `TEST` function in WMF 5.1 returns a CIM object, with a `[bool]` NoteProperty
136+
`InDesiredState` that has the boolean result of the test.
137+
138+
```PowerShell
139+
InDesiredState
140+
--------------
141+
True
142+
```
143+
144+
In PS7+, `Invoke-DscResource -Method Test ...` will return an object (not CIM)
145+
that has the same `InDesiredState` Property.
146+
147+
##### Set
148+
149+
The `SET` function in WMF 5.1 returns a CIM object, with a `[bool]` NoteProperty
150+
`RebootRequired`, corresponding whether the `$global:DSCMachineStatus` has been
151+
set to 1 in the resource.
152+
153+
```PowerShell
154+
RebootRequired
155+
--------------
156+
False
157+
```
158+
159+
In PS7+, `Invoke-DscResource -Method Set ...` will return an object (not CIM) that
160+
has the same `RebootRequired` Property, based on whether `$global:DSCMachineStatus`
161+
has been set to 1. This property from the returned object is what the users should
162+
use, and not the `$global:DSCMachineStatus` variable, subject to manipulation.
163+
164+
To avoid the manipulation of behavior by global variable,
165+
the `$global:DSCMachineStatus` variable will be reset before invoking the resource.
166+
167+
For the same security concerns and to avoid misuse, the `Invoke-DscResource` cmdlet
168+
will remove the variable `$global:DSCMachineStatus` from the session after invoking
169+
the DSC Resource.
170+
171+
# Out of Scope for initial work & other notes
172+
173+
We're aware that some extra work or feature could be solved at the same time, but we're trying to have the MVP (minimum viable product) out as soon as possible, to help addressing the points raised in the [Motivation](#Motivation) section.
174+
175+
## DSC Resource Parameters & Supported Types
176+
177+
As the `Invoke-DscResource` does not need to serialize and deserialize parameters
178+
using CIM (via MOF objects), it is not limiting the types it can accept for the
179+
DSC Resource functions (Get, Set, Test).
180+
181+
In simple words, a resource could in theory accept an `[hashtable]` as a parameter
182+
type, instead of a `[Microsoft.Management.Infrastructure.CimInstance[]]`.
183+
184+
The downside here is that it's not backward compatible, for this reason, we
185+
can't recommend any other type to be used for now.
186+
187+
Also, not all types are easily serializable and deserializable, so be careful
188+
when the Configuration Data has to be passed to the resource invocation over
189+
the network.
190+
191+
## PsDscRunAsCredential Support not built-in
192+
193+
Here's why we've decided to not handle the `PsDscRunAsCredential` from the `Invoke-DscResource`
194+
advanced function, and instead will try to publish a wrapper on the PS Gallery.
195+
196+
To be truly cross platform and support invoking a resource's method under another
197+
credential, Linux/Unix OSes creates another process under that user. In Windows
198+
it is also possible to Impersonate a user, using `Win32.AdvApi32` for instance.
199+
200+
In WMF 5.1, the LCM is in charge of this. But in PowerShell 7+, the only cross platform
201+
way to do this is by using PowerShell Jobs, which are relatively slow, heavy, and
202+
a bit more tricky to troubleshoot, as they need a way to serialize and deserialize
203+
objects.
204+
205+
In PowerShell, executing commands as job returns what we informally call "dead objects":
206+
the object after it was serialized and then deserialized, pertaining most of its
207+
properties but not an "live" object that still has its methods available.
208+
209+
Here, we could have `Invoke-DscResource` to always use Jobs, but that would severely
210+
impact performance, and would make troubleshooting difficult.
211+
212+
We could, as initially thought, handle both case: directly as the current user when
213+
`PsDscRunAsCredential` is not specified, and as Job when specified, but it would
214+
then have two different behavior, depending on the `-Property` value (and not
215+
the command's actual signature), obfuscating the potential issue to the user.
216+
217+
For those reasons, and with the possibility that an elegant or standardized solution
218+
emerges from the community, we believe it's best to leave it outside the scope of
219+
the `Invoke-DscResource` MVP.
220+
221+
In order to enable existing users to support the same behavior than the LCM,
222+
we will try to provide, separately, a function that wraps around this `Invoke-DscResource`
223+
and creates a job when `PsRunAsCredential` is specified, but this won't be part
224+
of the `PSDesiredStateConfiguration` module work.
225+
226+
## Invoke-DscResource will not clear the Builtin Provider Cache
227+
228+
The Built-in provider cache, located in `$env:ProgramData\Microsoft\Windows\PowerShell\Configuration\BuiltinProvCache`, is currently cleared by the LCM (in WMF 5.1).
229+
230+
With an Invoke-DscResource advanced function as described in this RFC, it is not guaranteed to have enough permissions to that path (it's running in the current user context unless using `PSDscRunAsCredential`), nor do we assume exclusivity (LCM might be in use and running).
231+
232+
For those reasons, it is not reasonable to expect `Invoke-DscResource` for PowerShell 7 to clear the cache, at least for the scope of the MVP.
233+
234+
DSC Resources that rely on this may experience unexpected behavior (compared to running `Invoke-DscResource` in WMF 5.1). It is up to the maintainers of those resource modules to handle (or not) this new possibility.
235+
236+
## File Resource not supported
237+
238+
Just for clarification, as the File resource is Native/Binary:
239+
240+
```text
241+
PS C:\ > Get-DscResource File
242+
243+
ImplementedAs Name ModuleName Version Properties
244+
------------- ---- ---------- ------- ----------
245+
Binary File {DestinationPath, Attributes, Checksum, Content...
246+
```
247+
248+
This resource won't be supported with this initial work. Only Resources `ImplementedAs PowerShell`, will be supported.
249+
250+
## Composite Resources not supported
251+
252+
The **Composite resources** won't be supported for this initial scope. The support for composite would require `Invoke-DscResource` to understand and extract individual Resources called within the composite which is currently handled either in the PowerShell engine or through the `Configuration` function in the PSDesiredStateConfiguration module.
253+
254+
Although it would be great to enable this scenario, decoupling the `Configuration` keyword from the MOF compilation is out of scope for this initial work.
255+
256+
# Alternate Proposals and Considerations
257+
258+
none

0 commit comments

Comments
 (0)