Citrix Provisioning Server auto-add is a waste of time.
I use this script from a Provisioning Server that has the MCLI snapin and XenServer Powershell SDK installed. The script connects to XenServer, gets a list of virtual machines and creates target devices for the virtual machines.
#Author: Phil Lindsey
#Website: http://www.ctxfarmer.com
#Last Modified: 11/4/2010
param(
#list of xenserver(s) - comma seperated for multiple xenservers
[Parameter(Mandatory=$true)]
[string]$Xenservers,
#provisioining server collection name for the new devices
[Parameter(Mandatory=$true)]
[string]$CollectionName,
#provisioning server site name for the new devices
[Parameter(Mandatory=$true)]
[string]$SiteName,
#apply the collection's template device properties to the new devices
[boolean]$copyTemplate=$false,
#only add devices that start with a specific string
[string]$startsWith=""
)
#Add snapins
Add-PSSnapin XenServer* -ErrorAction SilentlyContinue
Add-PSSnapin MCLI* -ErrorAction SilentlyContinue
#get xenserver credentials
$creds = Get-Credential
#split up the list of xenservers
foreach($XenServer in $Xenservers.Split(",")){
#connect to the xenserver
Connect-XenServer -Url http://$XenServer -NoWarnCertificates -Creds $creds
#get a list of virtual machines
$VMs = Get-XenServer:VM | Where-Object {$_.is_a_snapshot -eq $false -and $_.is_a_template -eq $false -and $_.is_control_domain -eq $false}
foreach($VM in $VMs){
#get the virtual machine's name label
$VMName = $VM.name_label
#get the virtual interfaces for the virtual machine
$VIFs = Get-XenServer:VM.VIFs -VM $VM
#do not add the vm if it has more that one network interface
if($VIFs -ne "" -and $VIFs.Count -lt 1){
#replace the : with - in the MAC address
$MAC = ($VIFs.MAC).ToString().Replace(":","-")
#if the user didn't define $startswith or
#if the user defined a $startwith value check the vm name
if($startsWith -eq "" -or $VMName.StartsWith($startsWith,1)){
#copy from the collection template?
$VMName
if($copyTemplate){
#adding the device
Mcli-Add Device -r `
siteName=$siteName,`
collectionName=$collectionName,`
deviceName=$VMName,`
deviceMac=$MAC,`
copyTemplate=1
}
else{
#adding the device
Mcli-Add Device -r `
siteName=$siteName,`
collectionName=$collectionName,`
deviceName=$VMName,`
deviceMac=$MAC
}
}
}
}
#disconnect from the xenserver
Disconnect-Xenserver
}
Target device retries can be seen from the Provisioning Services Console by expanding the farm, sites, your site, and then servers. Right click the Provisioning Server and click “show connected devices.”
![]()
The retry data from the Provisioning Services Console is nice, but is almost useless because the target device retries will increment while the target device is running and will reset when the target device is restarted. For example, a target device has been running for 2 weeks and has 3,000 retires listed in the console. I don’t know if 3,000 retries happened in the last 2 weeks or the last 2 minutes.
I want to baseline, track, and troubleshoot with this data. I can accomplish this with a SQL table, Powershell Provisioning Server commandlets, Citrix Provisioning Server, a scheduled task, and SQL reporting.
I’ll create a database called syslog and a table called “PVSDeviceRetries” with these columns…
*note – default value for the created column is getdate()
then a SQL user account called syslog with write permissions to the database.
Next, I’ll need a Powershell script and the Powershell Provisioning Server commandlets. The script will write the information to the SQL database.
#Author: Phil Lindsey
#Website: http://www.ctxfarmer.com
#Last Modified: 11/4/2010
Clear-Host
$SQLServer = "192.168.35.10"
$SQLDatabase = "Syslog"
$SQLTable = "PvsDeviceRetries"
$SQLUserId = "syslog"
$SQLPassword = "p@ssw0rd"
function get-value{
param([string]$strText="",[string]$strDelimiter="")
return $strText.SubString($strText.IndexOf($strDelimiter)+2)
}
function get-name{
param([string]$strText="",[string]$strDelimiter="")
return $strText.SubString(0,$strText.IndexOf($strDelimiter))
}
Add-PSSnapin McliPS* -ErrorAction SilentlyContinue
$all = @()
$obj = New-Object System.Collections.ArrayList
$lines = Mcli-Get DeviceInfo -f ServerName,`
ServerIpConnection,`
DeviceName,`
SiteName,`
CollectionName,`
Active,`
Status,`
diskLocatorName
for($i=0;$i -lt $lines.length;$i++){
if(($lines[$i].length -gt 0) -and ($lines[$i].contains(":")) -and -not ($lines[$i] -match "Executing: Get ")){
$name = get-name -strText $lines[$i] -strDelimiter ":"
$value = get-value -strText $lines[$i] -strDelimiter ":"
if ($name -eq "status" -and $value.Length -le 0){
$value = "0"
}
if ($value.Contains(",") -and $name -eq "status"){
$obj | Add-Member -membertype noteproperty -name $name -Value $value.Split(",")[0]
}else{
$obj | Add-Member -membertype noteproperty -name $name -Value $value
}
}
if($lines[$i].contains("#") -or (($i+1) -eq $lines.length)){
$all += $obj
$obj = New-Object psObject
}
}
$conn = New-Object System.Data.SqlClient.SqlConnection("Data Source="+$SQLServer+";`
Initial Catalog="+$SQLDatabase+"; User Id="+$SQLUserId+";Password="+$SQLPassword+";")
foreach($targetdevice in $all){
$targetdevice | fl *
$conn.Open()
$cmd = $conn.CreateCommand()
$cmd.CommandText = "INSERT INTO "+$SQLTable+"(`
ServerName,`
ServerIpConnection,`
DeviceName,`
SiteName,`
CollectionName,`
Active,`
Status,`
diskLocatorName)`
VALUES(`
'"+$targetdevice.serverName+"',`
'"+$targetdevice.ServerIpConnection+"',`
'"+$targetdevice.devicename+"',`
'"+$targetdevice.sitename+"',`
'"+$targetdevice.collectionname+"',`
"+[int]$targetdevice.active+",`
"+[int]$targetdevice.status+",`
'"+$targetdevice.diskLocatorName+"')"
$result = $cmd.ExecuteNonQuery()
$conn.Close()
}
In the next part, I'll setup a scheduled task on the Provisioning Server and create the SQL reports to display the data.
It’s no secert that Citrix released a Powershell SDKs for Provisioning Server that’s not Powershell “friendly”.
Here’s a script that will convert the output from MCli-Get to a System.Collections.ArrayList.
Requires the Provisioning Server Powershell snap-in.
Example
$myDevices = .\Get-PVSInfo.ps1 -type DeviceInfo
$myDevices | Out-GridView
#Author: Phil Lindsey
#Website: http://www.ctxfarmer.com
#Last Modified: 08/28/2010
param(
[string]$type=""
)
function get-value{
param([string]$strText="",[string]$strDelimiter="")
return $strText.SubString($strText.IndexOf($strDelimiter)+2)
}
function get-name{
param([string]$strText="",[string]$strDelimiter="")
return $strText.SubString(0,$strText.IndexOf($strDelimiter))
}
$type = $type.Trim()
switch($type){
"AdDomains" {}
"AuthGroup" {}
"Collection" {}
"Device" {}
"DeviceInfo" {}
"DeviceStatus" {}
"DiskInfo" {}
"DiskLocator" {}
"Farm" {}
"FarmView" {}
"Server" {}
"ServerInfo" {}
"Site" {}
"SiteView" {}
"Store" {}
"UserGroup" {}
default {write-output "Bad type"; exit;}
}
Add-PSSnapin McliPS* -ErrorAction SilentlyContinue
$all = @()
$obj = New-Object System.Collections.ArrayList
$lines = Mcli-Get $type
for($i=0;$i -lt $lines.length;$i++){
if(($lines[$i].length -gt 0) -and ($lines[$i].contains(":")) -and -not ($lines[$i] -match "Executing: Get ")){
$name = get-name -strText $lines[$i] -strDelimiter ":"
$value = get-value -strText $lines[$i] -strDelimiter ":"
$obj | Add-Member -membertype noteproperty -name $name -Value $value
}
if($lines[$i].contains("#") -or (($i+1) -eq $lines.length)){
$all += $obj
$obj = New-Object psObject
}
}
Write-Output $all