Deploying App-V to VMWare View Floating Pools using SCCM 2012 R2

Custom App-V Applications Installed and Ready on a View Linked Clone Pool?

This week I successfully designed and deployed a method for on-the-fly delivery of applications to VMWare View floating VMs using Microsoft’s App-V and SCCM 2012 R2. I wanted to achieve this in order to leverage the administrative capabilities of App-V while allowing the user experience to be enhanced by the upgradeable and customizable nature of the platform.

My design involves using a System Center Configuration Manager 2012 R2 server to deliver App-V 5.0 applications to targeted VMWare View pool device collections. This is in order to stage cloned machines, on-the-fly, and with specific group-based applications rather than deploying forked clones or one monolithic clone to each pool. The architecture allows for floating clones to immediately request a compliant  state as soon as the VM is finished cloning, using some special scripting.

The end result is a fully presentable, floating VM that is prepped and ready with all assigned applications available to a user at login.

Preparation

I haven’t found very much information in regards to setting up SCCM 2012 to do what we’re talking about here, but luckily the system is extensible and can be customized with just about any query that you can come up with. The problem is that SCCM wasn’t really designed to do what I wanted it to do.

The polling intervals, even at their most frequent, were too slow to get a discovered machine into a collection and push out all of the published apps all before a user grabs the desktop. There is just no built-in way to initiate a client check or software push, you have to wait for your configured schedules to pass or the schedule on the client in order for a health check to occur and for missing applications to be sent. I never let things like that stop me, though. I pulled up my bootstraps and went digging through logs, WMI, and process traces. After exhausting my resources and subjecting myself to hours of pouring through the different CCM namespaces and instances in the client and server WMI, I finally found some methods and queries to help accomplish my goal.

Because there isn’t much information on what we’re about to do here, and because it’s a somewhat non-standard architecture, I recommend performing a little extra development and stress testing to get a sense of how your network will handle the application deployment process. I’ve tested this deployment in a pool of machines that clone 10 at a time without any reaching any sort of limit on our 10GbE back-end network.

In the end this deployment can be used for group-limited or specialized apps that you need to deliver to only one set of users or many. In addition to locally installed applications on the base image, such as MS Office, and even ThinApp delivered applications using ThinReg, we can create a very customized and extensible experience for our users.

SCCM Configuration

There are a lot of great guides online for setting up SCCM 2012 R2. One in particular is this multi-part series on the windows-noob.com forum. I highly recommend using this or another guide for installing and setting up the initial configurations for your SCCM 2012 R2 system. If you use the guide linked above, follow it until Part 3 and stop. We’ll be configuring our Discovery Methods and everything else from this point on. If you use another guide, just get to the point where you have your initial site configured and all of your base roles installed.

The primary focus of our SCCM configuration will be in the discovery, client polling settings, application deployment settings, collection queries, as well as many other areas. We’ll also be assigning some scripts to the server and master clone image as well as to VMWare’s QuickPrep post-sync script assignment.

The CCM client also has to be installed in a particular way on a VMWare View master image in order for it to properly register with SCCM.

The idea is to have three collections of computers, one for Active and one for Inactive, and one for Non-Client machines. The active collection should be targeted towards the View pool OU where you’d like to deliver the applications, while the other two will help in management and keeping our deployment clean. We’ll want polling for discovery of systems and members of collections to happen very frequently in order to discover new machines as they’re being cloned. We will then have to customize our base image with a scheduled task and script in order for the policy request to happen, immediately, without waiting for the polling interval.

If you have your SCCM 2012 R2 server in place and have not yet configured it with any discovery or boundary settings, then we’re ready to begin.

Step 1 – Configuring Application Web Services

From a standard deployment, without any further configuration past install and site setup, we’ll require these two additional roles:

  1. Application Catalog Web Service Point
  2. Application Catalog Web Site Point

To add these roles, navigate to Administration> Site Configuration> Servers and Site System Role, right-click on the server that you want as your distribution point and select Add Site System Roles.

Add site role

Click Next through the General and Proxy pages to accept the defaults or enter your preferred values.

At the Role Selection screen choose the Application Catalog Web Service Point and Application Catalog Web Site Point and click Next.

Role Selection

In this example we won’t be using a certificate, only the default HTTP on port 80, but if you’d like to add a certificate and configure HTTPS please do so now.

Leave the IIS website and Web application name as the default and click Next to continue.

Web Services Point

 

Once at the Application Catalog Customization screen select a custom title to display on your Application Catalog web page. The color you select here will set the theme of the Application Catalog website only, not the Software Center.

Catalog Customization

After setting the name, click Next to add the roles and Close to finish.

To verify successful web services installation, use CMTrace to check C:\Program Files\Microsoft Configuration Manager\Logs\awebsvcMSI.log. Search for the message “installation operation completed successfully“.

Install Success

To verify that application web services are running and online, check C:\Program Files\Microsoft Configuration Manager\Logs\awebsctl.log for the message “previous state was 0” which indicates an Online status.

Previous State was Online

Step 2 – Configuring Discovery

