Advertisement
henrydenhengst

Migrate MachineCatalog

May 26th, 2015
550
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. Set-StrictMode -Version 2
  2.  
  3. Add-PSSnapin Citrix*
  4.  
  5. function New-MachineCatalog {
  6.     <#
  7.     .SYNOPSIS
  8.     Creates a new catalog
  9.     .PARAMETER Name
  10.     Name of the new catalog
  11.     .PARAMETER Description
  12.     Description of the new catalog
  13.     .PARAMETER AllocationType
  14.     Allocation type of the catalog
  15.     .PARAMETER ProvisioningType
  16.     Provisioning type of the catalog
  17.     .PARAMETER PersistUserChanges
  18.     Whether and how to persist user changes
  19.     .PARAMETER SessionSupport
  20.     How many sessions are permitted
  21.     .PARAMETER CatalogParams
  22.     Hash of settings for new broker catalog
  23.     .PARAMETER MasterImageVM
  24.     Path to master image
  25.     .PARAMETER CpuCount
  26.     Number of vCPUs for virtual machines
  27.     .PARAMETER MemoryMB
  28.     Memory in MB for virtual machines
  29.     .PARAMETER CleanOnBoot
  30.     Whether to discard changes on boot
  31.     .PARAMETER UsePersonalVDiskStorage
  32.     Whether to use Personal vDisk
  33.     .PARAMETER NamingScheme
  34.     Naming scheme for new virtual machines
  35.     .PARAMETER NamingSchemeType
  36.     Type of naming scheme
  37.     .PARAMETER OU
  38.     Organizational unit for new virtual machines
  39.     .PARAMETER Domain
  40.     Domain for new virtual machines
  41.     .PARAMETER HostingUnitName
  42.     Hosting connection to use
  43.     .PARAMETER Suffix
  44.     Suffix to be added to name of the catalog
  45.     .EXAMPLE
  46.     Get-BrokerCatalog | ConvertFrom-MachineCatalog | New-MachineCatalog -Suffix '-test'
  47.     .LINK
  48.     ConvertFrom-MachineCatalog
  49.     Export-MachineCatalog
  50.     Sync-MachineCatalog
  51.     Update-DeliveryGroup
  52.     .NOTES
  53.     Thanks to Aaron Parker (@stealthpuppy) for the original code (http://stealthpuppy.com/xendesktop-mcs-machine-catalog-powershell/)
  54.     #>
  55.     [CmdletBinding()]
  56.     param(
  57.         [Parameter(Mandatory=$True,HelpMessage='Name of the new catalog',ParameterSetName='Explicit')]
  58.         [Parameter(Mandatory=$True,HelpMessage='Name of the new catalog',ParameterSetName='Explicit2')]
  59.         [ValidateNotNullOrEmpty()]
  60.         [string]
  61.         $Name
  62.         ,
  63.         [Parameter(Mandatory=$False,HelpMessage='Description of the new catalog',ParameterSetName='Explicit')]
  64.         [Parameter(Mandatory=$False,HelpMessage='Description of the new catalog',ParameterSetName='Explicit2')]
  65.         [ValidateNotNullOrEmpty()]
  66.         [string]
  67.         $Description
  68.         ,
  69.         [Parameter(Mandatory=$True,HelpMessage='Allocation type of the catalog',ParameterSetName='Explicit')]
  70.         [Parameter(Mandatory=$True,HelpMessage='Allocation type of the catalog',ParameterSetName='Explicit2')]
  71.         [ValidateSet('Static','Permanent','Random')]
  72.         [string]
  73.         $AllocationType
  74.         ,
  75.         [Parameter(Mandatory=$True,HelpMessage='Provisioning type of the catalog',ParameterSetName='Explicit')]
  76.         [Parameter(Mandatory=$True,HelpMessage='Provisioning type of the catalog',ParameterSetName='Explicit2')]
  77.         [ValidateSet('Manual','PVS','MCS')]
  78.         [string]
  79.         $ProvisioningType
  80.         ,
  81.         [Parameter(Mandatory=$True,HelpMessage='Whether and how to persist user changes',ParameterSetName='Explicit')]
  82.         [Parameter(Mandatory=$True,HelpMessage='Whether and how to persist user changes',ParameterSetName='Explicit2')]
  83.         [ValidateSet('OnLocal','Discard','OnPvd')]
  84.         [string]
  85.         $PersistUserChanges
  86.         ,
  87.         [Parameter(Mandatory=$True,HelpMessage='How many sessions are permitted',ParameterSetName='Explicit')]
  88.         [Parameter(Mandatory=$True,HelpMessage='How many sessions are permitted',ParameterSetName='Explicit2')]
  89.         [ValidateSet('SingleSession','MultiSession')]
  90.         [string]
  91.         $SessionSupport
  92.         ,
  93.         [Parameter(Mandatory=$False,HelpMessage='Name of the new catalog',ParameterSetName='Explicit2')]
  94.         [ValidateNotNullOrEmpty()]
  95.         [bool]
  96.         $MachinesArePhysical = $False
  97.         ,
  98.         [Parameter(Mandatory=$True,HelpMessage='Path to master image',ParameterSetName='Explicit')]
  99.         [ValidateNotNullOrEmpty()]
  100.         [string]
  101.         $MasterImageVM
  102.         ,
  103.         [Parameter(Mandatory=$True,HelpMessage='Number of vCPUs for virtual machines',ParameterSetName='Explicit')]
  104.         [ValidateNotNullOrEmpty()]
  105.         [int]
  106.         $CpuCount
  107.         ,
  108.         [Parameter(Mandatory=$True,HelpMessage='Memory in MB for virtual machines',ParameterSetName='Explicit')]
  109.         [ValidateNotNullOrEmpty()]
  110.         [int]
  111.         $MemoryMB
  112.         ,
  113.         [Parameter(Mandatory=$True,HelpMessage='Whether to discard changes on boot',ParameterSetName='Explicit')]
  114.         [ValidateNotNullOrEmpty()]
  115.         [bool]
  116.         $CleanOnBoot
  117.         ,
  118.         [Parameter(Mandatory=$False,HelpMessage='Whether to use Personal vDisk',ParameterSetName='Explicit')]
  119.         [ValidateNotNullOrEmpty()]
  120.         [bool]
  121.         $UsePersonalVDiskStorage = $False
  122.         ,
  123.         [Parameter(Mandatory=$True,HelpMessage='Naming scheme for new virtual machines',ParameterSetName='Explicit')]
  124.         [ValidateNotNullOrEmpty()]
  125.         [string]
  126.         $NamingScheme
  127.         ,
  128.         [Parameter(Mandatory=$True,HelpMessage='Type of naming scheme',ParameterSetName='Explicit')]
  129.         [ValidateSet('Numeric','Alphabetic')]
  130.         [string]
  131.         $NamingSchemeType
  132.         ,
  133.         [Parameter(Mandatory=$True,HelpMessage='Organizational unit for new virtual machines',ParameterSetName='Explicit')]
  134.         [ValidateNotNullOrEmpty()]
  135.         [string]
  136.         $OU
  137.         ,
  138.         [Parameter(Mandatory=$True,HelpMessage='Domain for new virtual machines',ParameterSetName='Explicit')]
  139.         [ValidateNotNullOrEmpty()]
  140.         [string]
  141.         $Domain
  142.         ,
  143.         [Parameter(Mandatory=$True,HelpMessage='Hosting connection to use',ParameterSetName='Explicit')]
  144.         [ValidateNotNullOrEmpty()]
  145.         [string]
  146.         $HostingUnitName
  147.         ,
  148.         [Parameter(Mandatory=$True,HelpMessage='Collection of catalogs to be duplicated',ParameterSetName='CreateCatalogFromParam',ValueFromPipeline=$True)]
  149.         [ValidateNotNullOrEmpty()]
  150.         [psobject[]]
  151.         $CatalogParams
  152.         ,
  153.         [Parameter(Mandatory=$False,HelpMessage='Suffix to be added to name of the catalog',ParameterSetName='CreateCatalogFromParam')]
  154.         [ValidateNotNullOrEmpty()]
  155.         [string]
  156.         $Suffix = ''
  157.     )
  158.  
  159.     Begin {
  160.         Write-Debug ('[{0}] Process' -f $MyInvocation.MyCommand)
  161.     }
  162.  
  163.     Process {
  164.         if ($CatalogParams) {
  165.             foreach ($Catalog in $CatalogParams) {
  166.                 $Catalog.Name += $Suffix
  167.  
  168.                 if ($Catalog.ProvisioningType -like 'manual') {
  169.                     Write-Verbose ('[{0}] Calling recursively to create catalog with name {1} and provisioning type manual' -f $MyInvocation.MyCommand, $Catalog.Name)
  170.                     New-MachineCatalog -Name $Catalog.Name -AllocationType $Catalog.AllocationType -ProvisioningType $Catalog.ProvisioningType -PersistUserChanges $Catalog.PersistUserChanges -SessionSupport $Catalog.SessionSupport
  171.                     if ($Catalog.Description) { Set-BrokerCatalog -Name $Catalog.Name -Description $Catalog.Description }
  172.  
  173.                 } else {
  174.                     $Catalog.CleanOnBoot = $Catalog.CleanOnBoot -eq 'True'
  175.                     Write-Verbose ('[{0}] Calling recursively to create catalog with name {1} with provisioning scheme' -f $MyInvocation.MyCommand, $Catalog.Name)
  176.                     New-MachineCatalog `
  177.                         -Name $Catalog.Name -Description $Catalog.Description -AllocationType $Catalog.AllocationType -ProvisioningType $Catalog.ProvisioningType -PersistUserChanges $Catalog.PersistUserChanges -SessionSupport $Catalog.SessionSupport `
  178.                         -Domain $Catalog.Domain -OU $Catalog.OU -NamingScheme $Catalog.NamingScheme -NamingSchemeType $Catalog.NamingSchemeType `
  179.                         -MasterImageVM $Catalog.MasterImageVM -CpuCount $Catalog.CpuCount -MemoryMB $Catalog.MemoryMB -CleanOnBoot $Catalog.CleanOnBoot `
  180.                         -HostingUnitName $Catalog.HostingUnitName
  181.                 }
  182.             }
  183.  
  184.         } else {
  185.             if (Get-BrokerCatalog -Name $Name -Verbose:$False -ErrorAction SilentlyContinue) {
  186.                 throw ('[{0}] Broker catalog with name {1} already exists. Aborting.' -f $MyInvocation.MyCommand, $Name)
  187.             }
  188.             Write-Verbose ('[{0}] Creating broker catalog with name {1}' -f $MyInvocation.MyCommand, $Name)
  189.             if (-Not $Description) {
  190.                 $Description = $Name
  191.             }
  192.             $NewBrokerCatalog = New-BrokerCatalog -Name $Name -Description $Description -AllocationType $AllocationType -ProvisioningType $ProvisioningType -PersistUserChanges $PersistUserChanges -SessionSupport $SessionSupport -MachinesArePhysical $MachinesArePhysical -Verbose:$False
  193.  
  194.             if ($ProvisioningType -like 'manual') {
  195.                 Write-Verbose ('[{0}] Broker catalog named {1} does not need a provisioning scheme' -f $MyInvocation.MyCommand, $Name)
  196.                 continue
  197.             }
  198.            
  199.             if (Get-AcctIdentityPool -IdentityPoolName $Name -Verbose:$False -ErrorAction SilentlyContinue) {
  200.                 throw ('[{0}] Account identity pool with name {1} already exists. Aborting.' -f $MyInvocation.MyCommand, $Name)
  201.             }
  202.             Write-Verbose ('[{0}] Creating account identity pool with name {1}' -f $MyInvocation.MyCommand, $Name)
  203.             $NewAcctIdentityPool = New-AcctIdentityPool -Domain $Domain -IdentityPoolName $Name -NamingScheme $NamingScheme -NamingSchemeType $NamingSchemeType -OU $OU -Verbose:$False
  204.             Set-BrokerCatalogMetadata -CatalogId $NewBrokerCatalog.Uid -Name 'Citrix_DesktopStudio_IdentityPoolUid' -Value ([guid]::NewGuid()) -Verbose:$False
  205.            
  206.             if (Get-ProvScheme -ProvisioningSchemeName $Name -Verbose:$False -ErrorAction SilentlyContinue) {
  207.                 throw ('[{0}] Provisioning scheme with name {1} already exists. Aborting.' -f $MyInvocation.MyCommand, $Name)
  208.             }
  209.             Write-Verbose ('[{0}] Creating provisioning scheme with name {1}' -f $MyInvocation.MyCommand, $Name)
  210.             $NewProvTaskId = New-ProvScheme -ProvisioningSchemeName $Name -HostingUnitName $HostingUnitName -IdentityPoolName $Name -MasterImageVM $MasterImageVM -VMCpuCount $CpuCount -VMMemoryMB $MemoryMB -CleanOnBoot:$CleanOnBoot -Verbose:$False -RunAsynchronously
  211.  
  212.             $ProvTask = Get-ProvTask -TaskId $NewProvTaskId
  213.             Write-Debug ('[{0}] Tracking progress of creation process for provisioning scheme with name {1}' -f $MyInvocation.MyCommand, $Name)
  214.             $CurrentProgress = 0
  215.             While ($ProvTask.Active) {
  216.                 Try { $CurrentProgress = If ( $ProvTask.TaskProgress ) { $ProvTask.TaskProgress } Else {0} } Catch { }
  217.  
  218.                 Write-Progress -Activity ('[{0}] Creating Provisioning Scheme with name {1} (copying and composing master image)' -f $MyInvocation.MyCommand, $Name) -Status ('' + $CurrentProgress + '% Complete') -PercentComplete $CurrentProgress
  219.                 Start-Sleep -Seconds 10
  220.                 $ProvTask = Get-ProvTask -TaskID $NewProvTaskId
  221.             }
  222.             $NewProvScheme = Get-ProvScheme -ProvisioningSchemeName $Name
  223.  
  224.             if (-Not $ProvTask.WorkflowStatus -eq 'Completed') {
  225.                 throw ('[{0}] Creation of provisioning scheme with name {1} failed. Aborting.' -f $MyInvocation.MyCommand, $Name)
  226.  
  227.             } else {
  228.                 Set-BrokerCatalog -Name $Name -ProvisioningSchemeId $NewProvScheme.ProvisioningSchemeUid -Verbose:$False
  229.                 $Controllers = Get-BrokerController -Verbose:$False | Select-Object -ExpandProperty DNSName -Verbose:$False
  230.                 Add-ProvSchemeControllerAddress -ProvisioningSchemeName $Name -ControllerAddress $Controllers -Verbose:$False
  231.             }
  232.         }
  233.     }
  234.  
  235.     End {
  236.         Write-Debug ('[{0}] End' -f $MyInvocation.MyCommand)
  237.     }
  238. }
  239.  
  240. function Sync-MachineCatalog {
  241.     <#
  242.     .SYNOPSIS
  243.     Ensures the same amount of resource in the new broker catalog
  244.     .DESCRIPTION
  245.     Creates the same number of VMs in the new broker catalog as there are VMS present in the old broker catalog
  246.     .PARAMETER BrokerCatalogName
  247.     The currently active broker catalog
  248.     .PARAMETER NewBrokerCatalogName
  249.     The new broker catalog
  250.     .LINK
  251.     New-MachineCatalog
  252.     Update-DeliveryGroup
  253.     .EXAMPLE
  254.     Sync-ProvVM -BrokerCatalog 'BrokenCatalog' -NewBrokerCatalog 'FixedBrokerCatalog'
  255.     #>
  256.     [CmdletBinding()]
  257.     param(
  258.         [Parameter(Mandatory=$True,HelpMessage='The currently active broker catalog',ParameterSetName='Sync')]
  259.         [Parameter(Mandatory=$True,HelpMessage='The new broker catalog',ParameterSetName='Count')]
  260.         [ValidateNotNullOrEmpty()]
  261.         [string]
  262.         $BrokerCatalogName
  263.         ,
  264.         [Parameter(Mandatory=$True,HelpMessage='The new broker catalog',ParameterSetName='Sync')]
  265.         [ValidateNotNullOrEmpty()]
  266.         [string]
  267.         $NewBrokerCatalogName
  268.         ,
  269.         [Parameter(Mandatory=$True,HelpMessage='The new broker catalog',ParameterSetName='Count')]
  270.         [ValidateNotNullOrEmpty()]
  271.         [int]
  272.         $Count
  273.     )
  274.  
  275.     Write-Verbose ('[{0}] Processing catalog {1}' -f $MyInvocation.MyCommand, $BrokerCatalogName)
  276.  
  277.     $BrokerCatalog = Get-BrokerCatalog -Name $BrokerCatalogName
  278.     if ($BrokerCatalogName -And $NewBrokerCatalogName) {
  279.         $NewBrokerCatalog = Get-BrokerCatalog -Name $NewBrokerCatalogName
  280.         $VmCount = Get-ProvVM -ProvisioningSchemeUid $BrokerCatalog.ProvisioningSchemeId -Verbose:$False | Measure-Object -Line | Select-Object -ExpandProperty Lines
  281.         Write-Verbose ('[{0}] Calling recursively for catalog with name {1}' -f $MyInvocation.MyCommand, $NewBrokerCatalogName)
  282.         Sync-MachineCatalog -BrokerCatalog $NewBrokerCatalog.Name -Count $VmCount
  283.         return
  284.     }
  285.  
  286.     $AcctIdentityPool = Get-AcctIdentityPool -IdentityPoolName $BrokerCatalog.Name -Verbose:$False
  287.     $ProvScheme = Get-ProvScheme -ProvisioningSchemeName $BrokerCatalog.Name -Verbose:$False
  288.  
  289.     Write-Verbose ('[{0}] Creating new accounts in identity pool {1}' -f $MyInvocation.MyCommand, $AcctIdentityPool.IdentityPoolName)
  290.     $AdAccounts = New-AcctADAccount -IdentityPoolName $AcctIdentityPool.IdentityPoolName -Count $Count -Verbose:$False
  291.     $ProvTaskId = New-ProvVM -ADAccountName @($AdAccounts.SuccessfulAccounts) -ProvisioningSchemeName $ProvScheme.ProvisioningSchemeName -RunAsynchronously
  292.     $ProvTask = Get-ProvTask -TaskId $ProvTaskId
  293.  
  294.     $CurrentProgress = 0
  295.     While ( $ProvTask.Active -eq $True ) {
  296.         Try { $CurrentProgress = If ( $ProvTask.TaskProgress ) { $ProvTask.TaskProgress } Else {0} } Catch { }
  297.  
  298.         Write-Progress -Activity 'Creating Virtual Machines' -Status ('' + $CurrentProgress + '% Complete') -PercentComplete $CurrentProgress
  299.         Start-Sleep -Seconds 10
  300.         $ProvTask = Get-ProvTask -TaskID $ProvTaskId
  301.     }
  302.  
  303.     Write-Verbose ('[{0}] Assigning machines to catalog with name {1}' -f $MyInvocation.MyCommand, $ProvScheme.ProvisioningSchemeName)
  304.     $ProvVMs = Get-ProvVM -ProvisioningSchemeUid $ProvScheme.ProvisioningSchemeUid -Verbose:$False
  305.     ForEach ($ProvVM in $ProvVMs) {
  306.         Lock-ProvVM -ProvisioningSchemeName $ProvScheme.ProvisioningSchemeName -Tag 'Brokered' -VMID @($ProvVM.VMId) -Verbose:$False -ErrorAction SilentlyContinue
  307.         New-BrokerMachine -CatalogUid $BrokerCatalog.Uid -MachineName $ProvVM.ADAccountName -Verbose:$False | Out-Null
  308.     }
  309. }
  310.  
  311. function ConvertFrom-MachineCatalog {
  312.     <#
  313.     .SYNOPSIS
  314.     Convert a broker catalog to a hash
  315.     .DESCRIPTION
  316.     Only those fields are extracted from the catalog object that are required for creating the catalog
  317.     .PARAMETER BrokerCatalog
  318.     Collection of broker catalog to convert to a hash
  319.     .PARAMETER ExcludeProvScheme
  320.     Whether to exclude the provisioning scheme
  321.     .PARAMETER ExcludeAcctIdentityPool
  322.     Whether to exclude the account identity pool
  323.     .PARAMETER ExcludeHostingUnit
  324.     Whether to exclude the hosting unit
  325.     .LINK
  326.     ConvertTo-MachineCatalog
  327.     New-MachineCatalog
  328.     Export-MachineCatalog
  329.     .EXAMPLE
  330.     ConvertFrom-MachineCatalog -BrokerCatalog (Get-BrokerCatalog)
  331.     .EXAMPLE
  332.     Get-BrokerCatalog | ConvertFrom-MachineCatalog
  333.     #>
  334.     [CmdletBinding()]
  335.     param(
  336.         [Parameter(Mandatory=$True,HelpMessage='Collection of broker catalog to convert to a hash',ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)]
  337.         [ValidateNotNullOrEmpty()]
  338.         [Citrix.Broker.Admin.SDK.Catalog[]]
  339.         $BrokerCatalog
  340.         ,
  341.         [Parameter(Mandatory=$False,HelpMessage='Whether to exclude the provisioning scheme')]
  342.         [switch]
  343.         $ExcludeProvScheme
  344.         ,
  345.         [Parameter(Mandatory=$False,HelpMessage='Whether to exclude the account identity pool')]
  346.         [switch]
  347.         $ExcludeAcctIdentityPool
  348.         ,
  349.         [Parameter(Mandatory=$False,HelpMessage='Whether to exclude the hosting unit')]
  350.         [switch]
  351.         $ExcludeHostingUnit
  352.     )
  353.  
  354.     Process {
  355.         Write-Debug ('[{0}] Enumerating members of BrokerCatalog' -f $MyInvocation.MyCommand)
  356.  
  357.         foreach ($Catalog in $BrokerCatalog) {
  358.             Write-Verbose ('[{0}] [{1}] Processing BrokerCatalog.Name={2}' -f $MyInvocation.MyCommand, $Catalog.UUID, $Catalog.Name)
  359.  
  360.             $CatalogParams = New-Object psobject -Property @{
  361.                     Name               = $Catalog.Name
  362.                     Description        = $Catalog.Description
  363.                     AllocationType     = $Catalog.AllocationType
  364.                     ProvisioningType   = $Catalog.ProvisioningType
  365.                     PersistUserChanges = $Catalog.PersistUserChanges
  366.                     SessionSupport     = $Catalog.SessionSupport
  367.             }
  368.  
  369.             if (-Not $Catalog.ProvisioningSchemeId) {
  370.                 Write-Verbose ('[{0}] [{1}] No provisioning scheme specified' -f $MyInvocation.MyCommand, $Catalog.UUID)
  371.                 $CatalogParams
  372.                 continue
  373.             }
  374.  
  375.             if (-Not $ExcludeProvScheme) {
  376.                 Write-Debug ('[{0}] [{1}] Accessing ProvisioningScheme' -f $MyInvocation.MyCommand, $Catalog.UUID)
  377.                 $ProvScheme = Get-ProvScheme -ProvisioningSchemeUid $Catalog.ProvisioningSchemeId -Verbose:$False
  378.                 Write-Verbose ('[{0}] [{1}] Retrieved ProvisioningScheme.Name={2}' -f $MyInvocation.MyCommand, $Catalog.UUID, $Catalog.Name)
  379.  
  380.                 $CatalogParams | Add-Member -NotePropertyMembers @{
  381.                         MasterImageVM           = $ProvScheme.MasterImageVM
  382.                         CpuCount                = $ProvScheme.CpuCount
  383.                         MemoryMB                = $ProvScheme.MemoryMB
  384.                         CleanOnBoot             = $ProvScheme.CleanOnBoot
  385.                 }
  386.             }
  387.  
  388.             if (-Not $ExcludeAcctIdentityPool) {
  389.                 Write-Debug ('[{0}] [{1}] Accessing AcctIdentityPool' -f $MyInvocation.MyCommand, $Catalog.UUID)
  390.                 $AcctIdentityPool = Get-AcctIdentityPool -IdentityPoolUid $ProvScheme.IdentityPoolUid -Verbose:$False
  391.                 Write-Verbose ('[{0}] [{1}] Retrieved AcctIdentityPool.IdentityPoolName={2}' -f $MyInvocation.MyCommand, $Catalog.UUID, $AcctIdentityPool.IdentityPoolName)
  392.  
  393.                 $CatalogParams | Add-Member -NotePropertyMembers @{
  394.                         NamingScheme       = $AcctIdentityPool.NamingScheme
  395.                         NamingSchemeType   = $AcctIdentityPool.NamingSchemeType
  396.                         OU                 = $AcctIdentityPool.OU
  397.                         Domain             = $AcctIdentityPool.Domain
  398.                 }
  399.             }
  400.  
  401.             if (-Not $ExcludeHostingUnit) {
  402.                 Write-Debug ('[{0}] [{1}] Accessing HostingUnit' -f $MyInvocation.MyCommand, $Catalog.UUID)
  403.                 $HostingUnit = Get-ChildItem XDHyp:\HostingUnits -Verbose:$False | Where-Object HostingUnitUid -eq $ProvScheme.HostingUnitUid -Verbose:$False
  404.                 Write-Verbose ('[{0}] [{1}] Retrieved HostingUnit.HostingUnitName={2}' -f $MyInvocation.MyCommand, $Catalog.UUID, $HostingUnit.HostingUnitName)
  405.  
  406.                 $CatalogParams | Add-Member -NotePropertyMembers @{
  407.                         HostingUnitName    = $HostingUnit.HostingUnitName
  408.                 }
  409.             }
  410.  
  411.             Write-Debug ('[{0}] [{1}] Returning custom object with parameters for BrokerCatalog.Name={2}' -f $MyInvocation.MyCommand, $Catalog.UUID, $Catalog.Name)
  412.             $CatalogParams
  413.             Write-Debug ('[{0}] [{1}] Finished processing BrokerCatalog.Name={2}' -f $MyInvocation.MyCommand, $Catalog.UUID, $Catalog.Name)
  414.         }
  415.     }
  416. }
  417.  
  418. function ConvertTo-MachineCatalog {
  419.     <#
  420.     .SYNOPSIS
  421.     Creates broker catalogs from a CSV file
  422.     .DESCRIPTION
  423.     The contents of the specified file is parsed using ConvertFrom-Csv and piped to New-MachineCatalog
  424.     .PARAMETER Path
  425.     Path of CSV file to import catalogs from
  426.     .EXAMPLE
  427.     ConvertTo-MachineCatalog -Path .\Catalogs.csv
  428.     .LINK
  429.     ConvertFrom-MachineCatalog
  430.     New-MachineCatalog
  431.     Export-MachineCatalog
  432.     #>
  433.     [CmdletBinding()]
  434.     param(
  435.         [Parameter(Mandatory=$True,HelpMessage='Path of CSV file to import catalogs from')]
  436.         [ValidateNotNullOrEmpty()]
  437.         [string]
  438.         $Path
  439.     )
  440.  
  441.     if (-Not (Test-Path -Path $Path)) {
  442.         throw ('[{0}] File <{1}> does not exist. Aborting.' -f $MyInvocation.MyCommand, $Path)
  443.     }
  444.  
  445.     Get-Content -Path $Path | ConvertFrom-Csv | New-MachineCatalog
  446. }
  447.  
  448. function Export-MachineCatalog {
  449.     <#
  450.     .SYNOPSIS
  451.     Exports all broker catalogs to the specified CSV file
  452.     .DESCRIPTION
  453.     The output of Get-BrokerCatalog is piped through ConvertFrom-MachineCatalog and written to a CSV file
  454.     .PARAMETER Path
  455.     Path of the CSV file to export broker catalogs to
  456.     .LINK
  457.     ConvertFrom-MachineCatalog
  458.     ConvertTo-MachineCatalog
  459.     New-MachineCatalog
  460.     .EXAMPLE
  461.     Export-MachineCatalog -Path .\Catalogs.csv
  462.     #>
  463.     [CmdletBinding()]
  464.     param(
  465.         [Parameter(Mandatory=$True,HelpMessage='Path of the CSV file to export broker catalogs to')]
  466.         [ValidateNotNullOrEmpty()]
  467.         [string]
  468.         $Path
  469.     )
  470.  
  471.     if (Test-Path -Path $Path) {
  472.         throw ('[{0}] File <{1}> already exists. Aborting.' -f $MyInvocation.MyCommand, $Path)
  473.     }
  474.  
  475.     Get-BrokerCatalog | ConvertFrom-MachineCatalog | ConvertTo-Csv | Out-File -FilePath $Path
  476. }
  477.  
  478. function Remove-MachineCatalog {
  479.     <#
  480.     .SYNOPSIS
  481.     Removes a machine catalog with all associated objects
  482.     .DESCRIPTION
  483.     The following objects will be removed: virtual machines, computer accounts, broker catalog, account identity pool, provisioning scheme
  484.     .PARAMETER Name
  485.     Name of the objects to remove
  486.     .LINK
  487.     New-MachineCatalog
  488.     Rename-MachineCatalog
  489.     .EXAMPLE
  490.     Remove-BrokerCatalog -Name 'test'
  491.     #>
  492.     [CmdletBinding()]
  493.     param(
  494.         [Parameter(Mandatory=$True,HelpMessage='Name of the objects to remove')]
  495.         [ValidateNotNullOrEmpty()]
  496.         [string]
  497.         $Name
  498.     )
  499.  
  500.     Get-BrokerMachine | Where-Object CatalogName -eq $Name | Remove-BrokerMachine
  501.     Get-ProvVM -ProvisioningSchemeName $Name | foreach {
  502.         Unlock-ProvVM -ProvisioningSchemeName $Name -VMID $_.VMId
  503.         Remove-ProvVM -ProvisioningSchemeName $Name -VMName $_.VMName
  504.     }
  505.     Get-AcctADAccount    -IdentityPoolName $Name       -ErrorAction SilentlyContinue | Remove-AcctADAccount -IdentityPoolName $Name
  506.     Get-BrokerCatalog    -Name $Name                   -ErrorAction SilentlyContinue | Remove-BrokerCatalog
  507.     Get-AcctIdentityPool -IdentityPoolName $Name       -ErrorAction SilentlyContinue | Remove-AcctIdentityPool
  508.     Get-ProvScheme       -ProvisioningSchemeName $Name -ErrorAction SilentlyContinue | Remove-ProvScheme
  509. }
  510.  
  511. function Rename-MachineCatalog {
  512.     <#
  513.     .SYNOPSIS
  514.     Renames a machine catalog
  515.     .DESCRIPTION
  516.     The following objects are renamed: BrokerCatalog, ProvScheme, AcctIdentityPool
  517.     .PARAMETER Name
  518.     Name of the existing catalog
  519.     .PARAMETER NewName
  520.     New name for the catalog
  521.     .LINK
  522.     Remove-MachineCatalog
  523.     New-MachineCatalog
  524.     .EXAMPLE
  525.     Rename-MachineCatalog -Name 'OldName' -NewName 'NewName'
  526.     #>
  527.     [CmdletBinding()]
  528.     param(
  529.         [Parameter(Mandatory=$True,HelpMessage='Name of the existing catalog')]
  530.         [ValidateNotNullOrEmpty()]
  531.         [string]
  532.         $Name
  533.         ,
  534.         [Parameter(Mandatory=$True,HelpMessage='New name for the catalog')]
  535.         [ValidateNotNullOrEmpty()]
  536.         [string]
  537.         $NewName
  538.     )
  539.  
  540.     Rename-BrokerCatalog    -Name                   $Name -NewName                   $NewName
  541.     Rename-ProvScheme       -ProvisioningSchemeName $Name -NewProvisioningSchemeName $NewName
  542.     Rename-AcctIdentityPool -IdentityPoolName       $Name -NewIdentityPoolName       $NewName
  543. }
  544.  
  545. function Update-DeliveryGroup {
  546.     <#
  547.     .SYNOPSIS
  548.     Substitutes machines in a desktop group
  549.     .DESCRIPTION
  550.     The machines contained in the desktop group are removed and new machines are added from the specified catalog
  551.     .PARAMETER Name
  552.     Name of an existing desktop group
  553.     .PARAMETER CatalogName
  554.     Name of the catalog containing new machines
  555.     .PARAMETER Count
  556.     Number of machines to add
  557.     .LINK
  558.     New-MachineCatalog
  559.     Sync-MachineCatalog
  560.     .EXAMPLE
  561.     The following command adds all machines from the given catalog to the specified desktop group
  562.     Update-DeliveryGroup -Name 'DG-SessionHost' -CatalogName 'MCS-SessionHost'
  563.     .EXAMPLE
  564.     The following command adds two machines from the given catalog to the specified desktop group
  565.     Update-DeliveryGroup -Name 'DG-SessionHost' -CatalogName 'MCS-SessionHost' -Count 2
  566.     #>
  567.     [CmdletBinding()]
  568.     param(
  569.         [Parameter(Mandatory=$True,HelpMessage='Name of an existing desktop group')]
  570.         [ValidateNotNullOrEmpty()]
  571.         [string]
  572.         $Name
  573.         ,
  574.         [Parameter(Mandatory=$True,HelpMessage='Name of the catalog containing new machines')]
  575.         [ValidateNotNullOrEmpty()]
  576.         [string]
  577.         $CatalogName
  578.         ,
  579.         [Parameter(Mandatory=$False,HelpMessage='Number of machines to add')]
  580.         [ValidateNotNullOrEmpty()]
  581.         [int]
  582.         $Count
  583.     )
  584.  
  585.     Write-Verbose ('[{0}] Retrieving machines in desktop group named {1}' -f $MyInvocation.MyCommand, $Name)
  586.     $ExistingMachines = Get-BrokerMachine | Where-Object DesktopGroupName -eq $Name
  587.     $ExistingMachines | foreach { Write-Debug ('[{0}]   {1}' -f $MyInvocation.MyCommand, $_.MachineName) }
  588.    
  589.     $Catalog = Get-BrokerCatalog -Name $CatalogName
  590.     if (-Not $Count) {
  591.         $Count = $Catalog.UnassignedCount
  592.     }
  593.     Write-Verbose ('[{0}] Adding {2} machines from catalog {1} to desktop group <{3}>' -f $MyInvocation.MyCommand, $CatalogName, $Count, $Name)
  594.     $AddedCount = Add-BrokerMachinesToDesktopGroup -DesktopGroup $Name -Catalog $Catalog -Count $Count
  595.  
  596.     Write-Verbose ('[{0}] Removing old machines from desktop group named {1}' -f $MyInvocation.MyCommand, $Name)
  597.     $ExistingMachines | Set-BrokerMachine -InMaintenanceMode $True | Out-Null
  598.     $ExistingMachines | Remove-BrokerMachine -DesktopGroup $Name | Out-Null
  599.  
  600.     Write-Verbose ('[{0}] Starting new machines in delivery group named {1}' -f $MyInvocation.MyCommand, $Name)
  601.     Get-BrokerMachine -DesktopGroupName $Name | Where-Object { $_.SupportedPowerActions -icontains 'TurnOn' } | foreach {
  602.         New-BrokerHostingPowerAction -Action 'TurnOn' -MachineName $_.MachineName
  603.     }
  604. }
  605.  
  606. function New-HostingConnection {
  607.     <#
  608.     .SYNOPSIS
  609.     Create a new hosting connection
  610.     .DESCRIPTION
  611.     This function only creates a connection to a hosting environment without choosing any resources (see New-HostingResource)
  612.     .PARAMETER Name
  613.     Name of the hosting connection
  614.     .PARAMETER ConnectionType
  615.     Connection type can be VCenter, XenServer and SCVMM among several others
  616.     .PARAMETER HypervisorAddress
  617.     This contains the URL to the vCenter web API
  618.     .PARAMETER HypervisorCredential
  619.     A credentials object for authentication against the hypervisor
  620.     .LINK
  621.     New-HostingResource
  622.     .EXAMPLE
  623.     New-HostingConnection -Name vcenter-01 -ConnectionType VCenter -HypervisorAddress https://vcenter-01.example.com/sdk -HypervisorCredential (Get-Credential)
  624.     #>
  625.     [CmdletBinding()]
  626.     param(
  627.         [Parameter(Mandatory=$True,HelpMessage='Name of the hosting connection')]
  628.         [ValidateNotNullOrEmpty()]
  629.         [string]
  630.         $Name
  631.         ,
  632.         [Parameter(Mandatory=$True,HelpMessage='Connection type can be VCenter, XenServer and SCVMM among several others')]
  633.         [ValidateSet('VCenter','XenServer','SCVMM')]
  634.         [string]
  635.         $ConnectionType
  636.         ,
  637.         [Parameter(Mandatory=$True,HelpMessage='This contains the URL to the vCenter web API')]
  638.         [ValidateNotNullOrEmpty()]
  639.         [string]
  640.         $HypervisorAddress
  641.         ,
  642.         [Parameter(Mandatory=$True,HelpMessage='A credentials object for authentication against the hypervisor')]
  643.         [ValidateNotNullOrEmpty()]
  644.         [pscredential]
  645.         $HypervisorCredential
  646.     )
  647.  
  648.     if (-Not (Test-Path -Path XDHyp:\Connections\$Name)) {
  649.         $HostingConnection = New-Item -Path XDHyp:\Connections\$Name -ConnectionType $ConnectionType -HypervisorAddress $HypervisorAddress -HypervisorCredential $HypervisorCredential -Persist
  650.     } else {
  651.         $HostingConnection = Get-Item XDHyp:\Connections\$Name
  652.     }
  653.     $HypervisorConnectionUid = $HostingConnection.HypervisorConnectionUid | Select-Object -ExpandProperty Guid
  654.     New-BrokerHypervisorConnection -HypHypervisorConnectionUid $HypervisorConnectionUid | Out-Null
  655. }
  656.  
  657. function New-HostingResource {
  658.     <#
  659.     .SYNOPSIS
  660.     Create a new hosting resource
  661.     .DESCRIPTION
  662.     This function creates a resource (network and storage) based on a hosting connection (see New-HostingConnection)
  663.     .PARAMETER Name
  664.     Name of the hosting resource
  665.     .PARAMETER HypervisorConnectionName
  666.     Name of the hosting connection
  667.     .PARAMETER ClusterName
  668.     Name of the host cluster in vCenter
  669.     .PARAMETER NetworkName
  670.     Array of names of networks in vCenter
  671.     .PARAMETER StorageName
  672.     Array of names of datastores in vCenter
  673.     .LINK
  674.     New-HostingConnection
  675.     .EXAMPLE
  676.     New-HostingResource -Name cluster-01 -HypervisorConnectionName vcenter-01 -ClusterName cluster-01 -NetworkName (vlan_100,vlan_101) -StorageName (datastore1,datastore2)
  677.     #>
  678.     [CmdletBinding()]
  679.     param(
  680.         [Parameter(Mandatory=$True,HelpMessage='Name of the hosting resource')]
  681.         [ValidateNotNullOrEmpty()]
  682.         [string]
  683.         $Name
  684.         ,
  685.         [Parameter(Mandatory=$True,HelpMessage='Name of the hosting connection')]
  686.         [ValidateNotNullOrEmpty()]
  687.         [string]
  688.         $HypervisorConnectionName
  689.         ,
  690.         [Parameter(Mandatory=$True,HelpMessage='Name of the host cluster in vCenter')]
  691.         [ValidateNotNullOrEmpty()]
  692.         [string]
  693.         $ClusterName
  694.         ,
  695.         [Parameter(Mandatory=$True,HelpMessage='Array of names of networks in vCenter')]
  696.         [ValidateNotNullOrEmpty()]
  697.         [string[]]
  698.         $NetworkName
  699.         ,
  700.         [Parameter(Mandatory=$True,HelpMessage='Array of names of datastores in vCenter')]
  701.         [ValidateNotNullOrEmpty()]
  702.         [string[]]
  703.         $StorageName
  704.     )
  705.  
  706.     $HypervisorConnectionPath = Join-Path -Path XDHyp:\Connections -ChildPath $HypervisorConnectionName
  707.     $BasePath = Join-Path -Path XDHyp:\HostingUnits -ChildPath $ClusterName
  708.  
  709.     Write-Verbose ('[{0}] Caching objects for lookups under {1}' -f $MyInvocation.MyCommand, $HypervisorConnectionPath)
  710.     $CachedObjects = Get-ChildItem -Recurse $HypervisorConnectionPath -Verbose:$False
  711.  
  712.     $ClusterPath = $CachedObjects | Where-Object { $_.Name -like $ClusterName } | Select-Object FullPath
  713.     Write-Verbose ('[{0}] Using cluster named {1} via path <{2}>' -f $MyInvocation.MyCommand, $ClusterName,$ClusterPath.FullPath)
  714.  
  715.     $NetworkPath = $CachedObjects | Where-Object { $NetworkName -icontains $_.Name } | Select-Object FullPath
  716.     Write-Verbose ('[{0}] Using network named {1} via path <{2}>' -f $MyInvocation.MyCommand, [string]::Join(',', $NetworkName), [string]::Join(',', $NetworkPath.FullPath))
  717.  
  718.     $StoragePath = $CachedObjects | Where-Object { $StorageName -icontains $_.Name } | Select-Object FullPath
  719.     Write-Verbose ('[{0}] Using storage named {1} via path <{2}>' -f $MyInvocation.MyCommand, [string]::Join(',', $StorageName), [string]::Join(',', $StoragePath.FullPath))
  720.  
  721.     New-Item -Verbose:$False -Path $BasePath -RootPath $ClusterPath.FullPath `
  722.         -HypervisorConnectionName $HypervisorConnectionName `
  723.         -NetworkPath $NetworkPath.FullPath `
  724.         -PersonalvDiskStoragePath $StoragePath.FullPath `
  725.         -StoragePath $StoragePath.FullPath | Out-Null
  726. }
  727. New-HostingConnection -Name vcenter-01 -ConnectionType VCenter -HypervisorAddress https://vcenter-01.example.com/sdk -HypervisorCredential (Get-Credential)
  728. New-HostingResource -Name cluster-01 -HypervisorConnectionName vcenter-01 -ClusterName cluster-01 -NetworkName ('vlan_100','vlan_101') -StorageName ('datastore1','datastore2')
  729.  
  730. Export-MachineCatalog -Path .\MachineCatalog.csv
  731. # correct data as needed (e.g. HostingUnitName and MasterVMImage)
  732.  
  733. Get-Content .\MachineCatalog.csv | ConvertFrom-Csv | New-MachineCatalog -Suffix '-new' -Verbose
  734.  
  735. # for every catalog (example: Catalog_Office_DEV)
  736. Sync-MachineCatalog -BrokerCatalogName Catalog_Office_DEV -NewBrokerCatalogName Catalog_Office_DEV-new -Verbose
  737. Update-DeliveryGroup -Name Catalog_Office_DEV -CatalogName Catalog_Office_DEV-new
  738. Remove-MachineCatalog -Name Catalog_Office_DEV
  739. Rename-MachineCatalog -Name Catalog_Office_DEV-new -NewName Catalog_Office_DEV -Verbose
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement