Skip to content

Commit e63e10f

Browse files
authored
Create Copy-VmfsDatastoreFromFlashArraySnapshot.ps1
1 parent 6f49e57 commit e63e10f

File tree

1 file changed

+278
-0
lines changed

1 file changed

+278
-0
lines changed
Lines changed: 278 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,278 @@
1+
<#==========================================================================
2+
Script Name: Copy-VmfsDatastoreFromFlashArraySnapshot.ps1
3+
Created on: 9/20/2021
4+
Created by: Jase McCarty
5+
Github: http://www.github.com/jasemccarty
6+
Twitter: @jasemccarty
7+
Website: http://www.jasemccarty.com
8+
===========================================================================
9+
.DESCRIPTION
10+
Restore a VMFS Datastore from a Snapshot on a FlashArray
11+
Powershell Core supported - Requires PowerCLI, PureStorage.FlashArray.VMware, & PureStoragePowerShellSDK (v1) modules.
12+
13+
.SYNTAX
14+
Copy-VmfsDatastoreFromFlashArraySnapshot.ps1 -TargetvCenter <VCENTER> -TargetFlashArray <FlashArray> -TargetCluster <CusterName> -TargetVmFolder <VmFolder> -SourceVolumeName <SourceVolumeName> -LocalSnapshot <$true/$false> -SourceSnapCount <int> -RegisterVms <$true/$false> -TargetVmFolder <vm folder>
15+
#>
16+
17+
# Set our Parameters
18+
[CmdletBinding()]Param(
19+
[Parameter(Mandatory=$False)][string]$TargetVcenter="vc03.fsa.lab",
20+
[Parameter(Mandatory = $False)][String]$TargetFlashArray="sn1-m70r2-f07-27.puretec.purestorage.com",
21+
[Parameter(Mandatory = $False)][String]$TargetCluster="cluster-dr",
22+
[Parameter(Mandatory = $False)][String]$SourceVolumeName="sn1-m70-f06-33-vc02-jm01",
23+
[Parameter(Mandatory = $False)][Boolean]$LocalSnapshot=$false,
24+
[Parameter(Mandatory = $False)][ValidateRange(1,30)][int] $SourceSnapCount="1",
25+
[Parameter(Mandatory = $False)][Boolean]$RegisterVms=$false,
26+
[Parameter(Mandatory = $False)][String]$TargetVmFolder="Discovered virtual machine"
27+
)
28+
29+
###########################################################
30+
# Check for proper PowerShell modules installation #
31+
###########################################################
32+
33+
# Get the PowerCLI Version
34+
$PowerCLIVersion = Get-Module -Name VMware.PowerCLI -ListAvailable | Select-Object -Property Version
35+
36+
# If the PowerCLI Version is not v10 or higher, recommend that the user install PowerCLI 12 or higher
37+
If ($PowerCLIVersion.Version.Major -ge "12") {
38+
Write-Host "PowerCLI version 12 or higher present, " -NoNewLine
39+
Write-Host "proceeding" -ForegroundColor Green
40+
} else {
41+
Write-Host "PowerCLI version could not be determined or is less than version 12" -Foregroundcolor Red
42+
Write-Host "Please install PowerCLI 12 or higher and rerun this script" -Foregroundcolor Yellow
43+
Write-Host " "
44+
exit
45+
}
46+
# Check for Pure Storage PowerShell SDK (v1) installation, required to facilitate some FlashArray tasks
47+
If (-Not (Get-Module -ListAvailable -Name "PureStoragePowerShellSDK")) {
48+
Write-Host "Please install the Pure Storage PowerShell SDK (v1) Module and rerun this script to proceed" -ForegroundColor Yellow
49+
Write-Host "It can be installed using " -NoNewLine
50+
Write-Host "'Install-Module -Name PureStoragePowerShellSDK'" -ForegroundColor Green
51+
Write-Host
52+
exit
53+
}
54+
# Check for Pure Storage FlashArray Module for VMware installation, required to facilitate some VMware-based FlashArray tasks
55+
If (-Not (Get-Module -ListAvailable -Name "PureStorage.FlashArray.VMware")) {
56+
Write-Host "Please install the Pure Storage FlashArray Module for VMware and rerun this script to proceed" -ForegroundColor Yellow
57+
Write-Host "It can be installed using " -NoNewLine
58+
Write-Host "'Install-Module -Name PureStorage.FlashArray.VMware'" -ForegroundColor Green
59+
Write-Host
60+
exit
61+
}
62+
63+
########################################################################################################################
64+
# Check to see if we're connected to the Target FlashArray, if not, prompt for Credentials to connect to it. #
65+
########################################################################################################################
66+
67+
If ($DefaultFlashArray) {
68+
Write-Host "Target FlashArray: $($DefaultFlashArray.Endpoint) "
69+
$ConnectFA = $False
70+
} else {
71+
#connect to Target FlashArray
72+
try
73+
{
74+
$FaCredentials = Get-Credential -Message "Please enter the Target FlashArray Credentials for $($TargetFlashArray)"
75+
New-PfaConnection -EndPoint $TargetFlashArray -Credentials $FaCredentials -ErrorAction Stop -IgnoreCertificateError -DefaultArray
76+
$ConnectFA = $True
77+
}
78+
catch
79+
{
80+
write-host "Failed to connect to the Target FlashArray" -BackgroundColor Red
81+
write-host $Error
82+
write-host "Terminating Script" -BackgroundColor Red
83+
$ConnectFA = $False
84+
85+
return
86+
}
87+
}
88+
########################################################################################################################
89+
# Check to see if we're connected to the Target vCenter, if not, prompt for Credentials to connect to it. #
90+
########################################################################################################################
91+
92+
# Check to see if a current vCenter Server session is in place
93+
If ($Global:DefaultVIServer.Name -eq $TargetVcenter) {
94+
Write-Host "Connected to " -NoNewline
95+
Write-Host $Global:DefaultVIServer -ForegroundColor Green
96+
} else {
97+
# If not connected to vCenter Server make a connection
98+
Write-Host "Not connected to vCenter Server" -ForegroundColor Red
99+
# Prompt for credentials using the native PowerShell Get-Credential cmdlet
100+
$VICredentials = Get-Credential -Message "Enter credentials for vCenter Server: $($TargetVcenter)"
101+
try {
102+
# Attempt to connect to the vCenter Server
103+
Connect-VIServer -Server $TargetVcenter -Credential $VICredentials -ErrorAction Stop | Out-Null
104+
Write-Host "Connected to $TargetVcenter" -ForegroundColor Green
105+
# Note that we connected to vCenter so we can disconnect upon termination
106+
$ConnectTargetVc = $True
107+
}
108+
catch {
109+
# If we could not connect to vCenter report that and exit the script
110+
Write-Host "Failed to connect to $TargetVcenter" -BackgroundColor Red
111+
Write-Host $Error
112+
Write-Host "Terminating the script " -BackgroundColor Red
113+
# Note that we did not connect to vCenter Server
114+
$ConnectTargetVc = $False
115+
return
116+
}
117+
}
118+
119+
# If $LocalSnapshot is True, then don't look for replicated snaps
120+
If ($LocalSnapshot -eq $true) {
121+
$SourceVolume = $SourceVolumeName
122+
} else {
123+
$SourceVolume = "*:"+$SourceVolumeName
124+
}
125+
126+
# Get the Protection Group & Volumes
127+
$ProtectionGroup = New-PfaRestOperation -ResourceType pgroup -RestOperationType GET -Flasharray $DefaultFlashArray -SkipCertificateCheck | Where-Object {$_.volumes -Like $SourceVolume}
128+
129+
# If the number of snapshots isn't specified, return the latest snapshot, otherwise allow the choice of a snapshot to be selected
130+
If ($SourceSnapCount -le "1") {
131+
# Get the $SourceSnapCount latest snapshots from the protection group
132+
$LatestSnap = New-PfaRestOperation -ResourceType volume -RestOperationType GET -Flasharray $DefaultFlashArray -SkipCertificateCheck -QueryFilter "?snap=true&pgrouplist=$($ProtectionGroup.name)" | Where-Object {$_.name -Like "*"+$SourceVolumeName} | Sort-Object Created -Descending | Select-Object -First 1
133+
# Get the name of the latest snapshot
134+
$LatestSnapName = $LatestSnap.name
135+
} else {
136+
# Get the latest snapshot from the protection group
137+
$LatestSnap = New-PfaRestOperation -ResourceType volume -RestOperationType GET -Flasharray $DefaultFlashArray -SkipCertificateCheck -QueryFilter "?snap=true&pgrouplist=$($ProtectionGroup.name)" | Where-Object {$_.name -Like "*"+$SourceVolumeName} | Sort-Object Created -Descending | Select-Object -First $SourceSnapCount
138+
139+
# Retrieve the snaps & sort them by their created date
140+
141+
$LatestSnaps = $LatestSnap | Sort-Object Created
142+
143+
# If no clusters are found, exit the script
144+
if ($LatestSnaps.count -lt 1)
145+
{
146+
Write-Host "No snaps found. Terminating Script" -BackgroundColor Red
147+
exit
148+
}
149+
150+
# Select the Snapsnot
151+
Write-Host "1 or more snaps were found. Please choose a snapshot:"
152+
Write-Host ""
153+
154+
# Enumerate the cluster(s)
155+
1..$LatestSnaps.Length | Foreach-Object {
156+
$SnapName = $LatestSnaps[$_-1].name.Split(".")[1]+"."+$LatestSnaps[$_-1].name.Split(".")[2]
157+
$SnapDate = $LatestSnaps[$_-1].created
158+
Write-Host $($_)"- Name: $($SnapName) - Created:$($SnapDate)"
159+
}
160+
161+
# Wait until a valid snapshot is picked
162+
Do
163+
{
164+
Write-Host # empty line
165+
$Global:ans = (Read-Host 'Please select a snapshot') -as [int]
166+
167+
} While ((-not $ans) -or (0 -gt $ans) -or ($LatestSnaps.Length+1 -lt $ans))
168+
169+
# Assign the $LatestSnapshot variable to the Snapshot picked
170+
$LatestSnapShot = $LatestSnaps[($ans-1)]
171+
172+
# Return the selected snapshot
173+
Write-Host "Selected snapshot is " -NoNewline
174+
Write-Host $LatestSnaps[($ans-1)].name -ForegroundColor Green
175+
Write-Host ""
176+
# Set the Latest Snapshot Name
177+
$LatestSnapName = $LatestSnaps[($ans-1)].name
178+
}
179+
180+
# Get the suffix of the snapshot (will be appended to the datastore)
181+
$Suffix = $LatestSnapName.split(".")[1]
182+
183+
# Create the new volume name (includes the suffix)
184+
$NewVolumeName = $SourceVolumeName + "-" + $Suffix
185+
186+
# Create a new volume from the latest snapshot, overwrite if necessary
187+
New-PfaRestOperation -ResourceType volume/$($NewVolumeName) -RestOperationType POST -Flasharray $DefaultFlashArray -SkipCertificateCheck -jsonBody "{`"source`":`"$($LatestSnapName)`",`"overwrite`":`"$true`"}"
188+
189+
# Pause for a few seconds for the snap to take place
190+
Start-Sleep -Seconds 5
191+
192+
# Get the host group of the Target Cluster on the Target FlashArray
193+
$TargetHostGroup = Get-PfaHostGroupfromVcCluster -Cluster (Get-Cluster -Name $TargetCluster) -Flasharray $DefaultFlashArray
194+
195+
# Attach the snapped volume to the Target vCenter Cluster
196+
New-PfaRestOperation -ResourceType hgroup/$($TargetHostGroup.name)/volume/$($NewVolumeName) -RestOperationType POST -Flasharray $DefaultFlashArray -SkipCertificateCheck
197+
198+
# Select 1 host in the Target vCenter Cluster
199+
$VMHost = Get-Cluster -Name $TargetCluster | Get-VMhost | Select-Object -First 1
200+
201+
# Rescan the HBA's on the current host to both see the snapped volume (present as a snap) and put the datastores into an array variable
202+
Get-VMHostStorage -RescanAllHba -RescanVmfs -VMHost $VMhost | Out-Null
203+
204+
# Put all datastores attached to the host in an array variable
205+
$PreSnapDatastores = $VMhost | Get-Datastore
206+
207+
# Configure an esxcli instance so we can see snaps presented to the host
208+
$EsxCli = Get-EsxCli -VMHost $VMhost -V2
209+
# Return a snapshot list & put it in a variable
210+
$Snaps = $esxcli.storage.vmfs.snapshot.list.invoke()
211+
212+
# if the snap volume count is >0 then proceed
213+
if ($Snaps.Count -gt 0) {
214+
Foreach ($Snap in $Snaps) {
215+
# Mount the snapshot volume & resignature it
216+
$esxcli.storage.vmfs.snapshot.resignature.invoke(@{volumelabel=$($Snap.VolumeName)})
217+
}
218+
} else {
219+
# Exit the script, as no snapshots were found
220+
Write-Host "No Snapshot volumes found" -ForegroundColor Red
221+
exit
222+
}
223+
224+
# Rescan the HBAs to ensure that the datastore is visible and may be used
225+
Get-VMHostStorage -RescanAllHba -RescanVmfs -VMHost $VMhost | Out-Null
226+
227+
# Pause for a few seconds
228+
Start-Sleep -Seconds 5
229+
230+
# Get a list of all of the datastores on the host (including the new snapped datastore)
231+
$PostSnapDatastores = $VMhost | Get-Datastore
232+
233+
# Compare the pre/post datastore array variables to gather the name of the newly added datastore
234+
# This datastore will have a name like snap-32a052-old-volume-name
235+
$SnappedDatastore = (Compare-Object -ReferenceObject $PreSnapDatastores -DifferenceObject $PostSnapDatastores).InputObject
236+
237+
# Query the FlashArray to get the Snapped datastore's volume name
238+
$NewDatastoreVolume = Get-PfaVmfsVol -Datastore $SnappedDatastore -Flasharray $DefaultFlashArray
239+
240+
# Pause
241+
Start-Sleep -Seconds 5
242+
243+
# Retrieve the Target VM Folder Object
244+
$VMFolder = Get-Folder -Type VM -Name $TargetVmFolder
245+
246+
# Rename the datastore
247+
Set-Datastore -Datastore $SnappedDatastore -Name $($NewDatastoreVolume.Name)
248+
249+
# Register any .vmx found on the datastore in vSphere
250+
if ($RegisterVms -eq $true) {
251+
252+
# Search for .VMX Files in datastore
253+
$ds = Get-Datastore -Name $NewDatastoreVolume.Name | %{Get-View $_.Id}
254+
$SearchSpec = New-Object VMware.Vim.HostDatastoreBrowserSearchSpec
255+
$SearchSpec.matchpattern = "*.vmx"
256+
$dsBrowser = Get-View $ds.browser
257+
$DatastorePath = "[" + $ds.Summary.Name + "]"
258+
259+
# Find all .VMX file paths in Datastore variable and filters out .snapshot
260+
$SearchResults = $dsBrowser.SearchDatastoreSubFolders($DatastorePath,$SearchSpec) | Where-Object {$_.FolderPath -notmatch ".snapshot"} | %{$_.FolderPath + $_.File.Path}
261+
262+
# Register all .VMX files with vCenter
263+
$SearchResults | Foreach-Object {
264+
New-VM -VMFilePath $_ -VMHost $VMHost -Location $VMFolder -RunAsync -ErrorAction SilentlyContinue
265+
}
266+
}
267+
268+
# If we had to connect to vCenter, disconnect
269+
if ($ConnectTargetVc -eq $true) {
270+
# Disconnect from the Target vCenter Server and any others
271+
Disconnect-VIserver -Server $TargetVcenter -Confirm:$false
272+
}
273+
274+
# If we had to connect to FlashArray, disconnect
275+
if ($ConnectFA -eq $true) {
276+
# Disconnect from the Target FlashArray
277+
Disconnect-PfaArray -Array $DefaultFlashArray
278+
}

0 commit comments

Comments
 (0)