The Discovery Methods I’ve chosen are only Active Directory User Discovery and Heartbeat Discovery. Navigate to Administration> Hierarchy Configuration> Discovery Methods. 

We will be enabling only the following Discovery methods:

  1. Active Directory User Discovery
  2. Heartbeat Discovery

Discovery

WARNING: DO NOT ENABLE FOREST DISCOVERY

If you enable Active Directory Forest Discovery in hopes of automatically setting boundaries you might find that every object in your forest has been replicated to the SCCM server. This is unnecessary bloat that can be avoided by not enabling Forest Discovery.

Right-click Active Directory System Discovery and select Properties. Click the star icon to create a new Target OU and select the container holding the users for your View environment.

User Discovery

Click OK to save and close.

Right-click and configure the Heartbeat Discovery to collect client data every 1 hour.

Heartbeat

 

Step 3 – Configure Boundaries and Boundary Groups

To configure Boundaries and Boundary Groups without Forest Discovery turned on is no problem.

Navigate to Administration> Hierarchy Configuration> Boundaries. Right-click and select Create Boundary. In the Type dropdown select Active Directory site.

Click Browse to view your AD sites and choose the one for this boundary. Click OK to save and close. If you have multiple AD sites, repeat the process.

AD Site Boundary

Boundary Group

Once the Boundary is set up, right-click on the Boundary Groups node on the Navigation pane and select Create Boundary Group.

Give this a general name and add all of your targeted boundaries.

Boundary Group

Click OK to save and close.

We’ll be using this Boundary Group to associate with the Distribution Point that clients will be streaming the App-V packages from.

Step 4 – Configure Distribution Point

A default Distribution Point should have been installed with the initial site installation. If you want to configure a separate DP, add the new CM server, role, and configure it with the settings below.

Navigate to Administration> Site Configuration> Distribution Points and right-click the DP server. Select Properties.

We want to enable the following few settings:

  1. On the General tab check Enable and configure BranchCache for this distribution point.
  2. On the Boundary Groups tab add the boundary created in Step 3 above

Step 5 – Configuring Device Settings

In order to adjust some of our client polling schedule and agent settings, we must create a custom Device Setting.

To do so, Navigate to Administration> Client Settings. Right-click and select Create Custom Client Device Settings.

Create Client Settings

Give the new Device Setting template a descriptive name and check the boxes for:

  1. Client Policy
  2. Computer Agent Policy
  3. Software Deployment
  4. State Messaging

Device Settings

We’re setting high frequency polling intervals, against all recommendations, for the policy and client checks. This is in order to maintain communication so that we can more accurately age and decommission deleted linked clones.

On the Client Policy tab set the polling interval to 3 Minutes.

Client Polling

 

On Computer Agent, click Set Website and select your default catalog website that we configured in Step 1. 

Catalog Website

Still in Computer Agent, set an Organization name to be displayed in the Software Center, much like the “Organization Name” on the Application Catalog webpage.

Organization Name

Name displayed in Software Center

On the Software Deployment tab set the schedule to every 5 minutes.

Software Deployment

On the State Messaging tab, set the State message reporting cycle to 1 minute.

State Message

Click OK to save and continue.

Step 6 – Configuring Collections

Now that we have the Server Roles and Discovery squared away, we can focus on our Device Collections.

Collection Issues

I first wanted to talk a little about the issues I had to overcome in order to get my collections working how I wanted.

SCCM is a great tool because it allows for customizable queries based on pretty much any WQL command you can think of and has a number of built in queries available to use. You can also use Powershell, VBS, and check registry keys for queries. These are great features! However the built in aging and deletion policies just couldn’t keep up with the churn of a floating desktop pool where machines are constantly being created with the same name over and over again. The built-in tools just couldn’t handle it.

To resolve this I engineered a set of scripts and tasks to either automatically re-register an inactive device or remove it from one of the two inactive collections.

There are three sets of collections that we need in order to handle our immediate discover and app distribution. We also need scheduled scripts to poll the inactive collections to delete or register them in a controlled way.

Collection One – The Easy Collection (Healthy VMs)

The first device collection will be for our healthy VMs that were discovered. This is a very simple collection and only requires a couple of queries depending on how many OUs you are targeting. Ideally, we should only be targeting one View pool per DP and per Application Collection in order to maintain a manageable load.

To create the first Collection go to Assets and Compliance> Device Collections. Right-click and Create Device Collection.

Give the collection a name like “App-V Pool VMs” or something for the application group. Click Browse and select the All Systems device collection as the Limiting collection.

Device Collection

Click Next.

Click the Add Rule dropdown and select Query Rule.

In the next prompt give the rule a name identifying it as an OU rule and click Edit Query Statement…

Create Query

Click on the Criteria tab and then click the little star button to create a new criteria.

Criteria

 

Select System Resource as the Attribute Class and System OU Name for the Attribute.

Select is equal for the Operator and click the Value button to find and select your target OU.

OU Query

Click OK to continue and save. Repeat for any other target OUs in this deployment.

Once all of the queries are added check the box for Use incremental updates for this collection. 

Now click Schedule and set the Custom Interval for 1 minute.

