-
Notifications
You must be signed in to change notification settings - Fork 52
Expand file tree
/
Copy pathpresentVMFScopy.ps1
More file actions
321 lines (309 loc) · 14.3 KB
/
presentVMFScopy.ps1
File metadata and controls
321 lines (309 loc) · 14.3 KB
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
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
Write-Host " __________________________"
Write-Host " /++++++++++++++++++++++++++\"
Write-Host " /++++++++++++++++++++++++++++\"
Write-Host " /++++++++++++++++++++++++++++++\"
Write-Host " /++++++++++++++++++++++++++++++++\"
Write-Host " /++++++++++++++++++++++++++++++++++\"
Write-Host " /++++++++++++/----------\++++++++++++\"
Write-Host " /++++++++++++/ \++++++++++++\"
Write-Host " /++++++++++++/ \++++++++++++\"
Write-Host " /++++++++++++/ \++++++++++++\"
Write-Host " /++++++++++++/ \++++++++++++\"
Write-Host " \++++++++++++\ /++++++++++++/"
Write-Host " \++++++++++++\ /++++++++++++/"
Write-Host " \++++++++++++\ /++++++++++++/"
Write-Host " \++++++++++++\ /++++++++++++/"
Write-Host " \++++++++++++\ /++++++++++++/"
Write-Host " \++++++++++++\"
Write-Host " \++++++++++++\"
Write-Host " \++++++++++++\"
Write-Host " \++++++++++++\"
Write-Host " \------------\"
Write-Host
Write-host "Pure Storage VMware Volume Refresh Script v1.1"
write-host "----------------------------------------------"
write-host
<#
Written by Cody Hosterman www.codyhosterman.com
*******Disclaimer:******************************************************
This scripts are offered "as is" with no warranty. While this
scripts is tested and working in my environment, it is recommended that you test
this script in a test lab before using in a production environment. Everyone can
use the scripts/commands provided here without any written permission but I
will not be liable for any damage or loss to the system.
************************************************************************
This script will take in the source VMFS name and the target VMFS name and refresh the target with the latest snapshot of the source.
Enter in vCenter credentials and one or more FlashArrays. The FlashArrays must use the same credentials. If different credentials
are needed for each FlashArray the script must be altered slightly.
Supports:
-PowerShell 3.0 or later
-Pure Storage PowerShell SDK 1.0 or later
-PowerCLI 6.0 Release 1 or later (5.5/5.8 is likely fine, but not tested with this script version)
-REST API 1.4 and later
-Purity 4.1 and later
-FlashArray 400 Series and //m
#>
while ($varsCorrect -ne "Y")
{
$flasharrays = @()
$arraycount = Read-Host "How many FlashArrays do you want to search? [Enter a whole number 1 or higher]"
Write-Host "Please enter each FlashArray FQDN or IP one at a time and press enter after each entry"
for ($faentry=1; $faentry -le $arraycount; $faentry++)
{
$flasharrays += Read-Host "Enter FlashArray FQDN or IP"
}
$pureuser = Read-Host "Enter FlashArray user name"
$pureuserpwd = Read-Host "Enter FlashArray password" -AsSecureString
$vcenter = Read-Host "Enter vCenter FQDN or IP"
$vcuser = Read-Host "Enter vCenter user name"
$vcpass = Read-Host "Enter vCenter password" -AsSecureString
$vmfsname = Read-Host "Enter Source VMFS Name"
$recoveryvmfsname = Read-Host "Enter Recovery VMFS Name"
write-host ""
$varsCorrect = read-host "Are the above values entered accurately? Y/N"
}
$FACreds = New-Object System.Management.Automation.PSCredential ($pureuser, $pureuserpwd)
$VCCreds = New-Object System.Management.Automation.PSCredential ($vcuser, $vcpass)
#A function to rescan all of the input ESXi servers and rescan for VMFS volumes. This starts all host operations in parallel and waits for them all to complete. Is called throughout as needed
function rescanESXiHosts
{
foreach ($esxi in $hosts)
{
$argList = @($vcenter, $VCCreds, $esxi)
$job = Start-Job -ScriptBlock{
Connect-VIServer -Server $args[0] -Credential $args[1]
Get-VMHost -Name $args[2] | Get-VMHostStorage -RescanAllHba -RescanVMFS
Disconnect-VIServer -Confirm:$false
} -ArgumentList $argList
}
Get-Job | Wait-Job |out-null
}
#A function to unmount and detach the VMFS from all of the input ESXi servers. This starts all host operations in parallel and waits for them all to complete. Is called throughout as needed
function unmountandDetachVMFS
{
foreach ($esxi in $hosts)
{
$argList = @($vcenter, $VCCreds, $esxi, $recoverydatastore)
$job = Start-Job -ScriptBlock{
Connect-VIServer -Server $args[0] -Credential $args[1]
$esxihost = get-vmhost $args[2]
$datastore = get-datastore $args[3]
$storageSystem = Get-View $esxihost.Extensiondata.ConfigManager.StorageSystem
$StorageSystem.UnmountVmfsVolume($datastore.ExtensionData.Info.vmfs.uuid) |out-null
$storageSystem.DetachScsiLun((Get-ScsiLun -VmHost $esxihost | where {$_.CanonicalName -eq $datastore.ExtensionData.Info.Vmfs.Extent.DiskName}).ExtensionData.Uuid) |out-null
Disconnect-VIServer -Confirm:$false
} -ArgumentList $argList
}
Get-Job | Wait-Job |out-null
}
#Connect to each FlashArray and get all of their volume information
$facount = 0
$purevolumes=@()
$EndPoint= @()
foreach ($flasharray in $flasharrays)
{
if ($facount -eq 0)
{
$EndPoint = @(New-PfaArray -EndPoint $flasharray -Credentials $FACreds -IgnoreCertificateError)
$purevolumes += Get-PfaVolumes -Array $EndPoint[$facount]
$tempvols = @(Get-PfaVolumes -Array $EndPoint[$facount])
$arraysnlist = @($tempvols.serial[0].substring(0,16))
}
else
{
$EndPoint += New-PfaArray -EndPoint $flasharray -Credentials $FACreds -IgnoreCertificateError
$purevolumes += Get-PfaVolumes -Array $EndPoint[$facount]
$tempvols = Get-PfaVolumes -Array $EndPoint[$facount]
$arraysnlist += $tempvols.serial[0].substring(0,16)
}
$facount = $facount + 1
}
#Connect to vCenter
Set-PowerCLIConfiguration -DisplayDeprecationWarnings:$false -confirm:$false| Out-Null
connect-viserver -Server $vcenter -Credential $VCCreds|out-null
write-host "*****************************************************************"
write-host ""
#Find which FlashArray the source VMFS volume is on
$datastore = get-datastore $vmfsname
$lun = $datastore.ExtensionData.Info.Vmfs.Extent.DiskName
if ($lun -like 'naa.624a9370*')
{
$volserial = ($lun.ToUpper()).substring(12)
$purevol = $purevolumes | where-object { $_.serial -eq $volserial }
for($i=0; $i -lt $arraysnlist.count; $i++)
{
if ($arraysnlist[$i] -eq ($volserial.substring(0,16)))
{
$sourcearraychoice = $i
}
}
write-host ("The source VMFS named " + $vmfsname + " is on a FlashArray named " + $EndPoint[$sourcearraychoice].EndPoint)
write-host ("The source FlashArray volume is named " + $purevol.name)
if ($purevol -ne $null)
{
$volumeexists = 1
}
else
{
write-host "The target volume is a FlashArray volume, but not on one of the entered arrays"
}
}
else
{
write-host 'The source datastore is NOT a FlashArray volume.'
}
#Find which FlashArray the target VMFS volume is on
$recoverydatastore = get-datastore $recoveryvmfsname
$recoverylun = $recoverydatastore.ExtensionData.Info.Vmfs.Extent.DiskName
if ($recoverylun -like 'naa.624a9370*')
{
$recoveryvolserial = ($recoverylun.ToUpper()).substring(12)
$recoverypurevol = $purevolumes | where-object { $_.serial -eq $recoveryvolserial }
for($i=0; $i -lt $arraysnlist.count; $i++)
{
if ($arraysnlist[$i] -eq ($recoveryvolserial.substring(0,16)))
{
$targetarraychoice = $i
}
}
write-host ("The target VMFS named " + $recoveryvmfsname + " is on a FlashArray named " + $EndPoint[$targetarraychoice].EndPoint)
write-host ("The target FlashArray volume is named " + $recoverypurevol.name)
if ($recoverypurevol -ne $null)
{
$recoveryvolumeexists = 1
}
else
{
write-host "The target volume is a FlashArray volume, but not on one of the entered arrays"
}
}
else
{
write-host 'The target datastore is NOT a FlashArray volume.'
}
if (($volumeexists -eq 1) -and ($recoveryvolumeexists -eq 1))
{
$vms = $recoverydatastore |get-vm
#Make sure there are no VMs on the recovery VMFS
if ($vms.count -ge 1)
{
write-host ("There are VMs registered to the recovery datastore. Unregister them first then re-run this script.")
}
else
{
$hosts = $recoverydatastore |get-vmhost
write-host "Unmounting and detaching the VMFS volume from the following ESXi hosts:"
write-host $hosts
unmountandDetachVMFS
<# Does the following:
1) Get the latest FlashArray snapshot from the source VMFS.
2) Gets any host groups and host the recovery volume is connected to
3) Removes the recovery volume from the hosts and/or host groups
4) Deletes the volume
5) Creates a new volume with the same name from the latest snapshot of the source
6) Adds the volume back to all of its hosts and host groups
#>
rescanESXiHosts |out-null
$esxcli = $hosts[0] | get-esxcli
if ($EndPoint[$sourcearraychoice].EndPoint -eq $EndPoint[$targetarraychoice].EndPoint)
{
$snapshots = Get-PfaVolumeSnapshots -Array $EndPoint[$targetarraychoice] -VolumeName $purevol.name
}
if ($EndPoint[$sourcearraychoice].EndPoint -ne $EndPoint[$targetarraychoice].EndPoint)
{
$snaps = Get-PfaallVolumeSnapshots -array $EndPoint[$targetarraychoice]
$sourcearray = Get-PfaArrayAttributes -array $EndPoint[$sourcearraychoice]
$fullpurevolname = $sourcearray.array_name+":"+$purevol.name
$snapshots = @()
foreach ($snap in $snaps)
{
if ($snap.source -eq $fullpurevolname)
{
$snapshots += $snap
}
}
}
$fahosts = Get-PfaVolumeHostConnections -Array $EndPoint[$targetarraychoice] -VolumeName $recoverypurevol.name
$fahosts = $fahosts.host
$fahostgroups = Get-PfaVolumeHostGroupConnections -Array $EndPoint[$targetarraychoice] -VolumeName $recoverypurevol.name
$fahostgroups = $fahostgroups.hgroup |get-unique
if ($fahosts.count -ge 1)
{
write-host "The volume is presented privately to the following hosts:"
write-host $fahosts
write-host "Removing the volume from the host(s)..." -foregroundcolor "red"
foreach($fahost in $fahosts)
{
Remove-PfaHostVolumeConnection -Array $EndPoint[$targetarraychoice] -VolumeName $recoverypurevol.name -HostName $fahost |out-null
}
}
if ($fahostgroups.count -ge 1)
{
write-host "The volume is presented to the following host groups:"
write-host $fahostgroups
write-host "Removing the volume from the host groups(s)..." -foregroundcolor "red"
foreach($fahostgroup in $fahostgroups)
{
Remove-PfaHostGroupVolumeConnection -Array $EndPoint[$targetarraychoice] -VolumeName $recoverypurevol.name -HostGroupName $fahostgroup |out-null
}
}
write-host "Deleting and permanently eradicating the volume named" $recoverypurevol.name -foregroundcolor "red"
Remove-PfaVolumeOrSnapshot -Array $EndPoint[$targetarraychoice] -Name $recoverypurevol.name -Confirm:$false |out-null
Remove-PfaVolumeOrSnapshot -Array $EndPoint[$targetarraychoice] -Name $recoverypurevol.name -Confirm:$false -Eradicate |out-null
$newvol = New-PfaVolume -Array $EndPoint[$targetarraychoice] -VolumeName $recoverypurevol.name -Source $snapshots[0].name
write-host "Created a new volume with the name" $recoverypurevol.name "from the snapshot" $snapshots[0].name -foregroundcolor "green"
if ($fahosts.count -ge 1)
{
write-host "Adding the new volume back privately to the following host(s)" -foregroundcolor "green"
write-host $fahosts
foreach($fahost in $fahosts)
{
New-PfaHostVolumeConnection -Array $EndPoint[$targetarraychoice] -VolumeName $recoverypurevol.name -HostName $fahost |out-null
}
}
if ($fahostgroups.count -ge 1)
{
write-host "Adding the new volume back to the following host group(s)" -foregroundcolor "green"
write-host $fahostgroups
foreach($fahostgroup in $fahostgroups)
{
New-PfaHostGroupVolumeConnection -Array $EndPoint[$targetarraychoice] -VolumeName $recoverypurevol.name -HostGroupName $fahostgroup |out-null
}
}
Start-Sleep -s 30
rescanESXiHosts
#resignatures the datastore after a rescan
Start-sleep -s 10
$unresolvedvmfs = $esxcli.storage.vmfs.snapshot.list($vmfsname)
$recoverylun = ("naa.624a9370" + $newvol.serial)
if ($unresolvedvmfs.UnresolvedExtentCount -ge 2)
{
write-host "ERROR: There are more than one unresolved copies of the source VMFS named" $vmfsname -foregroundcolor "red"
write-host "Please remove the additional copies in order to mount"
}
else
{
write-host "Resignaturing the VMFS on the device" $recoverylun "and then mounting it..."
$esxcli.storage.vmfs.snapshot.resignature($vmfsname) |out-null
rescanESXiHosts
$datastores = $hosts[0] | Get-Datastore
#renames the VMFS back to the original recovery name
foreach ($ds in $datastores)
{
$naa = $ds.ExtensionData.Info.Vmfs.Extent.DiskName
if ($naa -eq $recoverylun.ToLower())
{
$resigds = $ds
}
}
$resigds | Set-Datastore -Name $recoveryvmfsname |out-null
write-host "Renaming the datastore" $resigds.name "back to" $recoveryvmfsname
}
}
}
#disconnecting sessions
disconnect-viserver -Server $vcenter -confirm:$false
foreach ($flasharray in $endpoint)
{
Disconnect-PfaArray -Array $flasharray
}