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 $AllocationUnitSize
113 )
114 $parameters = @{
115 Path = $Path
116 Full = $Full
117 }
118 if ($null -ne $UseLargeFRS) {
119 $parameters.Add("UseLargeFRS", $UseLargeFRS)
120 }
121 if ($null -ne $SetIntegrityStreams) {
122 $parameters.Add("SetIntegrityStreams", $SetIntegrityStreams)
123 }
124 if ($null -ne $Compress){
125 $parameters.Add("Compress", $Compress)
126 }
127 if ($null -ne $Label) {
128 $parameters.Add("NewFileSystemLabel", $Label)
129 }
130 if ($null -ne $FileSystem) {
131 $parameters.Add("FileSystem", $FileSystem)
132 }
133 if ($null -ne $AllocationUnitSize) {
134 $parameters.Add("AllocationUnitSize", $AllocationUnitSize)
135 }
136
137 Format-Volume @parameters -Confirm:$false | Out-Null
138
139 }
140
141 $ansible_volume = Get-AnsibleVolume -DriveLetter $drive_letter -Path $path -Label $label
142 $ansible_file_system = $ansible_volume.FileSystem
143 $ansible_volume_size = $ansible_volume.Size
144 $ansible_volume_alu = (Get-CimInstance -ClassName Win32_Volume -Filter "DeviceId = '$($ansible_volume.path.replace('\','\\'))'" -Property BlockSize).BlockSize
145
146 $ansible_partition = Get-Partition -Volume $ansible_volume
147
148 if (-not $force_format -and $null -ne $allocation_unit_size -and $ansible_volume_alu -ne 0 -and $null -ne $ansible_volume_alu -and $allocation_unit_size -ne $ansible_volume_alu) {
149 $module.FailJson("Force format must be specified since target allocation unit size: $($allocation_unit_size) is different from the current allocation unit size of the volume: $($ansible_volume_alu)")
150 }
151
152 foreach ($access_path in $ansible_partition.AccessPaths) {
153 if ($access_path -ne $Path) {
154 if ($null -ne $file_system -and
155 -not [string]::IsNullOrEmpty($ansible_file_system) -and
156 $file_system -ne $ansible_file_system)
157 {
158 if (-not $force_format)
159 {
160 $no_files_in_volume = (Get-ChildItem -LiteralPath $access_path -ErrorAction SilentlyContinue | Measure-Object).Count -eq 0
161 if($no_files_in_volume)
162 {
163 $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())")
164 }
165 else
166 {
167 $module.FailJson("Force format must be specified to format non-pristine volumes")
168 }
169 }
170 }
171 else
172 {
173 $pristine = -not $force_format
174 }
175 }
176 }
177
178 if ($force_format) {
179 if (-not $module.CheckMode) {
180 Format-AnsibleVolume -Path $ansible_volume.Path -Full $full_format -Label $new_label -FileSystem $file_system -SetIntegrityStreams $integrity_streams -UseLargeFRS $large_frs -Compress $compress_volume -AllocationUnitSize $allocation_unit_size
181 }
182 $module.Result.changed = $true
183 }
184 else {
185 if ($pristine) {
186 if ($null -eq $new_label) {
187 $new_label = $ansible_volume.FileSystemLabel
188 }
189 # Conditions for formatting
190 if ($ansible_volume_size -eq 0 -or
191 $ansible_volume.FileSystemLabel -ne $new_label) {
192 if (-not $module.CheckMode) {
193 Format-AnsibleVolume -Path $ansible_volume.Path -Full $full_format -Label $new_label -FileSystem $file_system -SetIntegrityStreams $integrity_streams -UseLargeFRS $large_frs -Compress $compress_volume -AllocationUnitSize $allocation_unit_size
194 }
195 $module.Result.changed = $true
196 }
197 }
198 }
199
200 $module.ExitJson()
201