Click Next to continue and create the collection.

Once the Device Collection has been created, navigate back to Administration> Client Settings and right-click the Custom Device Setting that you created in Step 5 and select Deploy.

Select your App-V Pool VMs and click OK to apply your device settings to the new device collection.

Deploy Client Settings

Collection Two – The Problem Child (Aged Device Records)

The second collection will be a collection of old VMs that have been replaced by new clones. We want our old device discoveries to be cleared out of our active collection in order to clear administrative clutter and and prevent possible issues.

This collection will be based on a custom query that I built after digging through the WMI to find a suitable value to represent an aged machine. I decided to use the Last Policy Request time because active clients maintain regular policy requests based on our configured polling schedule.

Create a new Device Collection and name it “Unresponsive Devices”. Select All Systems as the Limiting collection and click Next.

Create a new Query Rule like in the previous collection. Name the query “No Policy Check for 10 Minutes” and click Edit Query Statement…

On the General tab, click Show Query Language. Copy and paste the following custom query into the field and click OK to save.

Note: I’m a bit new to WQL queries, so if you have a suggestion on how to clean this up feel free to post a comment. This is not the most pretty statement I’ve ever written.

select SMS_G_System_CH_ClientSummary.LastPolicyRequest from SMS_R_System inner join SMS_G_System_CH_ClientSummary as s1 on s1.ResourceID = SMS_R_System.ResourceId inner join SMS_G_System_CH_ClientSummary on SMS_G_System_CH_ClientSummary.ResourceID = SMS_R_System.ResourceId WHERE dateDiff(mi, SMS_G_System_CH_ClientSummary.LastPolicyRequest, GetUTCDate()) > 10

Once you click OK you will be notified that the query has a syntax error. Just ignore this and click Yes to continue.
Syntax Error

Once the query is added check the box for Use incremental updates for this collection.

Click Schedule and set the Custom Interval for 2 minutes.

Click Next to continue and create the collection.

Add Collection Exclusion to Active Devices

Now we need to exclude the Unresponsive Devices collection from the App-V Pool VMs device collection.

To do so, right-click the App-V Pool VMs collection and select Properties.

Click the Membership Rules tab. Click the Add Rule dropdown and select Exclude Collections.

Check the box next to the Unresponsive Devices collection and click OK to save.

Select Unresponsive Collection

Unresponsive Devices

Collection 3 – Inactive Devices that need Re-register or Delete

In the third collection contains devices that I’ve identified as either needing to be re-registered or deleted.

The cloned machines all come up so fast that sometimes the old device entry is still in the collection and it causes some problem with the aging calculation. A machine like this will sit as “Inactive” in the Configuration Manager and never receive its deployed apps.

Once we put these machines into a collection,we can run a re-register commands to attempt and discover the machine. The method we’ll use has built in logic to only attempt to re-register a machine if it has not been re-registered in the last runtime cycle. This helps ensure fault-protection.

If the machines continue to appear here, we will have a scheduled task to remove them in the same way the unavailable machines will be removed. More on that below.

Create a new Device Collection and name it “Non-Client Devices“. Select the App-V Pool VMs device collection as the Limiting collection and click Next.

Create a new Query Rule. Name the query “Non-Client Devices” and click Edit Query Statement

Click on the Criteria tab and click the star icon to create a new criteria..

For the Criterion Type, select Null Value. Click Select and set the Attribute Class to System Resource and set the Attribute to Client Type.

Null Client Type

Click OK and then select is NULL for the Operator.

Null Client Criteria

Click OK to save this criteria and click the star icon again to create a second criteria for this rule.

For the Criterion Type, select Null Value. Click Select and set the Attribute Class to System Resource and set the Attribute to Client.

Null Client

Click OK and then select is NULL for the Operator.

Click OK to save this criteria. You should now see two Criteria linked with an And operator. This makes sure that both queries are true for this rule to take effect.

No Client Rules

Click OK to save this query.

Now add an exclusion rule to this collection to exclude the Unresponsive Devices collection.

Set the Schedule for this collection to every 3 minutes.

Non-Client Polling

Step 7 – Automatically Remove Unresponsive Devices or Re-Register Machines

We have our collections set up, the custom client settings applied, our boundaries configured, our Distribution Point in place, and our application web services ready and waiting. But before we move on to the client and application delivery, let’s take one last look at the SCCM server to do a little more for our cleanup routine.

We moved all of our Unresponsive Devices into a new collection that detects clients that haven’t checked in with the SCCM server for more than 15 minutes. SCCM has no way of automatically deleting or clearing a collections with an automated task, so I had to come up with a custom script to perform this as a Windows Scheduled Task.

Device Removal Tasks

The script is a PoSH script that queries WMI for all members of a specified collection and deletes them.

We first need to retrieve the Unresponsive Devices Collection ID for the script. To find this, right click the Unresponsive Devices collection and select Properties.

Collection ID
Record the Collection ID.

Now create a new PowerShell script under the folder C:\Scripts named removeUnresponsiveDevices.ps1.

Create the script with the following code. As always, code that needs to be modified is in Bold and Italics:


