Link App-V Packages to “C:\Program Files” Directory

Introduction

In working with sequencing different App-V 5 applications, I’ve found there can be requirements for binaries to exist at absolute paths in C:\Program Files.

This is somewhat problematic because, from what I can find, there is no built-in or easy way to deliver packages to their originally named, and absolute location on a system. No worries, though. We can use some custom scripting to help us out along with the help of System Center Configuration Manager 2012 R2.

Issues

The application that I was working with when I encountered the issue, Meditech Client Server, gave me an error stating that the program was “Not installed in the correct location under C:\Program Files“.

In researching, there wasn’t much info in the way of placing App-V packages into their original location. It always goes somewhere under the App-V folder using the Package ID and Version ID of the published application.

I decided that a symlink could possibly work for this situation since the app seemed to run fine and only complained about the file location. I created a new symlink in C:\Program Files\ with the following command from a PowerShell terminal:

mklink /J "C:\Program Files\APPLICATION_DIRECTORY" C:\ProgramData\App-V\*Package_ID*\*Package_Version*\root

Sure enough mapping the directory as a Windows junction allowed the application to run without issue.

If this application was going to work as an App-V package, an automated way to perform this symlink creation would need to be implemented so that the user would have a working App-V delivery without any additional wait or hassle.

Package Scripts, not

My first attempt at resolution was to use Package Scripts to configure the changes from within the application deployment. It was a logical solution.

The problem here is that the Machine and User Package Event tags don’t provide good timing in making the customization change. The way to make a symlink to an App-V package is by using both the Package and Version IDs, so we need for a script to run after the package has been published in order to use the get-appvclientpackage cmdlet to discover the parameters for mapping.

After playing with the different Event Tags I found that they either initiated too early, before get-appvclientpackage would return any information, or at first run of the App-V application which would cause the associated shortcuts to fail.

Script Installer

To work around this I set up a new Script Installer in SCCM 2012 and created a PowerShell script to perform the symlink creation. This allows us to config the junctions immediately after the application dependencies are met by linking the two in SCCM.

We can then configure Start Menu shortcuts pointing to “C:\Program Files\” during sequencing the App-V 5 applications, or by editing the DeploymentConfig.xml after sequencing. This allows users to launch App-V applications from shortcuts pointing to original absolute paths which will fulfill any path requirements that are hard-coded into the binaries.

Implementation

As mentioned above, the components of this implementation are:

  1. An App-V 5 Application w/ Absolute Path Requirements
  2. Symlink Creation Script
  3. SCCM 2012 R2 Script Installer Application
  4. New App-V Package Shortcuts (if needed)

Let’s start with the script since we’re assuming you already have your application sequenced and added to SCCM.

We’ll then move on to setting the absolute path shortcuts in your DeploymentConfig.xml file after discussing the creation of the Script Installer application in SCCM.

Please note: Don’t distribute the content of your package in SCCM until you’ve made the changes to the shortcuts or you’ll have to redistribute. You can add the package in order to assign the dependency of the Script Installer, but don’t distribute or deploy. Updating shortcuts is in the last section of this guide.

The Script

This PoSH script takes the “Name” of your application, returned in the results of the get-appvclientpackage cmdlet, and the name of your the Program Files folder that we’re creating for the application.

As always, portions to modify in this script are in BOLD & ITALICS:


############################################################################
#  Scriptname: mapPackage.ps1
#
#  Description: This script will map a specified App-V
#               appliaction to "C:\Program Files\"
#
#  By:          Adam Baldwin
#
#  Usage:       Define the value for your package name and
#               for the destination folder name under "C:\Program Files\".
#               This script assumes you are using the default installation
#               source for App-V in "C:\ProgramData\App-V"
############################################################################

# Define the package name to search from present packages
$name = "APPLICATION_NAME"

# Define the name of the folder under "C:\Program Files" to
# map the application
$pathName = "APPLICATION_FOLDER"

# Set the Package object to a string
$package = get-appvclientpackage | where {$_.Name -eq $name}

# Get the Package ID and Version ID
$id = $package.packageID.ToString()
$vid = $package.versionID.ToString()

# Create the symlink mapping command
$cmd = "mklink /J `"C:\Program Files\$pathName`" `"C:\ProgramData\App-V\$id\$vid\root`""

# Run the symlink mapping command
cmd /c $cmd

Put this script into your  application repository. I keep all of my App-V applications, software installers, and script installers in a central place in order to reference and add them to SCCM easily. You can also put this, or any other scripts for Script Installers, on your domain’s netlogon volume. We’ll be using this location in the example below.

Setting up the Script Installer

