-
Notifications
You must be signed in to change notification settings - Fork 1
/
Sync-PvsLocalStore.ps1
218 lines (177 loc) · 5.67 KB
/
Sync-PvsLocalStore.ps1
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
<#
.NOTES
===========================================================================
Filename : Sync-PvsLocalStore.ps1
Created on : 2014-09-26
Updated on : 2019-02-07
Created by : Frank Peter Schultze
===========================================================================
This script needs to be run on a system where Citrix Provisiong Service's
command-line interface MCLI.exe is installed.
WARNING: This script leverages robocopy's MIR switch; meaning that it may
delete so called EXTRA files on the given member PVS server(s) that are not
present in the local vDisk store of the given master PVS server! Therefore,
this script makes only sense when you consequently use only one PVS server
for vDisk maintenance. You need to keep that in mind when using this script.
DISCLAIMER: This PowerShell module is provided "as is", without any warranty,
whether express or implied, of its accuracy, completeness, fitness for a
particular purpose, title or non-infringement, and none of the third-party
products or information mentioned in the work are authored, recommended,
supported or guaranteed by me. Further, I shall not be liable for any damages
you may sustain by using this module, whether direct, indirect, special,
incidental or consequential, even if it has been advised of the possibility
of such damages.
.SYNOPSIS
Sync local vDisk store from a master PVS server to member PVS servers except
for vDisks in maintenance mode.
.DESCRIPTION
Sync all vDisks within the local vDisk store of a master PVS server to the
local store of one or more member PVS servers with the exception of vDisks in
maintenance mode.
#>
[CmdletBinding()]
Param
(
# Identifies the designated master PVS server whose local vDisk store is considered the source
[Parameter(Mandatory=$true)]
[String]
$MasterServer,
# Identifies one ore more member PVS servers whose local vDisk store is considered the target
[Parameter(Mandatory=$true)]
[String[]]
$MemberServer,
# The path of the local vDisk store
[Parameter(Mandatory=$true)]
[String]
$StorePath,
# The name of on ore more vDisks to be synchronized
[Parameter(Mandatory=$true)]
[String[]]
$DiskName,
# The name of the PVS site
[Parameter(Mandatory=$true)]
[String]
$SiteName,
# The name of the PVS store
[Parameter(Mandatory=$true)]
[String]
$StoreName
)
#----------------------------------------------------------------------------------------
#region Helper functions
function ConvertTo-PvsObject
{
[CmdletBinding(SupportsShouldProcess=$False)]
Param
(
[Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true)]
$InputObject
)
Process
{
switch -regex ($InputObject)
{
'^Record\s#\d+$'
{
if ($record.Count)
{
New-Object PSObject -Property $record
}
$record = @{}
}
'^\s{4}(?<Name>\w+):\s(?<Value>.*)'
{
$record.Add($Matches.Name, $Matches.Value)
}
}
}
End
{
if ($record.Count)
{
New-Object PSObject -Property $record
}
}
}
function Get-PvsDiskVersion
{
Param
(
$DiskLocatorName,
$SiteName,
$StoreName,
$Type
)
$mcliParams = @(
'Get', 'DiskVersion', '/p',
"diskLocatorName=${DiskLocatorName}",
"siteName=${SiteName}",
"storeName=${StoreName}",
"type=${Type}"
)
$mcliOutput = & "${env:ProgramFiles}\Citrix\Provisioning Services\MCLI.EXE" @mcliParams
$mcliOutput | ConvertTo-PvsObject
}
#endregion
#----------------------------------------------------------------------------------------
#----------------------------------------------------------------------------------------
#region Initialize
Set-Variable -Name C_PVS_DISKTYPE_MAINTENANCE -Value '1' -Option ReadOnly
# SourcePath is on MasterServer
if ($MasterServer -eq $env:COMPUTERNAME)
{
$SourcePath = $StorePath
}
else
{
$SourcePath = '\\{0}\{1}' -f $MasterServer, $StorePath.Replace(':', '$')
}
# TargetPath is (are) on MemberServer(s)
$TargetPath = @()
$MemberServer |
Where-Object {$_ -ne $MasterServer} |
ForEach-Object {
if ($_ -eq $env:COMPUTERNAME)
{
$TargetPath += $StorePath
}
else
{
$TargetPath += '\\{0}\{1}' -f $_, $StorePath.Replace(':', '$')
}
}
#endregion
#----------------------------------------------------------------------------------------
#----------------------------------------------------------------------------------------
#region Main
foreach ($DiskLocatorName in $DiskName)
{
# Get vDisk maintenance version information (if any)
$Params = @{
DiskLocatorName = $DiskLocatorName
SiteName = $SiteName
StoreName = $StoreName
Type = $C_PVS_DISKTYPE_MAINTENANCE
}
$vDisk = Get-PvsDiskVersion @Params
# Exclude vDisk maintenance version from sync (if any)
if ($vDisk)
{
$MaintenanceBaseName = $vDisk.diskFileName -replace '\.avhd.*$', '.*'
$RobocopyExcludes = '*.lok', $MaintenanceBaseName
'Maintenance vDisk excluded from sync: {0}' -f $MaintenanceBaseName | Write-Verbose -Verbose
}
else
{
$RobocopyExcludes = '*.lok'
}
# Invoke robocopy for each MemberServer/TargetPath
$TargetPath |
ForEach-Object {
# Remove '/L' from the next command line in order to let robocopy actually copy and delete EXTRA files
$RobocopyParam = $SourcePath, $_, "${DiskLocatorName}*", '/L', '/MIR', '/R:1', '/W:1', '/XF', $RobocopyExcludes
& "${env:SystemRoot}\system32\robocopy.exe" @RobocopyParam
}
}
#endregion
#----------------------------------------------------------------------------------------