############################################################################
# Scriptname: removeUnresponsiveDevicesMembers.ps1
# Description: Remove aged SCCM devices
# By: Adam Baldwin
#
# Usage: The script checks the Unresponsive device collection in
# SCCM and removes all members.
# Set as a scheduled task on the SCCM server
#
############################################################################

# Set site name and SCCM Server name

$SCCMServer = "YOURSERVERNAME"
$sitename = "YOURSITENAME"
$collID = "YOURCOLLECTIONID"

# Specify the Collection to target

$compObject = get-wmiobject -namespace "root\sms\site_$sitename" -query "select * from SMS_FullCollectionMembership WHERE SMS_FullCollectionMembership.CollectionID='$collID'" -computername $SCCMServer

# Delete each member of the Collection

foreach ($member in $compObject) {
	$resourceid = $member.ResourceID.ToString()
	
	If ($resourceid -eq $null) {
		Continue
	}
	Else {
		# Invoke delete() method on WMI instance sms_r_system
        
        $comp = [wmi]"\\$SCCMServer\root\sms\site_$($sitename):sms_r_system.resourceID=$($resourceid)"
		$comp.psbase.delete()
	}

}

Once this is ready and saved create a new scheduled task to run daily and repeat every 5 minutes, indefinitely.

5 minutes Delete

For the Action, select Start a program. Type in “powershell.exefor the Program/Script. Add the following Arguments:

-command "& c:\scripts\removeUnresponsiveDevices.ps1"

Action

The task should be set to run with an account that is local admin and is allowed to log on as service. Check the radio button to Run whether user is logged on or not and Run with highest privileges.

Run w privileges

 Non-Client Device Removal

Retrieve the Device Collection ID of the Non-Client Devices collection and create a second script called removeNonClientDevices.ps1. The script should be exactly the same as the one above except with the Non-Client Devices ID.

Create a Second Scheduled Task and set this one to run every 10 minutes to remove Non-Client Devices.

Remember to set the user account to run when not logged on and use the service account that we assigned in the previous task.

Re-Registration Task

Now we need to create a re-registration script and task to attempt to bring online Inactive devices.

Another PoSH script needs to be created and set to another scheduled task. You’ll need to fill in Both of the collection IDs for your Active App-V Pool VMs collection and for the Non-Client Devices collection.

You’ll also need a copy of Psexec for this to run, so pick it up in the Sysinternals suite and put it in your local scripts folder on the server where the task is set.

Here’s the script:

############################################################################
# Scriptname: registerDevices.ps1
# Description: Re-registers inactive SCCM devices
# By: Adam Baldwin
#
# Usage: The script checks the Non-client device collection in
# SCCM and re-registers them once per two rounds of execution.
# Set as a scheduled task on the SCCM server
#
############################################################################


# Creates registry keys if they do not already exist
# The key contains previously registered machines in the 
# Last iteration of the script 

if (!(Test-Path -Path "hklm:software\SCCM\register")) {
 new-item -path "hklm:software\SCCM"
 new-item -path "hklm:software\SCCM\register"
 New-ItemProperty "hklm:\software\SCCM\register" -Name "registered" -Value "" -PropertyType "String"
}



# Set site name and SCCM Server name

$SCCMServer = "YOURSCMSERVER"
$sitename = "YOURSITENAME"
$inactiveCol = "INACTIVEDEVICECOLLECTION-ID"
$activeCol = "ACTIVEDEVICECOLLECTION-ID"

# Assign the clients from the Active and Inactive device collections

$inactiveComps = get-wmiobject -namespace "root\sms\site_$sitename" -query "select * from SMS_FullCollectionMembership WHERE SMS_FullCollectionMembership.CollectionID='$inactiveCol'" -computername $SCCMServer
$activeComps = get-wmiobject -namespace "root\sms\site_$sitename" -query "select * from SMS_FullCollectionMembership WHERE SMS_FullCollectionMembership.CollectionID='$activeCol'" -computername $SCCMServer

$registered = ""

# Delete each member of the Collection

foreach ($inactive in $inactiveComps) {
 
   # Convert the member name to a string
   $inactiveName = $inactive.Name.ToString()
 
   # If active comps does not contain the inactive device
   # then perform the remote command


   # Collects the previously registered machines from registry
   # and splits it into an array
   $test = (Get-ItemProperty "hklm:software\SCCM\register").registered
   $test = $test -split ","

   # Check to see if the test array contains the current name
   # if so just run an empty statmenet. Else run the remote command
   if ($test -contains $inactiveName){}
   Else {
      # Use PSExec to run a re-register script on remote machines
      e:\scripts\psexec.exe /accepteula \\$inactiveName /d /s powershell.exe " \\contoso.local\netlogon\scripts\re-registerccm.ps1"
 
      # Record which devices have been registered this roud
      $registered += $inactiveName + ","
      $registered = $registered -Replace " ", ""
   } 


}

# Sets the registered devices from this round into the registry
Set-ItemProperty "hklm:software\SCCM\register" -Name registered -Value $registered

