1
0
Fork 0
mirror of https://github.com/ansible-collections/community.general.git synced 2024-09-14 20:13:21 +02:00

win_dsc - Add argument validation and other fixes (#53093)

* win_dsc - Add argument validation and other fixes

* Fix doc issues
This commit is contained in:
Jordan Borean 2019-03-06 06:49:37 +10:00 committed by GitHub
parent 853a65eead
commit 6b294eab4d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
27 changed files with 1585 additions and 990 deletions

View file

@ -0,0 +1,4 @@
minor_changes:
- win_dsc - The win_dsc module will now fail if an invalid DSC property is set.
- win_dsc - The module invocation and possible options will be displayed when running with ``-vvv``.
- win_dsc - The Verbose logs will be returned when running with ``-vvv``.

View file

@ -208,6 +208,8 @@ PowerShell module options and option choices are currently case insensitive to w
specification. This behaviour is deprecated and a warning displayed to the user if a case insensitive match was found. specification. This behaviour is deprecated and a warning displayed to the user if a case insensitive match was found.
A future release of Ansible will make these checks case sensitive. A future release of Ansible will make these checks case sensitive.
The ``win_dsc`` module will now validate the input options for a DSC resource. In previous versions invalid options would be ignored but are now not.
Modules removed Modules removed
--------------- ---------------

View file

@ -99,6 +99,67 @@ This is what the Ansible task version of the above DSC Registry resource would l
ValueName: TestValue ValueName: TestValue
ValueData: TestData ValueData: TestData
Starting in Ansible 2.8, the ``win_dsc`` module automatically validates the
input options from Ansible with the DSC definition. This means Ansible will
fail if the option name is incorrect, a mandatory option is not set, or the
value is not a valid choice. When running Ansible with a verbosity level of 3
or more (``-vvv``), the return value will contain the possible invocation
options based on the ``resource_name`` specified. Here is an example of the
invocation output for the above ``Registry`` task::
changed: [2016] => {
"changed": true,
"invocation": {
"module_args": {
"DependsOn": null,
"Ensure": "Present",
"Force": null,
"Hex": null,
"Key": "HKEY_LOCAL_MACHINE\\SOFTWARE\\ExampleKey",
"PsDscRunAsCredential_password": null,
"PsDscRunAsCredential_username": null,
"ValueData": [
"TestData"
],
"ValueName": "TestValue",
"ValueType": null,
"module_version": "latest",
"resource_name": "Registry"
}
},
"module_version": "1.1",
"reboot_required": false,
"verbose_set": [
"Perform operation 'Invoke CimMethod' with following parameters, ''methodName' = ResourceSet,'className' = MSFT_DSCLocalConfigurationManager,'namespaceName' = root/Microsoft/Windows/DesiredStateConfiguration'.",
"An LCM method call arrived from computer SERVER2016 with user sid S-1-5-21-3088887838-4058132883-1884671576-1105.",
"[SERVER2016]: LCM: [ Start Set ] [[Registry]DirectResourceAccess]",
"[SERVER2016]: [[Registry]DirectResourceAccess] (SET) Create registry key 'HKLM:\\SOFTWARE\\ExampleKey'",
"[SERVER2016]: [[Registry]DirectResourceAccess] (SET) Set registry key value 'HKLM:\\SOFTWARE\\ExampleKey\\TestValue' to 'TestData' of type 'String'",
"[SERVER2016]: LCM: [ End Set ] [[Registry]DirectResourceAccess] in 0.1930 seconds.",
"[SERVER2016]: LCM: [ End Set ] in 0.2720 seconds.",
"Operation 'Invoke CimMethod' complete.",
"Time taken for configuration job to complete is 0.402 seconds"
],
"verbose_test": [
"Perform operation 'Invoke CimMethod' with following parameters, ''methodName' = ResourceTest,'className' = MSFT_DSCLocalConfigurationManager,'namespaceName' = root/Microsoft/Windows/DesiredStateConfiguration'.",
"An LCM method call arrived from computer SERVER2016 with user sid S-1-5-21-3088887838-4058132883-1884671576-1105.",
"[SERVER2016]: LCM: [ Start Test ] [[Registry]DirectResourceAccess]",
"[SERVER2016]: [[Registry]DirectResourceAccess] Registry key 'HKLM:\\SOFTWARE\\ExampleKey' does not exist",
"[SERVER2016]: LCM: [ End Test ] [[Registry]DirectResourceAccess] False in 0.2510 seconds.",
"[SERVER2016]: LCM: [ End Set ] in 0.3310 seconds.",
"Operation 'Invoke CimMethod' complete.",
"Time taken for configuration job to complete is 0.475 seconds"
]
}
The ``invocation.module_args`` key shows the actual values that were set as
well as other possible values that were not set. Unfortunately this will not
show the default value for a DSC property, only what was set from the Ansible
task. Any ``*_password`` option will be masked in the output for security
reasons, if there are any other sensitive module options, set ``no_log: True``
on the task to stop all task output from being logged.
Property Types Property Types
-------------- --------------
Each DSC resource property has a type that is associated with it. Ansible Each DSC resource property has a type that is associated with it. Ansible
@ -123,9 +184,12 @@ For example:
SourceCredential_username: AdminUser SourceCredential_username: AdminUser
SourceCredential_password: PasswordForAdminUser SourceCredential_password: PasswordForAdminUser
.. Note:: You should set ``no_log: yes`` on the task definition in .. Note:: On versions of Ansible older than 2.8, you should set ``no_log: yes``
Ansible to ensure any credentials used are not stored in any log file or on the task definition in Ansible to ensure any credentials used are not
console output. stored in any log file or console output.
A ``[PSCredential]`` is defined with ``EmbeddedInstance("MSFT_Credential")`` in
a DSC resource MOF definition.
CimInstance Type CimInstance Type
++++++++++++++++ ++++++++++++++++
@ -144,13 +208,20 @@ For example, to define a ``[CimInstance]`` value in Ansible:
Windows: yes Windows: yes
In the above example, the CIM instance is a representation of the class In the above example, the CIM instance is a representation of the class
``MSFT_xWebAuthenticationInformation <https://github.com/PowerShell/xWebAdministration/blob/dev/DSCResources/MSFT_xWebsite/MSFT_xWebsite.schema.mof>``_. `MSFT_xWebAuthenticationInformation <https://github.com/PowerShell/xWebAdministration/blob/dev/DSCResources/MSFT_xWebsite/MSFT_xWebsite.schema.mof>`_.
This class accepts four boolean variables, ``Anonymous``, ``Basic``, This class accepts four boolean variables, ``Anonymous``, ``Basic``,
``Digest``, and ``Windows``. The keys to use in a ``[CimInstance]`` depend on ``Digest``, and ``Windows``. The keys to use in a ``[CimInstance]`` depend on
the class it represents. Please read through the documentation of the resource the class it represents. Please read through the documentation of the resource
to determine the keys that can be used and the types of each key value. The to determine the keys that can be used and the types of each key value. The
class definition is typically located in the ``<resource name>.schema.mof``. class definition is typically located in the ``<resource name>.schema.mof``.
HashTable Type
++++++++++++++
A ``[HashTable]`` object is also a dictionary but does not have a strict set of
keys that can/need to be defined. Like a ``[CimInstance]``, define it like a
normal dictionary value in YAML. A ``[HashTable]]`` is defined with
``EmbeddedInstance("MSFT_KeyValuePair")`` in a DSC resource MOF definition.
Arrays Arrays
++++++ ++++++
Simple type arrays like ``[string[]]`` or ``[UInt32[]]`` are defined as a list Simple type arrays like ``[string[]]`` or ``[UInt32[]]`` are defined as a list
@ -192,17 +263,39 @@ like this example:
Port: 80 Port: 80
IPAddress: '*' IPAddress: '*'
The above example, is an array with two values of the class ``MSFT_xWebBindingInformation <https://github.com/PowerShell/xWebAdministration/blob/dev/DSCResources/MSFT_xWebsite/MSFT_xWebsite.schema.mof>``_. The above example, is an array with two values of the class `MSFT_xWebBindingInformation <https://github.com/PowerShell/xWebAdministration/blob/dev/DSCResources/MSFT_xWebsite/MSFT_xWebsite.schema.mof>`_.
When defining a ``[CimInstance[]]``, be sure to read the resource documentation When defining a ``[CimInstance[]]``, be sure to read the resource documentation
to find out what keys to use in the definition. to find out what keys to use in the definition.
DateTime
++++++++
A ``[DateTime]`` object is a DateTime string representing the date and time in
the `ISO 8601 <https://www.w3.org/TR/NOTE-datetime>`_ date time format. The
value for a ``[DateTime]`` field should be quoted in YAML to ensure the string
is properly serialized to the Windows host. Here is an example of how to define
a ``[DateTime]`` value in Ansible:
.. code-block:: yaml+jinja
# As UTC-0 (No timezone)
DateTime: '2019-02-22T13:57:31.2311892+00:00'
# As UTC+4
DateTime: '2019-02-22T17:57:31.2311892+04:00'
# As UTC-4
DateTime: '2019-02-22T09:57:31.2311892-04:00'
All the values above are equal to a UTC date time of February 22nd 2019 at
1:57pm with 31 seconds and 2311892 milliseconds.
Run As Another User Run As Another User
------------------- -------------------
By default, DSC runs each resource as the SYSTEM account and not the account By default, DSC runs each resource as the SYSTEM account and not the account
that Ansible use to run the module. This means that resources that are dynamically that Ansible use to run the module. This means that resources that are dynamically
loaded based on a user profile, like the ``HKEY_CURRENT_USER`` registry hive, loaded based on a user profile, like the ``HKEY_CURRENT_USER`` registry hive,
will be loaded under the ``SYSTEM`` profile. The parameter will be loaded under the ``SYSTEM`` profile. The parameter
`PsDscRunAsCredential`` is a parameter that can be set for every DSC resource ``PsDscRunAsCredential`` is a parameter that can be set for every DSC resource
force the DSC engine to run under a different account. As force the DSC engine to run under a different account. As
``PsDscRunAsCredential`` has a type of ``PSCredential``, it is defined with the ``PsDscRunAsCredential`` has a type of ``PSCredential``, it is defined with the
``_username`` and ``_password`` suffix. ``_username`` and ``_password`` suffix.

View file

@ -4,272 +4,400 @@
# Copyright: (c) 2017, Ansible Project # Copyright: (c) 2017, Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
#Requires -Module Ansible.ModuleUtils.Legacy #AnsibleRequires -CSharpUtil Ansible.Basic
#Requires -Version 5 #Requires -Version 5
$ErrorActionPreference = "Stop" Function ConvertTo-ArgSpecType {
<#
.SYNOPSIS
Converts the DSC parameter type to the arg spec type required for Ansible.
#>
param(
[Parameter(Mandatory=$true)][String]$CimType
)
$params = Parse-Args $args -supports_check_mode $true $arg_type = switch($CimType) {
$result = @{ Boolean { "bool" }
changed = $false Char16 { [Func[[Object], [Char]]]{ [System.Char]::Parse($args[0].ToString()) } }
DateTime { [Func[[Object], [DateTime]]]{
# o == ISO 8601 format
[System.DateTime]::ParseExact($args[0].ToString(), "o", [CultureInfo]::InvariantCulture,
[System.Globalization.DateTimeStyles]::None)
}}
Instance { "dict" }
Real32 { "float" }
Real64 { [Func[[Object], [Double]]]{ [System.Double]::Parse($args[0].ToString()) } }
Reference { "dict" }
SInt16 { [Func[[Object], [Int16]]]{ [System.Int16]::Parse($args[0].ToString()) } }
SInt32 { "int" }
SInt64 { [Func[[Object], [Int64]]]{ [System.Int64]::Parse($args[0].ToString()) } }
SInt8 { [Func[[Object], [SByte]]]{ [System.SByte]::Parse($args[0].ToString()) } }
String { "str" }
UInt16 { [Func[[Object], [UInt16]]]{ [System.UInt16]::Parse($args[0].ToString()) } }
UInt32 { [Func[[Object], [UInt32]]]{ [System.UInt32]::Parse($args[0].ToString()) } }
UInt64 { [Func[[Object], [UInt64]]]{ [System.UInt64]::Parse($args[0].ToString()) } }
UInt8 { [Func[[Object], [Byte]]]{ [System.Byte]::Parse($args[0].ToString()) } }
Unknown { "raw" }
default { "raw" }
}
return $arg_type
} }
Function Cast-ToCimInstance($name, $value, $className) Function Get-DscCimClassProperties {
{ <#
# this converts a hashtable to a CimInstance .SYNOPSIS
Get's a list of CimProperties of a CIM Class. It filters out any magic or
read only properties that we don't need to know about.
#>
param([Parameter(Mandatory=$true)][String]$ClassName)
$valueType = $value.GetType() $resource = Get-CimClass -ClassName $ClassName -Namespace root\Microsoft\Windows\DesiredStateConfiguration
if ($valueType -ne [hashtable])
{ # Filter out any magic properties that are used internally on an OMI_BaseResource
Fail-Json -obj $result -message "CimInstance value for property $name must be a hashtable, was $($valueType.FullName)" # https://github.com/PowerShell/PowerShell/blob/master/src/System.Management.Automation/DscSupport/CimDSCParser.cs#L1203
$magic_properties = @("ResourceId", "SourceInfo", "ModuleName", "ModuleVersion", "ConfigurationName")
$properties = $resource.CimClassProperties | Where-Object {
($resource.CimSuperClassName -ne "OMI_BaseResource" -or $_.Name -notin $magic_properties) -and
-not $_.Flags.HasFlag([Microsoft.Management.Infrastructure.CimFlags]::ReadOnly)
} }
try return ,$properties
{
$cim = New-CimInstance -ClassName $className -Property $value -ClientOnly
}
catch
{
Fail-Json -obj $result -message "Failed to convert hashtable to CimInstance of $($className): $($_.Exception.Message)"
}
return ,$cim
} }
Function Cast-Value($value, $type, $typeString, $name) Function Add-PropertyOption {
{ <#
if ($type -eq [CimInstance]) .SYNOPSIS
{ Adds the spec for the property type to the existing module specification.
$newValue = Cast-ToCimInstance -name $name -value $value -className $typeString #>
} param(
ElseIf ($type -eq [CimInstance[]]) [Parameter(Mandatory=$true)][Hashtable]$Spec,
{ [Parameter(Mandatory=$true)]
if ($value -isnot [array]) [Microsoft.Management.Infrastructure.CimPropertyDeclaration]$Property
{ )
$value = @($value)
} $option = @{
[CimInstance[]]$newValue = @() required = $false
$baseTypeString = $typeString.Substring(0, $typeString.Length - 2)
foreach ($cim in $value)
{
$newValue += Cast-ToCimInstance -name $name -value $cim -className $baseTypeString
}
}
Else
{
$originalType = $value.GetType()
if ($originalType -eq $type)
{
$newValue = $value
}
Else
{
$newValue = $value -as $type
if ($newValue -eq $null)
{
Add-Warning -obj $result -message "failed to cast property $name from '$value' of type $($originalType.FullName) to type $($type.FullName), the DSC engine may ignore this property with an invalid cast"
$newValue = $value
}
} }
$property_name = $Property.Name
$property_type = $Property.CimType.ToString()
if ($Property.Flags.HasFlag([Microsoft.Management.Infrastructure.CimFlags]::Key) -or
$Property.Flags.HasFlag([Microsoft.Management.Infrastructure.CimFlags]::Required)) {
$option.required = $true
} }
return ,$newValue if ($null -ne $Property.Qualifiers['Values']) {
$option.choices = [System.Collections.Generic.List`1[Object]]$Property.Qualifiers['Values'].Value
}
if ($property_name -eq "Name") {
# For backwards compatibility we support specifying the Name DSC property as item_name
$option.aliases = @("item_name")
} elseif ($property_name -ceq "key") {
# There seems to be a bug in the CIM property parsing when the property name is 'Key'. The CIM instance will
# think the name is 'key' when the MOF actually defines it as 'Key'. We set the proper casing so the module arg
# validator won't fire a case sensitive warning
$property_name = "Key"
}
if ($Property.ReferenceClassName -eq "MSFT_Credential") {
# Special handling for the MSFT_Credential type (PSCredential), we handle this with having 2 options that
# have the suffix _username and _password.
$option_spec_pass = @{
type = "str"
required = $option.required
no_log = $true
}
$Spec.options."$($property_name)_password" = $option_spec_pass
$Spec.required_together.Add(@("$($property_name)_username", "$($property_name)_password")) > $null
$property_name = "$($property_name)_username"
$option.type = "str"
} elseif ($Property.ReferenceClassName -eq "MSFT_KeyValuePair") {
$option.type = "dict"
} elseif ($property_type.EndsWith("Array")) {
$option.type = "list"
$option.elements = ConvertTo-ArgSpecType -CimType $property_type.Substring(0, $property_type.Length - 5)
} else {
$option.type = ConvertTo-ArgSpecType -CimType $property_type
}
if (($option.type -eq "dict" -or ($option.type -eq "list" -and $option.elements -eq "dict")) -and
$Property.ReferenceClassName -ne "MSFT_KeyValuePair") {
# Get the sub spec if the type is a Instance (CimInstance/dict)
$sub_option_spec = Get-OptionSpec -ClassName $Property.ReferenceClassName
$option += $sub_option_spec
}
$Spec.options.$property_name = $option
} }
Function Parse-DscProperty($name, $value, $resourceProp) Function Get-OptionSpec {
{ <#
$propertyTypeString = $resourceProp.PropertyType .SYNOPSIS
if ($propertyTypeString.StartsWith("[")) Generates the specifiec used in AnsibleModule for a CIM MOF resource name.
{
$propertyTypeString = $propertyTypeString.Substring(1, $propertyTypeString.Length - 2)
}
$propertyType = $propertyTypeString -as [type]
# CimInstance and CimInstance[] are reperesented as the actual Cim .NOTES
# ClassName and the above returns a $null. We need to manually set the This won't be able to retrieve the default values for an option as that is not defined in the MOF for a resource.
# type in these cases Default values are still preserved in the DSC engine if we don't pass in the property at all, we just can't report
if ($propertyType -eq $null) on what they are automatically.
{ #>
if ($propertyTypeString.EndsWith("[]")) param(
{ [Parameter(Mandatory=$true)][String]$ClassName
$propertyType = [CimInstance[]] )
}
Else $spec = @{
{ options = @{}
$propertyType = [CimInstance] required_together = [System.Collections.ArrayList]@()
} }
$properties = Get-DscCimClassProperties -ClassName $ClassName
foreach ($property in $properties) {
Add-PropertyOption -Spec $spec -Property $property
} }
if ($propertyType.IsArray) return $spec
{
# convert the value to a list for later conversion
if ($value -is [string])
{
$value = $value.Split(",").Trim()
}
ElseIf ($value -isnot [array])
{
$value = @($value)
}
}
$newValue = Cast-Value -value $value -type $propertyType -typeString $propertyTypeString -name $name
return ,$newValue
} }
$check_mode = Get-AnsibleParam -obj $params -name "_ansible_check_mode" -type "bool" -default $false Function ConvertTo-CimInstance {
$resourcename = Get-AnsibleParam -obj $params -name "resource_name" -type "str" -failifempty $true <#
$module_version = Get-AnsibleParam -obj $params -name "module_version" -type "str" -default "latest" .SYNOPSIS
Converts a dict to a CimInstance of the specified Class. Also provides a
better error message if this fails that contains the option name that failed.
#>
param(
[Parameter(Mandatory=$true)][String]$Name,
[Parameter(Mandatory=$true)][String]$ClassName,
[Parameter(Mandatory=$true)][System.Collections.IDictionary]$Value,
[Parameter(Mandatory=$true)][Ansible.Basic.AnsibleModule]$Module,
[Switch]$Recurse
)
#From Ansible 2.3 onwards, params is now a Hash Array $properties = @{}
$Attributes = @{} foreach ($value_info in $Value.GetEnumerator()) {
foreach ($param in $params.GetEnumerator()) # Need to remove all null values from existing dict so the conversion works
{ if ($null -eq $value_info.Value) {
if ($param.Name -notin @("resource_name", "module_version") -and $param.Name -notlike "_ansible_*") continue
{ }
$Attributes[$param.Name] = $param.Value $properties.($value_info.Key) = $value_info.Value
}
if ($Recurse) {
# We want to validate and convert and values to what's required by DSC
$properties = ConvertTo-DscProperty -ClassName $ClassName -Params $properties -Module $Module
}
try {
return (New-CimInstance -ClassName $ClassName -Property $properties -ClientOnly)
} catch {
# New-CimInstance raises a poor error message, make sure we mention what option it is for
$Module.FailJson("Failed to cast dict value for option '$Name' to a CimInstance: $($_.Exception.Message)", $_)
} }
} }
if ($Attributes.Count -eq 0) Function ConvertTo-DscProperty {
{ <#
Fail-Json -obj $result -message "No attributes specified" .SYNOPSIS
} Converts the input module parameters that have been validated and casted
into the types expected by the DSC engine. This is mostly done to deal with
types like PSCredential and Dictionaries.
#>
param(
[Parameter(Mandatory=$true)][String]$ClassName,
[Parameter(Mandatory=$true)][System.Collections.IDictionary]$Params,
[Parameter(Mandatory=$true)][Ansible.Basic.AnsibleModule]$Module
)
$properties = Get-DscCimClassProperties -ClassName $ClassName
#Always return some basic info $dsc_properties = @{}
$result["reboot_required"] = $false foreach ($property in $properties) {
$property_name = $property.Name
$property_type = $property.CimType.ToString()
$Config = @{ if ($property.ReferenceClassName -eq "MSFT_Credential") {
Name = ($resourcename) $username = $Params."$($property_name)_username"
Property = @{} $password = $Params."$($property_name)_password"
}
#Get the latest version of the module # No user set == No option set in playbook, skip this property
if ($module_version -eq "latest") if ($null -eq $username) {
{ continue
$Resource = Get-DscResource -Name $resourcename -ErrorAction SilentlyContinue | sort Version | select -Last 1
}
else
{
$Resource = Get-DscResource -Name $resourcename -ErrorAction SilentlyContinue | where {$_.Version -eq $module_version}
}
if (!$Resource)
{
if ($module_version -eq "latest")
{
Fail-Json -obj $result -message "Resource $resourcename not found"
} }
else $sec_password = ConvertTo-SecureString -String $password -AsPlainText -Force
{ $value = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $username, $sec_password
Fail-Json -obj $result -message "Resource $resourcename with version $module_version not found" } else {
$value = $Params.$property_name
# The actual value wasn't set, skip adding this property
if ($null -eq $value) {
continue
} }
if ($property.ReferenceClassName -eq "MSFT_KeyValuePair") {
$key_value_pairs = [System.Collections.Generic.List`1[CimInstance]]@()
foreach ($value_info in $value.GetEnumerator()) {
$kvp = @{Key = $value_info.Key; Value = $value_info.Value.ToString()}
$cim_instance = ConvertTo-CimInstance -Name $property_name -ClassName MSFT_KeyValuePair `
-Value $kvp -Module $Module
$key_value_pairs.Add($cim_instance) > $null
}
$value = $key_value_pairs.ToArray()
} elseif ($null -ne $property.ReferenceClassName) {
# Convert the dict to a CimInstance (or list of CimInstances)
$convert_args = @{
ClassName = $property.ReferenceClassName
Module = $Module
Name = $property_name
Recurse = $true
}
if ($property_type.EndsWith("Array")) {
$value = [System.Collections.Generic.List`1[CimInstance]]@()
foreach ($raw in $Params.$property_name.GetEnumerator()) {
$cim_instance = ConvertTo-CimInstance -Value $raw @convert_args
$value.Add($cim_instance) > $null
}
$value = $value.ToArray() # Need to make sure we are dealing with an Array not a List
} else {
$value = ConvertTo-CimInstance -Value $value @convert_args
}
}
}
$dsc_properties.$property_name = $value
}
return $dsc_properties
} }
#Get the Module that provides the resource. Will be used as Function Invoke-DscMethod {
#mandatory argument for Invoke-DscResource <#
$Module = @{ .SYNOPSIS
ModuleName = $Resource.ModuleName Invokes the DSC Resource Method specified in another PS pipeline. This is
ModuleVersion = $Resource.Version done so we can retrieve the Verbose stream and return it back to the user
for futher debugging.
#>
param(
[Parameter(Mandatory=$true)][Ansible.Basic.AnsibleModule]$Module,
[Parameter(Mandatory=$true)][String]$Method,
[Parameter(Mandatory=$true)][Hashtable]$Arguments
)
# Invoke the DSC resource in a separate runspace so we can capture the Verbose output
$ps = [PowerShell]::Create()
$ps.AddCommand("Invoke-DscResource").AddParameter("Method", $Method) > $null
$ps.AddParameters($Arguments) > $null
$result = $ps.Invoke()
# Pass the warnings through to the AnsibleModule return result
foreach ($warning in $ps.Streams.Warning) {
$Module.Warn($warning.Message)
}
# If running at a high enough verbosity, add the verbose output to the AnsibleModule return result
if ($Module.Verbosity -ge 3) {
$verbose_logs = [System.Collections.Generic.List`1[String]]@()
foreach ($verbosity in $ps.Streams.Verbose) {
$verbose_logs.Add($verbosity.Message) > $null
}
$Module.Result."verbose_$($Method.ToLower())" = $verbose_logs
}
if ($ps.HadErrors) {
# Cannot pass in the ErrorRecord as it's a RemotingErrorRecord and doesn't contain the ScriptStackTrace
# or other info that would be useful
$Module.FailJson("Failed to invoke DSC $Method method: $($ps.Streams.Error[0].Exception.Message)")
}
return $result
}
# win_dsc is unique in that is builds the arg spec based on DSC Resource input. To get this info
# we need to read the resource_name and module_version value which is done outside of Ansible.Basic
if ($args.Length -gt 0) {
$params = Get-Content -Path $args[0] | ConvertFrom-Json
} else {
$params = $complex_args
}
if (-not $params.ContainsKey("resource_name")) {
$res = @{
msg = "missing required argument: resource_name"
failed = $true
}
Write-Output -InputObject (ConvertTo-Json -Compress -InputObject $res)
exit 1
}
$resource_name = $params.resource_name
if ($params.ContainsKey("module_version")) {
$module_version = $params.module_version
} else {
$module_version = "latest"
}
$module_versions = (Get-DscResource -Name $resource_name -ErrorAction SilentlyContinue | Sort-Object -Property Version)
$resource = $null
if ($module_version -eq "latest" -and $null -ne $module_versions) {
$resource = $module_versions[-1]
} elseif ($module_version -ne "latest") {
$resource = $module_versions | Where-Object { $_.Version -eq $module_version }
}
if (-not $resource) {
if ($module_version -eq "latest") {
$msg = "Resource '$resource_name' not found."
} else {
$msg = "Resource '$resource_name' with version '$module_version' not found."
$msg += " Versions installed: '$($module_versions.Version -join "', '")'."
}
Write-Output -InputObject (ConvertTo-Json -Compress -InputObject @{ failed = $true; msg = $msg })
exit 1
}
# Build the base args for the DSC Invocation based on the resource selected
$dsc_args = @{
Name = $resource.Name
} }
# Binary resources are not working very well with that approach - need to guesstimate module name/version # Binary resources are not working very well with that approach - need to guesstimate module name/version
if ( -not ($Module.ModuleName -or $Module.ModuleVersion)) { $module_version = $null
$Module = 'PSDesiredStateConfiguration' if ($resource.Module) {
$dsc_args.ModuleName = @{
ModuleName = $resource.Module.Name
ModuleVersion = $resource.Module.Version
}
$module_version = $resource.Module.Version.ToString()
} else {
$dsc_args.ModuleName = "PSDesiredStateConfiguration"
} }
#grab the module version if we can # To ensure the class registered with CIM is the one based on our version, we want to run the Get method so the DSC
# engine updates the metadata propery. We don't care about any errors here
try { try {
if ($Resource.Module.Version) Invoke-DscResource -Method Get -Property @{Fake="Fake"} @dsc_args > $null
{ } catch {}
$result["module_version"] = $Resource.Module.Version.ToString()
}
}
catch {}
#Convert params to correct datatype and inject # Dynamically build the option spec based on the resource_name specified and create the module object
foreach ($attribute in $Attributes.GetEnumerator()) $spec = Get-OptionSpec -ClassName $resource.ResourceType
{ $spec.supports_check_mode = $true
$key = $attribute.Name.Replace("item_name", "name") $spec.options.module_version = @{ type = "str"; default = "latest" }
$value = $attribute.Value $spec.options.resource_name = @{ type = "str"; required = $true }
$prop = $resource.Properties | Where-Object {$_.Name -eq $key}
if (!$prop)
{
#If its a credential specified as "credential", Ansible will support credential_username and credential_password. Need to check for that
$prop = $resource.Properties | Where-Object {$_.Name -eq $key.Replace("_username","")}
if ($prop)
{
#We need to construct a cred object. At this point keyvalue is the username, so grab the password
$PropUserNameValue = $value
$PropPassword = $key.Replace("_username","_password")
$PropPasswordValue = $Attributes.$PropPassword
$KeyValue = New-Object System.Management.Automation.PSCredential ($PropUserNameValue, ($PropPasswordValue | ConvertTo-SecureString -AsPlainText -Force)) $module = [Ansible.Basic.AnsibleModule]::Create($args, $spec)
$config.Property.Add($key.Replace("_username",""),$KeyValue) $module.Result.reboot_required = $false
} $module.Result.module_version = $module_version
ElseIf ($key.Contains("_password"))
{
#Do nothing. We suck in the password in the handler for _username, so we can just skip it.
}
Else
{
Fail-Json -obj $result -message "Property $key in resource $resourcename is not a valid property"
}
}
Else
{
if ($value -eq $null)
{
$keyValue = $null
}
Else
{
$keyValue = Parse-DscProperty -name $key -value $value -resourceProp $prop
}
$config.Property.Add($key, $keyValue) # Build the DSC invocation arguments and invoke the resource
$dsc_args.Property = ConvertTo-DscProperty -ClassName $resource.ResourceType -Module $module -Params $Module.Params
$dsc_args.Verbose = $true
$test_result = Invoke-DscMethod -Module $module -Method Test -Arguments $dsc_args
if ($test_result.InDesiredState -ne $true) {
if (-not $module.CheckMode) {
$result = Invoke-DscMethod -Module $module -Method Set -Arguments $dsc_args
$module.Result.reboot_required = $result.RebootRequired
} }
$module.Result.changed = $true
} }
try $module.ExitJson()
{
#Defined variables in strictmode
$TestError, $TestError = $null
$TestResult = Invoke-DscResource @Config -Method Test -ModuleName $Module -ErrorVariable TestError -ErrorAction SilentlyContinue -WarningVariable TestWarn
foreach ($warning in $TestWarn) {
Add-Warning -obj $result -message $warning.Message
}
if ($TestError)
{
throw ($TestError[0].Exception.Message)
}
ElseIf (($TestResult.InDesiredState) -ne $true)
{
if ($check_mode -eq $False)
{
$SetResult = Invoke-DscResource -Method Set @Config -ModuleName $Module -ErrorVariable SetError -ErrorAction SilentlyContinue -WarningVariable SetWarn
foreach ($warning in $SetWarn) {
Add-Warning -obj $result -message $warning.Message
}
if ($SetError -and ($SetResult -eq $null))
{
#If SetError was filled, throw to exit out of the try/catch loop
throw $SetError
}
$result["reboot_required"] = $SetResult.RebootRequired
}
$result["changed"] = $true
if ($SetError)
{
throw ($SetError[0].Exception.Message)
}
}
}
Catch
{
Fail-Json -obj $result -message $_[0].Exception.Message
}
Exit-Json -obj $result

View file

@ -54,6 +54,11 @@ options:
provided but a comma separated string also work. Use a list where provided but a comma separated string also work. Use a list where
possible as no escaping is required and it works with more complex types possible as no escaping is required and it works with more complex types
list C(CimInstance[]). list C(CimInstance[]).
- If the type of the DSC resource option is a C(DateTime), use a string in
the form of an ISO 8901 string.
- Since Ansible 2.8, Ansible will now validate the input fields against the
DSC resource definition automatically. Older versions will silently
ignore invalid fields.
type: str type: str
required: true required: true
notes: notes:
@ -65,6 +70,9 @@ notes:
- The DSC engine run's each task as the SYSTEM account, any resources that need - The DSC engine run's each task as the SYSTEM account, any resources that need
to be accessed with a different account need to have C(PsDscRunAsCredential) to be accessed with a different account need to have C(PsDscRunAsCredential)
set. set.
- To see the valid options for a DSC resource, run the module with C(-vvv) to
show the possible module invocation. Default values are not shown in this
output but are applied within the DSC engine.
author: author:
- Trond Hindenes (@trondhindenes) - Trond Hindenes (@trondhindenes)
''' '''
@ -103,6 +111,11 @@ EXAMPLES = r'''
Ensure: Present Ensure: Present
Type: Directory Type: Directory
- name: Call DSC resource with DateTime option
win_dsc:
resource_name: DateTimeResource
DateTimeOption: '2019-02-22T13:57:31.2311892+00:00'
# more complex example using custom DSC resource and dict values # more complex example using custom DSC resource and dict values
- name: Setup the xWebAdministration module - name: Setup the xWebAdministration module
win_psmodule: win_psmodule:
@ -137,7 +150,7 @@ EXAMPLES = r'''
RETURN = r''' RETURN = r'''
module_version: module_version:
description: The version of the dsc resource/module used. description: The version of the dsc resource/module used.
returned: success returned: always
type: str type: str
sample: "1.0.1" sample: "1.0.1"
reboot_required: reboot_required:
@ -146,9 +159,24 @@ reboot_required:
returned: always returned: always
type: bool type: bool
sample: true sample: true
message: verbose_test:
description: Any error message from invoking the DSC resource. description: The verbose output as a list from executing the DSC test
returned: error method.
type: str returned: Ansible verbosity is -vvv or greater
sample: Multiple DSC modules found with resource name xyz type: list
sample: [
"Perform operation 'Invoke CimMethod' with the following parameters, ",
"[SERVER]: LCM: [Start Test ] [[File]DirectResourceAccess]",
"Operation 'Invoke CimMethod' complete."
]
verbose_set:
description: The verbose output as a list from executing the DSC Set
method.
returned: Ansible verbosity is -vvv or greater and a change occurred
type: list
sample: [
"Perform operation 'Invoke CimMethod' with the following parameters, ",
"[SERVER]: LCM: [Start Set ] [[File]DirectResourceAccess]",
"Operation 'Invoke CimMethod' complete."
]
''' '''

View file

@ -1,5 +0,0 @@
---
# Feature not normally installed by default.
test_win_dsc_feature_name: Telnet-Client
test_win_dsc_folder: C:\ansible test
test_win_dsc_run_desctructive: no

View file

@ -1,44 +0,0 @@
xTestResource Version: 2.0.0
Ensure:
Type: System.String
Value: Present
StringParam:
Type: System.String
Value: string param
UInt32Param:
Type: System.UInt32
Value: 1000
UInt64Param:
Type: System.UInt64
Value: 1000000
StringArrayParam:
Type: System.String[]
Value: [ "string 1", "string 2" ]
UInt32ArrayParam:
Type: System.UInt32[]
Value: [ 1000, 2000 ]
UInt64ArrayParam:
Type: System.UInt64[]
Value: [ 1000000, 2000000 ]
BooleanParam:
Type: System.Boolean
Value: True
PSCredentialParam:
Type: System.Management.Automation.PSCredential
Username: username
Password: password
CimInstanceParam:
Type: Microsoft.Management.Infrastructure.CimInstance
CimInstanceArrayParam:
Type: Microsoft.Management.Infrastructure.CimInstance[]

View file

@ -1,44 +0,0 @@
xTestResource Version: 1.0.0
Ensure:
Type: System.String
Value: Present
StringParam:
Type: System.String
Value: string param
UInt32Param:
Type: System.UInt32
Value: 1000
UInt64Param:
Type: System.UInt64
Value: 1000000
StringArrayParam:
Type: System.String[]
Value: [ "string 1", "string 2" ]
UInt32ArrayParam:
Type: System.UInt32[]
Value: [ 1000, 2000 ]
UInt64ArrayParam:
Type: System.UInt64[]
Value: [ 1000000, 2000000 ]
BooleanParam:
Type: System.Boolean
Value: True
PSCredentialParam:
Type: System.Management.Automation.PSCredential
Username: username
Password: password
CimInstanceParam:
Type: Microsoft.Management.Infrastructure.CimInstance
CimInstanceArrayParam:
Type: Microsoft.Management.Infrastructure.CimInstance[]

View file

@ -0,0 +1,41 @@
#Requires -Version 5.0 -Modules CimCmdlets
Function Get-TargetResource
{
[CmdletBinding()]
[OutputType([Hashtable])]
param(
[Parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[String]$KeyParam
)
return @{Value = [bool]$global:DSCMachineStatus}
}
Function Set-TargetResource
{
[CmdletBinding()]
param (
[Parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[String]$KeyParam,
[Bool]$Value = $true
)
$global:DSCMachineStatus = [int]$Value
}
Function Test-TargetResource
{
[CmdletBinding()]
[OutputType([Boolean])]
param (
[Parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[String]$KeyParam,
[Bool]$Value = $true
)
$false
}
Export-ModuleMember -Function *-TargetResource

View file

@ -0,0 +1,7 @@
[ClassVersion("1.0.0"), FriendlyName("xSetReboot")]
class ANSIBLE_xSetReboot : OMI_BaseResource
{
[Key] String KeyParam;
[Write] Boolean Value;
};

View file

@ -0,0 +1,214 @@
#Requires -Version 5.0 -Modules CimCmdlets
Function ConvertFrom-CimInstance {
param(
[Parameter(Mandatory=$true)][CimInstance]$Instance
)
$hashtable = @{
_cim_instance = $Instance.CimSystemProperties.ClassName
}
foreach ($prop in $Instance.CimInstanceProperties) {
$hashtable."$($prop.Name)" = ConvertTo-OutputValue -Value $prop.Value
}
return $hashtable
}
Function ConvertTo-OutputValue {
param($Value)
if ($Value -is [DateTime[]]) {
$Value = $Value | ForEach-Object { $_.ToString("o") }
} elseif ($Value -is [DateTime]) {
$Value = $Value.ToString("o")
} elseif ($Value -is [Double]) {
$Value = $Value.ToString() # To avoid Python 2 double parsing issues on test validation
} elseif ($Value -is [Double[]]) {
$Value = $Value | ForEach-Object { $_.ToString() }
} elseif ($Value -is [PSCredential]) {
$password = $null
$password_ptr = [System.Runtime.InteropServices.Marshal]::SecureStringToGlobalAllocUnicode($Value.Password)
try {
$password = [System.Runtime.InteropServices.Marshal]::PtrToStringUni($password_ptr)
} finally {
[System.Runtime.InteropServices.Marshal]::ZeroFreeGlobalAllocUnicode($password_ptr)
}
$Value = @{
username = $Value.Username
password = $password
}
} elseif ($Value -is [CimInstance[]]) {
$value_list = [System.Collections.Generic.List`1[Hashtable]]@()
foreach ($cim_instance in $Value) {
$value_list.Add((ConvertFrom-CimInstance -Instance $cim_instance))
}
$Value = $value_list.ToArray()
} elseif ($Value -is [CimInstance]) {
$Value = ConvertFrom-CimInstance -Instance $Value
}
return ,$Value
}
Function Get-TargetResource
{
[CmdletBinding()]
[OutputType([Hashtable])]
param(
[Parameter(Mandatory = $true)]
[ValidateSet("Present", "Absent")]
[String] $Ensure = "Present",
[Parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[String] $Path
)
return @{
Ensure = $Ensure
Path = $Path
}
}
Function Set-TargetResource
{
[CmdletBinding()]
param
(
[Parameter(Mandatory = $true)]
[ValidateSet("Present", "Absent")]
[String] $Ensure = "Present",
[Parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[String] $Path,
[String] $DefaultParam = "Default",
[String] $StringParam,
[String[]] $StringArrayParam,
[SByte] $Int8Param,
[SByte[]] $Int8ArrayParam,
[Byte] $UInt8Param,
[Byte[]] $UInt8ArrayParam,
[Int16] $Int16Param,
[Int16[]] $Int16ArrayParam,
[UInt16] $UInt16Param,
[UInt16[]] $UInt16ArrayParam,
[Int32] $Int32Param,
[Int32[]] $Int32ArrayParam,
[UInt32] $UInt32Param,
[UInt32[]] $UInt32ArrayParam,
[Int64] $Int64Param,
[Int64[]] $Int64ArrayParam,
[UInt64] $UInt64Param,
[UInt64[]] $UInt64ArrayParam,
[Bool] $BooleanParam,
[Bool[]] $BooleanArrayParam,
[Char] $CharParam,
[Char[]] $CharArrayParam,
[Single] $SingleParam,
[Single[]] $SingleArrayParam,
[Double] $DoubleParam,
[Double[]] $DoubleArrayParam,
[DateTime] $DateTimeParam,
[DateTime[]] $DateTimeArrayParam,
[PSCredential] $PSCredentialParam,
[CimInstance[]] $HashtableParam,
[CimInstance] $CimInstanceParam,
[CimInstance[]] $CimInstanceArrayParam,
[CimInstance] $NestedCimInstanceParam,
[CimInstance[]] $NestedCimInstanceArrayParam
)
$info = @{
Version = "1.0.0"
Ensure = @{
Type = $Ensure.GetType().FullName
Value = $Ensure
}
Path = @{
Type = $Path.GetType().FullName
Value = $Path
}
DefaultParam = @{
Type = $DefaultParam.GetType().FullName
Value = $DefaultParam
}
}
foreach ($kvp in $PSCmdlet.MyInvocation.BoundParameters.GetEnumerator()) {
$info."$($kvp.Key)" = @{
Type = $kvp.Value.GetType().FullName
Value = (ConvertTo-OutputValue -Value $kvp.Value)
}
}
if (Test-Path -Path $Path) {
Remove-Item -Path $Path -Force > $null
}
New-Item -Path $Path -ItemType File > $null
Set-Content -Path $Path -Value (ConvertTo-Json -InputObject $info -Depth 10) > $null
Write-Verbose -Message "set verbose"
Write-Warning -Message "set warning"
}
Function Test-TargetResource
{
[CmdletBinding()]
[OutputType([Boolean])]
param
(
[Parameter(Mandatory = $true)]
[ValidateSet("Present", "Absent")]
[String] $Ensure = "Present",
[Parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[String] $Path,
[String] $DefaultParam = "Default",
[String] $StringParam,
[String[]] $StringArrayParam,
[SByte] $Int8Param,
[SByte[]] $Int8ArrayParam,
[Byte] $UInt8Param,
[Byte[]] $UInt8ArrayParam,
[Int16] $Int16Param,
[Int16[]] $Int16ArrayParam,
[UInt16] $UInt16Param,
[UInt16[]] $UInt16ArrayParam,
[Int32] $Int32Param,
[Int32[]] $Int32ArrayParam,
[UInt32] $UInt32Param,
[UInt32[]] $UInt32ArrayParam,
[Int64] $Int64Param,
[Int64[]] $Int64ArrayParam,
[UInt64] $UInt64Param,
[UInt64[]] $UInt64ArrayParam,
[Bool] $BooleanParam,
[Bool[]] $BooleanArrayParam,
[Char] $CharParam,
[Char[]] $CharArrayParam,
[Single] $SingleParam,
[Single[]] $SingleArrayParam,
[Double] $DoubleParam,
[Double[]] $DoubleArrayParam,
[DateTime] $DateTimeParam,
[DateTime[]] $DateTimeArrayParam,
[PSCredential] $PSCredentialParam,
[CimInstance[]] $HashtableParam,
[CimInstance] $CimInstanceParam,
[CimInstance[]] $CimInstanceArrayParam,
[CimInstance] $NestedCimInstanceParam,
[CimInstance[]] $NestedCimInstanceArrayParam
)
Write-Verbose -Message "test verbose"
Write-Warning -Message "test warning"
$exists = Test-Path -LiteralPath $Path -PathType Leaf
if ($Ensure -eq "Present") {
$exists
} else {
-not $exists
}
}
Export-ModuleMember -Function *-TargetResource

View file

@ -0,0 +1,60 @@
[ClassVersion("1.0.0")]
class ANSIBLE_xTestClass
{
[Key] String Key;
[Write] String StringValue;
[Write] SInt32 IntValue;
[Write] String StringArrayValue[];
};
[ClassVersion("1.0.0")]
class ANSIBLE_xNestedClass
{
[Key] String KeyValue;
[Write, EmbeddedInstance("ANSIBLE_xTestClass")] String CimValue;
[Write, EmbeddedInstance("MSFT_KeyValuePair")] String HashValue[];
[Write] SInt16 IntValue;
};
[ClassVersion("1.0.0"), FriendlyName("xTestResource")]
class ANSIBLE_xTestResource : OMI_BaseResource
{
[Key] String Path;
[Required, ValueMap{"Present", "Absent"}, Values{"Present", "Absent"}] String Ensure;
[Read] String ReadParam;
[Write] String DefaultParam;
[Write] String StringParam;
[Write] String StringArrayParam[];
[Write] SInt8 Int8Param;
[Write] SInt8 Int8ArrayParam[];
[Write] UInt8 UInt8Param;
[Write] UInt8 UInt8ArrayParam[];
[Write] SInt16 Int16Param;
[Write] SInt16 Int16ArrayParam[];
[Write] UInt16 UInt16Param;
[Write] UInt16 UInt16ArrayParam[];
[Write] SInt32 Int32Param;
[Write] SInt32 Int32ArrayParam[];
[Write] UInt32 UInt32Param;
[Write] UInt32 UInt32ArrayParam[];
[Write] SInt64 Int64Param;
[Write] SInt64 Int64ArrayParam[];
[Write] UInt64 UInt64Param;
[Write] UInt64 UInt64ArrayParam[];
[Write] Boolean BooleanParam;
[Write] Boolean BooleanArrayParam[];
[Write] Char16 CharParam;
[Write] Char16 CharArrayParam[];
[Write] Real32 SingleParam;
[Write] Real32 SingleArrayParam[];
[Write] Real64 DoubleParam;
[Write] Real64 DoubleArrayParam[];
[Write] DateTime DateTimeParam;
[Write] DateTime DateTimeArrayParam[];
[Write, EmbeddedInstance("MSFT_Credential")] String PSCredentialParam;
[Write, EmbeddedInstance("MSFT_KeyValuePair")] String HashtableParam[];
[Write, EmbeddedInstance("ANSIBLE_xTestClass")] String CimInstanceArrayParam[];
[Write, EmbeddedInstance("ANSIBLE_xNestedClass")] String NestedCimInstanceParam;
[Write, EmbeddedInstance("ANSIBLE_xNestedClass")] String NestedCimInstanceArrayParam[];
};

View file

@ -1,12 +1,13 @@
@{ @{
ModuleVersion = '{{item.version}}' ModuleVersion = '1.0.0'
GUID = '{{item.version|to_uuid}}' GUID = '80c895c4-de3f-4d6d-8fa4-c504c96b6f22'
Author = 'Ansible' Author = 'Ansible'
CompanyName = 'Ansible' CompanyName = 'Ansible'
Copyright = '(c) 2017' Copyright = '(c) 2019'
Description = 'Test DSC Resource for Ansible integration tests' Description = 'Test DSC Resource for Ansible integration tests'
PowerShellVersion = '5.0' PowerShellVersion = '5.0'
CLRVersion = '4.0' CLRVersion = '4.0'
FunctionsToExport = '*' FunctionsToExport = '*'
CmdletsToExport = '*' CmdletsToExport = '*'
} }

View file

@ -0,0 +1,214 @@
#Requires -Version 5.0 -Modules CimCmdlets
Function ConvertFrom-CimInstance {
param(
[Parameter(Mandatory=$true)][CimInstance]$Instance
)
$hashtable = @{
_cim_instance = $Instance.CimSystemProperties.ClassName
}
foreach ($prop in $Instance.CimInstanceProperties) {
$hashtable."$($prop.Name)" = ConvertTo-OutputValue -Value $prop.Value
}
return $hashtable
}
Function ConvertTo-OutputValue {
param($Value)
if ($Value -is [DateTime[]]) {
$Value = $Value | ForEach-Object { $_.ToString("o") }
} elseif ($Value -is [DateTime]) {
$Value = $Value.ToString("o")
} elseif ($Value -is [Double]) {
$Value = $Value.ToString() # To avoid Python 2 double parsing issues on test validation
} elseif ($Value -is [Double[]]) {
$Value = $Value | ForEach-Object { $_.ToString() }
} elseif ($Value -is [PSCredential]) {
$password = $null
$password_ptr = [System.Runtime.InteropServices.Marshal]::SecureStringToGlobalAllocUnicode($Value.Password)
try {
$password = [System.Runtime.InteropServices.Marshal]::PtrToStringUni($password_ptr)
} finally {
[System.Runtime.InteropServices.Marshal]::ZeroFreeGlobalAllocUnicode($password_ptr)
}
$Value = @{
username = $Value.Username
password = $password
}
} elseif ($Value -is [CimInstance[]]) {
$value_list = [System.Collections.Generic.List`1[Hashtable]]@()
foreach ($cim_instance in $Value) {
$value_list.Add((ConvertFrom-CimInstance -Instance $cim_instance))
}
$Value = $value_list.ToArray()
} elseif ($Value -is [CimInstance]) {
$Value = ConvertFrom-CimInstance -Instance $Value
}
return ,$Value
}
Function Get-TargetResource
{
[CmdletBinding()]
[OutputType([Hashtable])]
param(
[Parameter(Mandatory = $true)]
[ValidateSet("Present", "Absent")]
[String] $Ensure = "Present",
[Parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[String] $Path
)
return @{
Ensure = $Ensure
Path = $Path
}
}
Function Set-TargetResource
{
[CmdletBinding()]
param
(
[Parameter(Mandatory = $true)]
[ValidateSet("Present", "Absent")]
[String] $Ensure = "Present",
[Parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[String] $Path,
[String] $DefaultParam = "Default",
[String] $StringParam,
[String[]] $StringArrayParam,
[SByte] $Int8Param,
[SByte[]] $Int8ArrayParam,
[Byte] $UInt8Param,
[Byte[]] $UInt8ArrayParam,
[Int16] $Int16Param,
[Int16[]] $Int16ArrayParam,
[UInt16] $UInt16Param,
[UInt16[]] $UInt16ArrayParam,
[Int32] $Int32Param,
[Int32[]] $Int32ArrayParam,
[UInt32] $UInt32Param,
[UInt32[]] $UInt32ArrayParam,
[Int64] $Int64Param,
[Int64[]] $Int64ArrayParam,
[UInt64] $UInt64Param,
[UInt64[]] $UInt64ArrayParam,
[Bool] $BooleanParam,
[Bool[]] $BooleanArrayParam,
[Char] $CharParam,
[Char[]] $CharArrayParam,
[Single] $SingleParam,
[Single[]] $SingleArrayParam,
[Double] $DoubleParam,
[Double[]] $DoubleArrayParam,
[DateTime] $DateTimeParam,
[DateTime[]] $DateTimeArrayParam,
[PSCredential] $PSCredentialParam,
[CimInstance[]] $HashtableParam,
[CimInstance] $CimInstanceParam,
[CimInstance[]] $CimInstanceArrayParam,
[CimInstance] $NestedCimInstanceParam,
[CimInstance[]] $NestedCimInstanceArrayParam
)
$info = @{
Version = "1.0.1"
Ensure = @{
Type = $Ensure.GetType().FullName
Value = $Ensure
}
Path = @{
Type = $Path.GetType().FullName
Value = $Path
}
DefaultParam = @{
Type = $DefaultParam.GetType().FullName
Value = $DefaultParam
}
}
foreach ($kvp in $PSCmdlet.MyInvocation.BoundParameters.GetEnumerator()) {
$info."$($kvp.Key)" = @{
Type = $kvp.Value.GetType().FullName
Value = (ConvertTo-OutputValue -Value $kvp.Value)
}
}
if (Test-Path -Path $Path) {
Remove-Item -Path $Path -Force > $null
}
New-Item -Path $Path -ItemType File > $null
Set-Content -Path $Path -Value (ConvertTo-Json -InputObject $info -Depth 10) > $null
Write-Verbose -Message "set verbose"
Write-Warning -Message "set warning"
}
Function Test-TargetResource
{
[CmdletBinding()]
[OutputType([Boolean])]
param
(
[Parameter(Mandatory = $true)]
[ValidateSet("Present", "Absent")]
[String] $Ensure = "Present",
[Parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[String] $Path,
[String] $DefaultParam = "Default",
[String] $StringParam,
[String[]] $StringArrayParam,
[SByte] $Int8Param,
[SByte[]] $Int8ArrayParam,
[Byte] $UInt8Param,
[Byte[]] $UInt8ArrayParam,
[Int16] $Int16Param,
[Int16[]] $Int16ArrayParam,
[UInt16] $UInt16Param,
[UInt16[]] $UInt16ArrayParam,
[Int32] $Int32Param,
[Int32[]] $Int32ArrayParam,
[UInt32] $UInt32Param,
[UInt32[]] $UInt32ArrayParam,
[Int64] $Int64Param,
[Int64[]] $Int64ArrayParam,
[UInt64] $UInt64Param,
[UInt64[]] $UInt64ArrayParam,
[Bool] $BooleanParam,
[Bool[]] $BooleanArrayParam,
[Char] $CharParam,
[Char[]] $CharArrayParam,
[Single] $SingleParam,
[Single[]] $SingleArrayParam,
[Double] $DoubleParam,
[Double[]] $DoubleArrayParam,
[DateTime] $DateTimeParam,
[DateTime[]] $DateTimeArrayParam,
[PSCredential] $PSCredentialParam,
[CimInstance[]] $HashtableParam,
[CimInstance] $CimInstanceParam,
[CimInstance[]] $CimInstanceArrayParam,
[CimInstance] $NestedCimInstanceParam,
[CimInstance[]] $NestedCimInstanceArrayParam
)
Write-Verbose -Message "test verbose"
Write-Warning -Message "test warning"
$exists = Test-Path -LiteralPath $Path -PathType Leaf
if ($Ensure -eq "Present") {
$exists
} else {
-not $exists
}
}
Export-ModuleMember -Function *-TargetResource

View file

@ -0,0 +1,63 @@
[ClassVersion("1.0.1")]
class ANSIBLE_xTestClass
{
[Key] String KeyValue;
[Write, ValueMap{"Choice1", "Choice2"}, Values{"Choice1", "Choice2"}] String Choice;
[Write] String StringValue;
[Write] SInt32 IntValue;
[Write] String StringArrayValue[];
};
[ClassVersion("1.0.1")]
class ANSIBLE_xNestedClass
{
[Key] String KeyValue;
[Write, EmbeddedInstance("ANSIBLE_xTestClass")] String CimValue;
[Write, EmbeddedInstance("ANSIBLE_xTestClass")] String CimArrayValue[];
[Write, EmbeddedInstance("MSFT_KeyValuePair")] String HashValue[];
[Write] SInt16 IntValue;
};
[ClassVersion("1.0.1"), FriendlyName("xTestResource")]
class ANSIBLE_xTestResource : OMI_BaseResource
{
[Key] String Path;
[Required, ValueMap{"Present", "Absent"}, Values{"Present", "Absent"}] String Ensure;
[Read] String ReadParam;
[Write] String DefaultParam;
[Write] String StringParam;
[Write] String StringArrayParam[];
[Write] SInt8 Int8Param;
[Write] SInt8 Int8ArrayParam[];
[Write] UInt8 UInt8Param;
[Write] UInt8 UInt8ArrayParam[];
[Write] SInt16 Int16Param;
[Write] SInt16 Int16ArrayParam[];
[Write] UInt16 UInt16Param;
[Write] UInt16 UInt16ArrayParam[];
[Write] SInt32 Int32Param;
[Write] SInt32 Int32ArrayParam[];
[Write] UInt32 UInt32Param;
[Write] UInt32 UInt32ArrayParam[];
[Write] SInt64 Int64Param;
[Write] SInt64 Int64ArrayParam[];
[Write] UInt64 UInt64Param;
[Write] UInt64 UInt64ArrayParam[];
[Write] Boolean BooleanParam;
[Write] Boolean BooleanArrayParam[];
[Write] Char16 CharParam;
[Write] Char16 CharArrayParam[];
[Write] Real32 SingleParam;
[Write] Real32 SingleArrayParam[];
[Write] Real64 DoubleParam;
[Write] Real64 DoubleArrayParam[];
[Write] DateTime DateTimeParam;
[Write] DateTime DateTimeArrayParam[];
[Write, EmbeddedInstance("MSFT_Credential")] String PSCredentialParam;
[Write, EmbeddedInstance("MSFT_KeyValuePair")] String HashtableParam[];
[Write, EmbeddedInstance("ANSIBLE_xTestClass")] String CimInstanceParam;
[Write, EmbeddedInstance("ANSIBLE_xTestClass")] String CimInstanceArrayParam[];
[Write, EmbeddedInstance("ANSIBLE_xNestedClass")] String NestedCimInstanceParam;
[Write, EmbeddedInstance("ANSIBLE_xNestedClass")] String NestedCimInstanceArrayParam[];
};

View file

@ -0,0 +1,13 @@
@{
ModuleVersion = '1.0.1'
GUID = '80c895c4-de3f-4d6d-8fa4-c504c96b6f22'
Author = 'Ansible'
CompanyName = 'Ansible'
Copyright = '(c) 2019'
Description = 'Test DSC Resource for Ansible integration tests'
PowerShellVersion = '5.0'
CLRVersion = '4.0'
FunctionsToExport = '*'
CmdletsToExport = '*'
}

View file

@ -1,16 +0,0 @@
# (c) 2017 Red Hat, Inc.
#
# This file is part of Ansible
class FilterModule(object):
def filters(self):
return {
'strip_newline': self.strip_newline
}
def strip_newline(self, value):
# will convert \r\n and \n to just \n
split_lines = value.splitlines()
return "\n".join(split_lines)

View file

@ -1,41 +0,0 @@
#!powershell
# This file is part of Ansible
# Copyright (c) 2017 Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
#Requires -Module Ansible.ModuleUtils.Legacy
Import-Module -Name WebAdministration
$params = Parse-Args $args -supports_check_mode $true
$name = Get-AnsibleParam -obj $params -name "name" -type "str" -failifempty $true
$site = Get-Website -Name $name
$result = @{}
if ($site -eq $null) {
$result.exists = $false
} else {
$result.exists = $true
$site_config = Get-WebConfiguration -Filter "System.WebServer/Security/Authentication/*" -PSPath "IIS:\Sites\$name"
$http_bindings = $site.bindings.Collection | Where-Object { $_.protocol -eq "http" }
$https_bindings = $site.bindings.Collection | Where-Object { $_.protocol -eq "https" }
$result.http = @{
binding = $http_bindings.bindingInformation
}
$result.https = @{
binding = $https_bindings.bindingInformation
sslFlags = $https_bindings.sslFlags
store = ($https_bindings.Attributes | Where-Object { $_.Name -eq "certificateStoreName" }).Value
hash = ($https_bindings.Attributes | Where-Object { $_.Name -eq "certificateHash" }).Value
}
$result.auth = @{
anonymous = ($site_config | Where-Object { $_.ElementTagName -like "*anonymous*" }).enabled
basic = ($site_config | Where-Object { $_.ElementTagName -like "*basic*" }).enabled
digest = ($site_config | Where-Object { $_.ElementTagName -like "*digest*" }).enabled
windows = ($site_config | Where-Object { $_.ElementTagName -like "*windows*" }).enabled
}
}
Exit-Json -obj $result

View file

@ -0,0 +1,2 @@
dependencies:
- setup_remote_tmp_dir

View file

@ -1,135 +0,0 @@
# these tests are destructive and can be run manually on a throwaway host
# set test_win_dsc_run_desctructive: yes in default/main.yml
---
- name: ensure IIS features are installed
win_feature:
name: Web-Server
include_sub_features: yes
include_management_tools: no
state: present
- name: install xWebAdministration module
win_psmodule:
name: xWebAdministration
state: present
- name: ensure IIS website does not exist
win_iis_website:
name: Ansible DSC Test
state: absent
- name: get certificate hash for IIS test
win_shell: (Get-ChildItem -Path Cert:\LocalMachine\My)[0].Thumbprint
register: win_dsc_cert_thumbprint
- name: create an IIS website with auth and binding info (check mode)
win_dsc:
resource_name: xWebSite
Ensure: Present
Name: Ansible DSC Test
State: Started
PhysicalPath: C:\inetpub\wwwroot
BindingInfo:
- Protocol: https
Port: 8443
CertificateStoreName: MY
CertificateThumbprint: '{{win_dsc_cert_thumbprint.stdout_lines[0]}}'
HostName: DSCTest
IPAddress: '*'
SSLFlags: '1'
- Protocol: http
Port: 8888
IPAddress: '*'
AuthenticationInfo:
Anonymous: yes
Basic: no
Digest: no
Windows: yes
register: win_dsc_iis_check
check_mode: yes
- name: get result of create an IIS website (check mode)
test_win_dsc_iis_info:
name: Ansible DSC Test
register: win_dsc_iis_check_result
- name: assert results of create an IIS website (check mode)
assert:
that:
- win_dsc_iis_check is changed
- win_dsc_iis_check_result.exists == False
- name: create an IIS website with auth and binding info
win_dsc:
resource_name: xWebSite
Ensure: Present
Name: Ansible DSC Test
State: Started
PhysicalPath: C:\inetpub\wwwroot
BindingInfo:
- Protocol: https
Port: 8443
CertificateStoreName: MY
CertificateThumbprint: '{{win_dsc_cert_thumbprint.stdout_lines[0]}}'
HostName: Test
IPAddress: '*'
SSLFlags: '1'
- Protocol: http
Port: 8888
IPAddress: '*'
AuthenticationInfo:
Anonymous: yes
Basic: no
Digest: no
Windows: yes
register: win_dsc_iis
- name: get result of create an IIS website
test_win_dsc_iis_info:
name: Ansible DSC Test
register: win_dsc_iis_result
- name: assert results of create an IIS website
assert:
that:
- win_dsc_iis is changed
- win_dsc_iis_result.exists == True
- win_dsc_iis_result.auth.anonymous == True
- win_dsc_iis_result.auth.basic == False
- win_dsc_iis_result.auth.digest == False
- win_dsc_iis_result.auth.windows == True
- win_dsc_iis_result.http.binding == "*:8888:"
- win_dsc_iis_result.https.binding == "*:8443:Test"
- win_dsc_iis_result.https.hash == '{{win_dsc_cert_thumbprint.stdout_lines[0]}}'
- win_dsc_iis_result.https.sslFlags == 1
- win_dsc_iis_result.https.store == "MY"
- name: create an IIS website with auth and binding info (idempotent)
win_dsc:
resource_name: xWebSite
Ensure: Present
Name: Ansible DSC Test
State: Started
PhysicalPath: C:\inetpub\wwwroot
BindingInfo:
- Protocol: https
Port: 8443
CertificateStoreName: MY
CertificateThumbprint: '{{win_dsc_cert_thumbprint.stdout_lines[0]}}'
HostName: Test
IPAddress: '*'
SSLFlags: '1'
- Protocol: http
Port: 8888
IPAddress: '*'
AuthenticationInfo:
Anonymous: yes
Basic: no
Digest: no
Windows: yes
register: win_dsc_iis_again
- name: assert results of create an IIS website (idempotent)
assert:
that:
- win_dsc_iis_again is not changed

View file

@ -3,32 +3,37 @@
win_shell: $PSVersionTable.PSVersion.Major win_shell: $PSVersionTable.PSVersion.Major
register: powershell_version register: powershell_version
- name: run smoke tests when we can't run the full suite - name: expect failure when running on old PS hosts
include_tasks: smoke.yml win_dsc:
resource_name: File
register: fail_dsc_old
failed_when: '"This module cannot run as it requires a minimum PowerShell version of 5.0" not in fail_dsc_old.msg'
when: powershell_version.stdout_lines[0]|int < 5 when: powershell_version.stdout_lines[0]|int < 5
- block: - name: run tests when PSv5+
- name: run non-destructive tests when: powershell_version.stdout_lines[0]|int >= 5
block:
- name: add remote temp dir to PSModulePath
win_path:
name: PSModulePath
state: present
scope: machine
elements:
- '{{ remote_tmp_dir }}'
- name: copy custom DSC resources to remote temp dir
win_copy:
src: xTestDsc
dest: '{{ remote_tmp_dir }}'
- name: run tests
include_tasks: tests.yml include_tasks: tests.yml
- name: run destructive tests if flag is set
include_tasks: destructive.yml
when: test_win_dsc_run_desctructive == True
always: always:
- name: remove test feature - name: remove remote tmp dir from PSModulePath
win_feature: win_path:
name: '{{test_win_dsc_feature_name}}' name: PSModulePath
state: absent state: absent
scope: machine
- name: remove test folder elements:
win_file: - '{{ remote_tmp_dir }}'
path: '{{test_win_dsc_folder}}'
state: absent
- name: remove custom DSC resource folder
win_file:
path: C:\Program Files\WindowsPowerShell\Modules\xTestDsc
state: absent
when: powershell_version.stdout_lines[0]|int >= 5

View file

@ -1,8 +0,0 @@
# basic smoke tests run on hosts that cannot run DSC, verifies the code is at
# least runnable
---
- name: expect failure when running on old PS hosts
win_dsc:
resource_name: File
register: fail_dsc_old
failed_when: '"This module cannot run as it requires a minimum PowerShell version of 5.0, actual was " not in fail_dsc_old.msg'

View file

@ -1,333 +1,544 @@
# slightly non-destructive tests that will run if WMF 5.0 is installed
--- ---
- name: start with feature absent
win_feature:
name: '{{test_win_dsc_feature_name}}'
state: absent
- name: fail with incorrect DSC resource name - name: fail with incorrect DSC resource name
win_dsc: win_dsc:
resource_name: FakeResource resource_name: FakeResource
Name: fake
register: fail_invalid_resource register: fail_invalid_resource
failed_when: fail_invalid_resource.msg != "Resource FakeResource not found" failed_when: fail_invalid_resource.msg != "Resource 'FakeResource' not found."
- name: fail by not setting mandatory option - name: fail with invalid DSC version
win_dsc: win_dsc:
resource_name: WindowsFeature resource_name: xTestResource
module_version: 0.0.1
register: fail_invalid_version
failed_when: 'fail_invalid_version.msg != "Resource ''xTestResource'' with version ''0.0.1'' not found. Versions installed: ''1.0.0'', ''1.0.1''."'
- name: fail with mandatory option not set
win_dsc:
resource_name: xSetReboot
Value: yes
register: fail_man_key
failed_when: 'fail_man_key.msg != "missing required arguments: KeyParam"'
- name: fail with mandatory option not set in sub dict
win_dsc:
resource_name: xTestResource
Path: C:\path
Ensure: Present Ensure: Present
register: fail_missing_mandatory CimInstanceParam: # Missing KeyValue in dict
failed_when: fail_missing_mandatory.msg != "Could not find mandatory property Name. Add this property and try again." Choice: Choice1
register: fail_man_key_sub_dict
failed_when: 'fail_man_key_sub_dict.msg != "missing required arguments: KeyValue found in CimInstanceParam"'
- name: fail to add a non-existant feature - name: fail invalid option
win_dsc: win_dsc:
resource_name: WindowsFeature resource_name: xSetReboot
Name: InvalidFeature KeyParam: key
OtherParam: invalid
register: fail_invalid_option
failed_when: 'fail_invalid_option.msg != "Unsupported parameters for (win_dsc) module: OtherParam. Supported parameters include: KeyParam, PsDscRunAsCredential_username, module_version, Value, PsDscRunAsCredential_password, resource_name, DependsOn"'
- name: fail invalid option in sub dict
win_dsc:
resource_name: xTestResource
Path: C:\path
Ensure: Present Ensure: Present
register: fail_invalid_feature NestedCimInstanceParam:
failed_when: '"The requested feature InvalidFeature is not found on the target machine" not in fail_invalid_feature.msg' KeyValue: key
CimValue:
KeyValue: other key
InvalidKey: invalid
register: fail_invalid_option_sub_dict
failed_when: 'fail_invalid_option_sub_dict.msg != "Unsupported parameters for (win_dsc) module: InvalidKey found in NestedCimInstanceParam -> CimValue. Supported parameters include: IntValue, KeyValue, StringArrayValue, Choice, StringValue"'
- name: add Windows feature (check mode) - name: fail invalid read only option
win_dsc: win_dsc:
resource_name: WindowsFeature resource_name: xTestResource
Name: '{{test_win_dsc_feature_name}}' Path: C:\path
Ensure: Present Ensure: Present
register: win_dsc_add_feature_check ReadParam: abc
check_mode: yes register: fail_invalid_option_read_only
failed_when: '"Unsupported parameters for (win_dsc) module: ReadParam" not in fail_invalid_option_read_only.msg'
- name: get result of add Windows feature (check mode) - name: fail invalid choice
win_shell: (Get-WindowsFeature -Name {{test_win_dsc_feature_name}}).Installed
register: win_dsc_add_feature_result_check
- name: assert result of add Windows feature (check mode)
assert:
that:
- win_dsc_add_feature_check is changed
- win_dsc_add_feature_result_check.stdout == "False\r\n"
- name: add Windows feature
win_dsc: win_dsc:
resource_name: WindowsFeature resource_name: xTestResource
Name: '{{test_win_dsc_feature_name}}' Path: C:\path
Ensure: invalid
register: fail_invalid_choice
failed_when: 'fail_invalid_choice.msg != "value of Ensure must be one of: Present, Absent. Got no match for: invalid"'
- name: fail invalid choice in sub dict
win_dsc:
resource_name: xTestResource
Path: C:\path
Ensure: Present Ensure: Present
register: win_dsc_add_feature CimInstanceArrayParam:
- KeyValue: key
- KeyValue: key2
Choice: Choice3
register: fail_invalid_choice_sub_dict
failed_when: 'fail_invalid_choice_sub_dict.msg != "value of Choice must be one of: Choice1, Choice2. Got no match for: Choice3 found in CimInstanceArrayParam"'
- name: get result of add Windows feature - name: fail old version missing new option
win_shell: (Get-WindowsFeature -Name {{test_win_dsc_feature_name}}).Installed
register: win_dsc_add_feature_result
- name: assert result of add Windows feature
assert:
that:
- win_dsc_add_feature is changed
- win_dsc_add_feature_result.stdout == "True\r\n"
- name: add Windows feature (idempotent)
win_dsc: win_dsc:
resource_name: WindowsFeature resource_name: xTestResource
Name: '{{test_win_dsc_feature_name}}' module_version: 1.0.0
Path: C:\path
Ensure: Present Ensure: Present
register: win_dsc_add_feature_again CimInstanceParam: # CimInstanceParam does not exist in the 1.0.0 version
Key: key
register: fail_invalid_option_old
failed_when: '"Unsupported parameters for (win_dsc) module: CimInstanceParam" not in fail_invalid_option_old.msg'
- name: assert result of add Windows feature (idempotent) - name: fail old version missing new option sub dict
assert:
that:
- win_dsc_add_feature_again is not changed
- name: remove Windows feature (check mode)
win_dsc: win_dsc:
resource_name: WindowsFeature resource_name: xTestResource
Name: '{{test_win_dsc_feature_name}}' module_version: 1.0.0
Ensure: Absent Path: C:\path
register: win_dsc_remove_feature_check Ensure: Present
check_mode: yes CimInstanceArrayParam:
- Key: key
- name: get result of remove Windows feature (check mode) Choice: Choice1
win_shell: (Get-WindowsFeature -Name {{test_win_dsc_feature_name}}).Installed register: fail_invalid_option_old_sub_dict
register: win_dsc_remove_feature_result_check failed_when: 'fail_invalid_option_old_sub_dict.msg != "Unsupported parameters for (win_dsc) module: Choice found in CimInstanceArrayParam. Supported parameters include: Key, IntValue, StringArrayValue, StringValue"'
- name: assert result of remove Windows feature (check mode)
assert:
that:
- win_dsc_remove_feature_check is changed
- win_dsc_remove_feature_result_check.stdout == "True\r\n"
- name: remove Windows feature
win_dsc:
resource_name: WindowsFeature
Name: '{{test_win_dsc_feature_name}}'
Ensure: Absent
register: win_dsc_remove_feature
- name: get result of remove Windows feature
win_shell: (Get-WindowsFeature -Name {{test_win_dsc_feature_name}}).Installed
register: win_dsc_remove_feature_result
- name: assert result of remove Windows feature
assert:
that:
- win_dsc_remove_feature is changed
- win_dsc_remove_feature_result.stdout == "False\r\n"
- name: remove Windows feature (idempotent)
win_dsc:
resource_name: WindowsFeature
Name: '{{test_win_dsc_feature_name}}'
Ensure: Absent
register: win_dsc_remove_feature_again
- name: assert result of remove Windows feature (idempotent)
assert:
that:
- win_dsc_remove_feature_again is not changed
- name: ensure test folder doesn't exist before test
win_file:
path: '{{test_win_dsc_folder}}'
state: absent
- name: create test file (check mode) - name: create test file (check mode)
win_dsc: win_dsc:
resource_name: File resource_name: File
DestinationPath: '{{test_win_dsc_folder}}\dsc-file' DestinationPath: '{{ remote_tmp_dir }}\dsc-file'
Contents: file contents Contents: file contents
Attributes: Attributes:
- Hidden - Hidden
- ReadOnly - ReadOnly
Ensure: Present Ensure: Present
Type: File Type: File
register: win_dsc_create_file_check register: create_file_check
check_mode: yes check_mode: yes
- name: get result of create test file (check mode) - name: get result of create test file (check mode)
win_stat: win_stat:
path: '{{test_win_dsc_folder}}\dsc-file' path: '{{ remote_tmp_dir }}\dsc-file'
register: win_dsc_create_file_result_check register: create_file_actual_check
- name: assert results of create test file (check mode) - name: assert create test file (check mode)
assert: assert:
that: that:
- win_dsc_create_file_check is changed - create_file_check is changed
- win_dsc_create_file_result_check.stat.exists == False - create_file_check.module_version == None # Some built in modules don't have a version set
- not create_file_check.reboot_required
- not create_file_actual_check.stat.exists
- name: assert create test file verbosity (check mode)
assert:
that:
- create_file_check.verbose_test is defined
- not create_file_check.verbose_set is defined
when: ansible_verbosity >= 3
- name: create test file - name: create test file
win_dsc: win_dsc:
resource_name: File resource_name: File
DestinationPath: '{{test_win_dsc_folder}}\dsc-file' DestinationPath: '{{ remote_tmp_dir }}\dsc-file'
Contents: file contents Contents: file contents
Attributes: Attributes:
- Hidden - Hidden
- ReadOnly - ReadOnly
Ensure: Present Ensure: Present
Type: File Type: File
register: win_dsc_create_file register: create_file
- name: get result of create test file - name: get result of create test file
win_stat: win_stat:
path: '{{test_win_dsc_folder}}\dsc-file' path: '{{ remote_tmp_dir }}\dsc-file'
register: win_dsc_create_file_result register: create_file_actual
- name: assert results of create test file - name: assert create test file verbosity
assert: assert:
that: that:
- win_dsc_create_file is changed - create_file.verbose_test is defined
- win_dsc_create_file_result.stat.exists == True - create_file.verbose_set is defined
- win_dsc_create_file_result.stat.isdir == False when: ansible_verbosity >= 3
- win_dsc_create_file_result.stat.ishidden == True
- win_dsc_create_file_result.stat.isreadonly == True - name: assert create test file
assert:
that:
- create_file is changed
- create_file.module_version == None
- not create_file.reboot_required
- create_file_actual.stat.exists
- create_file_actual.stat.attributes == "ReadOnly, Hidden, Archive"
- create_file_actual.stat.checksum == 'd48daab51112b49ecabd917adc345b8ba257055e'
- name: create test file (idempotent) - name: create test file (idempotent)
win_dsc: win_dsc:
resource_name: File resource_name: File
DestinationPath: '{{test_win_dsc_folder}}\dsc-file' DestinationPath: '{{ remote_tmp_dir }}\dsc-file'
Contents: file contents Contents: file contents
Attributes: Hidden, ReadOnly Attributes:
- Hidden
- ReadOnly
Ensure: Present Ensure: Present
Type: File Type: File
register: win_dsc_create_file_again register: create_file_again
- name: assert results of create test file (idempotent) - name: assert create test file (idempotent)
assert: assert:
that: that:
- win_dsc_create_file_again is not changed - not create_file_again is changed
- create_file.module_version == None
- not create_file.reboot_required
- name: get SID of current ansible user - name: get SID of the current Ansible user
win_shell: (New-Object System.Security.Principal.NTAccount("{{ansible_user}}")).Translate([System.Security.Principal.SecurityIdentifier]).ToString() win_shell: |
register: win_dsc_actual_sid Add-Type -AssemblyName System.DirectoryServices.AccountManagement
[System.DirectoryServices.AccountManagement.UserPrincipal]::Current.Sid.Value
register: actual_sid
- name: run DSC process as another user - name: run DSC process as another user
win_dsc: win_dsc:
resource_name: Script resource_name: Script
GetScript: '@{ Result = "" }' GetScript: '@{ Result= "" }'
SetScript: | SetScript: |
$output = &whoami.exe Add-Type -AssemblyName System.DirectoryServices.AccountManagement
$sid = (New-Object System.Security.Principal.NTAccount($output)).Translate([System.Security.Principal.SecurityIdentifier]).ToString() $sid = [System.DirectoryServices.AccountManagement.UserPrincipal]::Current.Sid.Value
Set-Content -Path "{{test_win_dsc_folder}}\file" -Value $sid Set-Content -Path "{{ remote_tmp_dir }}\runas.txt" -Value $sid
TestScript: Test-Path -Path "{{test_win_dsc_folder}}\file" TestScript: $false
PsDscRunAsCredential_username: '{{ansible_user}}' PsDscRunAsCredential_username: '{{ ansible_user }}'
PsDscRunAsCredential_password: '{{ansible_password}}' PsDscRunAsCredential_password: '{{ ansible_password }}'
register: win_dsc_runas register: runas_user
- name: get content of script output file - name: get result of run DSC process as another user
slurp: slurp:
path: '{{test_win_dsc_folder}}\file' path: '{{ remote_tmp_dir }}\runas.txt'
register: win_dsc_runas_result register: runas_user_result
- name: assert results of run DSC process as another user - name: assert run DSC process as another user
assert: assert:
that: that:
- win_dsc_runas is changed - runas_user is changed
- win_dsc_runas_result.content|b64decode == win_dsc_actual_sid.stdout - runas_user.module_version != None # Can't reliably set the version but we can test it is set
- not runas_user.reboot_required
- runas_user_result.content|b64decode == actual_sid.stdout
- name: create custom DSC resource folder - name: run DSC that sets reboot_required with defaults
win_file: win_dsc:
path: C:\Program Files\WindowsPowerShell\Modules\xTestDsc\{{item}}\DSCResources\ANSIBLE_xTestResource resource_name: xSetReboot
state: directory KeyParam: value # Just to satisfy the Resource with key validation
with_items: register: set_reboot_defaults
- "1.0.0"
- "2.0.0"
- name: template custom DSC resource files - name: assert run DSC that sets reboot_required with defaults
win_template: assert:
src: '{{item.src}}' that:
dest: C:\Program Files\WindowsPowerShell\Modules\xTestDsc\{{item.version}}\{{item.dest}} - set_reboot_defaults.reboot_required
with_items:
- src: ANSIBLE_xTestResource.schema.mof
dest: DSCResources\ANSIBLE_xTestResource\ANSIBLE_xTestResource.schema.mof
version: "1.0.0"
- src: ANSIBLE_xTestResource.psm1
dest: DSCResources\ANSIBLE_xTestResource\ANSIBLE_xTestResource.psm1
version: "1.0.0"
- src: xTestDsc.psd1
dest: xTestDsc.psd1
version: "1.0.0"
- src: ANSIBLE_xTestResource.schema.mof
dest: DSCResources\ANSIBLE_xTestResource\ANSIBLE_xTestResource.schema.mof
version: "2.0.0"
- src: ANSIBLE_xTestResource.psm1
dest: DSCResources\ANSIBLE_xTestResource\ANSIBLE_xTestResource.psm1
version: "2.0.0"
- src: xTestDsc.psd1
dest: xTestDsc.psd1
version: "2.0.0"
- name: run custom DSC resource - name: run DSC that sets reboot_required with False
win_dsc: &dsc_params win_dsc:
resource_name: xSetReboot
KeyParam: value
Value: no
register: set_reboot_false
- name: assert run DSC that sets reboot_required with False
assert:
that:
- not set_reboot_false.reboot_required
- name: run DSC that sets reboot_required with True
win_dsc:
resource_name: xSetReboot
KeyParam: value
Value: yes
register: set_reboot_true
- name: assert run DSC that sets reboot_required with True
assert:
that:
- set_reboot_true.reboot_required
- name: test DSC with all types
win_dsc:
resource_name: xTestResource resource_name: xTestResource
Path: '{{test_win_dsc_folder}}\custom-output.txt' Path: '{{ remote_tmp_dir }}\test-types.json'
Ensure: Present Ensure: Present
StringParam: string param StringParam: string param
UInt32Param: 1000
UInt64Param: 1000000
StringArrayParam: StringArrayParam:
- string 1 - string 1
- string 2 - string 2
Int8Param: 127 # [SByte]::MaxValue
Int8ArrayParam:
- 127
- '127'
UInt8Param: 255 # [Byte]::MaxValue
UInt8ArrayParam:
- 255
- '255'
Int16Param: 32767 # [Int16]::MaxValue
Int16ArrayParam: 32767, 32767
UInt16Param: '65535' # [UInt16]::MaxValue
UInt16ArrayParam: 65535
Int32Param: 2147483647 # [Int32]::MaxValue
Int32ArrayParam: '2147483647'
UInt32Param: '4294967295' # [UInt32]::MaxValue
UInt32ArrayParam: UInt32ArrayParam:
- 1000 - '4294967295'
- 2000 - 4294967295
Int64Param: 9223372036854775807 # [Int64]::MaxValue
Int64ArrayParam:
- -9223372036854775808 # [Int64]::MinValue
- 9223372036854775807
UInt64Param: 18446744073709551615 # [UInt64]::MaxValue
UInt64ArrayParam: UInt64ArrayParam:
- 1000000 - 0 # [UInt64]::MinValue
- 2000000 - 18446744073709551615
BooleanParam: yes BooleanParam: True
PSCredentialParam_username: username BooleanArrayParam:
PSCredentialParam_password: password - True
- 'True'
- 'true'
- 'y'
- 'yes'
- 1
- False
- 'False'
- 'false'
- 'n'
- 'no'
- 0
CharParam: c
CharArrayParam:
- c
- h
- a
- r
SingleParam: 3.402823E+38
SingleArrayParam:
- '3.402823E+38'
- 1.2393494
DoubleParam: 1.79769313486232E+300
DoubleArrayParam:
- '1.79769313486232E+300'
- 3.56821831681516
DateTimeParam: '2019-02-22T13:57:31.2311892-04:00'
DateTimeArrayParam:
- '2019-02-22T13:57:31.2311892+00:00'
- '2019-02-22T13:57:31.2311892+04:00'
PSCredentialParam_username: username1
PSCredentialParam_password: password1
HashtableParam:
key1: string 1
key2: ''
key3: 1
CimInstanceParam: CimInstanceParam:
StringKey: a KeyValue: a
BooleanKey: yes
UInt32Key: 1
StringArrayKey:
- string 1
- string 2
CimInstanceArrayParam: CimInstanceArrayParam:
- StringKey: b - KeyValue: b
BooleanKey: no Choice: Choice1
UInt32Key: 2 StringValue: string 1
StringArrayKey: IntValue: 1
- string 3 StringArrayValue:
- string 4 - abc
- StringKey: c - def
BooleanKey: no - KeyValue: c
UInt32Key: 3 Choice: Choice2
StringArrayKey: StringValue: string 2
- string 5 IntValue: '2'
- string 6 StringArrayValue:
register: test_dsc_custom - ghi
- jkl
NestedCimInstanceParam:
KeyValue: key value
CimValue:
KeyValue: d
CimArrayValue:
- KeyValue: e
Choice: Choice2
HashValue:
a: a
IntValue: '300'
register: dsc_types
- name: get output of custom DSC resource - name: get result of test DSC with all types
slurp: slurp:
path: '{{test_win_dsc_folder}}\custom-output.txt' path: '{{ remote_tmp_dir }}\test-types.json'
register: test_dsc_custom_output register: dsc_types_raw
- name: get expected output of custom DSC resource - name: convert result of test DSC with all types to dict
set_fact: set_fact:
test_dsc_custom_expected: '{{lookup("file", "custom-result-normal.txt")}}' dsc_types_actual: '{{ dsc_types_raw.content | b64decode | from_json }}'
- name: assert result of custom DSC resource - name: assert test DSC with all types
assert: assert:
that: that:
- test_dsc_custom is changed - dsc_types is changed
- test_dsc_custom_output.content|b64decode|strip_newline == test_dsc_custom_expected|strip_newline - dsc_types.module_version == '1.0.1'
- test_dsc_custom.warnings | length == 2 - not dsc_types.reboot_required
- "'[[xTestResource]DirectResourceAccess] test warning' in test_dsc_custom.warnings[0]" - dsc_types_actual.Version == '1.0.1'
- "'[[xTestResource]DirectResourceAccess] set warning' in test_dsc_custom.warnings[1]" - dsc_types_actual.Verbose.Value.IsPresent
- dsc_types_actual.DefaultParam.Value == 'Default' # ensures that the default is set in the engine if we don't set it outselves
- dsc_types_actual.Ensure.Value == 'Present'
- dsc_types_actual.Path.Value == remote_tmp_dir + "\\test-types.json"
- dsc_types_actual.StringParam.Type == 'System.String'
- dsc_types_actual.StringParam.Value == 'string param'
- dsc_types_actual.StringArrayParam.Type == 'System.String[]'
- dsc_types_actual.StringArrayParam.Value == ['string 1', 'string 2']
- dsc_types_actual.Int8Param.Type == 'System.SByte'
- dsc_types_actual.Int8Param.Value == 127
- dsc_types_actual.Int8ArrayParam.Type == 'System.SByte[]'
- dsc_types_actual.Int8ArrayParam.Value == [127, 127]
- dsc_types_actual.UInt8Param.Type == 'System.Byte'
- dsc_types_actual.UInt8Param.Value == 255
- dsc_types_actual.UInt8ArrayParam.Type == 'System.Byte[]'
- dsc_types_actual.UInt8ArrayParam.Value == [255, 255]
- dsc_types_actual.Int16Param.Type == 'System.Int16'
- dsc_types_actual.Int16Param.Value == 32767
- dsc_types_actual.Int16ArrayParam.Type == 'System.Int16[]'
- dsc_types_actual.Int16ArrayParam.Value == [32767, 32767]
- dsc_types_actual.UInt16Param.Type == 'System.UInt16'
- dsc_types_actual.UInt16Param.Value == 65535
- dsc_types_actual.UInt16ArrayParam.Type == 'System.UInt16[]'
- dsc_types_actual.UInt16ArrayParam.Value == [65535]
- dsc_types_actual.Int32Param.Type == 'System.Int32'
- dsc_types_actual.Int32Param.Value == 2147483647
- dsc_types_actual.Int32ArrayParam.Type == 'System.Int32[]'
- dsc_types_actual.Int32ArrayParam.Value == [2147483647]
- dsc_types_actual.UInt32Param.Type == 'System.UInt32'
- dsc_types_actual.UInt32Param.Value == 4294967295
- dsc_types_actual.UInt32ArrayParam.Type == 'System.UInt32[]'
- dsc_types_actual.UInt32ArrayParam.Value == [4294967295, 4294967295]
- dsc_types_actual.Int64Param.Type == 'System.Int64'
- dsc_types_actual.Int64Param.Value == 9223372036854775807
- dsc_types_actual.Int64ArrayParam.Type == 'System.Int64[]'
- dsc_types_actual.Int64ArrayParam.Value == [-9223372036854775808, 9223372036854775807]
- dsc_types_actual.UInt64Param.Type == 'System.UInt64'
- dsc_types_actual.UInt64Param.Value == 18446744073709551615
- dsc_types_actual.UInt64ArrayParam.Type == 'System.UInt64[]'
- dsc_types_actual.UInt64ArrayParam.Value == [0, 18446744073709551615]
- dsc_types_actual.BooleanParam.Type == 'System.Boolean'
- dsc_types_actual.BooleanParam.Value == True
- dsc_types_actual.BooleanArrayParam.Type == 'System.Boolean[]'
- dsc_types_actual.BooleanArrayParam.Value == [True, True, True, True, True, True, False, False, False, False, False, False]
- dsc_types_actual.CharParam.Type == 'System.Char'
- dsc_types_actual.CharParam.Value == 'c'
- dsc_types_actual.CharArrayParam.Type == 'System.Char[]'
- dsc_types_actual.CharArrayParam.Value == ['c', 'h', 'a', 'r']
- dsc_types_actual.SingleParam.Type == 'System.Single'
- dsc_types_actual.SingleParam.Value|string == '3.402823e+38'
- dsc_types_actual.SingleArrayParam.Type == 'System.Single[]'
- dsc_types_actual.SingleArrayParam.Value|length == 2
- dsc_types_actual.SingleArrayParam.Value[0]|string == '3.402823e+38'
- dsc_types_actual.SingleArrayParam.Value[1]|string == '1.23934937'
- dsc_types_actual.DoubleParam.Type == 'System.Double'
- dsc_types_actual.DoubleParam.Value == '1.79769313486232E+300'
- dsc_types_actual.DoubleArrayParam.Type == 'System.Double[]'
- dsc_types_actual.DoubleArrayParam.Value|length == 2
- dsc_types_actual.DoubleArrayParam.Value[0] == '1.79769313486232E+300'
- dsc_types_actual.DoubleArrayParam.Value[1] == '3.56821831681516'
- dsc_types_actual.DateTimeParam.Type == 'System.DateTime'
- dsc_types_actual.DateTimeParam.Value == '2019-02-22T17:57:31.2311890+00:00'
- dsc_types_actual.DateTimeArrayParam.Type == 'System.DateTime[]'
- dsc_types_actual.DateTimeArrayParam.Value == ['2019-02-22T13:57:31.2311890+00:00', '2019-02-22T09:57:31.2311890+00:00']
- dsc_types_actual.PSCredentialParam.Type == 'System.Management.Automation.PSCredential'
- dsc_types_actual.PSCredentialParam.Value.username == 'username1'
- dsc_types_actual.PSCredentialParam.Value.password == 'password1'
# Hashtable is actually a CimInstance[] of MSFT_KeyValuePairs
- dsc_types_actual.HashtableParam.Type == 'Microsoft.Management.Infrastructure.CimInstance[]'
- dsc_types_actual.HashtableParam.Value|length == 3
# Can't guarantee the order of the keys so just check they are the values they could be
- dsc_types_actual.HashtableParam.Value[0].Key in ["key1", "key2", "key3"]
- dsc_types_actual.HashtableParam.Value[0].Value in ["string 1", "1", ""]
- dsc_types_actual.HashtableParam.Value[0]._cim_instance == 'MSFT_KeyValuePair'
- dsc_types_actual.HashtableParam.Value[1].Key in ["key1", "key2", "key3"]
- dsc_types_actual.HashtableParam.Value[1].Value in ["string 1", "1", ""]
- dsc_types_actual.HashtableParam.Value[1]._cim_instance == 'MSFT_KeyValuePair'
- dsc_types_actual.HashtableParam.Value[2].Key in ["key1", "key2", "key3"]
- dsc_types_actual.HashtableParam.Value[2].Value in ["string 1", "1", ""]
- dsc_types_actual.HashtableParam.Value[2]._cim_instance == 'MSFT_KeyValuePair'
- dsc_types_actual.CimInstanceParam.Type == 'Microsoft.Management.Infrastructure.CimInstance'
- dsc_types_actual.CimInstanceParam.Value.Choice == None
- dsc_types_actual.CimInstanceParam.Value.IntValue == None
- dsc_types_actual.CimInstanceParam.Value.KeyValue == 'a'
- dsc_types_actual.CimInstanceParam.Value.StringArrayValue == None
- dsc_types_actual.CimInstanceParam.Value.StringValue == None
- dsc_types_actual.CimInstanceParam.Value._cim_instance == "ANSIBLE_xTestClass"
- dsc_types_actual.CimInstanceArrayParam.Type == 'Microsoft.Management.Infrastructure.CimInstance[]'
- dsc_types_actual.CimInstanceArrayParam.Value|length == 2
- dsc_types_actual.CimInstanceArrayParam.Value[0].Choice == 'Choice1'
- dsc_types_actual.CimInstanceArrayParam.Value[0].IntValue == 1
- dsc_types_actual.CimInstanceArrayParam.Value[0].KeyValue == 'b'
- dsc_types_actual.CimInstanceArrayParam.Value[0].StringArrayValue == ['abc', 'def']
- dsc_types_actual.CimInstanceArrayParam.Value[0].StringValue == 'string 1'
- dsc_types_actual.CimInstanceArrayParam.Value[0]._cim_instance == 'ANSIBLE_xTestClass'
- dsc_types_actual.CimInstanceArrayParam.Value[1].Choice == 'Choice2'
- dsc_types_actual.CimInstanceArrayParam.Value[1].IntValue == 2
- dsc_types_actual.CimInstanceArrayParam.Value[1].KeyValue == 'c'
- dsc_types_actual.CimInstanceArrayParam.Value[1].StringArrayValue == ['ghi', 'jkl']
- dsc_types_actual.CimInstanceArrayParam.Value[1].StringValue == 'string 2'
- dsc_types_actual.CimInstanceArrayParam.Value[1]._cim_instance == 'ANSIBLE_xTestClass'
- dsc_types_actual.NestedCimInstanceParam.Type == 'Microsoft.Management.Infrastructure.CimInstance'
- dsc_types_actual.NestedCimInstanceParam.Value.CimArrayValue|length == 1
- dsc_types_actual.NestedCimInstanceParam.Value.CimArrayValue[0].Choice == 'Choice2'
- dsc_types_actual.NestedCimInstanceParam.Value.CimArrayValue[0].IntValue == None
- dsc_types_actual.NestedCimInstanceParam.Value.CimArrayValue[0].KeyValue == 'e'
- dsc_types_actual.NestedCimInstanceParam.Value.CimArrayValue[0].StringArrayValue == None
- dsc_types_actual.NestedCimInstanceParam.Value.CimArrayValue[0].StringValue == None
- dsc_types_actual.NestedCimInstanceParam.Value.CimArrayValue[0]._cim_instance == 'ANSIBLE_xTestClass'
- dsc_types_actual.NestedCimInstanceParam.Value.CimValue.Choice == None
- dsc_types_actual.NestedCimInstanceParam.Value.CimValue.IntValue == None
- dsc_types_actual.NestedCimInstanceParam.Value.CimValue.KeyValue == 'd'
- dsc_types_actual.NestedCimInstanceParam.Value.CimValue.StringArrayValue == None
- dsc_types_actual.NestedCimInstanceParam.Value.CimValue.StringValue == None
- dsc_types_actual.NestedCimInstanceParam.Value.CimValue._cim_instance == 'ANSIBLE_xTestClass'
- dsc_types_actual.NestedCimInstanceParam.Value.HashValue|length == 1
- dsc_types_actual.NestedCimInstanceParam.Value.HashValue[0].Key == 'a'
- dsc_types_actual.NestedCimInstanceParam.Value.HashValue[0].Value == 'a'
- dsc_types_actual.NestedCimInstanceParam.Value.HashValue[0]._cim_instance == 'MSFT_KeyValuePair'
- dsc_types_actual.NestedCimInstanceParam.Value.IntValue == 300
- dsc_types_actual.NestedCimInstanceParam.Value.KeyValue == 'key value'
- dsc_types_actual.NestedCimInstanceParam.Value._cim_instance == 'ANSIBLE_xNestedClass'
- name: run custom DSC resource with version - name: test DSC with all types older version
win_dsc: win_dsc:
<<: *dsc_params resource_name: xTestResource
module_version: '1.0.0' module_version: 1.0.0
register: test_dsc_custom_version Path: '{{ remote_tmp_dir }}\test-types.json'
Ensure: Absent
StringParam: string param old
CimInstanceArrayParam:
- Key: old key
StringValue: string old 1
IntValue: 0
StringArrayValue:
- zyx
- wvu
register: dsc_types_old
- name: get output of custom DSC resource with version - name: get result of test DSC with all types older version
slurp: slurp:
path: '{{test_win_dsc_folder}}\custom-output.txt' path: '{{ remote_tmp_dir }}\test-types.json'
register: test_dsc_custom_output_version register: dsc_types_old_raw
- name: get expected output of custom DSC resource with version - name: convert result of test DSC with all types to dict
set_fact: set_fact:
test_dsc_custom_expected_version: '{{lookup("file", "custom-result-versioned.txt")}}' dsc_types_old_actual: '{{ dsc_types_old_raw.content | b64decode | from_json }}'
- name: assert result of custom DSC resource with version - name: assert test DSC with all types older version
assert: assert:
that: that:
- test_dsc_custom is changed - dsc_types_old is changed
- test_dsc_custom_output_version.content|b64decode|strip_newline == test_dsc_custom_expected_version|strip_newline - dsc_types_old.module_version == '1.0.0'
- not dsc_types_old.reboot_required
- dsc_types_old_actual.Version == '1.0.0'
- dsc_types_old_actual.Verbose.Value.IsPresent
- dsc_types_old_actual.DefaultParam.Value == 'Default'
- dsc_types_old_actual.Ensure.Value == 'Absent'
- dsc_types_old_actual.Path.Value == remote_tmp_dir + "\\test-types.json"
- dsc_types_old_actual.StringParam.Type == 'System.String'
- dsc_types_old_actual.StringParam.Value == 'string param old'
- dsc_types_old_actual.CimInstanceArrayParam.Type == 'Microsoft.Management.Infrastructure.CimInstance[]'
- dsc_types_old_actual.CimInstanceArrayParam.Value|length == 1
- not dsc_types_old_actual.CimInstanceArrayParam.Value[0].Choice is defined # 1.0.0 does not have a Choice option
- dsc_types_old_actual.CimInstanceArrayParam.Value[0].IntValue == 0
- dsc_types_old_actual.CimInstanceArrayParam.Value[0].Key == 'old key'
- dsc_types_old_actual.CimInstanceArrayParam.Value[0].StringArrayValue == ['zyx', 'wvu']
- dsc_types_old_actual.CimInstanceArrayParam.Value[0].StringValue == 'string old 1'
- dsc_types_old_actual.CimInstanceArrayParam.Value[0]._cim_instance == 'ANSIBLE_xTestClass'

View file

@ -1,175 +0,0 @@
#Requires -Version 5.0 -Modules CimCmdlets
Function Get-TargetResource
{
[CmdletBinding()]
[OutputType([Hashtable])]
param(
[Parameter(Mandatory = $true)]
[ValidateSet("Present", "Absent")]
[String]
$Ensure = "Present",
[Parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[String]
$Path
)
return @{
Ensure = $Ensure
Path = $Path
}
}
Function Set-TargetResource
{
[CmdletBinding()]
param
(
[Parameter(Mandatory = $true)]
[ValidateSet("Present", "Absent")]
[String]
$Ensure = "Present",
[Parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[String]
$Path,
[String]
$StringParam,
[UInt32]
$UInt32Param,
[UInt64]
$UInt64Param,
[String[]]
$StringArrayParam,
[UInt32[]]
$UInt32ArrayParam,
[UInt64[]]
$UInt64ArrayParam,
[Boolean]
$BooleanParam,
[PSCredential]
$PSCredentialParam,
[Microsoft.Management.Infrastructure.CimInstance]
$CimInstanceParam,
[Microsoft.Management.Infrastructure.CimInstance[]]
$CimInstanceArrayParam
)
$file_contents = @"
xTestResource Version: {{item.version}}
Ensure:
Type: $($Ensure.GetType().FullName)
Value: $($Ensure.ToString())
StringParam:
Type: $($StringParam.GetType().FullName)
Value: $($StringParam)
UInt32Param:
Type: $($UInt32Param.GetType().FullName)
Value: $($UInt32Param.ToString())
UInt64Param:
Type: $($UInt64Param.GetType().FullName)
Value: $($UInt64Param.ToString())
StringArrayParam:
Type: $($StringArrayParam.GetType().FullName)
Value: [ "$($StringArrayParam -join '", "')" ]
UInt32ArrayParam:
Type: $($UInt32ArrayParam.GetType().FullName)
Value: [ $($UInt32ArrayParam -join ', ') ]
UInt64ArrayParam:
Type: $($UInt64ArrayParam.GetType().FullName)
Value: [ $($UInt64ArrayParam -join ', ') ]
BooleanParam:
Type: $($BooleanParam.GetType().FullName)
Value: $($BooleanParam.ToString())
PSCredentialParam:
Type: $($PSCredentialParam.GetType().FullName)
Username: $($PSCredentialParam.GetNetworkCredential().Username)
Password: $($PSCredentialParam.GetNetworkCredential().Password)
CimInstanceParam:
Type: $($CimInstanceParam.GetType().FullName)
CimInstanceArrayParam:
Type: $($CimInstanceArrayParam.GetType().FullName)
"@
if (Test-Path -Path $Path)
{
Remove-Item -Path $Path -Force > $null
}
New-Item -Path $Path -ItemType File > $null
Set-Content -Path $Path -Value $file_contents > $null
Write-Warning -Message "set warning"
}
Function Test-TargetResource
{
[CmdletBinding()]
[OutputType([Boolean])]
param
(
[Parameter(Mandatory = $true)]
[ValidateSet("Present", "Absent")]
[String]
$Ensure = "Present",
[Parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[String]
$Path,
[String]
$StringParam,
[UInt32]
$UInt32Param,
[UInt64]
$UInt64Param,
[String[]]
$StringArrayParam,
[UInt32[]]
$UInt32ArrayParam,
[UInt64[]]
$UInt64ArrayParam,
[Boolean]
$BooleanParam,
[PSCredential]
$PSCredentialParam,
[Microsoft.Management.Infrastructure.CimInstance]
$CimInstanceParam,
[Microsoft.Management.Infrastructure.CimInstance[]]
$CimInstanceArrayParam
)
Write-Warning -Message "test warning"
return $false
}
Export-ModuleMember -Function *-TargetResource

View file

@ -1,25 +0,0 @@
[ClassVersion("{{item.version}}")]
class ANSIBLE_xTestClass
{
[Write] String StringKey;
[Write] Boolean BooleanKey;
[Write] UInt32 UInt32Key;
[Write] String StringArrayKey[];
};
[ClassVersion("{{item.version}}"), FriendlyName("xTestResource")]
class ANSIBLE_xTestResource : OMI_BaseResource
{
[Key] String Path;
[Required, ValueMap{"Present", "Absent"}, Values{"Present", "Absent"}] String Ensure;
[Write] String StringParam;
[Write] UInt32 UInt32Param;
[Write] UInt64 UInt64Param;
[Write] String StringArrayParam[];
[Write] UInt32 UInt32ArrayParam[];
[Write] UInt64 UInt64ArrayParam[];
[Write] Boolean BooleanParam;
[Write, EmbeddedInstance("MSFT_Credential")] String PSCredentialParam;
[Write, EmbeddedInstance("ANSIBLE_xTestClass")] String CimInstanceParam;
[Write, EmbeddedInstance("ANSIBLE_xTestClass")] String CimInstanceArrayParam[];
};

View file

@ -30,9 +30,7 @@ lib/ansible/modules/windows/win_domain_membership.ps1 PSAvoidGlobalVars
lib/ansible/modules/windows/win_domain_membership.ps1 PSAvoidUsingWMICmdlet lib/ansible/modules/windows/win_domain_membership.ps1 PSAvoidUsingWMICmdlet
lib/ansible/modules/windows/win_domain_membership.ps1 PSUseApprovedVerbs lib/ansible/modules/windows/win_domain_membership.ps1 PSUseApprovedVerbs
lib/ansible/modules/windows/win_domain_membership.ps1 PSUseDeclaredVarsMoreThanAssignments lib/ansible/modules/windows/win_domain_membership.ps1 PSUseDeclaredVarsMoreThanAssignments
lib/ansible/modules/windows/win_dsc.ps1 PSAvoidUsingCmdletAliases
lib/ansible/modules/windows/win_dsc.ps1 PSAvoidUsingEmptyCatchBlock lib/ansible/modules/windows/win_dsc.ps1 PSAvoidUsingEmptyCatchBlock
lib/ansible/modules/windows/win_dsc.ps1 PSUseApprovedVerbs
lib/ansible/modules/windows/win_eventlog.ps1 PSUseDeclaredVarsMoreThanAssignments lib/ansible/modules/windows/win_eventlog.ps1 PSUseDeclaredVarsMoreThanAssignments
lib/ansible/modules/windows/win_find.ps1 PSAvoidUsingEmptyCatchBlock lib/ansible/modules/windows/win_find.ps1 PSAvoidUsingEmptyCatchBlock
lib/ansible/modules/windows/win_find.ps1 PSAvoidUsingWMICmdlet lib/ansible/modules/windows/win_find.ps1 PSAvoidUsingWMICmdlet
@ -72,7 +70,6 @@ lib/ansible/modules/windows/win_user.ps1 PSAvoidUsingCmdletAliases
lib/ansible/modules/windows/win_wait_for.ps1 PSAvoidUsingEmptyCatchBlock lib/ansible/modules/windows/win_wait_for.ps1 PSAvoidUsingEmptyCatchBlock
lib/ansible/modules/windows/win_webpicmd.ps1 PSAvoidUsingInvokeExpression lib/ansible/modules/windows/win_webpicmd.ps1 PSAvoidUsingInvokeExpression
test/integration/targets/win_audit_rule/library/test_get_audit_rule.ps1 PSAvoidUsingCmdletAliases test/integration/targets/win_audit_rule/library/test_get_audit_rule.ps1 PSAvoidUsingCmdletAliases
test/integration/targets/win_dsc/templates/ANSIBLE_xTestResource.psm1 PSAvoidDefaultValueForMandatoryParameter
test/integration/targets/win_iis_webbinding/library/test_get_webbindings.ps1 PSUseApprovedVerbs test/integration/targets/win_iis_webbinding/library/test_get_webbindings.ps1 PSUseApprovedVerbs
test/integration/targets/win_module_utils/library/argv_parser_test.ps1 PSUseApprovedVerbs test/integration/targets/win_module_utils/library/argv_parser_test.ps1 PSUseApprovedVerbs
test/integration/targets/win_module_utils/library/camel_conversion_test.ps1 PSUseDeclaredVarsMoreThanAssignments test/integration/targets/win_module_utils/library/camel_conversion_test.ps1 PSUseDeclaredVarsMoreThanAssignments

View file

@ -1 +1,6 @@
test/integration/targets/win_ping/library/win_ping_syntax_error.ps1 test/integration/targets/win_ping/library/win_ping_syntax_error.ps1
test/integration/targets/win_dsc/files/xTestDsc/1.0.0/DSCResources/ANSIBLE_xSetReboot/ANSIBLE_xSetReboot.psm1
test/integration/targets/win_dsc/files/xTestDsc/1.0.0/xTestDsc.psd1
test/integration/targets/win_dsc/files/xTestDsc/1.0.0/DSCResources/ANSIBLE_xTestResource/ANSIBLE_xTestResource.psm1
test/integration/targets/win_dsc/files/xTestDsc/1.0.1/xTestDsc.psd1
test/integration/targets/win_dsc/files/xTestDsc/1.0.1/DSCResources/ANSIBLE_xTestResource/ANSIBLE_xTestResource.psm1