Now it’s time to configure the Script Installer with the PoSH script that we created above. Be sure that you have your parent App-V application added to SCCM, first, before you create the Script Installer.

In SCCM, navigate to Software Library> Application Management> Applications. 

Right-click and select Create Application.

Check the radio button for Manually specify the application information and click Next

New Manual Application

On the General page, fill in the identifying information for this installer.

Since the function is to set up a specific configuration for an app, in this case to map a symlink to C:\Program Files\, give it some clear descriptions to indicate this behavior.

New Manual General

Click Next and select an Icon and set Categories if you’d like.

On the Deployment Types screen, click Add.

Add Deployment Type

Now you’ll be brought back to a screen that looks like the one we started with, except there is one additional option in the drop-down for Type. 

Click the drop-down and select Script Installer. Click Next to continue.

Script Installer

 

Again, give this installer a good name and description.

Script Installer General

Click Next to continue.

On the Content page, specify the Content location. If using a scripts folder on your netlogon volume, enter:

\\contoso.local\netlogon\scripts\

For the Installation Program, indicate PowerShell.exe with an -f switch pointing to the script created above.

Script Installer Content

Click Next to continue.

On the Detection page, Add a new Clause and specify a Folder for the Type.

Enter C:\Program Files\ for the Path field and enter your application’s folder name in the File or folder name field.

Script Installer Detection

Click OK to save and click Next on the Detection page to continue.

On the User Experience page, decide on your deployment settings. For this application, I’m deploying App-V apps to cloned machines, targeting device groups. In this situation, I’ve decided to use the following:

  1. Install for system if resource is device; otherwise install for user
  2. Whether or not user is logged on
  3. Hidden

Script Installer Experience

Click Next to continue. Click Next through the Requirements page.

On the Dependencies page, click Add and specify a name for the dependency group.

Click Add and browse to your parent application. Check the box and click OK to save.

Dependency

Click OK again to save and click Next to continue to the Summary. 

Verify your settings and click Next to complete.

Update App-V Shortcuts

You can edit the DeploymentConfig.xml file either during sequencing or after. Below I will describe how to make the changes after sequencing.

Open up the folder containing your App-V application and right-click on XXX_DeploymentConfig.xml to Edit or Open With your favorite editor or IDE.

Search for “<shortcut>” and find the entry with the Name and Target of the shortcut you’d like to update.

Once you’ve found your shortcut object, change the value for <Target> to point to your Symlink that we created with the Script Installer. Be sure to put quotes around your path name.

My particular application that was not working was Meditech Client Server. So you can see in my screen shot below, I’ve changed the target for the shortcut to point to an absolute path in C:\Program Files\ rather than to the App-V directory. Once the application is published, the dependent Script Installer will run and make this path accessible and create a seemless experience for the user.

Deployment Config

 

Once this is set, Distribute the content of your App-V app and the Script Installer to your Distribution Point and Deploy to your liking.

Summary

App-V is a great platform for delivering applications, but some, especially legacy applications, can be problematic because of the way they were coded.

If you find any applications that require absolute paths to the binaries, this method is the solution for you.

Let me know if you have any questions or comments below!

~Cheers!

ScriptdEEZ

Advertisements

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

 

 

Switching JRE Versions – AutoHotkey

Introduction

Have you ever needed to have two different versions of Java installed in order for various applications to work on a user platform? Have you then had issues with one version overriding as default, and had to manually disable one or the other?

In this article, I’ll discuss how to set up a keystroke to launch a VBScript that will effectively change between two installed versions of Java, on-the-fly. This can be customized for any two versions, but in the example below I will be using versions 5u11 and 7u40.

-Explanation-

After digging for a solution to maintaining different IE8/Java ThinApps in our environment, due to the number of different web applications the organization uses, I located a Java properties file that can be read or modified in order to view or change the currently running version in a user’s profile.

This file sits in one of the following locations depending on the version of Windows:

Win XP: C:\Documents and Settings\username\Application Data\Sun\Java\Deployment\deployment.properties
Win 7:   C:\Users\username\AppData\LocalLow\Sun\Java\Deployment\deployment.properties

Deployment.properties contains some, but not all, of the property values that are managed via the Java applet found in Control Panel, where one would normally configure JREs at a user-level.

Java Versions and Properties

If you open Control Panel> Java, click the Java tab, and click View, you will be presented with the screen below:

Java Versions

The above settings are read from and written to the deployment.properties file. Check or uncheck a box, and it updates this file. If you open C:\Users\username\AppData\LocalLow\Sun\Java\Deployment\deployment.properties, you will find something that looks like this:

deployment.properties

Notice that there are two unique versions of JRE present, distinguished as deployment.javaws.jre.0 and deployment.javaws.jre.1. The objects are further defined by a set of properties, such as product, path, platform, and enabled.