Make sure the account is able to write and read to the registry where we’re recording our hits. That key is HKLM\Software\SCCM\register.

Name the script registerDevices.ps1 and set the scheduled task to run every 5 minutes. Use the same service account that you used in the previous tasks.

Client Portion of the Re-Register

The above script references a PoSH script on the domain’s netlogon volume. It also requires Certmgr.exe in order to delete and re-register the certificates for the CCM agent. I’ve uploaded a x86 Visual Studio 2010 copy of certmgr.exe here. Save certmgr.exe it to the netlogon volume where your PoSH are sitting.

Place a new .ps1 there named “re-registerCCM.ps1” and use the following code:

############################################################################
# Scriptname: re-registerCCM.ps1
# Description: Resets the SCCM registration for the device
# 
# By: Adam Baldwin
#
# Usage: Place this script onto an accessible share and initiate 
# with the SCCM scheduled task that runs psexec against
# all inactive machines with this code
#
############################################################################

# Stop SMS AGEnt service
stop-service ccmexec

# Delete the SMS config
del c:\windows\smscfg.ini

# Reference shared volume for certmgr.exe
# to remove SMS certificates
\\contoso.local\netlogon\scripts\certmgr.exe -del -all -s -r localMachine "SMS"

# Starts the SMS Agent Service
start-service ccmexec

# Pause for 5 sec
sleep 5

# Run CCM Evaluation executeable
C:\Windows\CCM\CCMEval.exe

# Run local scheduled task to check-in with SCCM
SCHTASKS /Run /TN "Request Client Policy"

A Special Note about SCCM Service Account and Script Tasks

The service account used to drive these tasks on the SCCM Server should be assigned the Full Administrator role in SCCM and have had the PowerShell terminal launched from inside of SCCM.

*THIS IS IMPORTANT*

In order for the script to run with the specified account on the server, Powershell needs to be launched from the Configuration Manager while logged in with said account. Either log into windows with the account or right-click the Configuration Manager and run as different user.

Log into the Configuration Manager with the account that will be driving this scheduled task and click the Menu dropdown in the top left of the application. Select Connect via Windows PowerShell.

Connet via Powershell

This will enable your account to connect to and manage the SCCM namespace.

VMWare View Master Image Configuration

Now that the server components are all in place and ready we need to configure our master image to work with SCCM 2012 R2.

As part of the setup we need to configure the CCM agent to be available in a clean state until first run. We’re also going to implement a Computer Startup scheduled task that will initiate an immediate client policy health check, which in turn immediate requests missing software packages to be installed.

Part 1 – Configuring Master Image Check-in Task

To save time and avoid complication, we’re going to set the script and scheduled task first. This way we don’t have to repeat Part 2 of this process over again.

NOTE: The master image needs to be joined to the domain in this step and a service account needs to be configured to run scheduled tasks on the VM

Start up and log into your master clone image. Join it to the domain.

In order for our script to work we need to set the ExecutionPolicy to either Bypass, if you don’t plan to sign your script, or RemoteSigned if you plan to sign it. To set the ExecutionPolicy for the local machine, run PowerShell as an Administrator and type in following command:

Set-ExecutionPolicy -Scope MachinePolicy Bypass

This can also be applied in GPO under Computer Configuration> Policies> Administrative Templates> Windows Components> Windows Powershell. The setting is Turn on Script Execution. Set to Allow all scripts or Allow local scripts and remote signed scripts respectively.

Execution GPO

Now that ExecutionPolicy is set, create a new script PowerShell in C:\Scripts named requestMachinePolicy.ps1. 

The script should contain the following:

C:\Windows\CCM\CCMEval.exe

Invoke-WMIMethod -Namespace "root/ccm" -ComputerName "." -Class SMS_Client -EnableAllPrivileges -Name RequestMachinePolicy

This script immediately starts up the SMS Agent service and then performs a WMI method invocation that performs the Client Health and Policy check. This command will initiate communication back to the server and trigger software installation.

Now that the script is saved and ready we need to implement a Scheduled Task that runs at machine power on. Create a new Basic Task and name it Request Client Policy. Set the Trigger to run One Time. 

Since we’ll be running this on-demand, just set it to some time in the past and click Next.

One time task

 

For the Action, select Start a program and type “Powershell.exe” into the Program/script field. Add the following argument:

-command "& c:\scripts\requestMachinePolicy.ps1"

Check the box to bring up the task Properties once it’s been created.

For the User Account, use the service account that you created that has been set to allow Run as Service and is a local administrator on the VM. Check the radio button for Run whether user is logged on or not and Run with highest priveleges. Click OK and type in your Service Account credentials to save the task.

Policy Request Task AccountPolicy Request Task Account - Authenticate

Click on the Settings tab. Make sure that the box is checked to Allow task to be run on demand. I also set the retry to every 5 minutes.

Run on demand

Now that our scheduled task and client-side script is in place, Remove the VM from the Domain and continue along with Part 2 of the Client Setup.

Part 2 – Configuring CCM Agent for VMWare Master Image

Thanks to this article by Henk Hoogendoorn on his blog I was able to correctly configure the CCM client on a VMWare master image to show up properly in the management console. This was a big step forward in this project and the task is very straightforward.

The simple procedure is as follows:

  1. Install the CCM client on your master image with all of your site parameters
  2. Stop the SMS Agent service in the Services console or from command line
    (command line: net stop ccmexec)
  3. Delete %systemroot%\SMSCFG.ini
  4. Open Computer Account Certificates console. Start> Run> type “MMC” and press Enter.
  5. Click File> Add/Remove Snap-in and select Certificates. Choose Computer Account and click OK to continue.
  6. Navigate to SMS> Certificates and delete both SMS certificates.
  7. Immediately Shutdown and take a Snapshot

SMS Certs

This will make our master image so that it creates fresh identifiers in its CCM config for the server to identify it as a new machine.

Part 3 – Configure VMWare Script Timeout

In order for the next script to run for the amount of time we need it to we have to increase our master image’s quickprep script timeout in the registry. See this VMWare publication for more info.

We’ll be modifying a key in the registry so go to Start> Run – regedit.exe

Navigate to the key HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\vmware-viewcomposer-ga

Change the DWORD value of ExecScriptTimeout to 900000

ExecScriptTimeout

This gives us a total script runtime duration of 15 minutes, even though we’ll only be allowing up to 13 minutes of runtime at first.

Part 4 – VMWare View Pool Configuration

The final piece of the puzzle is configuring the VMWare View pool to allow the newly cloned VMs a certain amount of time in order for the applications to download and install.

I’ve accomplished this task by using the QuickPrep post-synchronization script which allows execution of a remote script on a new clone immediately following customization.

In my script I’ve included a method for preventing the new clone from becoming available by simply disabling the View Agent service for a period of time before re-enabling it. I used sleep in order to pause the execution of lines and include a call to the local scheduled task to ensure Client Health Check has initiated and passed.

Once the script finds that the folder C:\ProgramData\App-V exists it knows that the software has been installed and it then stops requesting health checks. This occurs every 1 minute for a maximum of 13 minutes.

Put this .ps1 script on the Domain’s netlogon volume for the client to access:




############################################################################
# Scriptname: ccmstart.ps1
# Description: Start SMS Agent and initiate client check-in
# procedure to begin installing App-V packages
# By: Adam Baldwin
#
# Usage: Set as the VMWare View QuickPrep Post-syncrhonization script
# for your App-V deployment pool
#
############################################################################


# Stop and disable View Agent Service
stop-service WSNM
set-service -name WSNM -StartupType Disabled

# Start SMS Agent service and execute CCMEval.exe
start-service ccmexec
C:\Windows\CCM\CCMEval.exe

# Set loop counter
$count = 0
$ding = 0
# Loop the check-in task every 1 minute while the App-V folder
# does not exist or for 6 minutes

while (((Test-path C:\ProgramData\App-V) -ne $True) -or ($count -lt 5)) {

   # Initiate the local task on the VM to perform
   # client check-in
   SCHTASKS /Run /TN "Request Client Policy"

   sleep 60

   $count++

   # If the count reaches 13 (minutes) or more, start the View service
   # and Exit the routine
   if (($count -eq 13) -or ($count -gt 13)) {
 
      Write-Host "Reached 10 minutes. Starting View Services..."

      set-service -name WSNM -StartupType Automatic
      start-service WSNM
      Exit
   }

   # If the count reaches 8 (minutes), initiate re-register
   if ($count -eq 8) {
 
      Write-Host "Reached 8 minutes. Initiating re-registration..."
 
      # Stop SMS AGEnt service
      stop-service ccmexec

      # Delete the SMS config
      del c:\windows\smscfg.ini

      # Reference shared volume for certmgr.exe
      # to remove SMS certificates
      \\contoso.local\netlogon\scripts\certmgr.exe -del -all -s -r localMachine "SMS"

      # Starts the SMS Agent Service
      start-service ccmexec

      # Pause for 5 sec
      sleep 5

      # Run CCM Evaluation executeable
      C:\Windows\CCM\CCMEval.exe

      # Run local scheduled task to check-in with SCCM
      SCHTASKS /Run /TN "Request Client Policy"

      Write-Host "Re-registration Complete"
   }

   # If the App-V folder is detected, write output
   if (((Test-path c:\ProgramData\App-V) -eq $True) -and ($ding -ne 1)) {
   
      Write-Host "App-V Folder Detected"
      $ding = 1
   }
}

Write-Host "Script Fully Completed"

# Enable and start the View Agent service
set-service -name WSNM -StartupType Automatic

start-service WSNM
 

 

Save this file as CCMSTART.PS1 in a location that is accessible to all the VMs in the pool, again recommended to be your netlogon volume. Once the script is saved and ready configure your VMWare View Floating Pool to use a QuickPrep post-synchronization script.

