From 1ce5fcf0616b525daacfab712fb34d0be8a52329 Mon Sep 17 00:00:00 2001 From: Jordan Borean Date: Thu, 9 Feb 2017 08:19:08 +1000 Subject: [PATCH] Added win_find module (#19144) --- CHANGELOG.md | 1 + lib/ansible/modules/windows/win_find.ps1 | 347 ++++++++ lib/ansible/modules/windows/win_find.py | 323 ++++++++ test/integration/targets/win_find/aliases | 1 + .../targets/win_find/defaults/main.yml | 1 + .../targets/win_find/files/set_attributes.ps1 | 9 + .../targets/win_find/files/set_filedate.ps1 | 6 + .../targets/win_find/files/set_share.ps1 | 7 + .../targets/win_find/meta/main.yml | 2 + .../targets/win_find/tasks/main.yml | 754 ++++++++++++++++++ test/integration/test_win_group2.yml | 1 + 11 files changed, 1452 insertions(+) create mode 100644 lib/ansible/modules/windows/win_find.ps1 create mode 100644 lib/ansible/modules/windows/win_find.py create mode 100644 test/integration/targets/win_find/aliases create mode 100644 test/integration/targets/win_find/defaults/main.yml create mode 100644 test/integration/targets/win_find/files/set_attributes.ps1 create mode 100644 test/integration/targets/win_find/files/set_filedate.ps1 create mode 100644 test/integration/targets/win_find/files/set_share.ps1 create mode 100644 test/integration/targets/win_find/meta/main.yml create mode 100644 test/integration/targets/win_find/tasks/main.yml diff --git a/CHANGELOG.md b/CHANGELOG.md index 874aed39af..70f4518137 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -233,6 +233,7 @@ Ansible Changes By Release - web_infrastructure * jenkins_script - windows: + * win_find * win_path * win_psexec * win_say diff --git a/lib/ansible/modules/windows/win_find.ps1 b/lib/ansible/modules/windows/win_find.ps1 new file mode 100644 index 0000000000..2e7bdb40ef --- /dev/null +++ b/lib/ansible/modules/windows/win_find.ps1 @@ -0,0 +1,347 @@ +#!powershell +# 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 + +$ErrorActionPreference = "Stop" + +$params = Parse-Args -arguments $args -supports_check_mode $true + +$paths = Get-AnsibleParam -obj $params -name 'paths' -failifempty $true + +$age = Get-AnsibleParam -obj $params -name 'age' -failifempty $false -default $null +$age_stamp = Get-AnsibleParam -obj $params -name 'age_stamp' -failifempty $false -default 'mtime' -ValidateSet 'mtime','ctime','atime' +$file_type = Get-AnsibleParam -obj $params -name 'file_type' -failifempty $false -default 'file' -ValidateSet 'file','directory' +$follow = Get-AnsibleParam -obj $params -name 'follow' -type "bool" -failifempty $false -default $false +$hidden = Get-AnsibleParam -obj $params -name 'hidden' -type "bool" -failifempty $false -default $false +$patterns = Get-AnsibleParam -obj $params -name 'patterns' -failifempty $false -default $null +$recurse = Get-AnsibleParam -obj $params -name 'recurse' -type "bool" -failifempty $false -default $false +$size = Get-AnsibleParam -obj $params -name 'size' -failifempty $false -default $null +$use_regex = Get-AnsibleParam -obj $params -name 'use_regex' -type "bool" -failifempty $false -default $false +$get_checksum = Get-AnsibleParam -obj $params -name 'get_checksum' -type "bool" -failifempty $false -default $true +$checksum_algorithm = Get-AnsibleParam -obj $params -name 'checksum_algorithm' -failifempty $false -default 'sha1' -ValidateSet 'md5', 'sha1', 'sha256', 'sha384', 'sha512' + +$result = @{ + files = @() + warnings = @() + examined = 0 + matched = 0 + changed = $false +} + +# C# code to determine link target, copied from http://chrisbensen.blogspot.com.au/2010/06/getfinalpathnamebyhandle.html +$symlink_util = @" +using System; +using System.Text; +using Microsoft.Win32.SafeHandles; +using System.ComponentModel; +using System.Runtime.InteropServices; + +namespace Ansible.Command { + public class SymLinkHelper { + private const int FILE_SHARE_WRITE = 2; + private const int CREATION_DISPOSITION_OPEN_EXISTING = 3; + private const int FILE_FLAG_BACKUP_SEMANTICS = 0x02000000; + + [DllImport("kernel32.dll", EntryPoint = "GetFinalPathNameByHandleW", CharSet = CharSet.Unicode, SetLastError = true)] + public static extern int GetFinalPathNameByHandle(IntPtr handle, [In, Out] StringBuilder path, int bufLen, int flags); + + [DllImport("kernel32.dll", EntryPoint = "CreateFileW", CharSet = CharSet.Unicode, SetLastError = true)] + public static extern SafeFileHandle CreateFile(string lpFileName, int dwDesiredAccess, + int dwShareMode, IntPtr SecurityAttributes, int dwCreationDisposition, int dwFlagsAndAttributes, IntPtr hTemplateFile); + + public static string GetSymbolicLinkTarget(System.IO.DirectoryInfo symlink) { + SafeFileHandle directoryHandle = CreateFile(symlink.FullName, 0, 2, System.IntPtr.Zero, CREATION_DISPOSITION_OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, System.IntPtr.Zero); + if(directoryHandle.IsInvalid) + throw new Win32Exception(Marshal.GetLastWin32Error()); + + StringBuilder path = new StringBuilder(512); + int size = GetFinalPathNameByHandle(directoryHandle.DangerousGetHandle(), path, path.Capacity, 0); + + if (size<0) + throw new Win32Exception(Marshal.GetLastWin32Error()); // The remarks section of GetFinalPathNameByHandle mentions the return being prefixed with "\\?\" // More information about "\\?\" here -> http://msdn.microsoft.com/en-us/library/aa365247(v=VS.85).aspx + if (path[0] == '\\' && path[1] == '\\' && path[2] == '?' && path[3] == '\\') + return path.ToString().Substring(4); + else + return path.ToString(); + } + } +} +"@ +Add-Type -TypeDefinition $symlink_util + +Function Assert-Age($info) { + $valid_match = $true + + if ($age -ne $null) { + $seconds_per_unit = @{'s'=1; 'm'=60; 'h'=3600; 'd'=86400; 'w'=604800} + $seconds_pattern = '^(-?\d+)(s|m|h|d|w)?$' + $match = $age -match $seconds_pattern + if ($match) { + [int]$specified_seconds = $matches[1] + if ($matches[2] -eq $null) { + $chosen_unit = 's' + } else { + $chosen_unit = $matches[2] + } + + $abs_seconds = $specified_seconds * ($seconds_per_unit.$chosen_unit) + $epoch = New-Object -Type DateTime -ArgumentList 1970, 1, 1, 0, 0, 0, 0 + if ($age_stamp -eq 'mtime') { + $age_comparison = $epoch.AddSeconds($info.lastwritetime) + } elseif ($age_stamp -eq 'ctime') { + $age_comparison = $epoch.AddSeconds($info.creationtime) + } elseif ($age_stamp -eq 'atime') { + $age_comparison = $epoch.AddSeconds($info.lastaccesstime) + } + + if ($specified_seconds -ge 0) { + $start_date = (Get-Date).AddSeconds($abs_seconds * -1) + if ($age_comparison -lt $start_date) { + $valid_match = $false + } + } else { + $start_date = (Get-Date).AddSeconds($abs_seconds) + if ($age_comparison -gt $start_date) { + $valid_match = $false + } + } + } else { + Fail-Json $result "failed to process age" + } + } + + $valid_match +} + +Function Assert-FileType($info) { + $valid_match = $true + + if ($file_type -eq 'directory' -and $info.isdir -eq $false) { + $valid_match = $false + } + if ($file_type -eq 'file' -and $info.isdir -eq $true) { + $valid_match = $false + } + + $valid_match +} + +Function Assert-Hidden($info) { + $valid_match = $true + + if ($hidden -eq $true -and $info.ishidden -eq $false) { + $valid_match = $false + } + if ($hidden -eq $false -and $info.ishidden -eq $true) { + $valid_match = $false + } + + $valid_match +} + +Function Assert-Pattern($info) { + $valid_match = $false + + if ($patterns -ne $null) { + foreach ($pattern in $patterns) { + if ($use_regex -eq $true) { + # Use -match for regex matching + if ($info.filename -match $pattern) { + $valid_match = $true + } + } else { + # Use -like for wildcard matching + if ($info.filename -like $pattern) { + $valid_match = $true + } + } + } + } else { + $valid_match = $true + } + + $valid_match +} + +Function Assert-Size($info) { + $valid_match = $true + + if ($size -ne $null) { + $bytes_per_unit = @{'b'=1; 'k'=1024; 'm'=1024*1024; 'g'=1024*1024*1024; 't'=1024*1024*1024*1024} + $size_pattern = '^(-?\d+)(b|k|m|g|t)?$' + $match = $size -match $size_pattern + if ($match) { + [int]$specified_size = $matches[1] + if ($matches[2] -eq $null) { + $chosen_byte = 'b' + } else { + $chosen_byte = $matches[2] + } + + $abs_size = $specified_size * ($bytes_per_unit.$chosen_byte) + if ($specified_size -ge 0) { + if ($info.size -lt $abs_size) { + $valid_match = $false + } + } else { + if ($info.size -gt $abs_size * -1) { + $valid_match = $false + } + } + } else { + Fail-Json $result "failed to process size" + } + } + + $valid_match +} + +Function Assert-FileStat($info) { + $age_match = Assert-Age -info $info + $file_type_match = Assert-FileType -info $info + $hidden_match = Assert-Hidden -info $info + $pattern_match = Assert-Pattern -info $info + $size_match = Assert-Size -info $info + + if ($age_match -and $file_type_match -and $hidden_match -and $pattern_match -and $size_match) { + $info + } else { + $false + } +} + +Function Get-FileStat($file) { + $epoch = New-Object -Type DateTime -ArgumentList 1970, 1, 1, 0, 0, 0, 0 + $access_control = $file.GetAccessControl() + $attributes = @() + foreach ($attribute in ($file.Attributes -split ',')) { + $attributes += $attribute.Trim() + } + + $file_stat = @{ + isreadonly = $attributes -contains 'ReadOnly' + ishidden = $attributes -contains 'Hidden' + isarchive = $attributes -contains 'Archive' + attributes = $file.Attributes.ToString() + owner = $access_control.Owner + lastwritetime = (New-TimeSpan -Start $epoch -End $file.LastWriteTime).TotalSeconds + creationtime = (New-TimeSpan -Start $epoch -End $file.CreationTime).TotalSeconds + lastaccesstime = (New-TimeSpan -Start $epoch -End $file.LastAccessTime).TotalSeconds + path = $file.FullName + filename = $file.Name + } + + $islink = $false + $isdir = $false + $isshared = $false + + if ($attributes -contains 'ReparsePoint') { + # TODO: Find a way to differenciate between soft and junction links + $islink = $true + $isdir = $true + + # Try and get the symlink source, can result in failure if link is broken + try { + $lnk_source = [Ansible.Command.SymLinkHelper]::GetSymbolicLinkTarget($file) + $file_stat.lnk_source = $lnk_source + } catch {} + } elseif ($file.PSIsContainer) { + $isdir = $true + + $share_info = Get-WmiObject -Class Win32_Share -Filter "Path='$($file.Fullname -replace '\\', '\\')'" + if ($share_info -ne $null) { + $isshared = $true + $file_stat.sharename = $share_info.Name + } + + #$dir_files_sum = Get-ChildItem $file.FullName -Recurse | Measure-Object -property length -sum + $dir_files_sum = Get-ChildItem $file.FullName -Recurse + + if ($dir_files_sum -eq $null -or ($dir_files_sum.PSObject.Properties.name -contains 'length' -eq $false)) { + $file_stat.size = 0 + } else { + $file_stat.size = ($dir_files_sum | Measure-Object -property length -sum).Sum + } + } else { + $file_stat.size = $file.length + $file_stat.extension = $file.Extension + + if ($get_checksum) { + $checksum = Get-FileChecksum -path $path -algorithm $checksum_algorithm + $file_stat.checksum = $checksum + } + } + + $file_stat.islink = $islink + $file_stat.isdir = $isdir + $file_stat.isshared = $isshared + + Assert-FileStat -info $file_stat +} + +Function Get-FilesInFolder($path) { + $items = @() + foreach ($item in (Get-ChildItem -Force -Path $path -ErrorAction SilentlyContinue)) { + if ($item.PSIsContainer -and $recurse) { + if (($item.Attributes -like '*ReparsePoint*' -and $follow) -or ($item.Attributes -notlike '*ReparsePoint*')) { + # File is a link and we want to follow a link OR file is not a link + $items += $item.FullName + $items += Get-FilesInFolder -path $item.FullName + } else { + # File is a link but we don't want to follow a link + $items += $item.FullName + } + } else { + $items += $item.FullName + } + } + + $items +} + +$paths_to_check = @() +foreach ($path in $paths) { + if (Test-Path $path) { + if ((Get-Item -Force $path).PSIsContainer) { + $paths_to_check += Get-FilesInFolder -path $path + } else { + Fail-Json $result "Argument path $path is a file not a directory" + } + } else { + Fail-Json $result "Argument path $path does not exist cannot get information on" + } +} +$paths_to_check = $paths_to_check | Select -Unique + +foreach ($path in $paths_to_check) { + $file = Get-Item -Force -Path $path + $info = Get-FileStat -file $file + $new_examined = $result.examined + 1 + $result.examined = $new_examined + + if ($info -ne $false) { + $files = $result.Files + $files += $info + + $new_matched = $result.matched + 1 + $result.matched = $new_matched + $result.files = $files + } +} + +Exit-Json $result diff --git a/lib/ansible/modules/windows/win_find.py b/lib/ansible/modules/windows/win_find.py new file mode 100644 index 0000000000..194621c730 --- /dev/null +++ b/lib/ansible/modules/windows/win_find.py @@ -0,0 +1,323 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# (c) 2016, Ansible, inc +# +# 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 . +# + +ANSIBLE_METADATA = {'status': ['preview'], + 'supported_by': 'community', + 'version': '1.0'} + +DOCUMENTATION = r''' +--- +module: win_find +version_added: "2.3" +short_description: return a list of files based on specific criteria +description: + - Return a list of files based on specified criteria. + - Multiple criteria are AND'd together. +options: + age: + description: + - Select files or folders whose age is equal to or greater than + the specified tim. Use a negative age to find files equal to or + less than the specified time. You can choose seconds, minues, + hours, days or weeks by specifying the first letter of an of + those words (e.g., "1w"). + required: false + age_stamp: + description: + - Choose the file property against which we compare C(age). The + default attribute we compare with is last modification time. + required: false + default: mtime + choices: ['atime', 'mtime', 'ctime'] + checksum_algorithm: + description: + - Algorithm to determine the checksum of a file. Will throw an error + if the host is unable to use specified algorithm. + required: false + default: sha1 + choices: ['md5', 'sha1', 'sha256', 'sha384', 'sha512'] + file_type: + description: Type of file to search for + required: false + default: file + choices: ['file', 'directory'] + follow: + description: + - Set this to true to follow symlinks in the path. This needs to + be used in conjunction with C(recurse). + required: false + default: false + choices: ['true', 'false'] + get_checksum: + description: + - Whether to return a checksum of the file in the return info (default sha1), + use C(checksum_algorithm) to change from the default. + required: false + default: true + choices: ['true', 'false'] + hidden: + description: Set this to include hidden files or folders + required: false + default: false + choices: ['true', 'false'] + paths: + description: + - List of paths of directories to search for files or folders in. + This can be supplied as a single path or a list of paths. + required: true + patterns: + description: + - One or more (powershell or regex) patterns to compare filenames + with. The type of pattern matching is controlled by C(use_regex) + option. The patterns retrict the list of files or folders to be + returned based on the filenames. For a file to be matched it + only has to match with one pattern in a list provided. + required: false + recurse: + description: + - Will recursively descend into the directory looking for files + or folders + required: false + default: false + choices: ['true', 'false'] + size: + description: + - Select files or folders whose size is equal to or greater than + the specified size. Use a negative value to find files equal to + or less than the specified size. You can specify the size with + a suffix of the byte type i.e. kilo = k, mega = m... Size is not + evaluated for symbolic links. + required: false + default: false + use_regex: + description: + - Will set patterns to run as a regex check if true + required: false + default: false + choices: ['true', 'false'] +author: "Jordan Borean (@jborean93)" +''' + +EXAMPLES = r''' +# Find files in path +- win_find: + paths: D:\temp + +# Find hidden files in path +- win_find: + paths: D:\temp + hidden: True + +# Find files in multiple paths +- win_find: + paths: ['C:\temp', 'D:\temp'] + +# Find files in directory while searching recursively +- win_find: + paths: D:\temp + recurse: True + +# Find files in directory while following symlinks +- win_find: + paths: D:\temp + recurse: True + follow: True + +# Find files with .log and .out extension using powershell wildcards +- win_find: + paths: D:\temp + patterns: ['*.log', '*.out'] + +# Find files in path based on regex pattern +- win_find: + paths: D:\temp + patterns: "out_\d{8}-\d{6}.log" + +# Find files older than 1 day +- win_find: + paths: D:\temp + age: 86400 + +# Find files older than 1 day based on create time +- win_find: + paths: D:\temp + age: 86400 + age_stamp: ctime + +# Find files older than 1 day with unit syntax +- win_find: + paths: D:\temp + age: 1d + +# Find files newer than 1 hour +- win_find: + paths: D:\temp + age: -3600 + +# Find files newer than 1 hour with unit syntax +- win_find: + paths: D:\temp + age: -1h + +# Find files larger than 1MB +- win_find: + paths: D:\temp + size: 1048576 + +# Find files larger than 1GB with unit syntax +- win_find: + paths: D:\temp + size: 1g + +# Find files smaller than 1MB +- win_find: + paths: D:\temp + size: -1048576 + +# Find files smaller than 1GB with unit syntax +- win_find: + paths: D:\temp + size: -1g + +# Find folders/symlinks in multiple paths +- win_find: + paths: ['C:\temp', 'D:\temp'] + file_type: directory + +# Find files and return SHA256 checksum of files found +- win_find: + paths: C:\temp + get_checksum: True + checksum_algorithm: sha256 + +# Find files and do not return the checksum +- win_find: + path: C:\temp + get_checksum: False +''' + +RETURN = r''' +changed: + description: Whether anything was chagned + returned: always + type: boolean + sample: True +examined: + description: The number of files/folders that was checked + returned: always + type: int + sample: 10 +matched: + description: The number of files/folders that match the criteria + returns: always + type: int + sample: 2 +files: + description: Information on the files/folders that match the criteria returned as a list of dictionary elements for each file matched + returned: success + type: dictionary + contains: + attributes: + description: attributes of the file at path in raw form + returned: success, path exists + type: string + sample: "Archive, Hidden" + checksum: + description: The checksum of a file based on checksum_algorithm specified + returned: success, path exists, path is a file, get_checksum == True + type: string + sample: 09cb79e8fc7453c84a07f644e441fd81623b7f98 + creationtime: + description: the create time of the file represented in seconds since epoch + returned: success, path exists + type: float + sample: 1477984205.15 + extension: + description: the extension of the file at path + returned: success, path exists, path is a file + type: string + sample: ".ps1" + isarchive: + description: if the path is ready for archiving or not + returned: success, path exists + type: boolean + sample: True + isdir: + description: if the path is a directory or not + returned: success, path exists + type: boolean + sample: True + ishidden: + description: if the path is hidden or not + returned: success, path exists + type: boolean + sample: True + islink: + description: if the path is a symbolic link or junction or not + returned: success, path exists + type: boolean + sample: True + isreadonly: + description: if the path is read only or not + returned: success, path exists + type: boolean + sample: True + isshared: + description: if the path is shared or not + returned: success, path exists + type: boolean + sample: True + lastaccesstime: + description: the last access time of the file represented in seconds since epoch + returned: success, path exists + type: float + sample: 1477984205.15 + lastwritetime: + description: the last modification time of the file represented in seconds since epoch + returned: success, path exists + type: float + sample: 1477984205.15 + lnk_source: + description: the target of the symbolic link, will return null if not a link or the link is broken + return: success, path exists, path is a symbolic link + type: string + sample: C:\temp + owner: + description: the owner of the file + returned: success, path exists + type: string + sample: BUILTIN\Administrators + path: + description: the full absolute path to the file + returned: success, path exists + type: string + sample: BUILTIN\Administrators + sharename: + description: the name of share if folder is shared + returned: success, path exists, path is a directory and isshared == True + type: string + sample: file-share + size: + description: the size in bytes of a file or folder + returned: success, path exists, path is not a link + type: int + sample: 1024 +''' diff --git a/test/integration/targets/win_find/aliases b/test/integration/targets/win_find/aliases new file mode 100644 index 0000000000..4a25390297 --- /dev/null +++ b/test/integration/targets/win_find/aliases @@ -0,0 +1 @@ +windows/ci/group/2 diff --git a/test/integration/targets/win_find/defaults/main.yml b/test/integration/targets/win_find/defaults/main.yml new file mode 100644 index 0000000000..d3d03f767f --- /dev/null +++ b/test/integration/targets/win_find/defaults/main.yml @@ -0,0 +1 @@ +win_find_dir: "{{win_output_dir}}\\win_find" diff --git a/test/integration/targets/win_find/files/set_attributes.ps1 b/test/integration/targets/win_find/files/set_attributes.ps1 new file mode 100644 index 0000000000..b57a368c43 --- /dev/null +++ b/test/integration/targets/win_find/files/set_attributes.ps1 @@ -0,0 +1,9 @@ +$path = $args[0] +$attr = $args[1] +$item = Get-Item "$path" + +$attributes = $item.Attributes -split ',' +If ($attributes -notcontains $attr) { + $attributes += $attr +} +$item.Attributes = $attributes -join ',' diff --git a/test/integration/targets/win_find/files/set_filedate.ps1 b/test/integration/targets/win_find/files/set_filedate.ps1 new file mode 100644 index 0000000000..3bc525a4ff --- /dev/null +++ b/test/integration/targets/win_find/files/set_filedate.ps1 @@ -0,0 +1,6 @@ +$date = Get-Date -Year 2016 -Month 11 -Day 1 -Hour 7 -Minute 10 -Second 5 -Millisecond 0 + +$item = Get-Item -Path "$($args[0])" +$item.CreationTime = $date +$item.LastAccessTime = $date +$item.LastWriteTime = $date diff --git a/test/integration/targets/win_find/files/set_share.ps1 b/test/integration/targets/win_find/files/set_share.ps1 new file mode 100644 index 0000000000..c56242cf40 --- /dev/null +++ b/test/integration/targets/win_find/files/set_share.ps1 @@ -0,0 +1,7 @@ +$share_name = $args[1] +$share_stat = Get-WmiObject -Class Win32_Share -Filter "name='$share_name'" +If ($share_stat) { + $share_stat.Delete() +} +$wmi = [wmiClass] 'Win32_Share' +$wmi.Create($args[0], $share_name, 0) diff --git a/test/integration/targets/win_find/meta/main.yml b/test/integration/targets/win_find/meta/main.yml new file mode 100644 index 0000000000..d328716dfa --- /dev/null +++ b/test/integration/targets/win_find/meta/main.yml @@ -0,0 +1,2 @@ +dependencies: + - prepare_win_tests diff --git a/test/integration/targets/win_find/tasks/main.yml b/test/integration/targets/win_find/tasks/main.yml new file mode 100644 index 0000000000..af6b2b7828 --- /dev/null +++ b/test/integration/targets/win_find/tasks/main.yml @@ -0,0 +1,754 @@ +--- +- name: remove links if they exist as win_file struggles + win_command: cmd.exe /c rmdir "{{item}}" + ignore_errors: True + with_items: + - "{{win_find_dir}}\\nested\\link" + - "{{win_find_dir}}\\broken-link" + - "{{win_find_dir}}\\hard-link-dest\\hard-link.log" + - "{{win_find_dir}}\\junction-link" + +- name: ensure the testing directory is cleared before setting up test + win_file: + path: "{{win_find_dir}}" + state: absent + +- name: ensure testing directories exist + win_file: + path: "{{item}}" + state: directory + with_items: + - "{{win_find_dir}}\\nested" + - "{{win_find_dir}}\\single" + - "{{win_find_dir}}\\link-dest" + - "{{win_find_dir}}\\link-dest\\sub-link" + - "{{win_find_dir}}\\hard-link-dest" + - "{{win_find_dir}}\\junction-link-dest" + - "{{win_find_dir}}\\broken-link-dest" + - "{{win_find_dir}}\\nested\\sub-nest" + - "{{win_find_dir}}\\shared" + - "{{win_find_dir}}\\shared\\folder" + - "{{win_find_dir}}\\hidden" + - "{{win_find_dir}}\\date" + +- name: create empty test files + win_file: + path: "{{item}}" + state: touch + with_items: + - "{{win_find_dir}}\\nested\\file.ps1" + - "{{win_find_dir}}\\nested\\test.ps1" + - "{{win_find_dir}}\\nested\\out.log" + - "{{win_find_dir}}\\nested\\archive.log" + - "{{win_find_dir}}\\nested\\sub-nest\\test.ps1" + - "{{win_find_dir}}\\nested\\sub-nest\\readonly.txt" + - "{{win_find_dir}}\\link-dest\\link.ps1" + - "{{win_find_dir}}\\single\\large.ps1" + - "{{win_find_dir}}\\single\\small.ps1" + - "{{win_find_dir}}\\single\\test.ps1" + - "{{win_find_dir}}\\single\\hidden.ps1" + - "{{win_find_dir}}\\date\\new.ps1" + - "{{win_find_dir}}\\date\\old.ps1" + - "{{win_find_dir}}\\single\\out_20161101-091005.log" + - "{{win_find_dir}}\\hidden\\out_20161101-091005.log" + - "{{win_find_dir}}\\hard-link-dest\\file-abc.log" + +- name: populate files with a test string + win_lineinfile: + dest: "{{item.path}}" + line: "{{item.text}}" + with_items: + - { 'path': "{{win_find_dir}}\\nested\\file.ps1", 'text': 'abcdefg1234567' } + - { 'path': "{{win_find_dir}}\\nested\\test.ps1", 'text': 'abcdefg1234567' } + - { 'path': "{{win_find_dir}}\\nested\\out.log", 'text': 'abcdefg1234567' } + - { 'path': "{{win_find_dir}}\\nested\\archive.log", 'text': 'abcdefg1234567' } + - { 'path': "{{win_find_dir}}\\nested\\sub-nest\\test.ps1", 'text': 'abcdefg1234567' } + - { 'path': "{{win_find_dir}}\\nested\\sub-nest\\readonly.txt", 'text': 'abcdefg1234567' } + - { 'path': "{{win_find_dir}}\\link-dest\\link.ps1", 'text': 'abcdefg1234567' } + - { 'path': "{{win_find_dir}}\\single\\test.ps1", 'text': 'abcdefg1234567' } + - { 'path': "{{win_find_dir}}\\single\\hidden.ps1", 'text': 'abcdefg1234567' } + - { 'path': "{{win_find_dir}}\\date\\new.ps1", 'text': 'abcdefg1234567' } + - { 'path': "{{win_find_dir}}\\date\\old.ps1", 'text': 'abcdefg1234567' } + - { 'path': "{{win_find_dir}}\\single\\out_20161101-091005.log", 'text': 'abcdefg1234567' } + - { 'path': "{{win_find_dir}}\\hidden\\out_20161101-091005.log", 'text': 'abcdefg1234567' } + - { 'path': "{{win_find_dir}}\\hard-link-dest\\file-abc.log", 'text': 'abcdefg1234567' } + - { 'path': "{{win_find_dir}}\\single\\small.ps1", 'text': "a" } + - { 'path': "{{win_find_dir}}\\date\\new.ps1", 'text': "random text for new date" } + - { 'path': "{{win_find_dir}}\\date\\old.ps1", 'text': "random text for old date" } + +- name: populate large text file + win_command: powershell "Set-Content {{win_find_dir}}\\single\\large.ps1 ('abcdefghijklmnopqrstuvwxyz' * 10000)" + +- name: create share + script: set_share.ps1 "{{win_find_dir}}\shared\folder" "folder-share" + +- name: create links + win_command: cmd.exe /c mklink /{{item.type}} "{{item.source}}" "{{item.target}}" + with_items: + - { type: 'D', source: "{{win_find_dir}}\\nested\\link", target: "{{win_find_dir}}\\link-dest" } + - { type: 'D', source: "{{win_find_dir}}\\broken-link", target: "{{win_find_dir}}\\broken-link-dest" } + - { type: 'H', source: "{{win_find_dir}}\\hard-link-dest\\hard-link.log", target: "{{win_find_dir}}\\hard-link-dest\\file-abc.log" } + - { type: 'J', source: "{{win_find_dir}}\\junction-link", target: "{{win_find_dir}}\\junction-link-dest" } + +- name: set modification date on files/folders + script: set_filedate.ps1 "{{item}}" + with_items: + - "{{win_find_dir}}\\nested\\file.ps1" + - "{{win_find_dir}}\\nested\\test.ps1" + - "{{win_find_dir}}\\nested\\out.log" + - "{{win_find_dir}}\\nested\\archive.log" + - "{{win_find_dir}}\\nested\\sub-nest\\test.ps1" + - "{{win_find_dir}}\\nested\\sub-nest\\readonly.txt" + - "{{win_find_dir}}\\link-dest\\link.ps1" + - "{{win_find_dir}}\\single\\large.ps1" + - "{{win_find_dir}}\\single\\small.ps1" + - "{{win_find_dir}}\\single\\test.ps1" + - "{{win_find_dir}}\\single\\hidden.ps1" + - "{{win_find_dir}}\\date\\old.ps1" + - "{{win_find_dir}}\\single\\out_20161101-091005.log" + - "{{win_find_dir}}\\hidden\\out_20161101-091005.log" + - "{{win_find_dir}}\\hard-link-dest\\file-abc.log" + - "{{win_find_dir}}\\nested" + - "{{win_find_dir}}\\single" + - "{{win_find_dir}}\\link-dest" + - "{{win_find_dir}}\\link-dest\\sub-link" + - "{{win_find_dir}}\\hard-link-dest" + - "{{win_find_dir}}\\junction-link-dest" + - "{{win_find_dir}}\\broken-link-dest" + - "{{win_find_dir}}\\nested\\sub-nest" + - "{{win_find_dir}}\\shared" + - "{{win_find_dir}}\\shared\\folder" + - "{{win_find_dir}}\\hidden" + - "{{win_find_dir}}\\date" + +- name: set file attributes for test + script: set_attributes.ps1 "{{item.path}}" {{item.attr}} + with_items: + - { 'path': "{{win_find_dir}}\\hidden", 'attr': "Hidden" } + - { 'path': "{{win_find_dir}}\\date", 'attr': "Hidden" } + - { 'path': "{{win_find_dir}}\\nested\\archive.log", 'attr': "Archive" } + - { 'path': "{{win_find_dir}}\\nested\\sub-nest\\readonly.txt", 'attr': "ReadOnly" } + - { 'path': "{{win_find_dir}}\\single\\hidden.ps1", 'attr': "Hidden" } + +- name: break the broken link target + win_file: + path: "{{win_find_dir}}\\broken-link-dest" + state: absent +# end test setup + +- name: expect failure when not setting paths + win_find: + patterns: a + register: actual + failed_when: "actual.msg != 'Missing required argument: paths'" + +- name: expect failure when setting paths to a file + win_find: + paths: "{{win_output_dir}}\\win_find\\single\\large.ps1" + register: actual + failed_when: "actual.msg != 'Argument path {{win_output_dir|regex_replace('\\\\', '\\\\\\\\')}}\\win_find\\single\\large.ps1 is a file not a directory'" + +- name: expect failure whe path is set to a non existant folder + win_find: + paths: "{{win_output_dir}}\\win_find\\thisisafakefolder" + register: actual + failed_when: "actual.msg != 'Argument path {{win_output_dir|regex_replace('\\\\', '\\\\\\\\')}}\\\\win_find\\\\thisisafakefolder does not exist cannot get information on'" + +- name: get files in single directory + win_find: + paths: "{{win_output_dir}}\\win_find\\single" + register: actual + +- name: set expected value for files in a single directory + set_fact: + expected: + changed: False + examined: 5 + files: + - { isarchive: True, + attributes: Archive, + checksum: f8d100cdcf0e6c1007db2f8dd0b7ee2884df89af, + creationtime: 1477984205, + extension: .ps1, + filename: large.ps1, + ishidden: False, + isdir: False, + islink: False, + lastaccesstime: 1477984205, + lastwritetime: 1477984205, + owner: BUILTIN\Administrators, + path: "{{win_find_dir}}\\single\\large.ps1", + isreadonly: False, + isshared: False, + size: 260002 } + - { isarchive: True, + attributes: Archive, + checksum: 8df33cee3325596517df5bb5aa980cf9c5c1fda3, + creationtime: 1477984205, + extension: .log, + filename: out_20161101-091005.log, + ishidden: False, + isdir: False, + islink: False, + lastaccesstime: 1477984205, + lastwritetime: 1477984205, + owner: BUILTIN\Administrators, + path: "{{win_find_dir}}\\single\\out_20161101-091005.log", + isreadonly: False, + isshared: False, + size: 14 } + - { isarchive: True, + attributes: Archive, + checksum: 86f7e437faa5a7fce15d1ddcb9eaeaea377667b8, + creationtime: 1477984205, + extension: .ps1, + filename: small.ps1, + ishidden: False, + isdir: False, + islink: False, + lastaccesstime: 1477984205, + lastwritetime: 1477984205, + owner: BUILTIN\Administrators, + path: "{{win_find_dir}}\\single\\small.ps1", + isreadonly: False, + isshared: False, + size: 1 } + - { isarchive: True, + attributes: Archive, + checksum: 8df33cee3325596517df5bb5aa980cf9c5c1fda3, + creationtime: 1477984205, + extension: .ps1, + filename: test.ps1, + ishidden: False, + isdir: False, + islink: False, + lastaccesstime: 1477984205, + lastwritetime: 1477984205, + owner: BUILTIN\Administrators, + path: "{{win_find_dir}}\\single\\test.ps1", + isreadonly: False, + isshared: False, + size: 14 } + matched: 4 + +- name: assert actual == expected + assert: + that: "actual == expected" + +- name: find hidden files + win_find: + paths: ['{{win_find_dir}}\\single', '{{win_find_dir}}\\nested'] + hidden: True + register: actual + +- name: set fact for hidden files + set_fact: + expected: + changed: False + examined: 11 + files: + - { isarchive: True, + attributes: "Hidden, Archive", + checksum: 8df33cee3325596517df5bb5aa980cf9c5c1fda3, + creationtime: 1477984205, + extension: .ps1, + filename: hidden.ps1, + ishidden: True, + isdir: False, + islink: False, + lastaccesstime: 1477984205, + lastwritetime: 1477984205, + owner: BUILTIN\Administrators, + path: "{{win_find_dir}}\\single\\hidden.ps1", + isreadonly: False, + isshared: False, + size: 14 } + matched: 1 + +- name: assert actual == expected + assert: + that: "actual == expected" + +- name: find file based on pattern + win_find: + paths: '{{win_find_dir}}\\single' + patterns: ['*.log', 'out_*'] + register: actual_pattern + +- name: find file based on pattern regex + win_find: + paths: '{{win_find_dir}}\\single' + patterns: "out_\\d{8}-\\d{6}.log" + use_regex: True + register: actual_regex + +- name: set fact for pattern files + set_fact: + expected: + changed: False + examined: 5 + files: + - { isarchive: True, + attributes: Archive, + checksum: 8df33cee3325596517df5bb5aa980cf9c5c1fda3, + creationtime: 1477984205, + extension: .log, + filename: out_20161101-091005.log, + ishidden: False, + isdir: False, + islink: False, + lastaccesstime: 1477984205, + lastwritetime: 1477984205, + owner: BUILTIN\Administrators, + path: "{{win_find_dir}}\\single\\out_20161101-091005.log", + isreadonly: False, + isshared: False, + size: 14 } + matched: 1 + +- name: assert actual == expected + assert: + that: + - "actual_pattern == expected" + - "actual_regex == expected" + +- name: find files with recurse set + win_find: + paths: "{{win_find_dir}}\\nested" + recurse: True + patterns: "*.ps1" + register: actual + +- name: set expected value for files in a nested directory + set_fact: + expected: + changed: False + examined: 8 + files: + - { isarchive: True, + attributes: Archive, + checksum: 8df33cee3325596517df5bb5aa980cf9c5c1fda3, + creationtime: 1477984205, + extension: .ps1, + filename: test.ps1, + ishidden: False, + isdir: False, + islink: False, + lastaccesstime: 1477984205, + lastwritetime: 1477984205, + owner: BUILTIN\Administrators, + path: "{{win_find_dir}}\\nested\\sub-nest\\test.ps1", + isreadonly: False, + isshared: False, + size: 14 } + - { isarchive: True, + attributes: Archive, + checksum: 8df33cee3325596517df5bb5aa980cf9c5c1fda3, + creationtime: 1477984205, + extension: .ps1, + filename: file.ps1, + ishidden: False, + isdir: False, + islink: False, + lastaccesstime: 1477984205, + lastwritetime: 1477984205, + owner: BUILTIN\Administrators, + path: "{{win_find_dir}}\\nested\\file.ps1", + isreadonly: False, + isshared: False, + size: 14 } + - { isarchive: True, + attributes: Archive, + checksum: 8df33cee3325596517df5bb5aa980cf9c5c1fda3, + creationtime: 1477984205, + extension: .ps1, + filename: test.ps1, + ishidden: False, + isdir: False, + islink: False, + lastaccesstime: 1477984205, + lastwritetime: 1477984205, + owner: BUILTIN\Administrators, + path: "{{win_find_dir}}\\nested\\test.ps1", + isreadonly: False, + isshared: False, + size: 14 } + matched: 3 + +- name: assert actual == expected + assert: + that: "actual == expected" + +- name: find files with recurse set and follow links + win_find: + paths: "{{win_find_dir}}\\nested" + recurse: True + follow: True + patterns: "*.ps1" + register: actual + +- name: set expected value for files in a nested directory while following links + set_fact: + expected: + changed: False + examined: 10 + files: + - { isarchive: True, + attributes: Archive, + checksum: 8df33cee3325596517df5bb5aa980cf9c5c1fda3, + creationtime: 1477984205, + extension: .ps1, + filename: link.ps1, + ishidden: False, + isdir: False, + islink: False, + lastaccesstime: 1477984205, + lastwritetime: 1477984205, + owner: BUILTIN\Administrators, + path: "{{win_find_dir}}\\nested\\link\\link.ps1", + isreadonly: False, + isshared: False, + size: 14 } + - { isarchive: True, + attributes: Archive, + checksum: 8df33cee3325596517df5bb5aa980cf9c5c1fda3, + creationtime: 1477984205, + extension: .ps1, + filename: test.ps1, + ishidden: False, + isdir: False, + islink: False, + lastaccesstime: 1477984205, + lastwritetime: 1477984205, + owner: BUILTIN\Administrators, + path: "{{win_find_dir}}\\nested\\sub-nest\\test.ps1", + isreadonly: False, + isshared: False, + size: 14 } + - { isarchive: True, + attributes: Archive, + checksum: 8df33cee3325596517df5bb5aa980cf9c5c1fda3, + creationtime: 1477984205, + extension: .ps1, + filename: file.ps1, + ishidden: False, + isdir: False, + islink: False, + lastaccesstime: 1477984205, + lastwritetime: 1477984205, + owner: BUILTIN\Administrators, + path: "{{win_find_dir}}\\nested\\file.ps1", + isreadonly: False, + isshared: False, + size: 14 } + - { isarchive: True, + attributes: Archive, + checksum: 8df33cee3325596517df5bb5aa980cf9c5c1fda3, + creationtime: 1477984205, + extension: .ps1, + filename: test.ps1, + ishidden: False, + isdir: False, + islink: False, + lastaccesstime: 1477984205, + lastwritetime: 1477984205, + owner: BUILTIN\Administrators, + path: "{{win_find_dir}}\\nested\\test.ps1", + isreadonly: False, + isshared: False, + size: 14 } + matched: 4 + +- name: assert actual == expected + assert: + that: "actual == expected" + +- name: find directories + win_find: + paths: "{{win_find_dir}}\\link-dest" + file_type: directory + register: actual + +- name: set expected fact for directories with recurse and follow + set_fact: + expected: + changed: False + examined: 2 + files: + - { isarchive: False, + attributes: Directory, + creationtime: 1477984205, + filename: sub-link, + ishidden: False, + isdir: True, + islink: False, + lastaccesstime: 1477984205, + lastwritetime: 1477984205, + owner: BUILTIN\Administrators, + path: "{{win_find_dir}}\\link-dest\\sub-link", + isreadonly: False, + isshared: False, + size: 0 } + matched: 1 + +- name: assert actual == expected + assert: + that: "actual == expected" + +- name: find directories recurse and follow with a broken link + win_find: + paths: "{{win_find_dir}}" + file_type: directory + recurse: True + follow: True + register: actual + +- name: check directory count with recurse and follow is correct + assert: + that: + - "actual.examined == 33" + - "actual.matched == 13" + - "actual.files[0].filename == 'broken-link'" + - "actual.files[0].islink == True" + - "actual.files[2].filename == 'junction-link'" + - "actual.files[2].islink == True" + - "actual.files[2].lnk_source == '{{win_find_dir|regex_replace('\\\\', '\\\\\\\\')}}\\\\junction-link-dest'" + - "actual.files[7].filename == 'link'" + - "actual.files[7].islink == True" + - "actual.files[7].lnk_source == '{{win_find_dir|regex_replace('\\\\', '\\\\\\\\')}}\\\\link-dest'" + - "actual.files[11].filename == 'folder'" + - "actual.files[11].islink == False" + - "actual.files[11].isshared == True" + - "actual.files[11].sharename == 'folder-share'" + +- name: filter files by size without byte specified + win_find: + paths: "{{win_find_dir}}\\single" + size: 260002 + register: actual_without_byte + +- name: filter files by size with byte specified + win_find: + paths: "{{win_find_dir}}\\single" + size: 253k + register: actual_with_byte + +- name: set expected fact for files by size + set_fact: + expected: + changed: False + examined: 5 + files: + - { isarchive: True, + attributes: Archive, + checksum: f8d100cdcf0e6c1007db2f8dd0b7ee2884df89af, + creationtime: 1477984205, + extension: ".ps1", + filename: large.ps1, + ishidden: False, + isdir: False, + islink: False, + lastaccesstime: 1477984205, + lastwritetime: 1477984205, + owner: BUILTIN\Administrators, + path: "{{win_find_dir}}\\single\\large.ps1", + isreadonly: False, + isshared: False, + size: 260002 } + matched: 1 + +- name: assert actual == expected + assert: + that: + - "actual_without_byte == expected" + - "actual_with_byte == expected" + +- name: filter files by size (less than) without byte specified + win_find: + paths: "{{win_find_dir}}\\single" + size: -4 + register: actual_without_byte + +- name: filter files by size (less than) with byte specified + win_find: + paths: "{{win_find_dir}}\\single" + size: -4b + register: actual_with_byte + +- name: set expected fact for files by size (less than) + set_fact: + expected: + changed: False + examined: 5 + files: + - { isarchive: True, + attributes: Archive, + checksum: 86f7e437faa5a7fce15d1ddcb9eaeaea377667b8, + creationtime: 1477984205, + extension: ".ps1", + filename: small.ps1, + ishidden: False, + isdir: False, + islink: False, + lastaccesstime: 1477984205, + lastwritetime: 1477984205, + owner: BUILTIN\Administrators, + path: "{{win_find_dir}}\\single\\small.ps1", + isreadonly: False, + isshared: False, + size: 1 } + matched: 1 + +- name: assert actual == expected + assert: + that: + - "actual_without_byte == expected" + - "actual_with_byte == expected" + +# For dates we cannot assert against expected as the times change, this is a poor mans attempt at testing +- name: filter files by age without unit specified + win_find: + paths: "{{win_find_dir}}\\date" + age: 3600 + register: actual_without_unit + +- name: filter files by age with unit specified + win_find: + paths: "{{win_find_dir}}\\date" + age: 1h + register: actual_with_unit + +- name: assert dates match each other + assert: + that: + - "actual_without_unit == actual_with_unit" + - "actual_without_unit.matched == 1" + - "actual_without_unit.files[0].checksum == '7454f04e3ac587f711a416f4edf26507255e0a2e'" + - "actual_without_unit.files[0].path == '{{win_find_dir|regex_replace('\\\\', '\\\\\\\\')}}\\\\date\\\\new.ps1'" + +- name: filter files by age (older than) without unit specified + win_find: + paths: "{{win_find_dir}}\\date" + age: -1 + register: actual_without_unit + +- name: filter files by age (older than) without unit specified + win_find: + paths: "{{win_find_dir}}\\date" + age: -1s + register: actual_with_unit + +- name: assert dates match each other + assert: + that: + - "actual_without_unit == actual_with_unit" + - "actual_without_unit.matched == 2" + - "actual_without_unit.files[0].checksum == '7454f04e3ac587f711a416f4edf26507255e0a2e'" + - "actual_without_unit.files[0].path == '{{win_find_dir|regex_replace('\\\\', '\\\\\\\\')}}\\\\date\\\\new.ps1'" + - "actual_without_unit.files[1].checksum == '031a04ecc76f794d7842651de732075dec6fef04'" + - "actual_without_unit.files[1].path == '{{win_find_dir|regex_replace('\\\\', '\\\\\\\\')}}\\\\date\\\\old.ps1'" + +- name: get list of files with md5 checksum + win_find: + paths: "{{win_find_dir}}\\single" + patterns: test.ps1 + checksum_algorithm: md5 + register: actual_md5_checksum + +- name: assert md5 checksum value + assert: + that: + - "actual_md5_checksum.files[0].checksum == 'd1713d0f1d2e8fae230328d8fd59de01'" + +- name: get list of files with sha1 checksum + win_find: + paths: "{{win_find_dir}}\\single" + patterns: test.ps1 + checksum_algorithm: sha1 + register: actual_sha1_checksum + +- name: assert sha1 checksum value + assert: + that: + - "actual_sha1_checksum.files[0].checksum == '8df33cee3325596517df5bb5aa980cf9c5c1fda3'" + +- name: get list of files with sha256 checksum + win_find: + paths: "{{win_find_dir}}\\single" + patterns: test.ps1 + checksum_algorithm: sha256 + register: actual_sha256_checksum + +- name: assert sha256 checksum value + assert: + that: + - "actual_sha256_checksum.files[0].checksum == 'c20d2eba7ffda0079812721b6f4e4e109e2f0c5e8cc3d1273a060df6f7d9f339'" + +- name: get list of files with sha384 checksum + win_find: + paths: "{{win_find_dir}}\\single" + patterns: test.ps1 + checksum_algorithm: sha384 + register: actual_sha384_checksum + +- name: assert sha384 checksum value + assert: + that: + - "actual_sha384_checksum.files[0].checksum == 'aed515eb216b9c7009ae8c4680f46c1e22004528b231aa0482a8587543bca47d3504e9f77e884eb2d11b2f9f5dc01651'" + +- name: get list of files with sha512 checksum + win_find: + paths: "{{win_find_dir}}\\single" + patterns: test.ps1 + checksum_algorithm: sha512 + register: actual_sha512_checksum + +- name: assert sha512 checksum value + assert: + that: + - "actual_sha512_checksum.files[0].checksum == '05abf64a68c4731699c23b4fc6894a36646fce525f3c96f9cf743b5d0c3bfd933dad0e95e449e3afe1f74d534d69a53b8f46cf835763dd42915813c897b02b87'" + +- name: get list of files without checksum + win_find: + paths: "{{win_find_dir}}\\single" + patterns: test.ps1 + get_checksum: False + register: actual_no_checksum + +- name: assert no checksum is returned + assert: + that: + - "actual_no_checksum.files[0].checksum is undefined" + +- name: check if broken symbolic link exists + win_stat: + path: "{{win_find_dir}}\\broken-link" + register: broken_link_exists + +- name: delete broken symbolic link if it exists + win_command: cmd.exe /c rmdir {{win_find_dir}}\broken-link + + when: broken_link_exists.stat.exists + +- name: check if junction symbolic link exists + win_stat: + path: "{{win_find_dir}}\\junction-link" + register: junction_link_exists + +- name: delete junction symbolic link if it exists + win_command: cmd.exe /c rmdir {{win_find_dir}}\junction-link + when: junction_link_exists.stat.exists + +- name: check if nested symbolic link exists + win_stat: + path: "{{win_find_dir}}\\nested\\link" + register: nested_link_exists + +- name: delete nested symbolic link if it exists + win_command: cmd.exe /c rmdir {{win_find_dir}}\nested\link + when: nested_link_exists.stat.exists + +- name: remove testing folder + win_file: + path: "{{win_find_dir}}" + state: absent diff --git a/test/integration/test_win_group2.yml b/test/integration/test_win_group2.yml index 27765ea599..5eae464ec3 100644 --- a/test/integration/test_win_group2.yml +++ b/test/integration/test_win_group2.yml @@ -7,6 +7,7 @@ - { role: win_template, tags: test_win_template } - { role: win_lineinfile, tags: test_win_lineinfile } - { role: win_stat, tags: test_win_stat } + - { role: win_find, tags: test_win_find } - { role: win_get_url, tags: test_win_get_url } - { role: win_msi, tags: test_win_msi } - { role: win_package, tags: test_win_package }