Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 100 additions & 8 deletions resources/PSScript/psscript.dsc.resource.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"$schema": "https://aka.ms/dsc/schemas/v3/bundled/resource/manifest.json",
"type": "Microsoft.DSC.Transitional/PowerShellScript",
"description": "Enable running PowerShell 7 scripts inline",
"version": "0.1.0",
"version": "0.2.0",
"condition": "[not(equals(tryWhich('pwsh'), null()))]",
"get": {
"executable": "pwsh",
Expand Down Expand Up @@ -57,26 +57,118 @@
},
"schema": {
"embedded": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"title": "Transitional PowerShell script resource",
"description": "Defines an instance of the `Microsoft.DSC.Transitional/PowerShellScript` resource, which enables users to define inline scripts for the get, set, and test resource operations.",
"oneOf": [
{
"description": "Defines constraints for the return data of the resource operations.",
"oneOf": [
{
"description": "Defines the valid return data for `get` and `set` operations with a defined script.",
"required": [
"output"
]
},
{
"description": "Defines the return data as an empty object for operations with an undefined script.",
"minProperties": 0,
"maxProperties": 0
},
{
"description": "Defines the valid return data for implemented `test` operations.",
"required": [
"_inDesiredState"
]
}
]
},
{
"description": "Defines constraints for the input data of the resource operations. You must define at least one script property to use this resource.",
"anyOf": [
{
"required": [
"getScript"
]
},
{
"required": [
"testScript"
]
},
{
"required": [
"setScript"
]
}
]
}
],
"properties": {
"getScript": {
"type": ["string", "null"]
"title": "Get operation script",
"description": "A PowerShell script that retrieves the current state of the instance.",
"$ref": "#/$defs/powershellScript"
},
"setScript": {
"type": ["string", "null"]
"title": "Set operation script",
"description": "A PowerShell script that enforces the desired state for the instance.",
"$ref": "#/$defs/powershellScript"
},
"testScript": {
"type": ["string", "null"]
"title": "Test operation script",
"description": "A PowerShell script that checks whether the instance is in the desired state.",
"$ref": "#/$defs/powershellScript"
},
"input": {
"type": ["string", "boolean", "integer", "object", "array", "null"]
"title": "Script input data",
"description": "Defines the data to pass to every script as a parameter. When defined, every script property must include a `param()` statement with a single parameter.",
"writeOnly": true,
"type": [
"string",
"boolean",
"integer",
"number",
"object",
"array"
]
},
"output": {
"type": ["array", "null"]
"title": "Script output data",
"description": "Defines output emitted to the success stream from the invoked script. The resource result for an operation only includes this property when the script emits one or more items to the success stream.",
"readOnly": true,
"type": [
"string",
"boolean",
"integer",
"number",
"object",
"array",
"null"
]
},
"_inDesiredState": {
"type": ["boolean", "null"],
"default": null
"$ref": "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/v3/resource/properties/inDesiredState.json"
}
},
"$defs": {
"powershellScript": {
"writeOnly": true,
"type": "string",
"minLength": 1,
"contentMediaType": "text/vnd.microsoft.powershell"
},
"https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/v3/resource/properties/inDesiredState.json": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/v3/resource/properties/inDesiredState.json",
"title": "Instance is in the Desired State",
"description": "Indicates whether the instance is in the desired state. This property is only returned by the `test` method.",
"type": [
"boolean",
"null"
],
"readOnly": true
}
}
}
Expand Down
19 changes: 18 additions & 1 deletion resources/PSScript/psscript.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -189,5 +189,22 @@ if ($Operation -eq 'Test') {
exit 1
}
} else {
@{ output = $outputObjects } | ConvertTo-Json -Compress -Depth 10
$outputData = @{}
if ($outputObjects.Count -eq 1) {
$outputData.output = $outputObjects | Select-Object -First 1
} elseif ($outputObjects.Count -gt 1) {
$outputData.output = $outputObjects
}

$toJsonParams = @{
Compress = $true
Depth = 10
}
# For PowerShell, use `-EnumsAsStrings` to ensure that enum values are serialized as strings instead of integers.
# No equivalent option for Windows PowerShell, so this is a limitation of the WindowsPowerShellScript resource.
if ($PSVersionTable.PSVersion -ge [Version]'6.0') {
$toJsonParams['EnumsAsStrings'] = $true
}

$outputData | ConvertTo-Json @toJsonParams
}
56 changes: 29 additions & 27 deletions resources/PSScript/psscript.tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@ Describe 'Tests for PSScript resource' {
param($resourceType)

$yaml = @"
GetScript: |
getScript: |
"Hello, World!"
1+1
SetScript: |
setScript: |
throw 'This should not be executed'
"@
$result = dsc resource get -r $resourceType -i $yaml 2> $TestDrive/error.txt | ConvertFrom-Json
Expand All @@ -42,7 +42,7 @@ Describe 'Tests for PSScript resource' {
param($resourceType)

$yaml = @"
SetScript: |
setScript: |
"Hello, World!"
1+1
"@
Expand All @@ -57,10 +57,10 @@ Describe 'Tests for PSScript resource' {
param($resourceType)

$yaml = @"
GetScript: |
getScript: |
"Hello, World!"
1+1
SetScript: |
setScript: |
"Hello, World!"
2+2
"@
Expand All @@ -78,7 +78,7 @@ Describe 'Tests for PSScript resource' {
param($resourceType)

$yaml = @'
TestScript: |
testScript: |
$true
'@
$result = dsc resource test -r $resourceType -i $yaml 2> $TestDrive/error.txt | ConvertFrom-Json
Expand All @@ -90,7 +90,7 @@ Describe 'Tests for PSScript resource' {
param($resourceType)

$yaml = @'
TestScript: |
testScript: |
$false
'@
$result = dsc resource test -r $resourceType -i $yaml 2> $TestDrive/error.txt | ConvertFrom-Json
Expand All @@ -102,7 +102,7 @@ Describe 'Tests for PSScript resource' {
param($resourceType)

$yaml = @'
TestScript: |
testScript: |
"This is not a boolean"
'@
$result = dsc resource test -r $resourceType -i $yaml 2> $TestDrive/error.txt | ConvertFrom-Json
Expand All @@ -116,7 +116,7 @@ Describe 'Tests for PSScript resource' {
param($resourceType)

$yaml = @'
TestScript: |
testScript: |
$true
$false
'@
Expand All @@ -127,14 +127,14 @@ Describe 'Tests for PSScript resource' {
$errorLog | Should -BeLike '*ERROR*:*Test operation did not return a single boolean value.*' -Because $errorLog
}

It 'Empty SetScript is ignored for <resourceType>' -TestCases $testCases {
It 'Empty setScript is ignored for <resourceType>' -TestCases $testCases {
param($resourceType)

$yaml = @'
GetScript: |
getScript: |
"Hello, World!"
1+1
TestScript: |
testScript: |
$true
'@

Expand All @@ -146,29 +146,29 @@ Describe 'Tests for PSScript resource' {
$result.afterState.output.Count | Should -Be 0
}

It 'Empty GetScript is ignored for <resourceType>' -TestCases $testCases {
It 'Empty getScript is ignored for <resourceType>' -TestCases $testCases {
param($resourceType)

$yaml = @'
SetScript: |
setScript: |
"Hello, World!"
1+1
TestScript: |
testScript: |
$true
'@
$result = dsc resource get -r $resourceType -i $yaml 2> $TestDrive/error.txt | ConvertFrom-Json
$LASTEXITCODE | Should -Be 0 -Because (Get-Content $TestDrive/error.txt -Raw | Out-String)
$result.actualState.output.Count | Should -Be 0 -Because ($result | ConvertTo-Json | Out-String)
}

It 'Empty TestScript is ignored for <resourceType>' -TestCases $testCases {
It 'Empty testScript is ignored for <resourceType>' -TestCases $testCases {
param($resourceType)

$yaml = @'
GetScript: |
getScript: |
"Hello, World!"
1+1
SetScript: |
setScript: |
"Hello, World!"
2+2
'@
Expand All @@ -181,7 +181,7 @@ Describe 'Tests for PSScript resource' {
param($resourceType)

$yaml = @'
GetScript: |
getScript: |
Write-Warning "This is a warning"
Write-Warning "This is second warning"
'@
Expand All @@ -198,7 +198,7 @@ Describe 'Tests for PSScript resource' {
param($resourceType)

$yaml = @'
GetScript: |
getScript: |
Write-Error "This is an error"
'@

Expand All @@ -213,7 +213,7 @@ Describe 'Tests for PSScript resource' {
param($resourceType)

$yaml = @'
GetScript: |
getScript: |
Write-Verbose "This is a verbose message"
'@
$result = dsc -l info resource get -r $resourceType -i $yaml 2> $TestDrive/error.txt | ConvertFrom-Json
Expand All @@ -227,7 +227,7 @@ Describe 'Tests for PSScript resource' {
param($resourceType)

$yaml = @'
GetScript: |
getScript: |
Write-Debug "This is a debug message"
'@
$result = dsc -l debug resource get -r $resourceType -i $yaml 2> $TestDrive/error.txt | ConvertFrom-Json
Expand All @@ -241,7 +241,7 @@ Describe 'Tests for PSScript resource' {
param($resourceType)

$yaml = @'
GetScript: |
getScript: |
$InformationPreference = 'Continue'
Write-Information "This is an information message"
'@
Expand All @@ -256,7 +256,7 @@ Describe 'Tests for PSScript resource' {
param($resourceType)

$yaml = @'
GetScript: |
getScript: |
throw "This is an exception"
'@
$result = dsc resource get -r $resourceType -i $yaml 2> $TestDrive/error.txt | ConvertFrom-Json
Expand Down Expand Up @@ -287,7 +287,8 @@ Describe 'Tests for PSScript resource' {
$result = dsc resource get -r $resourceType -i $yaml 2> $TestDrive/error.txt | ConvertFrom-Json
$LASTEXITCODE | Should -Be 0 -Because (Get-Content $TestDrive/error.txt -Raw | Out-String)
$result.actualState.output.Count | Should -Be 1 -Because ($result | ConvertTo-Json -Depth 10 | Out-String)
$result.actualState.output[0] | Should -BeExactly "Input: This is a string"
$result.actualState.output.GetType().Name | Should -Be 'String'
$result.actualState.output | Should -BeExactly "Input: This is a string"
}

It 'Input without param block is an error for <resourceType>' -TestCases $testCases {
Expand Down Expand Up @@ -347,7 +348,8 @@ Describe 'Tests for PSScript resource' {
$result = dsc -l debug resource get -r $resourceType -i $yaml 2> $TestDrive/error.txt | ConvertFrom-Json
$LASTEXITCODE | Should -Be 0 -Because (Get-Content $TestDrive/error.txt -Raw | Out-String)
$result.actualState.output.Count | Should -Be 1 -Because ($result | ConvertTo-Json -Depth 10 | Out-String)
$result.actualState.output[0] | Should -BeExactly "This should still be output"
$result.actualState.output.GetType().Name | Should -Be 'String'
$result.actualState.output | Should -BeExactly "This should still be output"
$errorLog = Get-Content $TestDrive/error.txt -Raw
$errorLog | Should -BeLike '*DEBUG*:*Non-terminating errors occurred during script execution.*' -Because $errorLog
}
Expand All @@ -356,7 +358,7 @@ Describe 'Tests for PSScript resource' {
param($resourceType)

$yaml = @'
GetScript: |
getScript: |
Get-Item "ThisFileDoesNotExist.txt" -ErrorAction Stop
'@
$result = dsc resource get -r $resourceType -i $yaml 2> $TestDrive/error.txt | ConvertFrom-Json
Expand Down
Loading