Here are the instructions:

  1. Open View Administrator
  2. Navigate to Inventory> Pools
  3. Right-click your pool and select Edit (or wait until the Guest Customization screen if creating a new pool)
  4. Open the Guest Customizations tab
  5. Next to Post-synchronization script name, type “C:\Windows\System32\WindowsPowerShell\v1.0\Powershell.exe”
  6. Next to Post-synchronization script parameters, type “-command & \\contso.local\netlogon\scripts\CCMSTART.ps1″ (Path to your CCMSTART.ps1 script)
  7. Click OK to save and close

Guest Customization

That’s it for the Client Setup!

 

SCCM App-V – Application Deployment Process

Now we need to move onto the process of distributing the App-V Applications. There are just a few specifications that we need to verify when publishing new App-V apps so be sure to review all areas closely.

Part 1 – Configure the Application

In the SCCM 2012 R2 console navigate to Software Library> Application Management. In this tree, right-click Applications and select Create Application.

Select Microsoft Application Virtualization 5 in the Type dropdown and Browse to your App-V application on the datastore.

Create Application

Click Next to continue and create the application.

Now that the application is added, we have to configure its distribution and deployment settings. To do so, right-click on the App-V program in the Applications window and select Properties.

On the General Information tab, check the box for Allow this application to be installed from the Install Application task sequence action without being deployed.

App Properties - General

On the Distribution Settings tab, check the radio button for Automatically download content when packages are assigned to distribution points and set the Distribution Priority to High.

Distribute Content

On the Deployment Types tab, select the Deployment type that is present and click Edit.

Deployment Type Edit

Click on the Content tab and make sure that the box for Enable peer-to-peer content distribution is checked. Click the dropdown for both Deployment options fields and select Stream content from distribution point. 

Deployment Type Properties

Click OK to save and close this window.

Now click OK to close and save the Properties window.

Part 2 – Deploy and Distribute the Application

Now that all the properties are set on the application, we need to distribute the content.

Still in the Applications window, right-click on the newly created application and select “Distribute Content“. Once you reach the Content Destination page, click Add and select Distribution Point.

Distribute

Select the Distribution Point we created earlier and click OK to save.

Select DP

 

Click Next to continue and distribute the content.

Now we need to Deploy the content to our VM device collection.

Right-click the Application and select Deploy. On the first page click Browse next to Collection to bring up the Select Collection window. Click the dropdown in the top left where it says User Collections and select Device Collections.

Select Collection

Select your App-V Pool VMs (or similarly named) device collection and click OK to continue.

Select Healthy Device Collection

Click Next. We’ve already distributed the content so you should be able to click Next through the Content page.

When you arrive at the Deployment Settings page, we need to change the Purpose field to have Required instead of Available. Click the dropdown and select Required. Click Next to continue.

Required

 

On the Scheduling page, keep the defaults with the radio button As soon as possible after the available time checked. click Next.

Scheduling

On the User Experience page, select your preferred User notifications option and check the box for Software Installation. This ensures that the software can be pushed to the desktops without intervention or waiting for a maintenance window.

User Experience

Click Next to continue through the remaining sections and deploy the software to your device collection.

Completion and Testing

Congratulations! You’ve just implemented a staging solution for App-V applications for VMWare View Floating VMs, which is no easy task!

Our implementation will cause a delay on the availability of newly cloned machines, but once they become ready the user should have access to all of the provisioned applications at login.

To test simply delete all available machines from your App-V View pool and delete all discovered devices in the SCCM 2012 R2 management console.

Once the new VMs have cloned they should sit in an Agent Unreachable state for the specified period of time. If they come up immediately, without a pause, then the post-synchronization script didn’t run or something went wrong.

Monitor the SCCM to make sure that new devices are being discovered and added to the App-V Pool VMs device collection. The devices must be discovered and available in the proper device collection in order for the correct policies and applications to be assigned.

A good way to ensure that your devices are checking in and communicating is to look at the timestamp of the Policy Request for a client. If the timestamp is within the last 10 minutes (according to our query rule) then the client is most likely active. A healthy client should be checking in every 5 minutes with our configuration.

Policy Request

 

Once machines are Available in your View pool, log into the pool to make sure you have your application load. If not, there are a couple of places to check for logs and see if the client ran all of the proper scripts and requests.

Logs

To check the VMWare QuickPrep logs, navigate to C:\Windows\Temp on the client machine and find the vmware-viewcomposer-ga-new.log. 

Search this file for the word “Post” and you should find the post-synchronization script results. All of the output from the script, including any errors returned from the PoSH script, are displayed here. You should see a similar output for a machine in the App-V pool. If the script completes successfully you will see “Script Fully Completed” at the end of the Post-script logging message, otherwise the machine will simply be enabled in View with or without applications:

2014-04-27 18:58:04,328 [336] INFO  Ready  -  [Ready.cpp, 128] Running the PostSync script: "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -command & \\dcprod1\netlogon\scripts\ccmstart.ps1 with timeout: 900000
2014-04-27 19:07:31,218 [336] INFO  Guest  -  [Guest.cpp, 509] Script "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -command & \\dcprod1\netlogon\scripts\ccmstart.ps1 standard ouput: WARNING: Waiting for service 'VMware View Agent (WSNM)' to stop...
SUCCESS: Attempted to run the scheduled task "Request Client Policy".

