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.
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
---------------

View file

@ -29,7 +29,7 @@ DSC and Ansible modules have a common goal which is to define and ensure the sta
resource. Because of
this, resources like the DSC `File resource <https://docs.microsoft.com/en-us/powershell/dsc/fileresource>`_
and Ansible ``win_file`` can be used to achieve the same result. Deciding which to use depends
on the scenario.
on the scenario.
Reasons for using an Ansible module over a DSC resource:
@ -99,6 +99,67 @@ This is what the Ansible task version of the above DSC Registry resource would l
ValueName: TestValue
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
--------------
Each DSC resource property has a type that is associated with it. Ansible
@ -110,9 +171,9 @@ require certain rules.
PSCredential
++++++++++++
A ``[PSCredential]`` object is used to store credentials in a secure way, but
Ansible has no way to serialize this over JSON. To set a DSC PSCredential property,
the definition of that parameter should have two entries that are suffixed with
``_username`` and ``_password`` for the username and password respectively.
Ansible has no way to serialize this over JSON. To set a DSC PSCredential property,
the definition of that parameter should have two entries that are suffixed with
``_username`` and ``_password`` for the username and password respectively.
For example:
.. code-block:: yaml+jinja
@ -123,9 +184,12 @@ For example:
SourceCredential_username: AdminUser
SourceCredential_password: PasswordForAdminUser
.. Note:: You should set ``no_log: yes`` on the task definition in
Ansible to ensure any credentials used are not stored in any log file or
console output.
.. Note:: On versions of Ansible older than 2.8, you should set ``no_log: yes``
on the task definition in Ansible to ensure any credentials used are not
stored in any log file or console output.
A ``[PSCredential]`` is defined with ``EmbeddedInstance("MSFT_Credential")`` in
a DSC resource MOF definition.
CimInstance Type
++++++++++++++++
@ -144,13 +208,20 @@ For example, to define a ``[CimInstance]`` value in Ansible:
Windows: yes
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``,
``Digest``, and ``Windows``. The keys to use in a ``[CimInstance]`` depend on
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
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
++++++
Simple type arrays like ``[string[]]`` or ``[UInt32[]]`` are defined as a list
@ -192,17 +263,39 @@ like this example:
Port: 80
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
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
-------------------
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
loaded based on a user profile, like the ``HKEY_CURRENT_USER`` registry hive,
will be loaded under the ``SYSTEM`` profile. The parameter
`PsDscRunAsCredential`` is a parameter that can be set for every DSC resource
will be loaded under the ``SYSTEM`` profile. The parameter
``PsDscRunAsCredential`` is a parameter that can be set for every DSC resource
force the DSC engine to run under a different account. As
``PsDscRunAsCredential`` has a type of ``PSCredential``, it is defined with the
``_username`` and ``_password`` suffix.
@ -331,7 +424,7 @@ Interact with Azure
win_psmodule:
name: xAzure
state: present
- name: Create virtual machine in Azure
win_dsc:
resource_name: xAzureVM

View file

@ -4,272 +4,400 @@
# 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
#AnsibleRequires -CSharpUtil Ansible.Basic
#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
$result = @{
changed = $false
$arg_type = switch($CimType) {
Boolean { "bool" }
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)
{
# this converts a hashtable to a CimInstance
Function Get-DscCimClassProperties {
<#
.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()
if ($valueType -ne [hashtable])
{
Fail-Json -obj $result -message "CimInstance value for property $name must be a hashtable, was $($valueType.FullName)"
$resource = Get-CimClass -ClassName $ClassName -Namespace root\Microsoft\Windows\DesiredStateConfiguration
# Filter out any magic properties that are used internally on an OMI_BaseResource
# 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
{
$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
return ,$properties
}
Function Cast-Value($value, $type, $typeString, $name)
{
if ($type -eq [CimInstance])
{
$newValue = Cast-ToCimInstance -name $name -value $value -className $typeString
Function Add-PropertyOption {
<#
.SYNOPSIS
Adds the spec for the property type to the existing module specification.
#>
param(
[Parameter(Mandatory=$true)][Hashtable]$Spec,
[Parameter(Mandatory=$true)]
[Microsoft.Management.Infrastructure.CimPropertyDeclaration]$Property
)
$option = @{
required = $false
}
ElseIf ($type -eq [CimInstance[]])
{
if ($value -isnot [array])
{
$value = @($value)
}
[CimInstance[]]$newValue = @()
$baseTypeString = $typeString.Substring(0, $typeString.Length - 2)
foreach ($cim in $value)
{
$newValue += Cast-ToCimInstance -name $name -value $cim -className $baseTypeString
}
$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
}
Else
{
$originalType = $value.GetType()
if ($originalType -eq $type)
{
$newValue = $value
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
}
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
$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 Get-OptionSpec {
<#
.SYNOPSIS
Generates the specifiec used in AnsibleModule for a CIM MOF resource name.
.NOTES
This won't be able to retrieve the default values for an option as that is not defined in the MOF for a resource.
Default values are still preserved in the DSC engine if we don't pass in the property at all, we just can't report
on what they are automatically.
#>
param(
[Parameter(Mandatory=$true)][String]$ClassName
)
$spec = @{
options = @{}
required_together = [System.Collections.ArrayList]@()
}
$properties = Get-DscCimClassProperties -ClassName $ClassName
foreach ($property in $properties) {
Add-PropertyOption -Spec $spec -Property $property
}
return $spec
}
Function ConvertTo-CimInstance {
<#
.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
)
$properties = @{}
foreach ($value_info in $Value.GetEnumerator()) {
# Need to remove all null values from existing dict so the conversion works
if ($null -eq $value_info.Value) {
continue
}
$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)", $_)
}
}
Function ConvertTo-DscProperty {
<#
.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
$dsc_properties = @{}
foreach ($property in $properties) {
$property_name = $property.Name
$property_type = $property.CimType.ToString()
if ($property.ReferenceClassName -eq "MSFT_Credential") {
$username = $Params."$($property_name)_username"
$password = $Params."$($property_name)_password"
# No user set == No option set in playbook, skip this property
if ($null -eq $username) {
continue
}
$sec_password = ConvertTo-SecureString -String $password -AsPlainText -Force
$value = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $username, $sec_password
} 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 ,$newValue
return $dsc_properties
}
Function Parse-DscProperty($name, $value, $resourceProp)
{
$propertyTypeString = $resourceProp.PropertyType
if ($propertyTypeString.StartsWith("["))
{
$propertyTypeString = $propertyTypeString.Substring(1, $propertyTypeString.Length - 2)
}
$propertyType = $propertyTypeString -as [type]
Function Invoke-DscMethod {
<#
.SYNOPSIS
Invokes the DSC Resource Method specified in another PS pipeline. This is
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
)
# CimInstance and CimInstance[] are reperesented as the actual Cim
# ClassName and the above returns a $null. We need to manually set the
# type in these cases
if ($propertyType -eq $null)
{
if ($propertyTypeString.EndsWith("[]"))
{
$propertyType = [CimInstance[]]
}
Else
{
$propertyType = [CimInstance]
# 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 ($propertyType.IsArray)
{
# convert the value to a list for later conversion
if ($value -is [string])
{
$value = $value.Split(",").Trim()
}
ElseIf ($value -isnot [array])
{
$value = @($value)
}
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)")
}
$newValue = Cast-Value -value $value -type $propertyType -typeString $propertyTypeString -name $name
return ,$newValue
return $result
}
$check_mode = Get-AnsibleParam -obj $params -name "_ansible_check_mode" -type "bool" -default $false
$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"
#From Ansible 2.3 onwards, params is now a Hash Array
$Attributes = @{}
foreach ($param in $params.GetEnumerator())
{
if ($param.Name -notin @("resource_name", "module_version") -and $param.Name -notlike "_ansible_*")
{
$Attributes[$param.Name] = $param.Value
# 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"
}
if ($Attributes.Count -eq 0)
{
Fail-Json -obj $result -message "No attributes specified"
$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 }
}
#Always return some basic info
$result["reboot_required"] = $false
$Config = @{
Name = ($resourcename)
Property = @{}
}
#Get the latest version of the module
if ($module_version -eq "latest")
{
$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"
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 "', '")'."
}
else
{
Fail-Json -obj $result -message "Resource $resourcename with version $module_version not found"
}
Write-Output -InputObject (ConvertTo-Json -Compress -InputObject @{ failed = $true; msg = $msg })
exit 1
}
#Get the Module that provides the resource. Will be used as
#mandatory argument for Invoke-DscResource
$Module = @{
ModuleName = $Resource.ModuleName
ModuleVersion = $Resource.Version
# 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
if ( -not ($Module.ModuleName -or $Module.ModuleVersion)) {
$Module = 'PSDesiredStateConfiguration'
$module_version = $null
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 {
if ($Resource.Module.Version)
{
$result["module_version"] = $Resource.Module.Version.ToString()
}
}
catch {}
Invoke-DscResource -Method Get -Property @{Fake="Fake"} @dsc_args > $null
} catch {}
#Convert params to correct datatype and inject
foreach ($attribute in $Attributes.GetEnumerator())
{
$key = $attribute.Name.Replace("item_name", "name")
$value = $attribute.Value
$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
# Dynamically build the option spec based on the resource_name specified and create the module object
$spec = Get-OptionSpec -ClassName $resource.ResourceType
$spec.supports_check_mode = $true
$spec.options.module_version = @{ type = "str"; default = "latest" }
$spec.options.resource_name = @{ type = "str"; required = $true }
$KeyValue = New-Object System.Management.Automation.PSCredential ($PropUserNameValue, ($PropPasswordValue | ConvertTo-SecureString -AsPlainText -Force))
$config.Property.Add($key.Replace("_username",""),$KeyValue)
}
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)
$module = [Ansible.Basic.AnsibleModule]::Create($args, $spec)
$module.Result.reboot_required = $false
$module.Result.module_version = $module_version
# 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
{
#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
}
$module.ExitJson()
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
possible as no escaping is required and it works with more complex types
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
required: true
notes:
@ -65,6 +70,9 @@ notes:
- 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)
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:
- Trond Hindenes (@trondhindenes)
'''
@ -103,6 +111,11 @@ EXAMPLES = r'''
Ensure: Present
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
- name: Setup the xWebAdministration module
win_psmodule:
@ -137,7 +150,7 @@ EXAMPLES = r'''
RETURN = r'''
module_version:
description: The version of the dsc resource/module used.
returned: success
returned: always
type: str
sample: "1.0.1"
reboot_required:
@ -146,9 +159,24 @@ reboot_required:
returned: always
type: bool
sample: true
message:
description: Any error message from invoking the DSC resource.
returned: error
type: str
sample: Multiple DSC modules found with resource name xyz
verbose_test:
description: The verbose output as a list from executing the DSC test
method.
returned: Ansible verbosity is -vvv or greater
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}}'
GUID = '{{item.version|to_uuid}}'
ModuleVersion = '1.0.0'
GUID = '80c895c4-de3f-4d6d-8fa4-c504c96b6f22'
Author = 'Ansible'
CompanyName = 'Ansible'
Copyright = '(c) 2017'
Copyright = '(c) 2019'
Description = 'Test DSC Resource for Ansible integration tests'
PowerShellVersion = '5.0'
CLRVersion = '4.0'
FunctionsToExport = '*'
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
register: powershell_version
- name: run smoke tests when we can't run the full suite
include_tasks: smoke.yml
- 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" not in fail_dsc_old.msg'
when: powershell_version.stdout_lines[0]|int < 5
- block:
- name: run non-destructive tests
- name: run tests when PSv5+
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
- name: run destructive tests if flag is set
include_tasks: destructive.yml
when: test_win_dsc_run_desctructive == True
always:
- name: remove test feature
win_feature:
name: '{{test_win_dsc_feature_name}}'
- name: remove remote tmp dir from PSModulePath
win_path:
name: PSModulePath
state: absent
- name: remove test folder
win_file:
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
scope: machine
elements:
- '{{ remote_tmp_dir }}'

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
win_dsc:
resource_name: FakeResource
Name: fake
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:
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
register: fail_missing_mandatory
failed_when: fail_missing_mandatory.msg != "Could not find mandatory property Name. Add this property and try again."
CimInstanceParam: # Missing KeyValue in dict
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:
resource_name: WindowsFeature
Name: InvalidFeature
resource_name: xSetReboot
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
register: fail_invalid_feature
failed_when: '"The requested feature InvalidFeature is not found on the target machine" not in fail_invalid_feature.msg'
NestedCimInstanceParam:
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:
resource_name: WindowsFeature
Name: '{{test_win_dsc_feature_name}}'
resource_name: xTestResource
Path: C:\path
Ensure: Present
register: win_dsc_add_feature_check
check_mode: yes
ReadParam: abc
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)
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
- name: fail invalid choice
win_dsc:
resource_name: WindowsFeature
Name: '{{test_win_dsc_feature_name}}'
resource_name: xTestResource
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
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
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)
- name: fail old version missing new option
win_dsc:
resource_name: WindowsFeature
Name: '{{test_win_dsc_feature_name}}'
resource_name: xTestResource
module_version: 1.0.0
Path: C:\path
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)
assert:
that:
- win_dsc_add_feature_again is not changed
- name: remove Windows feature (check mode)
- name: fail old version missing new option sub dict
win_dsc:
resource_name: WindowsFeature
Name: '{{test_win_dsc_feature_name}}'
Ensure: Absent
register: win_dsc_remove_feature_check
check_mode: yes
- name: get result of remove Windows feature (check mode)
win_shell: (Get-WindowsFeature -Name {{test_win_dsc_feature_name}}).Installed
register: win_dsc_remove_feature_result_check
- 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
resource_name: xTestResource
module_version: 1.0.0
Path: C:\path
Ensure: Present
CimInstanceArrayParam:
- Key: key
Choice: Choice1
register: fail_invalid_option_old_sub_dict
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: create test file (check mode)
win_dsc:
resource_name: File
DestinationPath: '{{test_win_dsc_folder}}\dsc-file'
DestinationPath: '{{ remote_tmp_dir }}\dsc-file'
Contents: file contents
Attributes:
- Hidden
- ReadOnly
Ensure: Present
Type: File
register: win_dsc_create_file_check
register: create_file_check
check_mode: yes
- name: get result of create test file (check mode)
win_stat:
path: '{{test_win_dsc_folder}}\dsc-file'
register: win_dsc_create_file_result_check
path: '{{ remote_tmp_dir }}\dsc-file'
register: create_file_actual_check
- name: assert results of create test file (check mode)
- name: assert create test file (check mode)
assert:
that:
- win_dsc_create_file_check is changed
- win_dsc_create_file_result_check.stat.exists == False
- create_file_check is changed
- 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
win_dsc:
resource_name: File
DestinationPath: '{{test_win_dsc_folder}}\dsc-file'
DestinationPath: '{{ remote_tmp_dir }}\dsc-file'
Contents: file contents
Attributes:
- Hidden
- ReadOnly
Ensure: Present
Type: File
register: win_dsc_create_file
register: create_file
- name: get result of create test file
win_stat:
path: '{{test_win_dsc_folder}}\dsc-file'
register: win_dsc_create_file_result
path: '{{ remote_tmp_dir }}\dsc-file'
register: create_file_actual
- name: assert results of create test file
- name: assert create test file verbosity
assert:
that:
- win_dsc_create_file is changed
- win_dsc_create_file_result.stat.exists == True
- win_dsc_create_file_result.stat.isdir == False
- win_dsc_create_file_result.stat.ishidden == True
- win_dsc_create_file_result.stat.isreadonly == True
- create_file.verbose_test is defined
- create_file.verbose_set is defined
when: ansible_verbosity >= 3
- 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)
win_dsc:
resource_name: File
DestinationPath: '{{test_win_dsc_folder}}\dsc-file'
DestinationPath: '{{ remote_tmp_dir }}\dsc-file'
Contents: file contents
Attributes: Hidden, ReadOnly
Attributes:
- Hidden
- ReadOnly
Ensure: Present
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:
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
win_shell: (New-Object System.Security.Principal.NTAccount("{{ansible_user}}")).Translate([System.Security.Principal.SecurityIdentifier]).ToString()
register: win_dsc_actual_sid
- name: get SID of the current Ansible user
win_shell: |
Add-Type -AssemblyName System.DirectoryServices.AccountManagement
[System.DirectoryServices.AccountManagement.UserPrincipal]::Current.Sid.Value
register: actual_sid
- name: run DSC process as another user
win_dsc:
resource_name: Script
GetScript: '@{ Result = "" }'
GetScript: '@{ Result= "" }'
SetScript: |
$output = &whoami.exe
$sid = (New-Object System.Security.Principal.NTAccount($output)).Translate([System.Security.Principal.SecurityIdentifier]).ToString()
Set-Content -Path "{{test_win_dsc_folder}}\file" -Value $sid
TestScript: Test-Path -Path "{{test_win_dsc_folder}}\file"
PsDscRunAsCredential_username: '{{ansible_user}}'
PsDscRunAsCredential_password: '{{ansible_password}}'
register: win_dsc_runas
Add-Type -AssemblyName System.DirectoryServices.AccountManagement
$sid = [System.DirectoryServices.AccountManagement.UserPrincipal]::Current.Sid.Value
Set-Content -Path "{{ remote_tmp_dir }}\runas.txt" -Value $sid
TestScript: $false
PsDscRunAsCredential_username: '{{ ansible_user }}'
PsDscRunAsCredential_password: '{{ ansible_password }}'
register: runas_user
- name: get content of script output file
- name: get result of run DSC process as another user
slurp:
path: '{{test_win_dsc_folder}}\file'
register: win_dsc_runas_result
path: '{{ remote_tmp_dir }}\runas.txt'
register: runas_user_result
- name: assert results of run DSC process as another user
- name: assert run DSC process as another user
assert:
that:
- win_dsc_runas is changed
- win_dsc_runas_result.content|b64decode == win_dsc_actual_sid.stdout
- runas_user is changed
- 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
win_file:
path: C:\Program Files\WindowsPowerShell\Modules\xTestDsc\{{item}}\DSCResources\ANSIBLE_xTestResource
state: directory
with_items:
- "1.0.0"
- "2.0.0"
- name: run DSC that sets reboot_required with defaults
win_dsc:
resource_name: xSetReboot
KeyParam: value # Just to satisfy the Resource with key validation
register: set_reboot_defaults
- name: template custom DSC resource files
win_template:
src: '{{item.src}}'
dest: C:\Program Files\WindowsPowerShell\Modules\xTestDsc\{{item.version}}\{{item.dest}}
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: assert run DSC that sets reboot_required with defaults
assert:
that:
- set_reboot_defaults.reboot_required
- name: run custom DSC resource
win_dsc: &dsc_params
- name: run DSC that sets reboot_required with False
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
Path: '{{test_win_dsc_folder}}\custom-output.txt'
Path: '{{ remote_tmp_dir }}\test-types.json'
Ensure: Present
StringParam: string param
UInt32Param: 1000
UInt64Param: 1000000
StringArrayParam:
- string 1
- 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:
- 1000
- 2000
- '4294967295'
- 4294967295
Int64Param: 9223372036854775807 # [Int64]::MaxValue
Int64ArrayParam:
- -9223372036854775808 # [Int64]::MinValue
- 9223372036854775807
UInt64Param: 18446744073709551615 # [UInt64]::MaxValue
UInt64ArrayParam:
- 1000000
- 2000000
BooleanParam: yes
PSCredentialParam_username: username
PSCredentialParam_password: password
- 0 # [UInt64]::MinValue
- 18446744073709551615
BooleanParam: True
BooleanArrayParam:
- 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:
StringKey: a
BooleanKey: yes
UInt32Key: 1
StringArrayKey:
- string 1
- string 2
KeyValue: a
CimInstanceArrayParam:
- StringKey: b
BooleanKey: no
UInt32Key: 2
StringArrayKey:
- string 3
- string 4
- StringKey: c
BooleanKey: no
UInt32Key: 3
StringArrayKey:
- string 5
- string 6
register: test_dsc_custom
- KeyValue: b
Choice: Choice1
StringValue: string 1
IntValue: 1
StringArrayValue:
- abc
- def
- KeyValue: c
Choice: Choice2
StringValue: string 2
IntValue: '2'
StringArrayValue:
- 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:
path: '{{test_win_dsc_folder}}\custom-output.txt'
register: test_dsc_custom_output
path: '{{ remote_tmp_dir }}\test-types.json'
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:
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:
that:
- test_dsc_custom is changed
- test_dsc_custom_output.content|b64decode|strip_newline == test_dsc_custom_expected|strip_newline
- test_dsc_custom.warnings | length == 2
- "'[[xTestResource]DirectResourceAccess] test warning' in test_dsc_custom.warnings[0]"
- "'[[xTestResource]DirectResourceAccess] set warning' in test_dsc_custom.warnings[1]"
- dsc_types is changed
- dsc_types.module_version == '1.0.1'
- not dsc_types.reboot_required
- dsc_types_actual.Version == '1.0.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:
<<: *dsc_params
module_version: '1.0.0'
register: test_dsc_custom_version
resource_name: xTestResource
module_version: 1.0.0
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:
path: '{{test_win_dsc_folder}}\custom-output.txt'
register: test_dsc_custom_output_version
path: '{{ remote_tmp_dir }}\test-types.json'
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:
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:
that:
- test_dsc_custom is changed
- test_dsc_custom_output_version.content|b64decode|strip_newline == test_dsc_custom_expected_version|strip_newline
- dsc_types_old is changed
- 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 PSUseApprovedVerbs
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 PSUseApprovedVerbs
lib/ansible/modules/windows/win_eventlog.ps1 PSUseDeclaredVarsMoreThanAssignments
lib/ansible/modules/windows/win_find.ps1 PSAvoidUsingEmptyCatchBlock
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_webpicmd.ps1 PSAvoidUsingInvokeExpression
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_module_utils/library/argv_parser_test.ps1 PSUseApprovedVerbs
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_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