############################################################### # # Scriptname: ReplicatePVSStoresV2.ps1 # # Autor: Urs Heeb # Date: 30.11.2022 # # Version: 2022.11.01 /30.11.22 / Urs Heeb # Create script # Version: 2022.12.01 /09.12.22 / Urs Heeb # Replace static Store choice by a dynamic # Modified the output # # # Description: Script does following: # Check on which PVS it runs # Let the admin choose which Store should be replicated # Let the admin choose if all or just a selected vDisk should be replicated # # # Requirements: # Read/Write permissions on source/destination # Existing PVS PowerShell module # Maximum of 5 vDisk stores to choose # Maximum of 5 dedicated vDisks to choose # ############################################################### # Script variables $PVS01 = "pvs01.domain.pit" $PVS02 = "pvs02.domain.pit" $PVSModulePath = "C:\Program Files\Citrix\Provisioning Services Console\Citrix.PVS.SnapIn.dll" # Load PVS PowerShell module Import-Module $PVSModulePath # Enumerate the local and the remote PVS $PVSLocal = $env:COMPUTERNAME + ".domain.pit" If ($PVSLocal -eq $PVS01) { $PVSRemote = $PVS02 } Else { $PVSRemote = $PVS01 } # UI Clear-Host Write-Host " " Write-Host " " Write-Host "***********************************************" Write-Host "** " Write-Host "** PVS vDisk replication" Write-Host "** " Write-Host "** vDisk stores will be enumerated and" Write-Host "** get ready for your choice" Write-Host "** " Write-Host "***********************************************" Write-Host " " # Get PVS vDisk stores from PVS configuration # Create an array for later use $Stores = Get-PvsStore $StoreArray = $null $StoreArray = @() $StoreID = 0 ForEach ($Store in $Stores){ $StoreID = $StoreID +1 $SplitChar = $Store.Path.IndexOf(":") $StoreDisk = $Store.Path.Substring(0,$SplitChar) $StorePath = $Store.Path.Substring($SplitChar+1) $StoreName = $Store.StoreName $StoreArray += [pscustomobject]@{StoreID=$StoreID;Store=$StoreName;StoreDisk=$StoreDisk;StorePath=$StorePath;StoreDescription=$Store.Description} } # Prompt for Store choice $StoreTitle = "PVS vDisk stores" $StoreMessage = "Chose the store to replicate:" $CancelAll = New-Object System.Management.Automation.Host.ChoiceDescription "&Cancel", "Skip this operation and all subsequent operations." # Generate choice output of each vDisk store to replicate $StoreOptionCount = 0 ForEach ($Store2 in $StoreArray) { $StoreOptionCount = $StoreOptionCount + 1 $ChoiceID = $Store2.StoreID $ChoiceStore = $Store2.Store $ChoiceHelp = $Store2.StoreDescription $ChoiceCmd = New-Object System.Management.Automation.Host.ChoiceDescription "&$ChoiceID $ChoiceStore", $ChoiceHelp New-Variable "StoreOption$ChoiceID" $ChoiceCmd } # Generate $StoreOptions variable for final choice output depending on the amount of options Switch ($StoreOptionCount) { 0 {$StoreOptions = [System.Management.Automation.Host.ChoiceDescription[]]($CancelAll)} 1 {$StoreOptions = [System.Management.Automation.Host.ChoiceDescription[]]($CancelAll, $StoreOption1)} 2 {$StoreOptions = [System.Management.Automation.Host.ChoiceDescription[]]($CancelAll, $StoreOption1, $StoreOption2)} 3 {$StoreOptions = [System.Management.Automation.Host.ChoiceDescription[]]($CancelAll, $StoreOption1, $StoreOption2, $StoreOption3)} 4 {$StoreOptions = [System.Management.Automation.Host.ChoiceDescription[]]($CancelAll, $StoreOption1, $StoreOption2, $StoreOption3, $StoreOption4)} 5 {$StoreOptions = [System.Management.Automation.Host.ChoiceDescription[]]($CancelAll, $StoreOption1, $StoreOption2, $StoreOption3, $StoreOption4, $StoreOption5)} } $Store2Replicate=$host.ui.PromptForChoice($StoreTitle, $StoreMessage, $StoreOptions, 0) # Prepare variables after the user entry If ($Store2Replicate -eq 0) { # Cancel all return; break } Else { $IDStore = $Store2Replicate-1 $StoreDisk = $StoreArray[$IDStore].StoreDisk $StorePath = $StoreArray[$IDStore].StorePath $LocalStore = $StoreDisk + ":" + $StorePath + "\" $RemoteStore = "\\" + $PVSRemote + "\" + $StoreDisk + "$" + $StorePath + "\" $LocalStorePath = $LocalStore + "*" $RemoteStorePath = $RemoteStore + "*" } # Compare servers $LocalStoreContent = Get-ChildItem -Path $LocalStorePath -Exclude WriteCache,*.lok,*.i.vhdx $RemoteStoreContent = Get-ChildItem -Path $RemoteStorePath -Exclude WriteCache,*.lok,*.i.vhdx $StoreDiff = Compare-Object -ReferenceObject $LocalStoreContent -DifferenceObject $RemoteStoreContent -Property Name, LastWriteTime # Enumerate a list of vDisks # Create an array with all disk names $DiskArray = $null $DiskArray = @() $DiskID = 1 ForEach ($File in $StoreDiff) { If ($File.SideIndicator -eq "<="){ $Filename = $File.Name If ($Filename -like "*.vhd*") { $DiskID = $DiskID+1 $SplitChar = $Filename.IndexOf(".") $DiskName = $Filename.Substring(0, $SplitChar) $PVPName = $DiskName + ".pvp" $DiskArray += [pscustomobject]@{DiskID=$DiskID;vDisk=$Filename;vDiskName=$DiskName;PVPName=$PVPName} } } } # UI Clear-Host Write-Host " " Write-Host " " Write-Host "***********************************************" Write-Host "** " Write-Host "** PVS vDisk replication" Write-Host "** " Write-Host "** vDisks will be enumerated and" Write-Host "** get ready for your choice" Write-Host "** " Write-Host "***********************************************" Write-Host " " # Prompt for replication choice $ReplTitle = "vDisk replication" $ReplMessage = "Choose what to replicate" $vDiskAll = New-Object System.Management.Automation.Host.ChoiceDescription "&All vDisks","Continue with all vDisks." $CancelAll = New-Object System.Management.Automation.Host.ChoiceDescription "&Cancel", "Skip this operation and all subsequent operations." # Generate choice output of each vDisk to replicate $ReplOptionCount = 0 ForEach ($vDisk in $DiskArray) { $ReplOptionCount = $ReplOptionCount +1 $ChoiceID = $vDisk.DiskID $ChoiceDisk = $vDisk.vDiskName $ChoiceCmd = New-Object System.Management.Automation.Host.ChoiceDescription "&$ChoiceID $ChoiceDisk", "Replicate selected vDisk." New-Variable "ReplOption$ChoiceID" $ChoiceCmd } # Generate $ReplOptions variable for final choice output depending on the amount of options Switch ($ReplOptionCount) { 0 {$ReplOptions = [System.Management.Automation.Host.ChoiceDescription[]]($vDiskAll, $CancelAll)} 1 {$ReplOptions = [System.Management.Automation.Host.ChoiceDescription[]]($vDiskAll, $CancelAll, $ReplOption2)} 2 {$ReplOptions = [System.Management.Automation.Host.ChoiceDescription[]]($vDiskAll, $CancelAll, $ReplOption2, $ReplOption3)} 3 {$ReplOptions = [System.Management.Automation.Host.ChoiceDescription[]]($vDiskAll, $CancelAll, $ReplOption2, $ReplOption3, $ReplOption4)} 4 {$ReplOptions = [System.Management.Automation.Host.ChoiceDescription[]]($vDiskAll, $CancelAll, $ReplOption2, $ReplOption3, $ReplOption4, $ReplOption5)} 5 {$ReplOptions = [System.Management.Automation.Host.ChoiceDescription[]]($vDiskAll, $CancelAll, $ReplOption2, $ReplOption3, $ReplOption4, $ReplOption5, $ReplOption6)} } $vDisk2Replicate=$host.ui.PromptForChoice($ReplTitle, $ReplMessage, $ReplOptions, 0) If ($vDisk2Replicate -eq 0) { # Copy all found vDisks and PVP files ForEach ($Disk in $DiskArray) { $SourcevDisk = $null $SourcePVP = $null $DestvDisk = $null $DestPVP = $null $vDiskFile = $Disk.vDisk $PVPFile = $Disk.PVPName $SourcevDisk = $LocalStore + $vDiskFile $SourcePVP = $LocalStore + $PVPFile $DestvDisk = $RemoteStore + $vDiskFile $DestPVP = $RemoteStore + $PVPFile Copy-Item $SourcevDisk -Destination $DestvDisk Copy-Item $SourcePVP -Destination $DestPVP } } ElseIf ($vDisk2Replicate -eq 1) { # Cancel all return; break } Else { # Copy the selected vDisk # ID has to be reduced by 2 to match the array IDs $SourceID = $vDisk2Replicate - 2 $SourcevDisk = $null $SourcePVP = $null $DestvDisk = $null $DestPVP = $null $vDiskFile = $DiskArray[$SourceID].vDisk $PVPFile = $DiskArray[$SourceID].PVPName $SourcevDisk = $LocalStore + $vDiskFile $SourcePVP = $LocalStore + $PVPFile $DestvDisk = $RemoteStore + $vDiskFile $DestPVP = $RemoteStore + $PVPFile Copy-Item $SourcevDisk -Destination $DestvDisk Copy-Item $SourcePVP -Destination $DestPVP }