1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
|
#!powershell
# Copyright: (c) 2017, Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
#AnsibleRequires -CSharpUtil Ansible.Basic
#Requires -Module Ansible.ModuleUtils.FileUtil
#Requires -Module Ansible.ModuleUtils.LinkUtil
function ConvertTo-Timestamp($start_date, $end_date) {
if ($start_date -and $end_date) {
return (New-TimeSpan -Start $start_date -End $end_date).TotalSeconds
}
}
function Get-FileChecksum($path, $algorithm) {
switch ($algorithm) {
'md5' { $sp = New-Object -TypeName System.Security.Cryptography.MD5CryptoServiceProvider }
'sha1' { $sp = New-Object -TypeName System.Security.Cryptography.SHA1CryptoServiceProvider }
'sha256' { $sp = New-Object -TypeName System.Security.Cryptography.SHA256CryptoServiceProvider }
'sha384' { $sp = New-Object -TypeName System.Security.Cryptography.SHA384CryptoServiceProvider }
'sha512' { $sp = New-Object -TypeName System.Security.Cryptography.SHA512CryptoServiceProvider }
default { Fail-Json -obj $result -message "Unsupported hash algorithm supplied '$algorithm'" }
}
$fp = [System.IO.File]::Open($path, [System.IO.Filemode]::Open, [System.IO.FileAccess]::Read, [System.IO.FileShare]::ReadWrite)
try {
$hash = [System.BitConverter]::ToString($sp.ComputeHash($fp)).Replace("-", "").ToLower()
} finally {
$fp.Dispose()
}
return $hash
}
function Get-FileInfo {
param([String]$Path, [Switch]$Follow)
$info = Get-AnsibleItem -Path $Path -ErrorAction SilentlyContinue
$link_info = $null
if ($null -ne $info) {
try {
$link_info = Get-Link -link_path $info.FullName
} catch {
$module.Warn("Failed to check/get link info for file: $($_.Exception.Message)")
}
# If follow=true we want to follow the link all the way back to root object
if ($Follow -and $null -ne $link_info -and $link_info.Type -in @("SymbolicLink", "JunctionPoint")) {
$info, $link_info = Get-FileInfo -Path $link_info.AbsolutePath -Follow
}
}
return $info, $link_info
}
$spec = @{
options = @{
path = @{ type='path'; required=$true; aliases=@( 'dest', 'name' ) }
get_checksum = @{ type='bool'; default=$true }
checksum_algorithm = @{ type='str'; default='sha1'; choices=@( 'md5', 'sha1', 'sha256', 'sha384', 'sha512' ) }
follow = @{ type='bool'; default=$false }
}
supports_check_mode = $true
}
$module = [Ansible.Basic.AnsibleModule]::Create($args, $spec)
$path = $module.Params.path
$get_checksum = $module.Params.get_checksum
$checksum_algorithm = $module.Params.checksum_algorithm
$follow = $module.Params.follow
$module.Result.stat = @{ exists=$false }
Load-LinkUtils
$info, $link_info = Get-FileInfo -Path $path -Follow:$follow
If ($null -ne $info) {
$epoch_date = Get-Date -Date "01/01/1970"
$attributes = @()
foreach ($attribute in ($info.Attributes -split ',')) {
$attributes += $attribute.Trim()
}
# default values that are always set, specific values are set below this
# but are kept commented for easier readability
$stat = @{
exists = $true
attributes = $info.Attributes.ToString()
isarchive = ($attributes -contains "Archive")
isdir = $false
ishidden = ($attributes -contains "Hidden")
isjunction = $false
islnk = $false
isreadonly = ($attributes -contains "ReadOnly")
isreg = $false
isshared = $false
nlink = 1 # Number of links to the file (hard links), overridden below if islnk
# lnk_target = islnk or isjunction Target of the symlink. Note that relative paths remain relative
# lnk_source = islnk os isjunction Target of the symlink normalized for the remote filesystem
hlnk_targets = @()
creationtime = (ConvertTo-Timestamp -start_date $epoch_date -end_date $info.CreationTime)
lastaccesstime = (ConvertTo-Timestamp -start_date $epoch_date -end_date $info.LastAccessTime)
lastwritetime = (ConvertTo-Timestamp -start_date $epoch_date -end_date $info.LastWriteTime)
# size = a file and directory - calculated below
path = $info.FullName
filename = $info.Name
# extension = a file
# owner = set outsite this dict in case it fails
# sharename = a directory and isshared is True
# checksum = a file and get_checksum: True
}
try {
$stat.owner = $info.GetAccessControl().Owner
} catch {
# may not have rights, historical behaviour was to just set to $null
# due to ErrorActionPreference being set to "Continue"
$stat.owner = $null
}
# values that are set according to the type of file
if ($info.Attributes.HasFlag([System.IO.FileAttributes]::Directory)) {
$stat.isdir = $true
$share_info = Get-CimInstance -ClassName Win32_Share -Filter "Path='$($stat.path -replace '\\', '\\')'"
if ($null -ne $share_info) {
$stat.isshared = $true
$stat.sharename = $share_info.Name
}
try {
$size = 0
foreach ($file in $info.EnumerateFiles("*", [System.IO.SearchOption]::AllDirectories)) {
$size += $file.Length
}
$stat.size = $size
} catch {
$stat.size = 0
}
} else {
$stat.extension = $info.Extension
$stat.isreg = $true
$stat.size = $info.Length
if ($get_checksum) {
try {
$stat.checksum = Get-FileChecksum -path $path -algorithm $checksum_algorithm
} catch {
$module.FailJson("Failed to get hash of file, set get_checksum to False to ignore this error: $($_.Exception.Message)", $_)
}
}
}
# Get symbolic link, junction point, hard link info
if ($null -ne $link_info) {
switch ($link_info.Type) {
"SymbolicLink" {
$stat.islnk = $true
$stat.isreg = $false
$stat.lnk_target = $link_info.TargetPath
$stat.lnk_source = $link_info.AbsolutePath
break
}
"JunctionPoint" {
$stat.isjunction = $true
$stat.isreg = $false
$stat.lnk_target = $link_info.TargetPath
$stat.lnk_source = $link_info.AbsolutePath
break
}
"HardLink" {
$stat.lnk_type = "hard"
$stat.nlink = $link_info.HardTargets.Count
# remove current path from the targets
$hlnk_targets = $link_info.HardTargets | Where-Object { $_ -ne $stat.path }
$stat.hlnk_targets = @($hlnk_targets)
break
}
}
}
$module.Result.stat = $stat
}
$module.ExitJson()
|