Thursday 16 February 2012

How to Downgrade Your Citrix Client From SCCM

Hi All,

Below are step by step instructions on how to package an application to remove the Citrix Receiver Updater and the Enterprise Client and Install the Citrix Online Plugin 12.1

I could not find a way to remove the Citrix Receiver Updater without being in interactive mode. It’s easy to deploy out onto your network but hard to take off.

I have asked the question on this Citrix thread but to date, I haven't received an answer.

This solution took me two weeks. We usually deliver applications via task sequences which makes everything easier. 

The reason why it took so long is because after the user runs the advertisement, the advertisement doesn't automatically remove itself from that computer.  The user could re-run the application as many times as they want. It didn't matter if I set the program to never rerun.

My Goal was to provide a solution that would remove the Receiver and Updater and Install the Online Plugin 12.1. It would then remove the advertisement from that computer so the user could not run it again. 

Some workstations are experiencing this issue with the new receiver so the solution should only run if they need it.  Sound easy?

The major steps involved include:
  • Creating the Collections for Deployment
  • Creating the Package for Deployment
  • Creating the Advertisement for the Program
  • Creating a Status Filter Rule to remove the computer from the collection
  • Creating a second Status Filter Rule to update another collection and send the Machine Policy and Evaluate Policy actions to the remote computer.
Creating the Collections for Deployment

The collections I used look like this:

  • Uninstall Citrix Receiver - Completed: This collection is for direct members who have completed the downgrade.
  • Uninstall Citrix Receiver - Inprogress: This collection is a query based collection the includes all computers that have the Receiver or Updater and are not a member of the completed collection
Below is the code. Substitute ChangeMe for the Uninstall Citrix Receiver - Completed collection ID.

select
SMS_R_SYSTEM.ResourceID,SMS_R_SYSTEM.ResourceType,SMS_R_SYSTEM.Name, SMS_R_SYSTEM.SMSUniqueIdentifier,SMS_R_SYSTEM.ResourceDomainORWorkgroup,SMS_R_SYSTEM.Client from SMS_R_System inner join SMS_G_System_ADD_REMOVE_PROGRAMS on SMS_G_System_ADD_REMOVE_PROGRAMS.ResourceID = SMS_R_System.ResourceId where (SMS_G_System_ADD_REMOVE_PROGRAMS.DisplayName = "Citrix Receiver Updater" or SMS_G_System_ADD_REMOVE_PROGRAMS.DisplayName = "Citrix Receiver (Enterprise)") AND SMS_R_System.ResourceId not in (select ResourceID from SMS_CM_RES_COLL_ChangeMe)

Creating the Package for Deployment

The SCCM package should contain the following:
  • CitrixReceiverUpdater.msi
  • CitrixReceiverEnterprise.exe
  • CitrixOnlinePluginFull.exe
  • DowngradeOnlinePlugin.vbs (The code provided below)

