diff --git a/lib/ansible/modules/windows/win_dsc.ps1 b/lib/ansible/modules/windows/win_dsc.ps1 index f40fc7632dd..87e1904ba5a 100644 --- a/lib/ansible/modules/windows/win_dsc.ps1 +++ b/lib/ansible/modules/windows/win_dsc.ps1 @@ -1,75 +1,169 @@ #!powershell -# (c) 2015, Trond Hindenes , and others -# # This file is part of Ansible -# -# Ansible is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Ansible is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Ansible. If not, see . -# WANT_JSON -# POWERSHELL_COMMON +# (c) 2015, Trond Hindenes , and others +# Copyright (c) 2017 Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) -#Temporary fix -#Set-StrictMode -Off +#Requires -Module Ansible.ModuleUtils.Legacy +#Requires -Version 5 + +$ErrorActionPreference = "Stop" $params = Parse-Args $args -supports_check_mode $true $result = @{ changed = $false } -#Check that we're on at least Powershell version 5 -if ($PSVersionTable.PSVersion.Major -lt 5) +Function ConvertTo-HashtableFromPsCustomObject($psObject) { - Fail-Json -obj $Result -message "This module only runs on Powershell version 5 or higher" + $hashtable = @{} + $psObject | Get-Member -MemberType *Property | ForEach-Object { + $value = $psObject.($_.Name) + if ($value -is [PSObject]) + { + $value = ConvertTo-HashtableFromPsCustomObject -myPsObject $value + } + $hashtable.($_.Name) = $value + } + + return ,$hashtable } + +Function Cast-ToCimInstance($name, $value, $className) +{ + # this converts a hashtable to a CimInstance + if ($value -is [PSObject]) + { + # convert to hashtable + $value = ConvertTo-HashtableFromPsCustomObject -psObject $value + } + + $valueType = $value.GetType() + if ($valueType -ne [hashtable]) + { + Fail-Json -obj $result -message "CimInstance value for property $name must be a hashtable, was $($valueType.FullName)" + } + + 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 +} + +Function Cast-Value($value, $type, $typeString, $name) +{ + if ($type -eq [CimInstance]) + { + $newValue = Cast-ToCimInstance -name $name -value $value -className $typeString + } + 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 + } + } + 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 + } + } + } + + return ,$newValue +} + +Function Parse-DscProperty($name, $value, $resourceProp) +{ + $propertyTypeString = $resourceProp.PropertyType + if ($propertyTypeString.StartsWith("[")) + { + $propertyTypeString = $propertyTypeString.Substring(1, $propertyTypeString.Length - 2) + } + $propertyType = $propertyTypeString -as [type] + + # 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] + } + } + + 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) + } + } + $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 -$resourcename = Get-AnsibleParam -obj $params -name "resource_name" -type "str" -failifempty $true -resultobj $result +$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 = $params.GetEnumerator() | - Where-Object { - $_.key -ne "resource_name" -and - $_.key -ne "module_version" -and - $_.key -notlike "_ansible_*" +$Attributes = @{} +foreach ($param in $params.GetEnumerator()) +{ + if ($param.Name -notin @("resource_name", "module_version") -and $param.Name -notlike "_ansible_*") + { + $Attributes[$param.Name] = $param.Value } +} -if (!($Attributes)) +if ($Attributes.Count -eq 0) { Fail-Json -obj $result -message "No attributes specified" } #Always return some basic info -$result["resource_name"] = $resourcename -$result["attributes"] = $Attributes -$result["reboot_required"] = $null - - -# Build Attributes Hashtable for DSC Resource Propertys -$Attrib = @{} -foreach ($key in $Attributes) -{ - $result[$key.name] = $key.value - $Attrib.Add($Key.Key,$Key.Value) -} - -$result["dsc_attributes"] = $attrib +$result["reboot_required"] = $false $Config = @{ Name = ($resourcename) - Property = @{ - } - } + Property = @{} +} #Get the latest version of the module if ($module_version -eq "latest") @@ -115,24 +209,24 @@ try { } catch {} - #Convert params to correct datatype and inject -$attrib.Keys | foreach-object { - $Key = $_.replace("item_name", "name") - $prop = $resource.Properties | where {$_.Name -eq $key} +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 {$_.Name -eq $key.Replace("_username","")} + $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 = $attrib.Item($_) + $PropUserNameValue = $value $PropPassword = $key.Replace("_username","_password") - $PropPasswordValue = $attrib.$PropPassword + $PropPasswordValue = $Attributes.$PropPassword - $cred = New-Object System.Management.Automation.PSCredential ($PropUserNameValue, ($PropPasswordValue | ConvertTo-SecureString -AsPlainText -Force)) - [System.Management.Automation.PSCredential]$KeyValue = $cred + $KeyValue = New-Object System.Management.Automation.PSCredential ($PropUserNameValue, ($PropPasswordValue | ConvertTo-SecureString -AsPlainText -Force)) $config.Property.Add($key.Replace("_username",""),$KeyValue) } ElseIf ($key.Contains("_password")) @@ -143,91 +237,21 @@ $attrib.Keys | foreach-object { { Fail-Json -obj $result -message "Property $key in resource $resourcename is not a valid property" } - } - ElseIf ($prop.PropertyType -eq "[string]") + Else { - [String]$KeyValue = $attrib.Item($_) - $config.Property.Add($key,$KeyValue) - } - ElseIf ($prop.PropertyType -eq "[string[]]") - { - #KeyValue is an array of strings - [String]$TempKeyValue = $attrib.Item($_) - [String[]]$KeyValue = $TempKeyValue.Split(",").Trim() - - $config.Property.Add($key,$KeyValue) - } - ElseIf ($prop.PropertyType -eq "[UInt32[]]") - { - #KeyValue is an array of integers - [String]$TempKeyValue = $attrib.Item($_) - [UInt32[]]$KeyValue = $attrib.Item($_.split(",").Trim()) - $config.Property.Add($key,$KeyValue) - } - ElseIf ($prop.PropertyType -eq "[bool]") - { - if ($attrib.Item($_) -like "true") + if ($value -eq $null) { - [bool]$KeyValue = $true + $keyValue = $null } - ElseIf ($attrib.Item($_) -like "false") + Else { - [bool]$KeyValue = $false + $keyValue = Parse-DscProperty -name $key -value $value -resourceProp $prop } - $config.Property.Add($key,$KeyValue) + + $config.Property.Add($key, $keyValue) } - ElseIf ($prop.PropertyType -eq "[int]") - { - [int]$KeyValue = $attrib.Item($_) - $config.Property.Add($key,$KeyValue) - } - ElseIf ($prop.PropertyType -eq "[CimInstance[]]") - { - #KeyValue is an array of CimInstance - [CimInstance[]]$KeyVal = @() - [String]$TempKeyValue = $attrib.Item($_) - #Need to split on the string }, because some property values have commas in them - [String[]]$KeyValueStr = $TempKeyValue -split("},") - #Go through each string of properties and create a hash of them - foreach($str in $KeyValueStr) - { - [string[]]$properties = $str.Split("{")[1].Replace("}","").Trim().Split([environment]::NewLine).Trim() - $prph = @{} - foreach($p in $properties) - { - $pArr = $p -split "=" - #if the value can be an int we must convert it to an int - if([bool]($pArr[1] -as [int] -is [int])) - { - $prph.Add($pArr[0].Trim(),$pArr[1].Trim() -as [int]) - } - else - { - $prph.Add($pArr[0].Trim(),$pArr[1].Trim()) - } - } - #create the new CimInstance - $cim = New-CimInstance -ClassName $str.Split("{")[0].Trim() -Property $prph -ClientOnly - #add the new CimInstance to the array - $KeyVal += $cim - } - $config.Property.Add($key,$KeyVal) - } - ElseIf ($prop.PropertyType -eq "[Int32]") - { - # Add Supoort for Int32 - [int]$KeyValue = $attrib.Item($_) - $config.Property.Add($key,$KeyValue) - } - ElseIf ($prop.PropertyType -eq "[UInt32]") - { - # Add Support for [UInt32] - [UInt32]$KeyValue = $attrib.Item($_) - $config.Property.Add($key,$KeyValue) - } - - } +} try { @@ -262,6 +286,4 @@ Catch Fail-Json -obj $result -message $_[0].Exception.Message } - -#set-attr -obj $result -name "property" -value $property Exit-Json -obj $result diff --git a/lib/ansible/modules/windows/win_dsc.py b/lib/ansible/modules/windows/win_dsc.py index a021def45c8..86655f973f2 100644 --- a/lib/ansible/modules/windows/win_dsc.py +++ b/lib/ansible/modules/windows/win_dsc.py @@ -1,25 +1,12 @@ #!/usr/bin/python # -*- coding: utf-8 -*- -# (c) 2015, Trond Hindenes , and others -# # This file is part of Ansible -# -# Ansible is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Ansible is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Ansible. If not, see . -# this is a windows documentation stub. actual code lives in the .ps1 -# file of the same name +# (c) 2015, Trond Hindenes , and others +# Copyright (c) 2017 Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + ANSIBLE_METADATA = {'metadata_version': '1.1', 'status': ['preview'], @@ -31,70 +18,131 @@ module: win_dsc version_added: "2.4" short_description: Invokes a PowerShell DSC configuration description: - - Invokes a PowerShell DSC Configuration. Requires PowerShell version 5 (February release or newer). - - Most of the parameters for this module are dynamic and will vary depending on the DSC Resource. - - See :doc:`windows_dsc` for more information on how to use this module. +- Configures a resource using PowerShell DSC. +- Requires PowerShell version 5.0 or newer. +- Most of the options for this module are dynamic and will vary depending on + the DSC Resource specified in I(resource_name). +- See :doc:`windows_dsc` for more information on how to use this module. options: resource_name: description: - - The DSC Resource to use. Must be accessible to PowerShell using any of the default paths. + - The name of the DSC Resource to use. + - Must be accessible to PowerShell using any of the default paths. required: true module_version: description: - - Can be used to configure the exact version of the dsc resource to be invoked. - - Useful if the target node has multiple versions installed of the module containing the DSC resource. - - If not specified, the module will follow standard Powershell convention and use the highest version available. + - Can be used to configure the exact version of the DSC resource to be + invoked. + - Useful if the target node has multiple versions installed of the module + containing the DSC resource. + - If not specified, the module will follow standard PowerShell convention + and use the highest version available. default: latest -author: Trond Hindenes + free_form: + description: + - The M(win_dsc) module takes in multiple free form options based on the + DSC resource being invoked by I(resource_name). + - There is no option actually named C(free_form) so see the examples. + - This module will try and convert the option to the correct type required + by the DSC resource and throw a warning if it fails. + - If the type of the DSC resource option is a C(CimInstance) or + C(CimInstance[]), this means the value should be a dictionary or list + of dictionaries based on the values required by that option. + - If the type of the DSC resource option is a C(PSCredential) then there + needs to be 2 options set in the Ansible task definition suffixed with + C(_username) and C(_password). + - If the type of the DSC resource option is an array, then a list should be + 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[]). + required: true +notes: +- By default there are a few builtin resources that come with PowerShell 5.0, + see U(https://docs.microsoft.com/en-us/powershell/dsc/builtinresource) for + more information on these resources. +- Custom DSC resources can be installed with M(win_psmodule) using the I(name) + option. +- 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. +author: +- Trond Hindenes (@trondhindenes) ''' EXAMPLES = r''' -# Playbook example - - name: Extract zip file - win_dsc: - resource_name: archive - ensure: Present - path: "C:\\Temp\\zipfile.zip" - destination: "C:\\Temp\\Temp2" +- name: Extract zip file + win_dsc: + resource_name: Archive + Ensure: Present + Path: C:\Temp\zipfile.zip + Destination: C:\Temp\Temp2 - - name: Invoke DSC with check mode - win_dsc: - resource_name: windowsfeature - name: telnet-client +- name: Install a Windows feature with the WindowsFeature resource + win_dsc: + resource_name: WindowsFeature + Name: telnet-client + +- name: Edit HKCU reg key under specific user + win_regedit: + resource_name: Registry + Ensure: Present + Key: HKEY_CURRENT_USER\ExampleKey + ValueName: TestValue + ValueData: TestData + PsDscRunAsCredential_username: '{{ansible_user}}' + PsDscRunAsCredentual_password: '{{ansible_password}}' + no_log: true + +- name: Create file with multiple attributes + win_dsc: + resource_name: File + DestinationPath: C:\ansible\dsc + Attributes: # can also be a comma separated string, e.g. 'Hidden, System' + - Hidden + - System + Ensure: Present + Type: Directory + +# more complex example using custom DSC resource and dict values +- name: Setup the xWebAdministration module + win_psmodule: + name: xWebAdministration + state: present + +- name: Create IIS Website with Binding and Authentication options + win_dsc: + resource_name: xWebsite + Ensure: Present + Name: DSC Website + State: Started + PhysicalPath: C:\inetpub\wwwroot + BindingInfo: # Example of a CimInstance[] DSC parameter (list of dicts) + - Protocol: https + Port: 1234 + CertificateStoreName: MY + CertificateThumbprint: C676A89018C4D5902353545343634F35E6B3A659 + HostName: DSCTest + IPAddress: '*' + SSLFlags: '1' + - Protocol: http + Port: 4321 + IPAddress: '*' + AuthenticationInfo: # Example of a CimInstance DSC parameter (dict) + Anonymous: no + Basic: true + Digest: false + Windows: yes ''' RETURN = r''' -resource_name: - description: The name of the invoked resource - returned: always - type: string - sample: windowsfeature module_version: description: The version of the dsc resource/module used. returned: success type: string sample: "1.0.1" -attributes: - description: The attributes/parameters passed in to the DSC resource as key/value pairs - returned: always - type: complex - sample: - contains: - Key: - description: Attribute key - Value: - description: Attribute value -dsc_attributes: - description: The attributes/parameters as returned from the DSC engine in dict format - returned: always - type: complex - contains: - Key: - description: Attribute key - Value: - description: Attribute value reboot_required: - description: flag returned from the DSC engine indicating whether or not the machine requires a reboot for the invoked changes to take effect + description: Flag returned from the DSC engine indicating whether or not + the machine requires a reboot for the invoked changes to take effect. returned: always type: boolean sample: True diff --git a/test/integration/targets/win_dsc/defaults/main.yml b/test/integration/targets/win_dsc/defaults/main.yml index e1833cd8a84..90aaec66569 100644 --- a/test/integration/targets/win_dsc/defaults/main.yml +++ b/test/integration/targets/win_dsc/defaults/main.yml @@ -1,4 +1,5 @@ --- - # Feature not normally installed by default. -test_win_feature_name: Telnet-Client +test_win_dsc_feature_name: Telnet-Client +test_win_dsc_folder: C:\ansible test +test_win_dsc_run_desctructive: no diff --git a/test/integration/targets/win_dsc/files/custom-result-normal.txt b/test/integration/targets/win_dsc/files/custom-result-normal.txt new file mode 100644 index 00000000000..8220d589f84 --- /dev/null +++ b/test/integration/targets/win_dsc/files/custom-result-normal.txt @@ -0,0 +1,44 @@ +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[] diff --git a/test/integration/targets/win_dsc/files/custom-result-versioned.txt b/test/integration/targets/win_dsc/files/custom-result-versioned.txt new file mode 100644 index 00000000000..fe5a6e2dfff --- /dev/null +++ b/test/integration/targets/win_dsc/files/custom-result-versioned.txt @@ -0,0 +1,44 @@ +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[] diff --git a/test/integration/targets/win_dsc/filter_plugins/strip_newline.py b/test/integration/targets/win_dsc/filter_plugins/strip_newline.py new file mode 100644 index 00000000000..bfa642de499 --- /dev/null +++ b/test/integration/targets/win_dsc/filter_plugins/strip_newline.py @@ -0,0 +1,16 @@ +# (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) diff --git a/test/integration/targets/win_dsc/library/test_win_dsc_iis_info.ps1 b/test/integration/targets/win_dsc/library/test_win_dsc_iis_info.ps1 new file mode 100644 index 00000000000..3c353d01ccd --- /dev/null +++ b/test/integration/targets/win_dsc/library/test_win_dsc_iis_info.ps1 @@ -0,0 +1,41 @@ +#!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 diff --git a/test/integration/targets/win_dsc/tasks/destructive.yml b/test/integration/targets/win_dsc/tasks/destructive.yml new file mode 100644 index 00000000000..f455f9dbd6b --- /dev/null +++ b/test/integration/targets/win_dsc/tasks/destructive.yml @@ -0,0 +1,135 @@ +# 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 exists + 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|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|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: + - not win_dsc_iis_again|changed diff --git a/test/integration/targets/win_dsc/tasks/main.yml b/test/integration/targets/win_dsc/tasks/main.yml index 3e8d6ed6625..1c241e72174 100644 --- a/test/integration/targets/win_dsc/tasks/main.yml +++ b/test/integration/targets/win_dsc/tasks/main.yml @@ -1,119 +1,34 @@ -# test code for the win_feature module -# (c) 2014, Chris Church +--- +- name: get powershell version + win_shell: $PSVersionTable.PSVersion.Major + register: powershell_version -# This file is part of Ansible -# -# Ansible is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Ansible is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Ansible. If not, see . +- name: run smoke tests when we can't run the full suite + include_tasks: smoke.yml + when: powershell_version.stdout_lines[0]|int < 5 +- block: + - name: run non-destructive tests + include_tasks: tests.yml + + - name: run destructive tests if flag is set + include_tasks: destructive.yml + when: test_win_dsc_run_desctructive == True -- name: check whether servermanager module is available (windows 2008 r2 or later) - raw: PowerShell -Command Import-Module ServerManager - register: win_feature_has_servermanager - ignore_errors: true + always: + - name: remove test feature + win_feature: + name: '{{test_win_dsc_feature_name}}' + 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 - -- name: start with feature absent - win_feature: - name: "{{ test_win_feature_name }}" - state: absent - when: (win_feature_has_servermanager|success) and (ansible_powershell_version is defined) and (ansible_powershell_version >= 5) - -- name: Invoke DSC with check mode - win_dsc: - resource_name: windowsfeature - name: "{{ test_win_feature_name }}" - check_mode: yes - register: win_dsc_checkmode_result - when: (win_feature_has_servermanager|success) and (ansible_powershell_version is defined) and (ansible_powershell_version >= 5) - -- name: check result of Invoke DSC with check mode - assert: - that: - - "win_dsc_checkmode_result|changed" - - "win_dsc_checkmode_result|success" - when: (win_feature_has_servermanager|success) and (ansible_powershell_version is defined) and (ansible_powershell_version >= 5) - -- name: Make sure the feature is still absent - win_dsc: - resource_name: windowsfeature - name: "{{ test_win_feature_name }}" - ensure: absent - register: win_dsc_1_result - when: (win_feature_has_servermanager|success) and (ansible_powershell_version is defined) and (ansible_powershell_version >= 5) - -- name: check result of Make sure the feature is still absent - assert: - that: - - "not win_dsc_1_result|changed" - - "win_dsc_1_result|success" - when: (win_feature_has_servermanager|success) and (ansible_powershell_version is defined) and (ansible_powershell_version >= 5) - -- name: Install feature for realz - win_dsc: - resource_name: windowsfeature - name: "{{ test_win_feature_name }}" - register: win_dsc_2_result - when: (win_feature_has_servermanager|success) and (ansible_powershell_version is defined) and (ansible_powershell_version >= 5) - -- name: check result of Install feature for realz - assert: - that: - - "win_dsc_2_result|changed" - - "win_dsc_2_result|success" - when: (win_feature_has_servermanager|success) and (ansible_powershell_version is defined) and (ansible_powershell_version >= 5) - -- name: Ensure clean failure - win_dsc: - resource_name: some_unknown_resource_that_wont_ever_exist - name: "{{ test_win_feature_name }}" - register: win_dsc_3_result - ignore_errors: true - when: (win_feature_has_servermanager|success) and (ansible_powershell_version is defined) and (ansible_powershell_version >= 5) - -- name: check result of Ensure clean failure - assert: - that: - - "not win_dsc_3_result|changed" - - "not win_dsc_3_result|success" - when: (win_feature_has_servermanager|success) and (ansible_powershell_version is defined) and (ansible_powershell_version >= 5) - -- name: Make sure the feature is absent - win_dsc: - resource_name: windowsfeature - name: "{{ test_win_feature_name }}" - ensure: absent - register: win_dsc_4_result - when: (win_feature_has_servermanager|success) and (ansible_powershell_version is defined) and (ansible_powershell_version >= 5) - -- name: check result of Make sure the feature is absent - assert: - that: - - "win_dsc_4_result|changed" - - "win_dsc_4_result|success" - when: (win_feature_has_servermanager|success) and (ansible_powershell_version is defined) and (ansible_powershell_version >= 5) - -- name: Make sure the feature is still absent with no changes - win_dsc: - resource_name: windowsfeature - name: "{{ test_win_feature_name }}" - ensure: absent - register: win_dsc_5_result - when: (win_feature_has_servermanager|success) and (ansible_powershell_version is defined) and (ansible_powershell_version >= 5) - -- name: check result of Make sure the feature is absent - assert: - that: - - "not win_dsc_5_result|changed" - - "win_dsc_5_result|success" - when: (win_feature_has_servermanager|success) and (ansible_powershell_version is defined) and (ansible_powershell_version >= 5) + when: powershell_version.stdout_lines[0]|int >= 5 diff --git a/test/integration/targets/win_dsc/tasks/smoke.yml b/test/integration/targets/win_dsc/tasks/smoke.yml new file mode 100644 index 00000000000..5489cf4dfad --- /dev/null +++ b/test/integration/targets/win_dsc/tasks/smoke.yml @@ -0,0 +1,8 @@ +# 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' diff --git a/test/integration/targets/win_dsc/tasks/tests.yml b/test/integration/targets/win_dsc/tasks/tests.yml new file mode 100644 index 00000000000..98660017969 --- /dev/null +++ b/test/integration/targets/win_dsc/tasks/tests.yml @@ -0,0 +1,330 @@ +# 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" + +- name: fail by not setting mandatory option + win_dsc: + resource_name: WindowsFeature + Ensure: Present + register: fail_missing_mandatory + failed_when: fail_missing_mandatory.msg != "Could not find mandatory property Name. Add this property and try again." + +- name: fail to add a non-existant feature + win_dsc: + resource_name: WindowsFeature + Name: InvalidFeature + 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' + +- name: add Windows feature (check mode) + win_dsc: + resource_name: WindowsFeature + Name: '{{test_win_dsc_feature_name}}' + Ensure: Present + register: win_dsc_add_feature_check + check_mode: yes + +- 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|changed + - win_dsc_add_feature_result_check.stdout == "False\r\n" + +- name: add Windows feature + win_dsc: + resource_name: WindowsFeature + Name: '{{test_win_dsc_feature_name}}' + Ensure: Present + register: win_dsc_add_feature + +- 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|changed + - win_dsc_add_feature_result.stdout == "True\r\n" + +- name: add Windows feature (idempotent) + win_dsc: + resource_name: WindowsFeature + Name: '{{test_win_dsc_feature_name}}' + Ensure: Present + register: win_dsc_add_feature_again + +- name: assert result of add Windows feature (idempotent) + assert: + that: + - not win_dsc_add_feature_again|changed + +- name: remove Windows feature (check mode) + 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|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|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: + - not win_dsc_remove_feature_again|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) + win_dsc: + resource_name: File + DestinationPath: '{{test_win_dsc_folder}}\dsc-file' + Contents: file contents + Attributes: + - Hidden + - ReadOnly + Ensure: Present + Type: File + register: win_dsc_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 + +- name: assert results of create test file (check mode) + assert: + that: + - win_dsc_create_file_check|changed + - win_dsc_create_file_result_check.stat.exists == False + +- name: create test file + win_dsc: + resource_name: File + DestinationPath: '{{test_win_dsc_folder}}\dsc-file' + Contents: file contents + Attributes: + - Hidden + - ReadOnly + Ensure: Present + Type: File + register: win_dsc_create_file + +- name: get result of create test file + win_stat: + path: '{{test_win_dsc_folder}}\dsc-file' + register: win_dsc_create_file_result + +- name: assert results of create test file + assert: + that: + - win_dsc_create_file|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 + +- name: create test file (idempotent) + win_dsc: + resource_name: File + DestinationPath: '{{test_win_dsc_folder}}\dsc-file' + Contents: file contents + Attributes: Hidden, ReadOnly + Ensure: Present + Type: File + register: win_dsc_create_file_again + +- name: assert results of create test file (idempotent) + assert: + that: + - not win_dsc_create_file_again|changed + +- 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: run DSC process as another user + win_dsc: + resource_name: Script + 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 + +- name: get content of script output file + slurp: + path: '{{test_win_dsc_folder}}\file' + register: win_dsc_runas_result + +- name: assert results of run DSC process as another user + assert: + that: + - win_dsc_runas|changed + - win_dsc_runas_result.content|b64decode == win_dsc_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: 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: run custom DSC resource + win_dsc: &dsc_params + resource_name: xTestResource + Path: '{{test_win_dsc_folder}}\custom-output.txt' + Ensure: Present + StringParam: string param + UInt32Param: 1000 + UInt64Param: 1000000 + StringArrayParam: + - string 1 + - string 2 + UInt32ArrayParam: + - 1000 + - 2000 + UInt64ArrayParam: + - 1000000 + - 2000000 + BooleanParam: yes + PSCredentialParam_username: username + PSCredentialParam_password: password + CimInstanceParam: + StringKey: a + BooleanKey: yes + UInt32Key: 1 + StringArrayKey: + - string 1 + - string 2 + 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 + +- name: get output of custom DSC resource + slurp: + path: '{{test_win_dsc_folder}}\custom-output.txt' + register: test_dsc_custom_output + +- name: get expected output of custom DSC resource + set_fact: + test_dsc_custom_expected: '{{lookup("file", "custom-result-normal.txt")}}' + +- name: assert result of custom DSC resource + assert: + that: + - test_dsc_custom|changed + - test_dsc_custom_output.content|b64decode|strip_newline == test_dsc_custom_expected|strip_newline + +- name: run custom DSC resource with version + win_dsc: + <<: *dsc_params + module_version: '1.0.0' + register: test_dsc_custom_version + +- name: get output of custom DSC resource with version + slurp: + path: '{{test_win_dsc_folder}}\custom-output.txt' + register: test_dsc_custom_output_version + +- name: get expected output of custom DSC resource with version + set_fact: + test_dsc_custom_expected_version: '{{lookup("file", "custom-result-versioned.txt")}}' + +- name: assert result of custom DSC resource with version + assert: + that: + - test_dsc_custom|changed + - test_dsc_custom_output_version.content|b64decode|strip_newline == test_dsc_custom_expected_version|strip_newline diff --git a/test/integration/targets/win_dsc/templates/ANSIBLE_xTestResource.psm1 b/test/integration/targets/win_dsc/templates/ANSIBLE_xTestResource.psm1 new file mode 100644 index 00000000000..59569f8ff79 --- /dev/null +++ b/test/integration/targets/win_dsc/templates/ANSIBLE_xTestResource.psm1 @@ -0,0 +1,173 @@ +#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 +} + +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 + ) + return $false +} + +Export-ModuleMember -Function *-TargetResource diff --git a/test/integration/targets/win_dsc/templates/ANSIBLE_xTestResource.schema.mof b/test/integration/targets/win_dsc/templates/ANSIBLE_xTestResource.schema.mof new file mode 100644 index 00000000000..00632f3f558 --- /dev/null +++ b/test/integration/targets/win_dsc/templates/ANSIBLE_xTestResource.schema.mof @@ -0,0 +1,25 @@ +[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[]; +}; diff --git a/test/integration/targets/win_dsc/templates/xTestDsc.psd1 b/test/integration/targets/win_dsc/templates/xTestDsc.psd1 new file mode 100644 index 00000000000..b3cdc08d57d --- /dev/null +++ b/test/integration/targets/win_dsc/templates/xTestDsc.psd1 @@ -0,0 +1,12 @@ +@{ + ModuleVersion = '{{item.version}}' + GUID = '{{item.version|to_uuid}}' + Author = 'Ansible' + CompanyName = 'Ansible' + Copyright = '(c) 2017' + Description = 'Test DSC Resource for Ansible integration tests' + PowerShellVersion = '5.0' + CLRVersion = '4.0' + FunctionsToExport = '*' + CmdletsToExport = '*' +}