fredag den 30. maj 2014

XenApp hotfix management

One thing I never understood is how to figure out what patches are needed on a XenApp server. And it has always annoyed me with the whole process of needing to download everything and never knowing what fixes need a reboot.

So a few days ago I started searching for something smarter. Here someone made a script to get the patches but it only works with newer versions of PowerShell, and here someone made a complete solution. but, I like the ability to get status back and it doesn’t seem to check if a patch is actually needed. So I combined the two, into one PowerShell script that also works in PowerShell 2.0.
( download link )

Set-Location 'c:\'
$snapin = Get-PSSnapin | where {$_.name -eq 'Citrix.Common.Commands'}
if($snapin -eq $null){ Add-PSSnapin Citrix.Common.Commands }
$snapin = Get-PSSnapin | where {$_.name -eq 'Citrix.XenApp.Commands'}
if($snapin -eq $null){ Add-PSSnapin Citrix.XenApp.Commands }

function installXenappHotfix([string]$HotfixName, [string]$hotfixpath ){
$exitcode = (Start-Process -FilePath "msiexec.exe" -ArgumentList "/qb /passive /norestart /p `"$hotfixpath`"" -Wait -Passthru).ExitCode
if($exitcode -eq 3010){
$exitcode = 1604
#Write-Host 'Restart needed, so restarting. doh!'
#restart-computer -force -throttlelimit 10; exit $exitcode
#exit $exitcode
return $exitcode
}
if($exitcode -ne 0){
Write-Host ('Unknown exitcode: ' + $exitcode)
#exit $exitcode
return $exitcode
}
return 0
}


function installXenappHotfixWithIsNeededCheck([string]$HotfixName, [string]$hotfixpath ){
# Get current computername and XenServer object
$computername = $env:computername

$isInstalled = $false;
try {
foreach($hotfix in (Get-XAServerHotFix -ServerName $computername)){
if($hotfix.HotfixName -eq $HotfixName){ $isInstalled = $true; }
}
# IMA service proberly not running.
} catch {
if($_.invocationinfo) {
status ($_.Exception.Message + "`n `n" + $_.InvocationInfo.PositionMessage)
} else {
status $_.ToString()
}
return 1604
}
if($isInstalled -eq $false){
Write-Host ('Missing ' + $HotfixName)
$exitcode = (Start-Process -FilePath "msiexec.exe" -ArgumentList "/qb /passive /norestart /p `"$hotfixpath`"" -Wait -Passthru).ExitCode
if($exitcode -eq 3010){
$exitcode = 1604
Write-Host 'Restart needed, so restarting. doh!'
#restart-computer -force -throttlelimit 10; exit $exitcode
#exit $exitcode
return $exitcode
}
if($exitcode -ne 0){
Write-Host ('Unknown exitcode: ' + $exitcode)
#exit $exitcode
return $exitcode
}
} else {
# Write-Host ($HotfixName + ' ok')
return 0
}
}

function Get-URLContent ($url) {
$client = new-object System.Net.WebClient
#$client.DownloadFile( $url, [IO.Path]::GetTempFileName() )
return $client.downloadString($url)
}
function Get-URLFile ($url, $saveas) {
$client = new-object System.Net.WebClient
#$client.DownloadFile( $url, [IO.Path]::GetTempFileName() )
$client.DownloadFile( $url, $saveas )
}

function CheckXenappHotfix() {
# XenApp 6.5 : $url = "http://support.citrix.com/product/xa/v6.5_2008r2/hotfix/general/?rss=on"
# XenApp 6.0 : $url = "http://support.citrix.com/product/xa/v6.0_2008r2/hotfix/general/?rss=on"
# XenApp 5.0 : $url = "http://support.citrix.com/product/xa/v5.0_2008/hotfix/general/?rss=on"

# PVS 6.1 : $url = "http://support.citrix.com/product/provsvr/pvsv6.1/hotfix/general/?rss=on"
}