SUCCESS: Attempted to run the scheduled task "Request Client Policy".

SUCCESS: Attempted to run the scheduled task "Request Client Policy".

SUCCESS: Attempted to run the scheduled task "Request Client Policy".

SUCCESS: Attempted to run the scheduled task "Request Client Policy".

SUCCESS: Attempted to run the scheduled task "Request Client Policy".

SUCCESS: Attempted to run the scheduled task "Request Client Policy".

SUCCESS: Attempted to run the scheduled task "Request Client Policy".

Reached 8 minutes. Initiating re-registration...
CertMgr Succeeded

SUCCESS: Attempted to run the scheduled task "Request Client Policy".

Re-registration Complete
INFO: scheduled task "Request Client Policy" is currently running.

SUCCESS: Attempted to run the scheduled task "Request Client Policy".

SUCCESS: Attempted to run the scheduled task "Request Client Policy".

Script Fully Completed

To verify the scheduled task ran successfully, check the task in Task Scheduler for the Last Run Time and the Last Run Results.

If you would like to investigate the CCM logs, navigate to C:\Windows\CCM\logs and use CMTrace.exe to check through the following log files:

  1. AppDiscovery.log
  2. CAS.log
  3. CCMEval.log

You should find recent messages about successfully running checks and retrievals of application packages.

Increase Timeout

If you find that VMs are coming available after the timeout but still don’t have the requested applications installed, increase the timeout on the CCMSTART.PS1 file that we set in the Post-synchronization scripts field.

The default is to allow for 13 minutes until forcing a VM online, whether apps are available or not. Increase this timeout to give the machines more time to install the application load. Look for the line of code where $count -eq 13 and $count -gt 13 and set the values to 15 minutes before forcing the VM to an available state:

# If the count reaches 15 (minutes) or more, start the View service
# and Exit the routine
if (($count -eq 15) -or ($count -gt 15)) {
 

Also monitor the App-V Pool VMs device collection during the cloning phases to see how your devices are showing up and if they become Active. You may see duplicates and the old machines will be moved to the Unresponsive Devices collection, this is normal. Verify the timestamps on the Policy Request for a client in order to verify that the new machine is active in the correct device collection.

Manually Initiating Client Policy Request

In order to manually initiate a client policy request to check for new software, you can run the PowerShell script that we created on the local VM or run the scheduled task that we created. Either one will perform the Client Health Policy check-in to request missing software and compliance states. If you’d like to just run the PowerShell command that initiates this client check, simply use the following:

Invoke-WMIMethod -Namespace "root/ccm" -ComputerName "." -Class SMS_Client -EnableAllPrivileges -Name RequestMachinePolicy

Summary

That’s it! Some of the components of this deployment aren’t necessarily the most pretty, but they’re functional. If you’d like to hang on to your VMWare View linked-clone pools while still using an App-V solution then this is the design for you.

We delayed the availability of our VMs a bit but the resulting effect is a fully staged VM with App-V applications delivered and ready. I feel that this App-V deployment, in conjunction with both locally installed and other virtualized applications, can deliver the benefit of increased flexibility to the user experience. We hope to cut down the time it takes to make changes or upgrade applications in our environment, to the point where testing and configuration can occur in the same cycle and be released much sooner than the cycle of image change requests that we currently use.

I’ve considered testing full download and deployment rather than streaming for some of the Applications, because of the delay when first launching, so stay tuned for any new advice or tricks that I might come up with.

Please let me know if you have any trouble, questions, or suggestions. This is still a work in progress that I hope to improve upon as time goes by!

Happy Scripting!
~ScriptdEEZ

 

 

Advertisements

2 thoughts on “Deploying App-V to VMWare View Floating Pools using SCCM 2012 R2

  1. This is great and really expands on my own implementation of this in regards to the clean up of inactive devices etc. which I plan on adding to my setup.

    Just one question in regard to the removeUnresponsiveDevicesMembers.ps1 script…

    This makes use of the “Unresponsive devices” collection (which is in fact a collection of responsive devices but is then excluded from Active devices to achieve the desired result).

    Unless I am reading the script wrong (this is always a possibility! ) it seems that the script will delete all of the active devices as opposed to the inactive ones.

    Am I missing something here?

    Thanks and great post!

    • Thanks so much!

      In looking at the first few variable declarations in the script, we’ll actually need to define the Collection ID for the target collection of our choosing.

      # Set site name and SCCM Server name
      
      $SCCMServer = "YOURSERVERNAME"
      $sitename = "YOURSITENAME"
      $collID = "YOURCOLLECTIONID"    <---------  Retrieve Collection ID from SCCM
      
      # Specify the Collection to target
      
      $compObject = get-wmiobject -namespace "root\sms\site_$sitename" -query "select * from SMS_FullCollectionMembership WHERE SMS_FullCollectionMembership.CollectionID='$collID'" -computername $SCCMServer
      

      The last line uses the ID to reference WMI for the collection. So, technically, you can use this script to remove the devices from any collection that you define.

      To retrieve the Collection ID, just browse the properties on the General page.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s