For our script, we will be focusing on the following lines:

deployment.javaws.jre.0.enabled=
deployment.javaws.jre.1.enabled=

Also, make a note of the base versions, or platforms, associated with jre.0 and jre.1:

deployment.javaws.jre.0.platform=
deployment.javaws.jre.1.platform=

In my case, I have 1.5 and 1.7 for JRE 5 and JRE 7, respectively. There’s a more specific property,  product, that gives the exact version, but it’s not needed in our situation since our two platforms are different.

AutoHotkey

I implemented AutoHotkey for the listener. It’s an easy-to-use application that runs either as an item in the taskbar or hidden in the background. AutoHotkey can do things like open applications, focus different windows, send messages, perform command line operations, or even autocorrect anything you’d like with “hotstrings“. There are great resources online and really cool things you can do with it, so I recommend checking it out for other projects.

In our situation, we’ll be using AutoHotkey to launch the VBScript from a local (or shared) location.

Download AutoHotkey Here.

Installing

Download and run the installer. Always choose Custom to make sure there are no ads when installing anything new, as a precaution. Once finished, choose to Run.

You will be prompted to create your first AHK file in My Documents. Click Yes to continue. This will bring up a notepad with your new Autohotkey.ahk opened.

AutoHotkey Install

Go ahead read the comments, and then highlight and delete the following lines:

Autohotkey.ahk