The Program for this package should contain the following:
  • Command Line: cscript.exe DowngradeOnlinePlugin.vbs
  • After Running: ConfigMgr restarts computer

  • Program Can Run: Only when the user is logged on
  • Run Mode: Run with administrative rights and Allow users to interact with this program.

    • Additional Criteria: Suppress program notifications

    Set the other settings as you so desire.

    Creating the Advertisement for the Program
    • Package: The package you just created
    • Program: The program you created for the package
    • Collection: Uninstall Citrix Receiver - InProgress


  • Advertisement Start Time: When you want it to start
  • Mandatory Assignment: Sometime way into the future so it never actually forces the user to run it. Setting a date allows the client to prestage the package.


  • Set the other settings as you so desire.

    Status Filters


    The First Status Filter (Downgrade Citrix Client: Add computer to Collection. Step 1)  will run when the workstation reports back reboot pending.
    • It will call one Vb Script called AddComputerToCollection.vbs. (The code provided below)
    • Because we can not change the membership of the inprogress collection directly, we will instead add the computer to the collection completed and then email me so I am aware of the downgrade.
    • Change the above property value to reflect your Advertisement ID
    • We will report the event creation in the event log and we will also run the script that adds the computer to the collection and send me an email. We will pass the script the variable %msgsys which includes the computer name.
    • cscript.exe <LocationToScript>\AddComputerToCollection.vbs %msgsys
    The Second Status Filter (Downgrade Citrix Client: Refresh collection And Perform Machine Policy. Step 2) will run when the workstation reports back the the advertisement has completed successfully.
    • It will run the problem UpdateCollectionAndPerformMachinePolicyUpdate.vbs that will call two Vb scripts (The code provided below)
      • UpdateCollection.vbs: Forces the completed collection to update (The code provided below)
      • sendsched.vbs (Sends to the computer a Machine Policy and Evaluate Policy actions) This script is part of the Systems Management Server 2003 Toolkit 2 and can be downloaded from here

    • Change the above property value to reflect your Advertisement ID 

    • We will report the event creation in the event log and we will also run the script the following script and pass the variable %msgsys which includes the computer name.
    • cscript.exe  <LocationToScript>\UpdateCollectionAndPerformMachinePolicyUpdate.vbs %msgsys

    That's about it. When the user runs the advertisement. It will downgrade the Citrix client to 12.1, send you an email that it has been completed and remove the advertisement from the computer. Give it try and let me know how you go.

    Below is the code:

    UpdateCollectionAndPerformMachinePolicyUpdate.vbs

    Option Explicit
    
    Dim Args  
    Dim strComputerName
    Dim objshell
    
    On Error Resume Next  
    
    
    Set args = WScript.Arguments
    strComputername = args.Item(0)
    
    If strComputerName = NULL then
       wscript.quit
    End if
    
    '------------------------------------------------------------
    'Main script 
    set objShell = CreateObject("WScript.Shell")
    objShell.Run "<LocationOfScript>\UpdateCollection.vbs",1,True
    WScript.Sleep(9000) 
    objShell.Run "<LocationOfScript>\sendsched.vbs {00000000-0000-0000-0000-000000000021} " & strcomputername,1,True
    WScript.Sleep(9000) 
    objShell.Run "<LocationOfScript>\sendsched.vbs {00000000-0000-0000-0000-000000000022} " & strcomputername,1,True
    WScript.Sleep(9000) 
    Wscript.Quit


    UpdateCollection.vbs

    on error resume next
    Dim strSMSServer,strSMSSiteCode,strCollID
    
    strSMSServer = "ServerName" 
    strSMSSiteCode = "SiteName" 
    strCollID = "CollectionIDOfCompletedCollection" 
    
    Set objCollection = GetObject( "WinMgmts:!\\" & strSMSServer & _ 
    "\root\SMS\site_" & strSMSSiteCode & _ 
    ":SMS_Collection.CollectionID='" & strCollID & "'") 
    objCollection.RequestRefresh False

    AddComputerToCollection.vbs


    Option Explicit
    ' Constants for type of event log entry
    const EVENTLOG_INFORMATION = 4
    'http://ccmexec.com/2010/03/remove-a-computer-from-a-collections-when-osd-task-sequence-is-completed/
    
    Dim Args  
    Dim swbemLocator, SWbemServices, objCollection, oProviderLocation, oLocation   
    Dim strComputerName, arrComputers, objComputer, sCollectionIDs
    Dim objDirectRule
    Dim strmessage, objshell
    Dim seventlog, sClearPxeflag
    Dim oCollection,collectionquery, sCollectionIDUpdate
    Dim StrRun
    Dim objEmail
    On Error Resume Next  
    
    
    'CollectionIDs from which to remove the computer
    'Should an eventlog entry be generated, set Seventlog=1
    
    sEventlog = "1" 
    sCollectionIDs = "CollectionCompletedId"  ' Completed Collection 
    sCollectionIDUpdate =  "CollectionInProgressID" ' In Progress Collection 
    '------------------------------------------------------------
    'Get Command Line arguments
    
    Set args = WScript.Arguments
    strComputername = args.Item(0)
    
    If strComputerName = NULL then
       wscript.quit
    End if
    
    '------------------------------------------------------------
    'Main script 
    
    set objShell = CreateObject("WScript.Shell")
    
        Set swbemLocator = CreateObject("WbemScripting.SWbemLocator")
        swbemLocator.Security_.AuthenticationLevel = 6 'Packet Privacy.
        Set swbemServices = swbemLocator.ConnectServer(".", "root\SMS")
        Set oProviderLocation = swbemServices.InstancesOf("SMS_ProviderLocation")
        For Each oLocation In oProviderLocation
            If oLocation.ProviderForLocalSite = True Then
                Set swbemServices = swbemLocator.ConnectServer(oLocation.Machine, "root\sms\site_" + oLocation.SiteCode)
            End If        
        Next 
    
    Set arrComputers = SWbemServices.ExecQuery("select * from SMS_R_System where Name='" & strComputerName & "' and Obsolete = 0")
    
    For Each objComputer In arrComputers
       AddCollectionMembership objComputer.ResourceID
       
    'Write to eventlog if Seventlog = 1   
       If Seventlog = "1" then
       strMessage = strcomputername & " will be added to the following collection ID's " & scollectionids
       objShell.LogEvent EVENTLOG_INFORMATION, strMessage
       End IF
       
    Next
    
    
    SendEmail
    
    Set objCollection = Nothing
    Set SWbemServices = Nothing
    Set SWbemLocator = Nothing
    
    Wscript.Quit
    
    
    '------------------------------------------------
    Sub AddCollectionMembership(intresourceid)
    on error resume next
    
    Dim mCollectionID, i
    mCollectionID = Split (sCollectionIDs, ":")
    for i = Lbound(mCollectionID) to UBound(mCollectionID)
    
        ' Add Member to completed collection 
        Set objCollection = SWbemServices.Get("SMS_Collection='" & MCollectionID(i) & "'")
        Set ObjDirectRule = SWbemServices.Get("SMS_CollectionRuleDirect").SpawnInstance_
        ObjDirectRule.ResourceID = intresourceid
        ObjDirectRule.RuleName = intresourceid
        ObjCollection.AddMembershipRule objDirectRule
        ObjCollection.RequestRefresh True
        
        next
    
    End Sub
    
    Sub SendEmail 
    
    Set objEmail = CreateObject("CDO.Message")
    objEmail.From = "EmailAddressFrom"
    objEmail.To = "EmailAddressTo"
    objEmail.Subject = strcomputername & " has downgraded its Citrix Client" 
    objEmail.Configuration.Fields.Item ("http://schemas.microsoft.com/cdo/configuration/sendusing") = 2
    objEmail.Configuration.Fields.Item ("http://schemas.microsoft.com/cdo/configuration/smtpserver") = "10.18.128.17" 'Modify to your SMTP Server Address
    objEmail.Configuration.Fields.Item ("http://schemas.microsoft.com/cdo/configuration/smtpserverport") = 25
    objEmail.Configuration.Fields.Update
    objEmail.Send
    
    End Sub
    
    
    '------------------------------------------------
    
    
    WScript.Quit(0)

    AddComputerToCollection.vbs

    ON ERROR RESUME NEXT
    
    Dim WshShell
    Set WshShell = Wscript.CreateObject("Wscript.Shell")
    
     '******************* START REMOVE CITRIX RECEIVER UPDATER ************************************
    wscript.echo "Removing Citrix Reciever Updater. Please Wait...."
    WshShell.Run "msiexec.exe /uninstall CitrixReceiverUpdater.msi /quiet /norestart", 1, True
    
    DIM strComputer,strProcess
    
    strComputer = "." ' local computer
    strProcess = "Receiver.exe"
    i = 1
    Do Until i = 6
        IF isProcessRunning(strComputer,strProcess) THEN
            'wscript.echo strProcess & " is running on computer '" & strComputer & "'"
            WScript.Sleep(9000) 
            i = i + 1
        ELSE
            'wscript.echo strProcess & " is NOT running on computer '" & strComputer & "'"
            i = 6
        END IF
    Loop
    i = 1
    'msgbox "Exit Receiver Loop"
    strProcess = "Updater.exe"
    Do Until i = 6
        IF isProcessRunning(strComputer,strProcess) THEN
            'wscript.echo strProcess & " is running on computer '" & strComputer & "'"
            WScript.Sleep(9000)
            i = i + 1
        ELSE
            'wscript.echo strProcess & " is NOT running on computer '" & strComputer & "'"
            i = 6
        END IF
    Loop
    
    '******************* FINSHED REMOVE CITRIX RECEIVER UPDATER ************************************
    
     '******************* START REMOVE CITRIX ENTERPRISE CLIENT ************************************
     
    wscript.echo "Removing Citrix Reciever Enterprise Client. Please Wait...."
    
    
    WshShell.Run "CitrixReceiverEnterprise.exe  /uninstall /silent /noreboot", 1, True 
    
    i = 1
    'msgbox "Exit Receiver Loop"
    strProcess = "CitrixReceiverEnterprise.exe"
    
    Do Until i = 6
        IF isProcessRunning(strComputer,strProcess) THEN
            'wscript.echo strProcess & " is running on computer '" & strComputer & "'"
            WScript.Sleep(9000)
            i = i + 1
        ELSE
            'wscript.echo strProcess & " is NOT running on computer '" & strComputer & "'"
            i = 6
        END IF
    Loop
    
     '******************* FINISHED REMOVE CITRIX ENTERPRISE CLIENT ************************************
    
     'msgbox "Finished Enterprise Removing Reciever"
     
     '******************* START INSTALLING ONLINE PLUGIN ************************************
    
     wscript.echo "Installing New Citrix Client. Please Wait...."
     
    WshShell.Run "CitrixOnlinePluginFull.exe  /noreboot /silent SERVER_LOCATION=https://citrix.lchs.com.au", 1, True  
    
    
    i = 1
    'msgbox "Exit Receiver Loop"
    strProcess = "CitrixOnlinePluginFull.exe"
    
    Do Until i = 6
        IF isProcessRunning(strComputer,strProcess) THEN
            'wscript.echo strProcess & " is running on computer '" & strComputer & "'"
            WScript.Sleep(9000)
            i = i + 1
        ELSE
            'wscript.echo strProcess & " is NOT running on computer '" & strComputer & "'"
            i = 6
        END IF
    Loop
    
    '******************* END INSTALLING ONLINE PLUGIN ************************************
    
    
    wscript.echo "Downgrade Complete. Your Computer will now restart..."
    WScript.Sleep(3000)
    
    ' Function to check if a process is running
    FUNCTION isProcessRunning(BYVAL strComputer,BYVAL strProcessName)
    
        DIM objWMIService, strWMIQuery
    
        strWMIQuery = "Select * from Win32_Process where name like '" & strProcessName & "'"
        
        SET objWMIService = GETOBJECT("winmgmts:" _
            & "{impersonationLevel=impersonate}!\\" _ 
                & strComputer & "\root\cimv2") 
    
    
        IF objWMIService.ExecQuery(strWMIQuery).Count > 0 THEN
            isProcessRunning = TRUE
        ELSE
            isProcessRunning = FALSE
        END IF
    
    END FUNCTION

    No comments:

    Post a Comment