1 #!powershell
2
3 # Copyright: (c) 2019, Varun Chopra (@chopraaa) <v@chopraaa.com>
4 # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
5
6 #AnsibleRequires -CSharpUtil Ansible.Basic
7 #AnsibleRequires -OSVersion 6.2
8
9 Set-StrictMode -Version 2
10
11 $ErrorActionPreference = "Stop"
12
13 $spec = @{
14 options = @{
15 drive_letter = @{ type = "str" }
16 path = @{ type = "str" }
17 label = @{ type = "str" }
18 new_label = @{ type = "str" }
19 file_system = @{ type = "str"; choices = "ntfs", "refs", "exfat", "fat32", "fat" }
20 allocation_unit_size = @{ type = "int" }
21 large_frs = @{ type = "bool" }
22 full = @{ type = "bool"; default = $false }
23 compress = @{ type = "bool" }
24 integrity_streams = @{ type = "bool" }
25 force = @{ type = "bool"; default = $false }
26 }
27 mutually_exclusive = @(
28 ,@('drive_letter', 'path', 'label')
29 )
30 required_one_of = @(
31 ,@('drive_letter', 'path', 'label')
32 )
33 supports_check_mode = $true
34 }
35
36 $module = [Ansible.Basic.AnsibleModule]::Create($args, $spec)
37
38 $drive_letter = $module.Params.drive_letter
39 $path = $module.Params.path
40 $label = $module.Params.label
41 $new_label = $module.Params.new_label
42 $file_system = $module.Params.file_system
43 $allocation_unit_size = $module.Params.allocation_unit_size
44 $large_frs = $module.Params.large_frs
45 $full_format = $module.Params.full
46 $compress_volume = $module.Params.compress
47 $integrity_streams = $module.Params.integrity_streams
48 $force_format = $module.Params.force
49
50 # Some pre-checks
51 if ($null -ne $drive_letter -and $drive_letter -notmatch "^[a-zA-Z]$") {
52 $module.FailJson("The parameter drive_letter should be a single character A-Z")
53 }
54 if ($integrity_streams -eq $true -and $file_system -ne "refs") {
55 $module.FailJson("Integrity streams can be enabled only on ReFS volumes. You specified: $($file_system)")
56 }
57 if ($compress_volume -eq $true) {
58 if ($file_system -eq "ntfs") {
59 if ($null -ne $allocation_unit_size -and $allocation_unit_size -gt 4096) {
60 $module.FailJson("NTFS compression is not supported for allocation unit sizes above 4096")
61 }
62 }
63 else {
64 $module.FailJson("Compression can be enabled only on NTFS volumes. You specified: $($file_system)")
65 }
66 }
67
Get-AnsibleVolumenull68 function Get-AnsibleVolume {
69 param(
70 $DriveLetter,
71 $Path,
72 $Label
73 )
74
75 if ($null -ne $DriveLetter) {
76 try {
77 $volume = Get-Volume -DriveLetter $DriveLetter
78 } catch {
79 $module.FailJson("There was an error retrieving the volume using drive_letter $($DriveLetter): $($_.Exception.Message)", $_)
80 }
81 }
82 elseif ($null -ne $Path) {
83 try {
84 $volume = Get-Volume -Path $Path
85 } catch {
86 $module.FailJson("There was an error retrieving the volume using path $($Path): $($_.Exception.Message)", $_)
87 }
88 }
89 elseif ($null -ne $Label) {
90 try {
91 $volume = Get-Volume -FileSystemLabel $Label
92 } catch {
93 $module.FailJson("There was an error retrieving the volume using label $($Label): $($_.Exception.Message)", $_)
94 }
95 }
96 else {
97 $module.FailJson("Unable to locate volume: drive_letter, path and label were not specified")
98 }
99
100 return $volume
101 }
102
Format-AnsibleVolume()103 function Format-AnsibleVolume {
104 param(
105 $Path,
106 $Label,
107 $FileSystem,
108 $Full,
109 $UseLargeFRS,
110 $Compress,
111 $SetIntegrityStreams
112 )
113 $parameters = @{
114 Path = $Path
115 Full = $Full
116 }
117 if ($null -ne $UseLargeFRS) {
118 $parameters.Add("UseLargeFRS", $UseLargeFRS)
119 }
120 if ($null -ne $SetIntegrityStreams) {
121 $parameters.Add("SetIntegrityStreams", $SetIntegrityStreams)
122 }
123 if ($null -ne $Compress){
124 $parameters.Add("Compress", $Compress)
125 }
126 if ($null -ne $Label) {
127 $parameters.Add("NewFileSystemLabel", $Label)
128 }
129 if ($null -ne $FileSystem) {
130 $parameters.Add("FileSystem", $FileSystem)
131 }
132
133 Format-Volume @parameters -Confirm:$false | Out-Null
134
135 }
136
137 $ansible_volume = Get-AnsibleVolume -DriveLetter $drive_letter -Path $path -Label $label
138 $ansible_file_system = $ansible_volume.FileSystem
139 $ansible_volume_size = $ansible_volume.Size
140
141 $ansible_partition = Get-Partition -Volume $ansible_volume
142
143 foreach ($access_path in $ansible_partition.AccessPaths) {
144 if ($access_path -ne $Path) {
145 $files_in_volume = (Get-ChildItem -LiteralPath $access_path -ErrorAction SilentlyContinue | Measure-Object).Count
146
147 if (-not $force_format -and $files_in_volume -gt 0) {
148 $module.FailJson("Force format must be specified to format non-pristine volumes")
149 } else {
150 if (-not $force_format -and
151 -not $null -eq $file_system -and
152 -not [string]::IsNullOrEmpty($ansible_file_system) -and
153 $file_system -ne $ansible_file_system) {
154 $module.FailJson("Force format must be specified since target file system: $($file_system) is different from the current file system of the volume: $($ansible_file_system.ToLower())")
155 } else {
156 $pristine = $true
157 }
158 }
159 }
160 }
161
162 if ($force_format) {
163 if (-not $module.CheckMode) {
164 Format-AnsibleVolume -Path $ansible_volume.Path -Full $full_format -Label $new_label -FileSystem $file_system -SetIntegrityStreams $integrity_streams -UseLargeFRS $large_frs -Compress $compress_volume
165 }
166 $module.Result.changed = $true
167 }
168 else {
169 if ($pristine) {
170 if ($null -eq $new_label) {
171 $new_label = $ansible_volume.FileSystemLabel
172 }
173 # Conditions for formatting
174 if ($ansible_volume_size -eq 0 -or
175 $ansible_volume.FileSystemLabel -ne $new_label) {
176 if (-not $module.CheckMode) {
177 Format-AnsibleVolume -Path $ansible_volume.Path -Full $full_format -Label $new_label -FileSystem $file_system -SetIntegrityStreams $integrity_streams -UseLargeFRS $large_frs -Compress $compress_volume
178 }
179 $module.Result.changed = $true
180 }
181 }
182 }
183
184 $module.ExitJson()
185