(Note: If you want to run Autohotkey in hidden mode, add #NoTrayIcon anywhere in this file.)

Configuring

Now that AutoHotkey is installed, we’ll need to define the hotkey and action. I use Ctrl+Alt+J as an easy to remember keystroke.

For a local system, place your script in C:\Scripts\ and name it java_swtich.vbs. To use Ctrl+Alt+J to launch c:\scripts\java_switch.vbs, add the following line to AutoHotkey.ahk:

^!j::Run "c:\scripts\java_switch.vbs"

(Note: For complete documentation on hotkeys, refer Here.)

Save, close, and double click AutoHotkey.ahk in My Documents to reload. You may be prompted with the message below, click Yes.

Reload Autohotkey

If you chose not to add #NoTrayIcon then you will see AutoHotkey running in your taskbar. Otherwise, to verify, you will see AutoHotkey.exe running in your processes under Task Manager.

AH Taskbar

Copy and paste your AutoHotkey.ahk file into the Startup folder under the Start Menu to have launch at startup. If you want to launch for all users, add an string entry to the Windows registry under HKLM:\Software\Microsoft\Windows\CurrentVersion\Run and set it to the path of your .ahk file.

The Script

I wrote this in VBScript because we still have XP machines deployed as our primary desktop image. I’ve found that VBScript is easier to run as a background mechanism in XP rather than having to implement a PS console and invoke a script from there.

I mentioned before that this is coded to switch between Java versions 5u11 and 7u40, but this can be modified to use ANY version. I am putting values that would need to be changed or checked in BOLD AND ITALICS so that you can identify what needs to be modified in order to use other versions.

In addition to needing to update the script, you will also need to make sure that your deployment.properties file has the right versions listed in the right order. The best way to do this is to simply copy the current deployment.properties file and review the values that are present for the entries deployment.javaws.jre.0.platform and deployment.javaws.jre.1.platform. Assuming you only have two versions installed, these should be the only two “platforms” present.

-Preparation-

Win 7 vs XP

I’ve made two versions of this script to be used with Win7 and XP since deployment.properties exists in different locations on each system. Please be sure you are using the correct script for the correct system.

Deployment Properties

In order for the script to work, we will need two versions of deployment.properties. Copy deployment.properties from the user’s appdata location into C:\Scripts. For a network deployment put it onto a public share.

Name this first file deployment.properties5 and edit the following lines. (Note: If you have different versions of Java than what I’m using, match up your lower version to jre.1.platform and set jre.1.enabled=true)

deployment.javaws.jre.0.platform=1.7
deployment.javaws.jre.0.enabled=false
deployment.javaws.jre.1.platform=1.5
deployment.javaws.jre.1.enabled=true

Make a second copy of the file and name this one deployment.properties7. Edit the following lines. (Note: If you have different versions of Java than what I’m using, match up your higher version to jre.0.platform and set jre.0.enabled=true)

deployment.javaws.jre.0.platform=1.7
deployment.javaws.jre.0.enabled=true
deployment.javaws.jre.1.platform=1.5
deployment.javaws.jre.1.enabled=false

The Code

As mentioned above, there is a version of this script to be used with XP and another to be used for Win7. If you are using different versions of Java than what I have, just update your search string with the correct platform number. I have highlighted those values in BOLD AND ITALICS. I’ve also italicized the path for the custom properties files, which will need to be changed if everything is running from a network share.

Windows XP

'
' Title: Java Switch
' Author: Adam Baldwin
' Date: 1/8/14
' Function: The purpose of this script is to switch between two versions of java. The two 
' particular versions of Java coded into this script are 1.5 and 1.7. CODE FOR XP
'
'
'
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Dim objFSO, filepath, objInputFile, tmpStr, substrToFind1, substrToFind2, substrToFind3, substrToFind4, appdata, java7check, java5check

Set objFSO = CreateObject("Scripting.FileSystemObject")

' Expand user's AppData path into the appdata string

Set wshShell = CreateObject( "wScript.Shell" )
appdata = wshShell.ExpandEnvironmentStrings( "%APPDATA%" )

' Check if deployment.properties file exists

If (objFSO.FileExists(appdata & "\sun\java\deployment\deployment.properties")) Then

   filepath = appdata & "\sun\java\deployment\deployment.properties"

   ' Define strings for logic in validating deployment.properties

   substrToFind1 = "deployment.javaws.jre.0.enabled=true"
   substrToFind2 = "deployment.javaws.jre.1.enabled=true"

   substrToFind3 = "deployment.javaws.jre.0.platform=1.7"
   substrToFind4 = "deployment.javaws.jre.1.platform=1.5"

   ' Assign the text of deployment.properties to the objTextFile string

   Set objTextFile = objFSO.OpenTextFile(filepath, 1)

   ' Validator values to check for if Java 5 is truly jre.1 and Java 7 is jre.0

   java5check = 0
   java7check = 0

   ' Read each line of the text and increment javacheck value for version 5 or 7 if the string is found

   do until objTextFile.AtEndOfStream

      tmpStr = objTextFile.ReadLine

      If InStr(tmpStr, substrToFind1) >= 1 Then
         java7check = java7check + 1
      End If

      If InStr(tmpStr, substrToFind2) >= 1 Then
         java5check = java5check + 1
      End If

   Loop

   ' Assign the text of deployment.properties to objTextFile string again for second validation and applying the change

   Set objTextFile = objFSO.OpenTextFile(filepath, 1)

   do until objTextFile.AtEndOfStream

      tmpStr = objTextFile.ReadLine

      ' If the platform for jre.0 is 1.7 and if jre.0 is enabled, perform the following action (make 1.5 active)

      If InStr(tmpStr, substrToFind3) >= 1 AND java7check >= 1 Then

         strFileToCopy = "c:\scripts\deployment.properties5"
         strFileName = appdata & "\sun\java\deployment\deployment.properties"
         objFSO.copyFile strFileToCopy, strFileName,True

         'Write version 1.5 to registry for tracking

         set wshShell = CreateObject("WScript.Shell")
         wshShell.RegWrite "HKCU\Software\JavaSoft\DeploymentProperties\JavaVersion", "1.5", "REG_SZ"

         set wshShell = nothing

      End If

      ' If the platform for jre.1 is 1.5 and if jre.1 is enabled, perform the following action (make 1.7 active)

      If InStr(tmpStr, substrToFind4) >= 1 AND java5check >= 1 Then

         strFileToCopy = "c:\scripts\deployment.properties7"
         strFileName = appdata & "\sun\java\deployment\deployment.properties"
         objFSO.copyFile strFileToCopy, strFileName,True

         'Write version 1.7 to registry for tracking

          set wshShell = CreateObject("WScript.Shell")
          wshShell.RegWrite "HKCU\Software\JavaSoft\DeploymentProperties\JavaVersion", "1.7", "REG_SZ"

          set wshShell = nothing

      End If

   Loop

' If no config found, assume latest version is being used and make 1.5 active

Else
   strFileToCopy = "c:\scripts\deployment.properties5"
   strFileName = appdata & "\sun\java\deployment\deployment.properties"

   ' If the folder does not exist (as with a brand new user), create the directory path

   If Not objFSO.FolderExists(appdata & "\Sun\Java\Deployment") Then
      Set objFolder = objFSO.CreateFolder(appdata & "\Sun")
      Set objFolder = objFSO.CreateFolder(appdata & "\Sun\Java")
      Set objFolder = objFSO.CreateFolder(appdata & "\Sun\Java\Deployment")
   End If

   ' Copy custom deployment.properties to the active location
   objFSO.copyFile strFileToCopy, strFileName,True

   'Write version 1.5 to registry for tracking 
   set wshShell = CreateObject("WScript.Shell") 
   wshShell.RegWrite "HKCU\Software\JavaSoft\DeploymentProperties\JavaVersion", "1.5", "REG_SZ" 
   set wshShell = nothing 

End If

Windows 7

'
' Title: Java Switch
' Author: Adam Baldwin
' Date: 1/8/14
' Function: The purpose of this script is to switch between two versions of java. The two 
' particular versions of Java coded into this script are 1.5 and 1.7. CODE FOR WIN7
'
'
'
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Dim objFSO, filepath, objInputFile, tmpStr, substrToFind1, substrToFind2, substrToFind3, substrToFind4, username, java7check, java5check

Set objFSO = CreateObject("Scripting.FileSystemObject")

' Expand current username from environment

Set wshShell = CreateObject( "wScript.Shell" )
username = wshShell.ExpandEnvironmentStrings( "%username%" )

' Check if deployment.properties file exists

If (objFSO.FileExists("C:\Users\" & username & "\Appdata\LocalLow\sun\java\deployment\deployment.properties")) Then

   filepath = "C:\Users\" & username & "\Appdata\LocalLow\sun\java\deployment\deployment.properties"

   ' Define strings for logic in validating deployment.properties

   substrToFind1 = "deployment.javaws.jre.0.enabled=true"
   substrToFind2 = "deployment.javaws.jre.1.enabled=true"

   substrToFind3 = "deployment.javaws.jre.0.platform=1.7"
   substrToFind4 = "deployment.javaws.jre.1.platform=1.5"

   ' Assign the text of deployment.properties to the objTextFile string

   Set objTextFile = objFSO.OpenTextFile(filepath, 1)

   ' Validator values to check for if Java 5 is truly jre.1 and Java 7 is jre.0

   java5check = 0
   java7check = 0

   ' Read each line of the text and increment javacheck value for version 5 or 7 if the string is found

   do until objTextFile.AtEndOfStream

      tmpStr = objTextFile.ReadLine

      If InStr(tmpStr, substrToFind1) >= 1 Then
         java7check = java7check + 1
      End If

      If InStr(tmpStr, substrToFind2) >= 1 Then
         java5check = java5check + 1
      End If

   Loop

   ' Assign the text of deployment.properties to objTextFile string again for second validation and applying the change

   Set objTextFile = objFSO.OpenTextFile(filepath, 1)

   do until objTextFile.AtEndOfStream

      tmpStr = objTextFile.ReadLine

      ' If the platform for jre.0 is 1.7 and if jre.0 is enabled, perform the following action (make 1.5 active)

      If InStr(tmpStr, substrToFind3) >= 1 AND java7check >= 1 Then

         strFileToCopy = "c:\scripts\deployment.properties5"
         strFileName = "C:\Users\" & username & "\Appdata\LocalLow\sun\java\deployment\deployment.properties"
         objFSO.copyFile strFileToCopy, strFileName,True

         'Write version 1.5 to registry for tracking

         set wshShell = CreateObject("WScript.Shell")
         wshShell.RegWrite "HKCU\Software\JavaSoft\DeploymentProperties\JavaVersion", "1.5", "REG_SZ"

         set wshShell = nothing
      End If

      ' If the platform for jre.1 is 1.5 and if jre.1 is enabled, perform the following action (make 1.7 active)

      If InStr(tmpStr, substrToFind4) >= 1 AND java5check >= 1 Then

         strFileToCopy = "c:\scripts\deployment.properties7"
         strFileName = "C:\Users\" & username & "\Appdata\LocalLow\sun\java\deployment\deployment.properties"
         objFSO.copyFile strFileToCopy, strFileName,True

         'Write version 1.7 to registry for tracking

         set wshShell = CreateObject("WScript.Shell")
         wshShell.RegWrite "HKCU\Software\JavaSoft\DeploymentProperties\JavaVersion", "1.7", "REG_SZ"

         set wshShell = nothing
      End If

   Loop

' If no config found, assume latest version is being used and make 1.5 active

Else
   strFileToCopy = "c:\scripts\deployment.properties5"
   strFileName = "C:\Users\" & username & "\Appdata\LocalLow\sun\java\deployment\deployment.properties"

   ' If the folder does not exist (as with a brand new user), create the directory path

   If Not objFSO.FolderExists("C:\Users\" & username & "\AppData\LocalLow\Sun\Java\Deployment") Then
      Set objFolder = objFSO.CreateFolder("C:\Users\"&username&"\AppData\LocalLow\Sun")
      Set objFolder = objFSO.CreateFolder("C:\Users\"&username&"\AppData\LocalLow\Sun\Java")
      Set objFolder = objFSO.CreateFolder("C:\Users\"&username&"\AppData\LocalLow\Sun\Java\Deployment")
   End If

   ' Copy the custom deployment.properties file to the active location
   objFSO.copyFile strFileToCopy, strFileName,True 

   'Write version 1.5 to registry for tracking 
   set wshShell = CreateObject("WScript.Shell") 
   wshShell.RegWrite "HKCU\Software\JavaSoft\DeploymentProperties\JavaVersion", "1.5", "REG_SZ" 
   set wshShell = nothing 
End If

Save the script as java_switch.vbs under C:\Scripts or to your network location.

Testing

Make sure that AutoHotkey is configured with a hotkey pointing to C:\Scripts\java_switch.vbs, and make sure your ahk is loaded. Go to Control Panel> Java and check what version is currently enabled. Close the window and press the hotkey. Now go back into the Java applet and see if the second checkbox is checked with the previous one blank. If so, the script is working and you now have a method to easily switch between two versions! Be sure to close or restart your browser after switching Java versions to avoid any issues.

If not working, make sure that:

  1. AutoHotkey is running with the latest .ahk.
  2. The correct platform version is set to enabled=true for the its deployment.properties file. For example, if jre.0 is 1.7 and the file is deployment.properties7, make sure jre.0.enabled=true.
  3. You are using the correct script for your version of Windows.

Summary

This is a very useful mechanism in our environment because of the many web applications that still require older versions of Java. Now, with the ability for a user to simply switch between the two, we have mitigated the need for excessive workarounds.

Please feel free to leave any questions or comments below, and good luck!

-ScriptdEEZ

If you found this article helpful or interesting, please donate a tip!
(LTC): LYs82mDXPohGDCzeRct8HkJwUCfwveGH1t
(BTC): 19JUVeefSBNbxUZNNmbDqfcctU6im6vsNg

Alert for Sustained Max CPU Usage

Introduction

Today, we’ll be looking at a reporting mechanism for servers, or workstations, that are experiencing sustained 100% CPU usage.

This week, in our environment, we had a print server that was maxing out CPU at random times, and sustaining indefinitely. The cause seemed to be bad devices/drivers, but it is still unclear what had made the ‘System’ process eat up about 75% of CPU with ‘spoolsv’ using the remaining 25%. The server has since calmed down, but we needed to put a tool in place that would alert us if the CPU spiked and sustained high levels again.

The VBScript is set as a Windows scheduled task to run every 1 minute. It uses a .txt file named ‘proc.txt’ with two lines, each being just 0 (see below). The txt will need to be placed in the c:\temp directory, or wherever you choose to configure your script to point. We’re also using the CDO.Message class to forward the alert email through SMTP.

The Script

Using WMI to query Win32_PerfFormattedData_PerfOS_Processor.Name =  _total  for the PercentProcessorTime value. As mentioned above, we’re writing to a .txt file in order to check usage over time without having the script running constantly in the background. To begin, create a file called proc.txt in c:\temp. This file should just contain the two lines:

 0
 0

The first is percentage, the second is count. We’ll send an email if the count reaches 5. Adjust the value of count variable to change the threshold.

Place on the server you want to monitor. Code to be replaced for your environment are in bold & italics, so please update where necessary.

set objFS = CreateObject("Scripting.FileSystemObject")

strFile = "C:\temp\proc.txt"
strTemp = "C:\temp\temp_proc.txt"

set objFile = objFS.OpenTextFile(strFile)
set objOutFile = objFS.CreateTextFile(strTemp, True)

strComputer = "."

set objService = GetObject("winmgmts:" & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2") 

Set perf_instance = objService.get("Win32_PerfFormattedData_PerfOS_Processor.Name='_total'")

procTime = perf_instance.PercentProcessorTime

maxed = 0
reset = 0
count = 5

if procTime >= 100 Then
	maxed = 1
End If

if procTime < 100 Then
	reset = 1
End If

a = 1

For i = 1 to 2
	strLine = objFile.ReadLine

	if a = 1 Then
		objOutFile.Write(procTime & vbCrLf)
	End If

	if a = 2 Then
		if reset = 0 Then
			count = strLine + maxed
			objOutFile.Write(count)
		End If

		if reset = 1 Then
			objOutFile.Write(0)
		End If

		if strLine >= count Then
			Set wshShell = WScript.CreateObject( "Wscript.Shell" )
			strComputerName = wshShell.ExpandEnvironmentStrings( "%COMPUTERNAME%" )
			strBody = strComputerName & " has sustained 100% CPU usage."

			Const schema   = "http://schemas.microsoft.com/cdo/configuration/"
			Const cdoBasic = 2
			Const cdoSendUsingPort = 2
			Dim oMsg, oConf

			strTo = "recipient@yourdomain.com"

			' E-mail properties
			Set oMsg      = CreateObject("CDO.Message")
			oMsg.From     = "Alerts@yourdomain.com"  
			oMsg.To       = strTo          
			oMsg.Subject  = strComputerName & " CPU MAX USAGE"
			oMsg.TextBody = strBody

			'SMTP server configuration and authentication info
			Set oConf = oMsg.Configuration
			oConf.Fields(schema & "smtpserver")     = "smtpserver.yourdomain.local"
			oConf.Fields(schema & "smtpserverport") = 25
			oConf.Fields(schema & "sendusing")      = cdoSendUsingPort
			oConf.Fields(schema & "smtpauthenticate") = 0
			oConf.Fields.Update()

			' send message
			oMsg.Send()
		End If

	End If

	a = a + 1
Next

objOutFile.Close
objFile.Close
objFS.DeleteFile(strFile)
objFS.MoveFile strTemp,strFile

Be sure to have a working SMTP or exchange server. The smtpauthenticate type I used was 0, which is Anonymous, so make sure your relay is set up properly.

Other than that, you should be able to plug it in, create your first proc.txt, and set the schedule.

Please reply below for any questions or comments!

Happy Scripting!
-ScriptdEEZ

 

If you found this article helpful or interesting, please donate a tip!
(LTC): LYs82mDXPohGDCzeRct8HkJwUCfwveGH1t
(BTC): 19JUVeefSBNbxUZNNmbDqfcctU6im6vsNg

 

 

Duplicate View Sessions

Introduction

This week we’re going to be looking at a simple export of current VMWare View sessions into a SQL table and the following SQL code to identify multiple single-user logins.

Many times we find that users are being given multiple sessions, whether due to issues on the previously connected VM, preventing full log off, or because of load balancing issues. We find that users who have multiple sessions eventually begin noticing unusual behavior such as Persona Management profiles not updating or account lockouts occurring after a password change.

We’ll be using a VMWare PowerCLI cmdlet to pull the session data, a mechanism that works relatively quickly and shows us exact associations of VMs and users.

The Situation

At OMC we run two distinct View 5.2 deployments. We’ve made it so that all of the pools and entitlement groups that we use are on each system so that regardless of where a user logs in they will still be able to connect. Each “side” of our View architecture has two Connection servers, and one from each side is presented to the users by an F5 load-balancer.

The load-balancer uses Active Directory group membership to decide whether a user goes to View Deployment “Side-A” or View Deployment “Side-B”. This works well a large majority of the time, but it’s possible that users can bypass the F5 and use FQDN to go to any of the connection servers from either deployment directly. In this situation, a user might have already been logged in on one View system and thus could have created a duplicate session on the “other side”.

Normally this shouldn’t be a problem, but if a user’s password is reset while they have a machine still logged in and that machine never gets logged out there will be eventual issues with the account locking.

In addition, we find that multiple user sessions show up on each deployment individual. I suspect the cause of this is some error that is preventing the VM from logging off, and so it sits in a disconnected state yet still allows the user to get a new desktop. This script will also identify these types of sessions.

The Script

In my previous write-ups I queried View’s ADAM database to analyze the View data. This time I just used the get-remotesession cmdlet which gives a list of logged in users and the associated VM names.

Preperation

To start, configure an MS SQL server and create a new database for the tables to be written to. Name the database ViewDuplicates.

The account used to drive the script requires permission on the database and also must be an administrator on the View Connection server(s). The script should be configured to run locally on both environments’ connection servers if you have two independent View deployments.

In the example below we’re comparing two distinct sets of sessions from independent environments. If you have only one environment you won’t require the Second View Deployment Server script or the Cross Duplicate SQL View code mentioned below. Just use one PoSH script and one SQL script to find duplicate sessions within a single View Deployment.

I have highlighted the portions that need to be reviewed in bold and italic. Please check and update where necessary.

PoSH Scripts

First View Deployment – Connection Server Script

############################################################################
# Scriptname:     Pool_Duplicates.ps1
# Description:     Export View sessions to SQL table
# By:            Adam Baldwin
#
# Usage: Will parse and export all View sessions to a SQL table 
# 
############################################################################

Import-Module -Name 'C:\Program Files\VMware\VMware View\Server\extras\PowerShell\add-snapin.ps1'
$Sessions = get-remotesession
$domain = "YOURDOMAIN.local\\"

$conn = New-Object System.Data.SqlClient.SqlConnection
$conn.ConnectionString = "Data Source=SQLSERVER;Initial Catalog=ViewDuplicates;Integrated Security=SSPI;"
$conn.open()
$cmd = New-Object System.Data.SqlClient.SqlCommand
$cmd.connection = $conn

$cmd.commandtext = "DELETE FROM ViewServer1"
$cmd.executenonquery()

foreach ($Session in $Sessions)
{
    $state = $Session.state
    $pool = $Session.pool_id
    $username = $Session.username -replace ($domain, "")

    $conn = New-Object System.Data.SqlClient.SqlConnection
    $conn.ConnectionString = "Data Source=SQLSERVER;Initial Catalog=ViewDuplicates;Integrated Security=SSPI;"

    $conn.open()
    $cmd = New-Object System.Data.SqlClient.SqlCommand
    $cmd.connection = $conn
    $cmd.commandtext = "INSERT INTO ViewServer1 (username,constate,pool) VALUES('$username','$state','$pool')"
    $cmd.executenonquery()
    $conn.close()

}

Second View Deployment – Connection Server Script


############################################################################
# Scriptname:     Pool_Duplicates.ps1
# Description:     Export View sessions to SQL table
# By:            Adam Baldwin
#
# Usage: Will parse and export all View sessions to a SQL table 
# 
############################################################################

Import-Module -Name 'C:\Program Files\VMware\VMware View\Server\extras\PowerShell\add-snapin.ps1'
$Sessions = get-remotesession
$domain = "YOURDOMAIN.local\\"

$conn = New-Object System.Data.SqlClient.SqlConnection
$conn.ConnectionString = "Data Source=SQLSERVER;Initial Catalog=ViewDuplicates;Integrated Security=SSPI;"
$conn.open()
$cmd = New-Object System.Data.SqlClient.SqlCommand
$cmd.connection = $conn

$cmd.commandtext = "DELETE FROM ViewServer2"
$cmd.executenonquery()

foreach ($Session in $Sessions)
{
    $state = $Session.state
    $pool = $Session.pool_id
    $username = $Session.username -replace ($domain, "")

    $conn = New-Object System.Data.SqlClient.SqlConnection
    $conn.ConnectionString = "Data Source=SQLSERVER;Initial Catalog=ViewDuplicates;Integrated Security=SSPI;"

    $conn.open()
    $cmd = New-Object System.Data.SqlClient.SqlCommand
    $cmd.connection = $conn
    $cmd.commandtext = "INSERT INTO ViewServer2 (username,constate,pool) VALUES('$username','$state','$pool')"
    $cmd.executenonquery()
    $conn.close()

}

Once you’ve confirmed that the data is being dumped into SQL (this will include username, pool, and state), we will need to create three new SQL Views named View-Env1-Dups, View-Env2-Dups, and View-Cross-Dups. (If you only have one deployment just create the first SQL View).

SQL Code

The first two SQL View codes compare each individual connection environment’s table. The third SQL View is used to compare the tables from both connection environments for “cross-duplicates”.

Note: If you have only one VMWare View Deployment then you’ll just need to use the first SQL View below to check for duplicates in a single table. Ignore the Cross Duplicate SQL View.

Attention to items in bold and italic. Check and update where necessary.

SQL Views

First View Deployment – SQL View Code

 SELECT username, pool, COUNT(*) AS DupCount
FROM dbo.ViewServer1
GROUP BY username, pool
HAVING (COUNT(*) > 1)

Second View Deployment – SQL View Code

 SELECT username, pool, COUNT(*) AS DupCount
FROM dbo.ViewServer2
GROUP BY username, pool
HAVING (COUNT(*) > 1)

Cross Duplicates – SQL View Code

SELECT DISTINCT dbo.ViewServer1.Username, dbo.ViewServer1.Pool

FROM dbo.ViewServer1 INNER JOIN
dbo.ViewServer2 ON dbo.ViewServer1.Username = dbo.ViewServer2.username AND dbo.ViewServer1.Pool = dbo.ViewServer2.pool

These Views compare data between all of the tables to output sessions that match on both Username and Pool ID. The SQL View can then be presented as a DataSource for creating tables or web forms for intranet content.

I decided to use a GridView in VisualStudio to display the info in a table, allowing desktop support and other technical staff to monitor which users have duplicate sessions in which pools.

Summary

This might seem confusing since we have a unique setup in having two mirrored View environments and a custom load balancing solution, but the concept and script can still be applied to just a single environment, or possibly many more.

Since the data is presented as a SQL View, it can be delivered to tech staff in any number of ways. Through a dashboard, a website, or more. It’s up to you.

Please let me know if you have any questions, comments, or trouble figuring it out below.

Cheers!
-ScriptdEEZ

If you found this article helpful or interesting, please donate a tip!
(LTC): LYs82mDXPohGDCzeRct8HkJwUCfwveGH1t
(BTC): 19JUVeefSBNbxUZNNmbDqfcctU6im6vsNg