microsoft / requirements Goto Github PK
View Code? Open in Web Editor NEWPowerShell framework for declaratively defining and idempotently imposing system configurations
License: MIT License
PowerShell framework for declaratively defining and idempotently imposing system configurations
License: MIT License
Latest version still uses the deprecated "Name" property when creating DSC based requirement:
switch ($PSCmdlet.ParameterSetName) {
"Script" {
[Requirement]@{
Namespace = $Namespace
Describe = $Describe
Test = $Test
Set = $Set
DependsOn = $DependsOn
}
}
"Dsc" {
$dscParams = @{
Name = $ResourceName
ModuleName = $ModuleName
Property = $Property
}
[Requirement]@{
Name = $Namespace
Describe = $Describe
Test = { Invoke-DscResource -Method "Test" @dscParams }.GetNewClosure()
Set = { Invoke-DscResource -Method "Set" @dscParams }.GetNewClosure()
DependsOn = $DependsOn
}
}
}
The DSC portion needs to be updated to
[Requirement]@{
Namespace = $Namespace
Describe = $Describe
Test = { Invoke-DscResource -Method "Test" @dscParams }.GetNewClosure()
Set = { Invoke-DscResource -Method "Set" @dscParams }.GetNewClosure()
DependsOn = $DependsOn
}
Would submit PR but don't have CLA...
Is executing requirements on remote machine a viable use case for the tool?
For example extending the requirement schema with ComputerName and winrm connectivity details, so that the tool can orchestrate the execution on remote machines.
If so, I can contribute.
$Requirements = @(
@{
Name = 'vscode-powershell'
Describe = 'VSCode PowerShell Extension is installed'
Test = { (code --list-extensions) -match 'ms\-vscode\.powershell' }
Set = {
$VSCodePowerShell = 'https://github.com/PowerShell/vscode-powershell/releases/download/v2019.9.0/PowerShell-2019.9.0.vsix'
Invoke-WebRequest -OutFile ~/powershell.vsix -Uri $VSCodePowerShell
code --install-extension ~/powershell.vsix
}
}
)
$RequirementsResult = $Requirements | Invoke-Requirement
Invoke-Requirement
runs successfully.
Invoke-Requirement : The input object cannot be bound to any parameters for the command either because the command does not take pipeline input or the input and its properties do not match any of the parameters that take pipeline input.
At line:1 char:39
+ $RequirementsResult = $Requirements | Invoke-Requirement
+ ~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (System.Collections.Hashtable:Hashtable) [Invoke-Requirement], ParameterBindingException
+ FullyQualifiedErrorId : InputObjectNotBound,Invoke-Requirement
2.2.7
@(
@{
Describe = 1
Test = { $true }
},
@{
Describe = 2
Test = { $false }
},
@{
Describe = 3
Test = { $true }
}
) | Invoke-Requirement
Invoke-Requirement
throws a validation error after the second Requirement
Invoke-Requirement
processes all Requirements
I've only just started using this module in the past few days, so I'll apologize in advance if this is something that's already covered in the documentation that I just haven't seen.
I've created an external file named ResourceVariables.ps1, so that anybody using my script can easily plug in their own variables without having to make any changes to the actual requirements script file (CreateResources.ps1)
Within CreateResources.ps1, I'm dot sourcing ResourceVariables.ps1 to import it's variables. However, the variables only exist within the current Resource block, ie:
@(
@{
Describe = "First Requirement"
Set = { . .\ResourceVariables.ps1;
Write-Host "Import Variables block value of var1 is $var1"
}
}
@{
Describe = "Second Requirement"
Set = { Write-Host "Use Variables block value of var1 is $var1" }
}
) | Invoke-Requirement | Format-Verbose
In the above example, only "First Requirement" has a value for $var1, but "Second Requirement" does not.
If I declare $var1 within CreateResource.ps1 instead, then both requirements have access to the $var1. But similarly, if I set the value of $var1 within "First Requirement", then "Second Requirement" does not see that value.
I presume this has something to do with requirement nesting, which is no longer supported. But I don't see anything in the Patterns section that would help resolve this issue.
Can anybody give me some guidance on where I'm going wrong ?
The current version of the PSD lists the following:
FunctionsToExport = @(
'Format-Checklist',
'Format-Verbose',
'Invoke-Requirement',
'New-Requirement',
'Set-Requirement',
'Test-Requirement'
)
Note, Push-Namespace is not listed and thus not available when module is imported to a PS session.
Unless this is currently intentional, recommend updating the PSD to the following so Push-Namespace is provided:
FunctionsToExport = @(
'Format-Checklist',
'Format-Verbose',
'Invoke-Requirement',
'New-Requirement',
'Set-Requirement',
'Test-Requirement',
'Push-Namespace'
)
There are important files that Microsoft projects should all have that are not present in this repository. A pull request has been opened to add the missing file(s). When the pr is merged this issue will be closed automatically.
Microsoft teams can learn more about this effort and share feedback within the open source guidance available internally.
Push-Requirement [-Namespace] <string> [[-Requirements] <Requirements[]>] [[-ScriptBlock] <ScriptBlock>]
for composing arrays of requirements, automatically prefixing the Name
property of the Requirements
with Namespace
.Name
vs Description
in formattersExamples of using normal requirements mixed with DSC requirements would be helpful. The suggested method of using implicit and defining an array does not work if DSC requirements are inserted. Error below is given:
The input object cannot be bound to any parameters for the command either because the command does not take pipeline input or the input and its properties do not match any of the parameters that take pipeline input.
A current workaround is to pipe the requirements array to New-Requirement while splatting the hashtable. Because we need to splat we have to use a foreach-object instead of a normal pipe:
$requirements | % { $r = $_; New-Requirement @r } | Invoke-Requirement | Format-Callstack
Sample code: https://gist.github.com/cdhunt/80984dea7c6e45f42badf6c7f7f7bd8f
I've tried .GetNewClosure()
on the Test and Set block as described in the Readme and $Name is always $null
.
However, adding .GetNewClosure()
on the New-RequirementGroup
scriptblock did create a correctly scoped closure.
Name Value
---- -----
PSVersion 7.0.3
PSEdition Core
GitCommitId 7.0.3
OS Linux 4.19.128-microsoft-standard #1 SMP Tue Jun 23 12:58:10 UTC 2020
Platform Unix
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0…}
PSRemotingProtocolVersion 2.3
SerializationVersion 1.1.0.1
WSManStackVersion 3.0
Hi guys,
For my use case, I would need to call the test blocks only of the requirements. I would still need to set them, but I would like to keep control of the action of 'setting' and use the test functions to simply have an overview of the state of a machine, without necessarly applying the setting.
Is that possible with this module? I looked and tried a bit, but I couldn't find it in the invoke-requirement parameter set.
Perhaps, that could be a nice feature, having a -TestsOnly
parameter or so .:)
Hello @chriskuech ,
As a feature request, could you add the date in the output of Format-Checklist cmdlet ? like the Format-Table
Thank you!
Hello @chriskuech ,
Could we passthrough variables between block ?
Because I use "invoke-command" cmdlet in block of Requirements and I would like to use a PSSession instead of creating a new session each time I invoke a remote command. Initiate a New-PSSession inside a Requirement is mandatory because in my code I test the WinRM connection before invoking any remote command, like:
@{ Describe = "Test WinRM connection '$VmName'" Test = { $online = $false ; while ($online -ne $true) { try { Test-WSMan -ComputerName $VmName -ErrorAction Stop ; $online = $true } catch { Start-Sleep 5 } } } },
Thank you !
[PS C:\users\zer0trust\Desktop> $requirements | Invoke-Requirement | Format-Checklist
Format-Checklist : The input object cannot be bound to any parameters for the command either because the command does not take pipeline input or the input and its properties do not match any of the parameters that take pipeline input.
At line:1 char:38
+ $requirements | Invoke-Requirement | Format-Checklist
+ ~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (RequirementEvent:RequirementEvent) [Format-Checklist], ParameterBindingException
+ FullyQualifiedErrorId : InputObjectNotBound,Format-Checklist]
PS C:\users\zer0trust\Desktop> $results = $requirements | Invoke-Requirement
PS C:\users\zer0trust\Desktop> $results.gettype()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Object[] System.Array
The Format-Checklist function appears to be looking for a "RequirementEvent" data type from the output of Invoke-Requirement, but the output of the commands show that it has the System.Array type instead.
It will be great if we can have some real-world examples of Requirements module in action
May I work on it ?
Hi,
following your video i found this:
$requirements = @(
@{
Describe = 'Folder tempi present in the system'
Test = { test-path -path 'c:/temp' }
#Set = { new-item -ItemType Directory -Path 'c:/temp'}
}
)
c:/temp still is not created, but the command fail:
pplyRequirement : Failed to apply Requirement 'Folder tempi present in the system'
At C:\Program Files\WindowsPowerShell\Modules\Requirements\2.3.6\src\core.ps1:49 char:23
~~~~~~~~~~~~~~~~~~~
We currently only have unit tests, where we dot-source the files and extensively test each function. We currently do not have integration tests where we Import-Module
Requirements and test the functions. We have manually-validated integration testing using /examples.ps1
. We need true integration tests, perhaps copied/forked from our interface.tests.ps1
tests.
We have had a few (now solved) issues already due to lack of true integration testing.
Using the following snippet from "Managing large configurations with Namespaces" produces Requirements without a Namespace (Namespace = "::" or ":"):
New-RequirementGroup "local" {
New-RequirementGroup "clis" {
@{
Describe = "az is installed"
Test = { ... }
Set = { ... }
}
@{
Describe = "kubectl is installed"
Test = { ... }
Set = { ... }
}
}
New-RequirementGroup "configs" {
@{
Describe = "cluster config is built"
Test = { ... }
Set = { ... }
}
}
}
New-RequirementGroup "cloud" {
@{
Describe = "Terraform is deployed"
Test = { ... }
Set = { ... }
}
}
This is the output:
DependsOn : {}
Namespace : ::
Describe : az is installed
Test : ...
Set : ...
DependsOn : {}
Namespace : ::
Describe : kubectl is installed
Test : ...
Set : ...
DependsOn : {}
Namespace : ::
Describe : cluster config is built
Test : ...
Set : ...
DependsOn : {}
Namespace : :
Describe : Terraform is deployed
Test : ...
Set : ...
Requirements version 2.3.5
Same results in Powershell 5.1 and 7.0 (preview)
Name Value
---- -----
PSVersion 5.1.17763.1007
PSEdition Desktop
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0...}
BuildVersion 10.0.17763.1007
CLRVersion 4.0.30319.42000
WSManStackVersion 3.0
PSRemotingProtocolVersion 2.3
SerializationVersion 1.1.0.1
Name Value
---- -----
PSVersion 7.0.0-rc.3
PSEdition Core
GitCommitId 7.0.0-rc.3
OS Microsoft Windows 10.0.17763
Platform Win32NT
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0…}
PSRemotingProtocolVersion 2.3
SerializationVersion 1.1.0.1
WSManStackVersion 3.0
Invoke-Requirement
should have a switch -Parallel
that allows requirements to be executed in parallel according to the Name
and DependsOn
properties of each Requirement.
This opt-in feature would provide a major improvement over DSC’s synchronous execution.
Right now, indentation seems to thrash between 2 spaces and 4 spaces.
It looks like the PS classes are not being properly exposed. Invoke-Requirement
does not see the class RequirementEvent
.
Unable to find type [RequirementEvent].
At C:\Users\Brandon\Documents\PowerShell\Modules\Requirements\2.0\src\interface.ps1:87 char:17
+ [OutputType([RequirementEvent])]
+ ~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (RequirementEvent:TypeName) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : TypeNotFound
Here is a repo script:
Import-Module Requirements
$requirements = @(
@{
Name = "Resource 1"
Describe = "Resource 1 is present in the system"
Test = { $mySystem -contains 1 }
Set = { $mySystem.Add(1) | Out-Null; Start-Sleep 1 }
},
@{
Name = "Resource 2"
Describe = "Resource 2 is present in the system"
Test = { $mySystem -contains 2 }
Set = { $mySystem.Add(2) | Out-Null; Start-Sleep 1 }
}
)
# demo using Format-Table
$mySystem = [System.Collections.ArrayList]::new()
$requirements | Invoke-Requirement | Format-Table
Hi team,
Interesting project, thank you for putting effort and open-sourcing this.
Can be very useful PS_based replacement of ServerSpec, InSpec and other non-PS based tools.
That said, can you please mention the status of this project?
Eg., who and how works on this, what is the roadmap and future, will it be supported in a long run or just abandoned at some point?
All this is useful to make informed decision on Requirements usage.
There is a small error in the README.md file regarding DSC in Requirement
Property = @{
Contents = "Hello World"
DestinationFile = "C:\myFile.txt"
Force = $true
}
Should be
Property = @{
Contents = "Hello World"
DestinationPath = "C:\myFile.txt"
Force = $true
}
I will make a PR
PS C:\users\zer0trust\Desktop> $requirements | Invoke-Requirement | Format-Checklist
03:27:04 [ ] Add test.txt fileFormat-Checklist : Cannot bind parameter 'Date' to the target. Exception setting "Date": "Cannot convert null to type "System.DateTime"."
At line:1 char:38
+ $requirements | Invoke-Requirement | Format-Checklist
+ ~~~~~~~~~~~~~~~~
+ CategoryInfo : WriteError: (:) [Format-Checklist], ParameterBindingException
+ FullyQualifiedErrorId : ParameterBindingFailed,Format-Checklist
The "Date" field output from Invoke-Requirement has spaces in it.
Date : 7/1/2019 3:26:43 PM
Method : Validate
State : Stop
Result : True
Modifying line 28 of formatters.ps1 as follows:
$timestamp = Get-Date -Date "$_.Date" -Format 'hh:mm:ss'
fixed the issue on my client.
While working on some examples with Requirements I have noticed that output for the test state in on the same line
11:46:46 [ ] Create a folder for the app11:46:46 [ ] Create the json config File
$WebConfigRequirements = @(
@{
name = "AppFolder"
describe = "Create a folder for the app"
test = {
test-path -Path $AppPath
}
set = {
new-item -path $AppPath -ItemType Directory
}
},
@{
name = "configfile"
describe = "Create the json config File"
test = {
test-path -Path "$($AppPath)config.json"
}
set = {
new-item -Path "$($AppPath)config.json"
}
}
)
$WebConfigRequirements | Invoke-Requirement | Format-Checklist
I will make some investigation on it
I have few remarks regarding how the module is tested and build
I did not see any build or CD information in the module. There is no badge, no build process.
If you look at the final product, the one you get from the PowerShell Gallery, include the same folder as the GitHub repos. This include the source, the .git, the .vscode and the images folders, readme.md and the test files.
My suggestions:
We heavily rely on classes, which don't integrate well with Import-Module
, which forces us to dot source a lot. using module
should solve our import woes.
I downloaded and have been trying out the module from the gallery version 2.3.4.
Whilst it's very likely that I'm doing something wrong, when I take the sample namespace code from the readme, the output on my systems shows :: instead of the actual namespace from the requriementgroup.
I found that i had to update line 162 of interface.ps1 to use $name instead ($r.Namespace = $Name, $r.Namespace -join $NamespaceDelimiter) because some for some reason the alias doesn't work on my system.
Sorry if this isn't logged in the exactly correct method (it's my first day)
I would like to have a summary format that is like Format-Checklist the final state of each Requirement is listed with a bool.
eg.
Requirement Result
----------- ------
SecretManagement is installed True
A New-Password function exists True
SQL SA Password secret is created True
Docker Network is created True
SQL Server image is cached True
SQL Server container exists True
SQL Server container is running True
Create ProGet db True
Proget image is cached True
Proget container exists True
Local proget-packages folder exists True
Proget container is running True
Run only Test
method of Requirements
Topics that need to be covered
if
, foreach
, etc)The Format-Callstack example in example.ps1
does not print the date. I think $_.Date
needs to be reassigned outside of the switch
expression, just like the other variables. The unit tests for Format-Callstack should've caught this issue.
PS C:\users\zer0trust\Desktop> get-command -Module Requirements
CommandType Name Version Source
----------- ---- ------- ------
Function Invoke-Requirement 2.1 requirements
Function New-Requirement 2.1 requirements
Function Set-Requirement 2.1 requirements
Function Test-Requirement 2.1 requirements
From Requirements.psd1:
# Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export.
FunctionsToExport = @(
'Invoke-Requirement',
'New-Requirement',
'Set-Requirement',
'Test-Requirement'
)
Missed some cases where Requirements failed to error correctly. We should enumerate and test these cases:
Methods | Scenario |
---|---|
Test |
Test outputs a falsey value |
Set |
Set throws an error |
Test Set |
Test fails both times it is called |
Getting a strange problem using format-checklist, if the test fails then the PowerShell session exits. This is my first attempt at using this module but I'm sure nothing I'm doing should cause this?
Example code:
$requirements = @(
@{
Name = "format-checklist-test"
Describe = "Failing test exits session"
Test = { Test-Path ./sagsgsg }
}
)
$requirements | invoke-requirement | format-checklist
07:46:15 [ X ] Failing test exits session
If the test is successful then it works fine, but if it fails then the PowerShell window closes after printing the result (I only managed to see the output by opening a second PowerShell session within the first one.)
I do not get the same problem when using format-callstack or no formatting at all.
Tested on 2 machines with same results
> $PSVersionTable
Name Value
---- -----
PSVersion 5.1.17134.858
PSEdition Desktop
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0...}
BuildVersion 10.0.17134.858
CLRVersion 4.0.30319.42000
WSManStackVersion 3.0
PSRemotingProtocolVersion 2.3
SerializationVersion 1.1.0.1
> get-module requirements
ModuleType Version Name ExportedCommands
---------- ------- ---- ----------------
Script 2.2.6 requirements {Format-CallStack, Format-Checklist, Invoke-Requirement, New-Requirement...}
Format-Checklist has reached an unexpected state 'TestSet Set Stop True'.
If you are piping the output of Invoke-Requirement directly to this
cmdlet, then this is probably a bug in Format-Checklist.
At C:\Users\chkuech\Documents\PowerShell\Modules\Requirements\2.2.4\src\formatters.ps1:128 char:13
+ throw @"
+ ~~~~~~~~
+ CategoryInfo : OperationStopped: (Format-Checklist ha\u2026n Format-Checklist.:String) [], RuntimeException
+ FullyQualifiedErrorId : Format-Checklist has reached an unexpected state 'TestSet Set Stop True'.
If you are piping the output of Invoke-Requirement directly to this
cmdlet, then this is probably a bug in Format-Checklist.
Format-Checklist fails when passing a RequirementEvent[] object as a parameter. It should format the objects as it does when they are passed in from the pipeline.
Error:
Format-Checklist : Cannot bind parameter 'Date' to the target. Exception setting "Date": "Cannot convert null to type
"System.DateTime"."
At line:25 char:1
+ Format-Checklist -RequirementEvent $output # fails
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : WriteError: (:) [Format-Checklist], ParameterBindingException
+ FullyQualifiedErrorId : ParameterBindingFailed,Format-Checklist
Code to reproduce:
$mySystem = [collections.generic.list[int]]::new()
$requirements = @(
@{
Name = "Resource 1"
Describe = "Resource 1 is present in the system"
Test = { $mySystem -contains 1 }
Set = { $mySystem.Add(1) | Out-Null; Start-Sleep 1 }
},
@{
Name = "Resource 2"
Describe = "Resource 2 is present in the system"
Test = { $mySystem -contains 2 }
Set = { $mySystem.Add(2) | Out-Null; Start-Sleep 1 }
}
)
$output = $requirements | Invoke-Requirement
$output | Format-Table | Out-Host # works
Format-Table -InputObject $output | Out-Host # works
$output | Format-Checklist | Out-Host # works
Format-Checklist -RequirementEvent $output # fails
Dear @chriskuech,
I use this requirement block :
@{ Describe = "Set Secret" Test = { Invoke-CommandAs -ComputerName $VmName -ScriptBlock { Get-SecretInfo -Name $Using:UserSecret } -AsSystem } Set = { Invoke-CommandAs -ComputerName $VmName -ScriptBlock { Set-Secret -Name $Using:UserSecret -Secret $Using:PasswordSecret -Vault CredManStore } -AsSystem } }
But I get the error:
Cannot validate argument on parameter 'Name'. The argument is null or empty. Provide an argument that is not null or empty, and
then try the command again.
+ CategoryInfo : InvalidData : (:) [Set-Secret], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.PowerShell.SecretManagement.SetSecretCommand
+ PSComputerName : MYVMNAME
I already tried the same cmdlet without Requirements module and it works.
It seems the Remote Variables are not usable with Requirements, or is it a mistake from my side?
Thank you for your support!
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.