ZENworks: Implementing Dynamic Variables Based Upon Location

over 1 year ago

The goal of this article is to create  Windows variables that automatically updates in real-time based upon a network location.  One common use is to automatically detect and use the closes Windows Share for software distribution from a UNC resource instead of using the Content-Repo.

Please watch the brief video below before reading the article to get an understanding of the objective of the article.


The first step is to ensure the proper "Network Locations" and "Network Environments" are configured n the "ZENworks" using the ZCC.

Network_Location.png Above is a graphic that shows where a "Network Environment" can be created in the "ZCC" and the various options that can be used to assist in defining the network location.  Multiple "Network Environments" can be assigned to a single "Network Location".  The "Network Location" tends to be a general site such as perhaps "Main Office Downtown".  The "Network Environment"  could be defined simply so it would encompass any device at that location.  Alternately, many "Network Environments"  may be defined to break it down so that "Meeting Room 3 on 5th Floor" to fine-tune where a device is located in the building.  Then depending on need, one could examine the device's general or specific locations.

Once the Network Locations and Environments are working properly in ZCM, it will be possible to get down to the details of creating useful variables based upon those locations.  The effective Network Location and Environment Settings for a device are stored in the HKLM\Software\Novell\ZCM\Location Key in ZCM 17.3 or later.  Prior versions would require parsing results from the "zac cl" command, but that will not be covered in this article.


I have created a simple PowerShell script that will read this data and set local windows variable called %ZCMSOURCE%, which will reference a UNC Share.  Below is the "CORE" part of the script, with a few lines omitted that will handle edge scenarios.  The excluded parts will be explained later.


The first line of the script will read the "CurrentLocationName" registry value and place it into a temporary  PowerShell variable called $mylocation.

The second line of the script starts a "Switch" statement which is very similar to a "Case" statement.  This switch statement will set the PowerShell Variable $LocalShare to the defined value on lines three through six.  The "Default" entry on line seven is the value that will be used if there are no other matching values.  The most likely cause for "Default" to be hit in this script is if there is a defined location in ZCM that is not defined in the script.  If the device's network environment falls outside of any defined parameters, it should match "~unknown~".  The "break" setting inside the switch statements indicates that the switch statement should terminate at that point, so that in this example once a match is found it will not perform any more comparisons.  To deploy the script, simply update the values that match your environment.

The ninth and final line sets the Windows environment variable %ZCMSOURCE% in the machine space.   At this point, there is still one minor detail.  Running processes such as "Explorer" and "ZAPP" are unaware of the new or updated variable %ZCMSOURCE%.

This is where the final portion of the script comes into play, which is displayed below.


A function to issue the "WM_SETTINGCHANGE" command is added, which will advertise the environment change to running processes.  Most applications actually ignore this, but Windows Explorer.exe does listen, which is critical so that processes launched by Explorer.exe receive the updated value.  ZAPP does not actively listen for changes from WM_SETTINGCHANGE, but each time a bundle is launched by ZAPP, it will update its environment space from Explorer.  (Important: The environment is only updated when a new bundle is launched, not between actions within a single bundle.)

The "Send-SettingChange" function, which loads "User32.dll", issues a native "WM_SETTINGCHANGE" command.  This function is implemented "as is" from the following: https://gist.github.com/alphp/78fffb6d69e5bb863c76bbfc767effda.  However, there are many other similar PowerShell implementations I discovered dating back to 2012, which the GitHub entry may be based upon. 

The "Advertisement" only occurs for processes in the same "User Space".  For this reason, the advertisement is actually sent twice....Once as SYSTEM in the same script that updates the variable and then called again in another action set to run as the logged-on user, if a user is logged into the device.


Attached is a Sample Bundle Called "!SetLocationVariable".

This bundle has a few subtle settings on the "Summary Page" that I want to cover first.

  • "Enable Bundle Ordering: was enabled to help prioritize this bundle over other bundles.
  • "Bundle Order" is set to ZERO so that it has the highest priority of ordered bundles.
  • The Bundle Name starts with an Exclamation Point ("!") since alphabetical order will break ties for bundles with the same "Bundle Order" number.

Make sure to edit the "Script" in the first action - "Set Location Variable in System Space" so that it is updated to include "Locations" and "UNC Paths" in your environment.  The second action does not need editing.  The third action which adds a 1-second delay is likely spurious, but I included anyway.  Assign the bundle to some test devices with a "Launch Schedule" of "On Device Refresh". 

(Note: If other bundles are set to run on "Refresh" and depend upon "Dynamic Variables", I recommend setting those bundles to run with a 60-second delay after refresh to ensure the updates are finalized prior to their execution.)


A second bundle is attached called "ZCMSourceTest".  This is a bundle that demonstrated in the video above that will launch the UNC path defined in the variable %ZCMSOURCE%.  For testing purposes, make sure that the "!SetLocationVariable" bundle above sets that variable to a location to which the test logged-on users have at least read access.  Production use of the features in the article will most likely end up using the "Credential Vault", but "Credential Vault" adds an extra layer of complexity and will be covered in a future article for those not already familiar with the use of "Credential Vault" with "Dynamic Administrative Users".

For more details about using Variable in bundles:  ZENworks: Understanding how to use Environment Variables in Bundles. 


To find other articles by Craig Wilson simply follow the link below:


If you find this article useful, please be sure to give it a like at the bottom of the page!

Comment List
Related Discussions