$hotfixurl = 'http://support.citrix.com/product/xa/v6.0_2008r2/hotfix/general/?rss=on'
$source = Join-Path (Get-Location).Path 'xa_hotfix'
if(! (Test-Path $source)) { New-Item -ItemType directory -Path $source | Out-Null }

$service = Get-Service imaservice
if($service.Status.ToString() -eq 'Stopped') {
Get-Service imaservice | Start-Service
}
try {
$computername = $env:computername
$installed = (Get-XAServerHotFix -ServerName $computername)
} catch {
if($_.invocationinfo) {
write-error ($_.Exception.Message + "`n `n" + $_.InvocationInfo.PositionMessage)
} else {
write-error $_.ToString()
}
}

write-progress -id 1 -Activity "Xenapp Hotfix Script" -Status "Fetch lastest xenapp hotfixes"
write-progress -id 2 -ParentId 1 -Activity "Xenapp Hotfix Script" -Status "Fetch $hotfixurl"

$hotfixes = @()
$xml = [xml](Get-URLContent $hotfixurl)
foreach($fix in $xml.rdf.item) {
write-progress -id 2 -ParentId 1 -Activity "Xenapp Hotfix Script" -Status "Fetch $($fix.link)"

$html = Get-URLContent $fix.link
$pattern = '(?<=.)/servlet/KbServlet/download/.+?(?=")'
$results = ($html | Select-String -Pattern $Pattern -AllMatches).Matches | select value
if($results) {
if($results -is [system.array]){ $results = $results[0] }
$url = ('http://support.citrix.com' + $results.Value)
$filename = [string][io.path]::GetFileName($url)
if($filename.Contains('.msp')) {
$HotfixName = [string][io.path]::GetFileNameWithoutExtension($filename)
if(! ($installed | ?{$_.HotfixName -eq $HotfixName})) {
$saveas = (Join-Path $source $filename)
if(! (Test-Path $saveas)) {
write-progress -id 2 -ParentId 1 -Activity "Xenapp Hotfix Script" -Status "Downloading $filename"
write-verbose "Downloading $filename"
Get-URLFile $url $saveas
} else {
write-progress -id 2 -ParentId 1 -Activity "Xenapp Hotfix Script" -Status "$filename has allready been downloaded"
write-verbose "$filename has allready been downloaded"
}
$hotfixes += $saveas
} else {
write-progress -id 2 -ParentId 1 -Activity "Xenapp Hotfix Script" -Status "$filename has allready been installed"
write-verbose "$filename has allready been installed"
}
} else {
write-progress -id 2 -ParentId 1 -Activity "Xenapp Hotfix Script" -Status "skipping $filename"
write-verbose "skipping $filename"
}
}
}

$needreboot = $false
$updateSystemInfo = new-object -com Microsoft.Update.SystemInfo
if($updateSystemInfo.rebootRequired){ $needreboot = $true }

write-progress -id 1 -Activity "Xenapp Hotfix Script" -Status "Installing missing xenapp hotfixes"
foreach($filename in $hotfixes) {
$HotfixName = [string][io.path]::GetFileNameWithoutExtension($filename)
write-progress -id 2 -ParentId 1 -Activity "Xenapp Hotfix Script" -Status "Installing $HotfixName"

$exitcode = installXenappHotfix $HotfixName $filename
# ERROR_SUCCESS_REBOOT_REQUIRED
if($exitcode -eq 3010){ $needreboot = $true; }
if($exitcode -eq 1642){
# some hotfixes will shut down the IMA service
# If you then start the service without rebooting it will not report the patch installed
# if that is NOT the case, go do some troubleshootnig to figure out what is wrong

Write-Warning "$HotfixName has allready been installed (ERROR_PATCH_TARGET_NOT_FOUND)"
$needreboot = $true
}
}

write-progress -id 2 -ParentId 1 -Activity "Xenapp Hotfix Script" -Status "n/a" -Completed
if($needreboot) {
write-progress -id 2 -ParentId 1 -Activity "Updating" -Status "Rebooting system"
Write-Warning "Reboot required"
Restart-Computer -Force
}

1 kommentar: