FSLogix on a Scale Out File Server – Backup Solution

here

see url Recently I’ve had the privalege of working with FSLogix Profile and 365 Containers to support user personalisation on Virtual Desktops. Whilst working with this solution I’ve gone through iterations of various storage solutions and recently landed (with a little help on the design areas) on a Scales-Out-File-Server (SOFS). The SOFS allow us to host files that are meant to be continuously available.

Questo perché in quel momento RSI si trova in una zona di ipercomprato sopra 80 http://www.mcmp.cz/biorefre/3587 e ipervenduto sotto i 20.. , cashback, This setup is hosted in Azure so I’m providing a reference to an article I found when running through this setup, I will aim to provide a full blog on deploying FSLogix on a Virtual Desktop using SOFS as storage later on this year. Time is a little short now.

mujer busca hombre en lujan bs as Microsoft’s Implementation Guide for SOFS:
https://docs.microsoft.com/en-us/windows-server/remote/remote-desktop-services/rds-storage-spaces-direct-deployment

ATTENZIONE! http://modernhomesleamington.co.uk/component/k2/itemlist/user/21941?format=feedption - Dunque è una truffa? Si tratta di un broker sicuro ed affidabile o è una truffa? Leggi prima di Iscriverti! During the implementation approach and reviewing all the operational consideration on SOFS I quickly realised there is next to no information on backup solutions. Microsoft’s own Data Protection Manager doesn’t backup the files on the SOFS, well… of course not. They are continuously available; we come to the root of the reason for this post.

I wrote a script to copy the contents of VHD files over night during server reboot windows. The contents are copied to a separate server with Volume shadow copies enabled and then this server is the actual backup target for DPM.

click here Prerequisites:

  • A D3 Series machine in Azure or you cannot install the Hyper-V role
  • Permissions on your VHD files so that a user/service account can access them
  • Separate server/storage as a backup location or a backup location

pub site de rencontre 2015 The Script Process:

  • Mounts a drive (Y:) to the fslogix file share
  • Creates a list of all folders in fslogix share
  • Loops through each folder and gets a list of vhds in the folder
    • Mounts each vhd in a folder (MountFolder) and copys the contents excluding system volume information and .ost files
    • Runs through the removal files text document and loops through each line searching for a folder / file inside the vhd and if found removes it
    • Optimises the vhd to shrink it if possible
    • Unmounts the VHD
  • Deletes the mount folder
  • Loops back around to the next vhd

http://www.ribo.co.at/deniro/7318 The Script Variables and Parts that need changing:

  • Line 56 – Change the path for the log file
  • Line 116 – Drive letter for the mapped drive
  • Line 121 – Root share location for all the FSLogix folders
  • Line 126 – Backup location for the VHD contents
  • Line 131 – Folder which will be created to host the contents of a VHD for backup
  • Line 136 – Robocopy Log folder
  • Line 146 – Removal list file, all entries must be relative to the VHD root
  • Line 150 – Number of hours you want the script to run for from the time the scheduled tasks runs

The script also writes to the EventLog on the machine it is running on so that Monitoring solution can feedback on backup results and then logs can be reviewed.

half life motrin 800 mg Event Log IDs:

  • Event ID 9000 – VHD in use and will be skipped – Warning
  • Event ID 9001 – VHD shrink failed, there was a problem – Warning
  • Event ID 9999 – VHD Mountfolder is still writeable even after a dismount, script execution will stop – Error

kosten pariet 20mg Scheduled Task Settings:

  • RunAs – FSLogix Service Account (With access to VHD’s)
  • Timed Trigger – Daily at 01:00
  • Action
    • Program – powershell.exe
    • Arguments – -ExecutionPolicy Unrestricted -NonInteractive -NoProfile -File “<Path To>\FSLogix Backup Script.ps1”

buy cheap micardis online FileRemoval.txt Usage:

  • Profile\Desktop\File.txt – Removes file.txt from the profile disk when the like is located on the desktop
  • ODFC\OneDrive\User\File.txt – Removes file.txt from the office disk when the like is located in the OneDrive folder
  • ODFC\OneDrive\User\Attachments– Removes the entrie Attachments folder from the office VHD located in the OneDrive folder

The Source Code (Zip file for download http://chennaitrekkers.org/wp-json/oembed/1.0/embed?url=http://chennaitrekkers.org/2009/04/trek-on-tracks-sakleshpur-march-27-28/ here):

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
#Checks for a file lock
function checkFileStatus($filePath) {
$fileInfo = New-Object System.IO.FileInfo $filePath
try
{
   $fileStream = $fileInfo.Open( [System.IO.FileMode]::Open, [System.IO.FileAccess]::Read, [System.IO.FileShare]::Read )
   $filestream.Close()
   return $false
} catch {
    return $true
}
}
#Gets user ID from Folder Path
Function GetUid($uidString) {
$uidStart = $uidString.LastIndexOf("_")
$userID = $uidString.Substring($uidStart+1)
return $userID
}
#Gets the type of VHD from the name of the VHD file
Function GetVhdType($vhdString) {
$vhdTypeFinish = $vhdString.IndexOf("_")
$vhdType = $vhdString.Substring(0,$vhdTypeFinish)
return $vhdType
}
#Function to write a log file out
######CHANGE LOCATION OF LOGFILE BELOW######
function Write-Log
{
[CmdletBinding()]
Param
(
    [Parameter(Mandatory=$true,
       ValueFromPipelineByPropertyName=$true)]
    [ValidateNotNullOrEmpty()]
    [Alias("LogContent")]
    [string]$Message,
[Parameter(Mandatory=$false)]
    [ValidateSet("Error","Warn","Info")]
    [string]$Level="Info",
    [Parameter(Mandatory=$false)]
    [switch]$NoClobber
)
Begin
{
    # Set VerbosePreference to Continue so that verbose messages are displayed.
    $VerbosePreference = 'Continue'
    #Set the log location and Append the date to the migration log file
    $FormattedDate = Get-Date -Format "yyyy-MM-dd"
    $Path = "Drive:\Folder\Log\VHD_Backup" + "_" + $FormattedDate + ".log"
}
Process
{
    # If the file already exists and NoClobber was specified, do not write to the log.
    if ((Test-Path $Path) -AND $NoClobber) {
Write-Error "Log file $Path already exists, and you specified NoClobber. Either delete the file or specify a different name."
Return
}
    # If attempting to write to a log file in a folder/path that doesn't exist create the file including the path.
    elseif (!(Test-Path $Path)) {
Write-Verbose "Creating $Path."
$NewLogFile = New-Item $Path -Force -ItemType File
}
    else {
# Nothing to see here yet.
}  
# Write message to error, warning, or verbose pipeline and specify $LevelText
    switch ($Level) {
'Error' {
    Write-Error $Message
    $LevelText = 'ERROR:'
    }
'Warn' {
    Write-Warning $Message
    $LevelText = 'WARNING:'
    }
'Info' {
    Write-Verbose $Message
    $LevelText = 'INFO:'
    }
}
# Write log entry to $Path
    $timeStamp = Get-Date -Format o | foreach {$_ -replace ":", "."}
    "$timeStamp $LevelText $Message" | Out-File -FilePath $Path -Append
}
End
{
}
}
#Script Execution Started
Write-Log "##########Script Execution Started##########" -Verbose -Level Info

##########################Functions preloaded at the top of the script##########################
#Get the time as the script starts to run and add x amount of hours to set the time limit
$now = Get-Date
#Get the date time for the log
$FormattedDate = Get-Date -Format "yyyy-MM-dd"
############CHANGE ME############
#Network Drive Letter
$networkLetter = "X"
Write-Log "Network Drive Letter - $networkLetter" -Verbose -Level Info
############CHANGE ME############
#Location for VHD Files
$vhdLocation = "\\server\share"
Write-Log "Location for VHD Files - $vhdLocation" -Verbose -Level Info
############CHANGE ME############
#Backup Location
$backupLocation = "drive:\folder"
Write-Log "Location for VHD Backups - $backupLocation" -Verbose -Level Info
############CHANGE ME############
#Mount Folder for VHD
$mountFolder = "drive:\folder"
Write-Log "VHD Mount Folder - $mountFolder" -Verbose -Level Info
############CHANGE ME############
#Robocopy log location
$robocopyLog = "Drive:\Folder\Log\RoboCopy"
$origRoboCopyLog = $robocopyLog
Write-Log "Robocopy log folder - $robocopyLog" -Verbose -Level Info
#Add custom Windows EventLog Source
if (-not (Get-EventLog -LogName "Application" -Source "FSLogix Backup Script" -Newest 1)) {
New-EventLog -LogName "Application" -Source "FSLogix Backup Script"
}
############CHANGE ME############
#File and Folder Removal List
$removalList = "Drive:\Folder\RemovalList.txt"
############CHANGE ME############
#Get the time at script start and add 5 hours
$limit = Get-Date($now).AddHours(5)
#Map a network drive to use as the location
try {
if (Test-Path "$networkLetter`:") {
    Get-PSDrive $networkLetter | Remove-PSDrive -Force
    net use "$networkLetter`:" /delete
    New-PSDrive –Name $networkLetter –PSProvider FileSystem –Root $vhdLocation –Persist
    Write-Log "Network drive already in use, attempting removal and remapping" -Verbose -Level Error
}
New-PSDrive –Name $networkLetter –PSProvider FileSystem –Root $vhdLocation –Persist
} catch [System.Management.Automation.ParameterBindingException]{
$ErrorMessage = $_.Exception.Message
$ErrorMessage
Write-Log "Network drive not mounted" -Verbose -Level Error
Write-Log  $ErrorMessage -Level Error
Break
}
#Check network drive mapped properly
 if (-not (Test-Path "Y:")) {
    Write-Log "Network drive not mounted, script stopped" -Verbose -Level Error
    Exit
} else {
Write-Log "Network drive mapped successfully" -Verbose -Level Info
}
#Get all folders in the FSLogix folder
$folderItems = Get-ChildItem -Path "$networkLetter`:" -Recurse | ?{ $_.PSIsContainer }
#For each folder, loop through and find all VHD files and perform tasks
foreach ($folderItem in $folderItems) {
#Get userID from folder name
$userID = GetUid($folderItem.Name)
Write-Log "Beginning backup process for user - $userID" -Level Info
$vhds = Get-ChildItem "$networkLetter`:\$folderItem" -Recurse -Include *.vhdx
#Loop through each VHD found
:vhdloop foreach ($vhd in $vhds) {
#Check if the time is ok, exit the script if its 5 hours after start time (1:30AM)
$current = Get-Date
if ($current -ge $limit) {
    Write-Log "The time is $current and the limit was $limit so the script is exiting" -Level Info
    Write-Log "######Script ended on time limited######" -Level Info
    Start-Sleep -s 20
    [Environment]::Exit(1)
}
#Test the VHD to see if it is locked
$vhdPath = $vhd.FullName
$locked = checkFileStatus -filePath $vhdPath
#If the file is locked, skip it
if ($locked -eq $true) {
    Write-Log "$UserID VHD file in use - skipping $vhdPath" -Level Error
    Write-EventLog -LogName "Application" -Source "FSLogix Backup Script" -EventID 9000 -EntryType Warning -Message "$UserID VHD file in use - skipping $vhdPath"                      
    #Jumps back to the top of the loop skipping this vhd file
    continue
}

            #Get the type of VHD
$vhdType = GetVhdType($vhd.Name)
Write-Log "Beginning backup process for VHD Type - $vhdType - $userID" -Level Info
#Create the mountpoint folder access path
mkdir $mountFolder
#Mount the VHD and get back the drive letter
$mountPoint=Mount-VHD $vhd -Passthru -Verbose | Get-Disk | Get-Partition | Add-PartitionAccessPath -AccessPath $mountFolder -PassThru -Verbose | get-volume | select *        
#Create the backup folder for the user
if (-Not (Test-Path "$backupLocation\$userID\$vhdType")) {
    New-Item -ItemType directory -Path "$backupLocation\$userID\$vhdType"
}            
#Set the robocopy log folder per user
$robocopyLog = $robocopyLog + $userID + "_" + $vhdType + ".log"
#Robocopy excluding the OST file and exluding the System Volume Information Folder
robocopy $mountFolder "$backupLocation\$userID\$vhdType" /XO /XF *.ost /XD "System Volume Information" /E /W:0 /R:0 /MT:100 /LOG:$robocopyLog
#Run through a text file to delete folders and files from the VHD files
foreach($line in Get-Content $removalList) {
    $filePath = $mountFolder + "" + $line
    if (Test-Path $filePath) {
        Remove-Item -Path "$filePath" -Recurse -Force
        Write-Log "Remove the following file/folder from $userId $vhdType VHD - $filePath" -Level Info
    }
}
    #Remove Drive Letter from the mounted VHD
Get-Volume -FilePath $vhd | Get-Partition | Remove-PartitionAccessPath -accesspath $mountFolder -Verbose
#Log that disk backup is complete
Write-Log "Finished backup process for VHD Type - $vhdType" -Level Info
#Give the Storage Sub-System time to catch up
Start-Sleep -Seconds 2
#Starting VHD shrink cycle
#Get VHD size before
$sizeBefore = [math]::Round((gi $vhd | select -expand length)/1mb,2)
try {
Optimize-VHD $vhd -Mode Full -ErrorAction SilentlyContinue  
#Get VHD size after
$sizeAfter = [math]::Round((gi $vhd | select -expand length)/1mb,2)
Write-Log "The VHD was successfully shrunk Before Size - $sizeBefore | After Size - $sizeAfter" -Level Info          
} catch {
    Write-Log "There was an error shrinking VHD - $vhdPath, this VHD will not be shrunk" -Level Warn
    Write-EventLog -LogName "Application" -Source "FSLogix Backup Script" -EventID 9001 -EntryType Warning -Message "There was an error shrinking VHD - $vhdPath, this VHD will not be shrunk"                      
}        
#Dismount the VHD
Dismount-VHD -Path $vhd -Passthru -Verbose
#Test and Remove the mount folder
$directoryInfo = Get-ChildItem $mountFolder | Measure-Object
$directoryInfo.count #Returns the count of all of the files in the directory
If ($directoryInfo.count -eq 0) {                            
        Remove-Item $mountFolder -Recurse -Force
} else {
        Write-Log "Files still exist in the mountFolder, Script exiting, possible risk to overwrite VHD contents, $userID VHD file type $vhdType still potentially mounted" -Level Error
        Write-EventLog -LogName "Application" -Source "FSLogix Backup Script" -EventID 9999 -EntryType Error -Message "Files still exist in the mountFolder, Script exiting, possible risk to overwrite VHD contents, $userID VHD file type $vhdType still potentially mounted"
        Exit
}                                      
#Give the storage sub-system a second to catch up
Start-Sleep -Seconds 2
#Empty Varibales within loop and move to the next VHD
$vhdLetter = $null
$mountPoint = $null
$robocopyLog = $origRoboCopyLog
}
}
#Test and Remove the mount folder                      
If (Test-Path $mountFolder) {
Remove-Item $mountFolder -Recurse -Force
Write-Log "Removed Mount Folder as it was still existing" -Verbose -Level Info
}
Write-Log "##########Script Execution Finished##########" -Verbose -Level Info

5 thoughts on “FSLogix on a Scale Out File Server – Backup Solution”

  1. Hi Lee,

    The inbuilt “Windows Server Backup” (WSB) feature of Windows Server 2016 is capable of backing up the SOFS data via the C:\ClusterStorage\VolumeX\* paths on all the cluster nodes.
    WSB supports VSS Full and Copy Backup methods and therefore open files are handled.
    WSB supports the ReFS file systems for the SOFS Cluster Shared Volume and the back destination can be a Remote shared folder or a server local path.

    1. Hi Brett, thanks for the steer here. This particular case is in Azure so I was looking at using azure backup, it didn’t work so well. I also tried WSB but it failed more often than not. The script is still in play at present as once it’s done the initial seed it’s pretty quick.

  2. In a typical redirected folders scenario, where a user s files reside on a network share there occurs a situation such as at the beginning of the workday or just after lunch when all of the users attempt to logon at once. This run on the bank can create delays for the user while the file server attempts to service their request. In a typical redirected folders scenario, Windows must open each file on the desktop in order to extract the file name and icon. Because file opens are handled synchronously a server can quickly succumb to the stress of trying to handle all of the file open requests.

Leave a Reply

Your email address will not be published. Required fields are marked *