# Desktop A-Game

# Desktop Fileset Timed Events

## Description

Filesets have the option to set an activation time, but what about items based upon timing of day, for example, rather than a dedicated date.

[![image.png](https://kb.filewave.com/uploads/images/gallery/2024-07/scaled-1680-/bUD8dOsEWuj4trrN-image.png)](https://kb.filewave.com/uploads/images/gallery/2024-07/bUD8dOsEWuj4trrN-image.png)

[Policy Blocker Scripts](https://kb.filewave.com/books/filesets-payloads/page/filewave-fileset-types#bkmrk-policy) are really designed to pause management of clients.<span class="Apple-converted-space"> </span>However, with some clever use, a Policy Blocker Script can provide us with some assistance.<span class="Apple-converted-space"> </span>This script type runs every 5 minutes on clients.<span class="Apple-converted-space"> </span>Although the intention is to pause management until the script reports an exit status of 0, the 5 minute continual trigger can be leveraged.

Extending this with Custom Fields, it is possible to build out a desired outcome.

## Ingredients

- One (or more) Custom Fields; 3 provided - [Active Time Custom Fields.customfields](https://kb.filewave.com/attachments/376)
- Policy Blocker Scripts

<table border="1" id="bkmrk-macos-windows-policy" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 50%;"></col><col style="width: 50%;"></col></colgroup><tbody><tr><td>macOS</td><td>Windows</td></tr><tr><td>[Policy - Timed Event macOS.fileset.zip](https://kb.filewave.com/attachments/377)</td><td>[Policy - Timed Event Windows.fileset.zip](https://kb.filewave.com/attachments/378)</td></tr></tbody></table>

## Directions

- Download and import the provided Custom Fields
- Download and import the appropriate Fileset(s) (macOS and/or Windows)

Alter the Custom Fields values for Inactive and Active times to suit.<span class="Apple-converted-space"> </span>Time is set using hours, minutes and seconds.<span class="Apple-converted-space"> </span>E.g.

<table border="1" id="bkmrk-desired-time-%28hh%3Amm%29" style="border-collapse: collapse; width: 100%; height: 116px;"><colgroup><col style="width: 50%;"></col><col style="width: 50%;"></col></colgroup><tbody><tr style="height: 29px;"><td style="height: 29px;">Desired Time (HH:MM)</td><td style="height: 29px;">Custom Field Value (HHMMSS not including leading zeros)</td></tr><tr style="height: 29px;"><td style="height: 29px;">09:30</td><td style="height: 29px;">93000</td></tr><tr style="height: 29px;"><td style="height: 29px;">12:55</td><td style="height: 29px;">125500</td></tr><tr style="height: 29px;"><td style="height: 29px;">18:00</td><td style="height: 29px;">180000</td></tr></tbody></table>

<p class="callout warning">If changing the Custom Field value for a device which is already running the policy, 2 subsequent Model Updates will need to be received by the client, if looking for a more ‘immediate’ result.<span class="Apple-converted-space"> </span>The blocker script holds the client until success.<span class="Apple-converted-space"> </span>This means, during a Model Update, the blocker will run before the new Custom Field Value will be read by the device.<span class="Apple-converted-space"> </span>As such, only after a subsequent update (or inventory) will the blocker script be aware of the new Custom Field value.<span class="Apple-converted-space"> </span>Custom Fields will naturally update on devices with inventory, but this is less frequent.</p>

### Time Order

Times can be either way around.<span class="Apple-converted-space"> </span>

#### Examples:

Consider working hours to begin at 08:30 and end at 18:00

##### Example 1

An item should only be considered outside of standard working hours.

- Disable Active Time: 83000
- Enable Active Time: 180000

[![image.png](https://kb.filewave.com/uploads/images/gallery/2024-07/scaled-1680-/VDw6zf9ZY5N8bkR3-image.png)](https://kb.filewave.com/uploads/images/gallery/2024-07/VDw6zf9ZY5N8bkR3-image.png)

##### Example 2

Alternatively, an item should be considered during working hours:

- Enable Active Time: 83000
- Disable Active Time: 180000

[![image.png](https://kb.filewave.com/uploads/images/gallery/2024-07/scaled-1680-/BAhhZ995ZBuff2UY-image.png)](https://kb.filewave.com/uploads/images/gallery/2024-07/BAhhZ995ZBuff2UY-image.png)

Imported Custom Fields are disabled for all devices by default. Once tested, consider using the option to assign to all devices for each Custom Field imported. The file provided contains all 3 Custom Fields.

[![image.png](https://kb.filewave.com/uploads/images/gallery/2024-07/scaled-1680-/hJEjRvmBZiHr7czo-image.png)](https://kb.filewave.com/uploads/images/gallery/2024-07/hJEjRvmBZiHr7czo-image.png)

### Smart Groups

A third Custom Field holds a true/false value.<span class="Apple-converted-space"> </span>This value may be used with a Smart Group query, to determine if an item should be associated at this time or not.

<p class="callout info">This Custom Field is set to use custom\_bool\_01.<span class="Apple-converted-space"> </span>If this is already in use, an alternate Custom Bool number should be utilised instead.<span class="Apple-converted-space"> </span>This is editable through the Scripts Environment Variables.<span class="Apple-converted-space"> </span></p>

The script uses the following method to set these values.

[https://kb.filewave.com/books/custom-fields/page/add-filewave-custom-inventory-fields-remotely-using-a-fileset](https://kb.filewave.com/books/custom-fields/page/add-filewave-custom-inventory-fields-remotely-using-a-fileset)

#### Example

An update to Firefox needs to occur after 17:00 or before 09:30

- Disable Active Time = 93000
- Enable Active Time = 170000

Between these times, the 3rd Custom Field ‘Active Time’ should be False/0.<span class="Apple-converted-space"> </span>Outside of these times, the ‘Active Time’ Custom Field should be True/1. <span class="Apple-converted-space"> </span>

[![image.png](https://kb.filewave.com/uploads/images/gallery/2024-07/scaled-1680-/RSitf8u0jR2Hx88v-image.png)](https://kb.filewave.com/uploads/images/gallery/2024-07/RSitf8u0jR2Hx88v-image.png)

Smart Group can be based upon the following:

- Is Active Time True/1
- Is the version of Firefox matching that within the Fileset

<p class="callout success">Do not just use the active time, unless intentional.<span class="Apple-converted-space"> </span>Devices will continually enter and leave the Smart Group if this is set to only use the Active Time, each day.<span class="Apple-converted-space"> </span>If an item is associated in this way, associated Filesets will trigger every time the device enters the group.</p>

## Deeper Dive

The Policy Blocker script has 2 considerations initially:

- The hours between which the timed event should occur
- The current time

This means there is a time beyond which the desired action may occur and a time beyond which the action should not occur and this needs to be compared with the current time.

The enable/disable active times are provided by way of Executable Environments.<span class="Apple-converted-space"> </span>Taking this a step further, these times are defined using Administrator Custom Fields.<span class="Apple-converted-space"> </span>This way the times can more easily be altered if required.

A third Custom Field is being used to indicate if the current time is one of activity allowance or not, but this time a Client Command Line Custom Field.

Client Command Line Custom Fields are stored locally on the device and then this value is available to the server, both for visibility, but can also be used in queries, for Smart Groups.

[![image.png](https://kb.filewave.com/uploads/images/gallery/2024-07/scaled-1680-/PRPwF3Lg4yYn7kOY-image.png)](https://kb.filewave.com/uploads/images/gallery/2024-07/PRPwF3Lg4yYn7kOY-image.png)

<p class="callout warning">Client Command Liine Custom Fields may be altered in FileWave Central Admin App, however, as soon as the device checks back inventory, the value from the client will be pushed back to the server.</p>

# Apple Profiles & Dependencies

## Description

Dependencies offer a structure for Fileset installations, ensuring one or more Filesets are installed prior to one or more other Filesets.<span class="Apple-converted-space"> </span>This works great, apart from where Apple MDM Filesets are involved.

### Fileset Activation Quick Re-cap

#### Standard Fileset

1. Client checks-in.
2. Manifest is observed
3. New items are pushed to device and activate

#### Apple MDM Fileset (Profiles)

1. APNs request sent to Apple
2. Device pulls queued APNs requests from Apple
3. For each APNs request, device reaches out to relevant servers, for MDM requests, this is the FileWave Server
4. Device checks-in
5. Queued MDM commands are pushed to device, e.g. InstallProfile
6. Profile instals

For standard Filesets, FileWave is in control of the communication.<span class="Apple-converted-space"> </span>However, for Apple MDM, there is an unknown amount of delay until the Profile is installed.

**The Issue**

Since Filesets are installed sequentially, if a Fileset were allowed to depend upon an Apple MDM Fileset, the client would be held waiting for an unknown period time, preventing other Filesets and configuration from actioning.<span class="Apple-converted-space"> </span>For this reason, Apple MDM Filesets can only depend on a different Fileset type and not the other way around.

**Requirement Scripts**

Requirement Scripts allow a Fileset to fail, let the client continue and then 2 minutes later try the requirement again.<span class="Apple-converted-space"> </span>The Requirement Script will continue with this process, whilst there is a non-zero exit code.<span class="Apple-converted-space"> </span>By way of this process, the Requirement Script gives the ability to delay the installation of the Fileset, until any required Profiles are installed beforehand.

## Ingredients

- Fileset designed to use a Requirement Script to ensure Profile is installed prior to activation
- Associated Profile ID(s)

[Profile Dependency Fileset Template.fileset.zip](https://kb.filewave.com/attachments/379)

## Directions

Download the Fileset, import into FileWave and edit to match requirements.<span class="Apple-converted-space"> </span>Select the ‘check\_for\_profile.sh’ script and click ‘Get Info’:

![Pasted Graphic 14.png](https://kb.filewave.com/uploads/images/gallery/2024-07/uOTc0HmOmBhkJLUl-embedded-image-urycbv4g.png)

The Launch Arguments will initially appear empty.

![Pasted Graphic 16.png](https://kb.filewave.com/uploads/images/gallery/2024-07/AchucSejYEnl4L7F-embedded-image-jnb3xiaw.png)

For each Profile that needs to be considered for installation prior to this Fileset, its ID must be added to the list of Launch Arguments (one entry per Profile ID).<span class="Apple-converted-space"> </span>Profile IDs can be obtained from within the Payload details of the Profile Filesets.

For eah Profile that must be installed, open the Profile for editing, highlight the Identifier and copy.

![Pasted Graphic 15.png](https://kb.filewave.com/uploads/images/gallery/2024-07/HRYSYHdE2C93I5LY-embedded-image-zgv2wn2m.png)

Copy these IDs into the LaunchArguments of the Fileset.<span class="Apple-converted-space"> </span>Example below shows 5 Profile IDs added for a Microsoft Defender Installer.

![Pasted Graphic 13.png](https://kb.filewave.com/uploads/images/gallery/2024-07/B9XKYGXV7rlVfO8X-embedded-image-gssl9vvg.png)

The script allows for the idea of either by way of an Environment Variable (all\_or\_one). Set the value appropriately:

<table border="1" id="bkmrk-all-all-of-the-liste" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 50%;"></col><col style="width: 50%;"></col></colgroup><tbody><tr><td>all</td><td>All of the listed Profiles must be installed prior to the Fileset becoming active.</td></tr><tr><td>one</td><td>At least one of the included Profiles must be installed prior to the Fileset becoming active</td></tr></tbody></table>

The below, shows a Fileset set to require all Profiles are installed, before Fileset activation for the same Microsoft Defender example:

![Pasted Graphic 12.png](https://kb.filewave.com/uploads/images/gallery/2024-07/FA655Mp8QNwHheJm-embedded-image-yyfhruvi.png)

With this set, add any additional installers into the Fileset, that would need to be installed, once the provided Profiles are installed.

Create a Fileset Group and add this Fileset and all necessary Profiles to the same group (not necessary, but somewhat neater to manage)

For example:

![Pasted Graphic 17.png](https://kb.filewave.com/uploads/images/gallery/2024-07/44LJ96KpdHny4yKj-embedded-image-kmlcvnkc.png)

Associate the Fileset Group, test and then rollout to more devices once happy.

<p class="callout success">This Fileset is particular useful with Apple TCC Privacy Settings Profiles.<span class="Apple-converted-space"> </span>Privacy settings provide access permissions for software to function.<span class="Apple-converted-space"> </span>However, typically these Profiles need to be installed before the process that they are allowing is started.<span class="Apple-converted-space"> </span>This means, if the software is allowed to instal before the Profile is installed, the software process would need restarting after the Profile is installed.<span class="Apple-converted-space"> </span>The above Fileset offers the solution around this, where the Fileset will only attempt download and installation once the Profile is in place.</p>

# Policy Loops

## What

A policy loop happens when a Smart Group's criteria are changed by the Fileset or association assigned to that same Smart Group. The device enters the group, receives an action, then no longer matches the criteria. On the next Smart Group refresh it may leave the group, remove or change the Fileset, and then qualify again. The result can be repeated installs, removals, downgrades, or confusing association churn.

[![Example Filesets used in policy loop scenarios](https://kb.filewave.com/uploads/images/gallery/2024-07/scaled-1680-/x7fMnqYjp7NriOlr-image.png)](https://kb.filewave.com/uploads/images/gallery/2024-07/x7fMnqYjp7NriOlr-image.png)

## When/Why

The risk is highest when group membership is based on the exact state that the Fileset changes, such as an application version, installed-file presence, or another inventory value that changes immediately after activation.

### Example 1: version-based installer loop

Imagine a PKG macOS installer Fileset for an app called **CLU.app**, version 1.0. It is associated to all devices based on two criteria:

- Device OS is macOS
- Device does not have CLU.app version 1.0 installed

Once the software is installed, those devices no longer belong to the group because version 1.0 is now installed.

A new version of the software is released: CLU.app version 1.1. A new association is created with a different Smart Group using similar criteria:

- Device OS is macOS
- Device does not have CLU.app version 1.1 installed

Devices running version 1.0 will join the new Smart Group at the next refresh. The new Fileset activates, the software upgrades from 1.0 to 1.1, and the devices then leave the version 1.1 group because they no longer match its criteria.

The problem appears on the next Smart Group refresh. Because version 1.0 is no longer installed, those same devices may qualify again for the older version 1.0 Smart Group. If the older PKG can install over the newer version, the software is downgraded back to 1.0. Once that happens, the device qualifies again for the 1.1 group, and the cycle repeats.

<p class="callout warning">This is a policy loop: the device keeps moving between groups because each successful deployment changes the criteria used to target the next deployment.</p>

### Example 2: self-healing Fileset loop

The same principle can happen with one group. In this example, CLU.exe version 1.0 is delivered as a file-level self-healing Fileset for Windows.

The Smart Group criteria are:

- Device OS is Windows
- Device does not have this software installed

[![Smart Group criteria for Windows devices without the CLU application](https://kb.filewave.com/uploads/images/gallery/2024-07/scaled-1680-/w9F7U1Guwt7NWqEC-image.png)](https://kb.filewave.com/uploads/images/gallery/2024-07/w9F7U1Guwt7NWqEC-image.png)

Windows devices without the software enter the Smart Group, receive the Fileset, and report that the software is now installed. At the next Smart Group refresh, those devices no longer meet the criteria and leave the group.

Because the Fileset is self-healing, leaving the association can remove the software. The user loses the application, the next refresh sees the device as missing the software again, and the device re-enters the group. The software is then installed again, removed again, and the loop continues.

## Avoiding the loop

- Do not leave old and new version associations active when each group only means "does not have version X installed." Retire or supersede the older deployment association when the newer version becomes the intended state.
- Use stable targeting criteria where possible, such as department, building, device role, enrollment workflow, or a curated group that represents deployment intent instead of current application state.
- If application or file presence is needed as a safety check, make sure the device does not leave the long-term deployment target solely because the Fileset succeeded.
- Test the Smart Group and association on a small set of devices, then verify membership again after client inventory and Smart Group refresh have both run.

<p class="callout success">The answer is not to avoid Smart Groups or self-healing Filesets. Both are core FileWave workflows. The important part is to design criteria so a successful deployment does not immediately undo its own targeting logic.</p>

<p class="callout info">Fast Smart Group Evaluation can be useful for time-sensitive membership changes, but it does not fix a policy loop. If the criteria are unstable, faster evaluation can simply make the loop show up sooner.</p>

## Related Content

- [Using Queries to create Smart Groups](https://kb.filewave.com/books/filewave-central-anywhere/page/using-queries-to-create-smart-groups)
- [Fast Smart Group Evaluation](https://kb.filewave.com/books/filewave-central-anywhere/page/fast-smart-group-evaluation)
- [Fileset Association types and precedence](https://kb.filewave.com/books/filesets-payloads/page/fileset-association-types-and-precedence)

# Updating 3rd Party Software

## What

Naturally devices require software and that software needs updating.<span class="Apple-converted-space"> </span>The question is how.

For managed software, e.g. Apple VPP Apps, updates occur automatically, but other software deployed using PKG, MSI, EXE or file level Filesets then what happens.<span class="Apple-converted-space"> </span>Essentially, there are a couple of key choices.

Some software attempts to auto update, which may or may not work, in particularly when users are not admins, whilst other software will always require updates pushed out.

[![image.png](https://kb.filewave.com/uploads/images/gallery/2024-07/scaled-1680-/mjs8gDNgjs0F58d3-image.png)](https://kb.filewave.com/uploads/images/gallery/2024-07/mjs8gDNgjs0F58d3-image.png)

## Why

Back to the choice.<span class="Apple-converted-space"> </span>Allow software to auto update or prevent such activity and choose to build new Fileets to push out updates.<span class="Apple-converted-space"> </span>Making that choice, though, can be impacted by other factors.

For example:

- Is the software being deployed critical to business
- Are there company restrictions that prevent software being updated before approval
- Does the software even have an auto updater
- How easy is it to prevent the software from updating, where an auto update does exist
- Do you trust the software supplier enough to allow updates to occur without prior testing
- What impact could occur if an update went wrong and what is the rollback option
- Is a reboot required after the update

## How

Those are some considerations.<span class="Apple-converted-space"> </span>Now to consider some finer details.

### Denying AutoUpdates

For software that has no autoupdates, this is already a consideration, but denying updates takes some greater work.<span class="Apple-converted-space"> </span>Firstly, a requirement to locate how the update works and then how to prevent it.

[![image.png](https://kb.filewave.com/uploads/images/gallery/2024-07/scaled-1680-/h3Pp8R4gzE06aTKW-image.png)](https://kb.filewave.com/uploads/images/gallery/2024-07/h3Pp8R4gzE06aTKW-image.png)

Most software vendors are likely to have either a Windows registry entry or a macOS plist preference file that can be configured to prevent the updates.<span class="Apple-converted-space"> </span>Identifying the file to alter and the values to set, in some instances can be easy to address.<span class="Apple-converted-space"> </span>In fact, many other Admins often post these settings or they may be available from vendors.<span class="Apple-converted-space"> </span>However, sometimes this information isn’t readily available.

[![image.png](https://kb.filewave.com/uploads/images/gallery/2024-07/scaled-1680-/hdX83Krp5wr5fRpI-image.png)](https://kb.filewave.com/uploads/images/gallery/2024-07/hdX83Krp5wr5fRpI-image.png)

Various methods exist, but generally, the process is look at files before and after making preference changes made available through the software GUI if available.<span class="Apple-converted-space"> </span>Fileset Magic is one method to assist with this process.<span class="Apple-converted-space"> </span>This option of the FileWave application takes a snapshot of the device and then after changes are made, a second snapshot is taken.<span class="Apple-converted-space"> </span>It is then a case of comparing the before and after to see what has changed.

### Allowing AutoUpdates

One key question is, does micro management of updates of all applications really improve management of devices.<span class="Apple-converted-space"> </span>Many applications are not business critical or a bad update could easily have minimal impact.<span class="Apple-converted-space"> </span>With that in mind, why not allow updates.<span class="Apple-converted-space"> </span>Indeed, Apple VPP Apps leave little choice.<span class="Apple-converted-space"> </span>Of course, just making that decision does not mean auto updates are on by default.<span class="Apple-converted-space"> </span>As such, the same process to calculate how to disable updates may need to be actioned to work out how to enable updates.

Add to this, as eluded to prior, will the auto update work if the user is not an Admin.<span class="Apple-converted-space"> </span>This needs to be tested, but if not, then the same process used for denying updates would likely be required.

## Considerations

For either method, there are some additional considerations, which mostly centre around self-healing.

### Denying Autoupdates

When using a file level Fileset to deploy software, files should be set as self-healing.<span class="Apple-converted-space"> </span>

[![image.png](https://kb.filewave.com/uploads/images/gallery/2024-07/scaled-1680-/oT5bPs12NgBvoBAj-image.png)](https://kb.filewave.com/uploads/images/gallery/2024-07/oT5bPs12NgBvoBAj-image.png)

Not only does this ensure the most efficient delivery of files from server to devices, it adds some greater benefits.<span class="Apple-converted-space"> </span>When the association of the new version is associated, in the same Model, the older version should be disassociated. <span class="Apple-converted-space"> </span>

If both Filesets are left associated, updated files will be replaced, whilst new files will be pushed to devices, however what about files that the software no longer uses.<span class="Apple-converted-space"> </span>If the older Fileset is not disassociated, these files will be left behind.<span class="Apple-converted-space"> </span>Although this may seem harmless enough, actually they can be very damaging.<span class="Apple-converted-space"> </span>Developers of software would not expect those files to be in existence with the new application and with thousands of lines of code, it could be easy enough that these files still have references and could cause havoc with the newer version.

### Allowing AutoUpdates

So, how about handling software where the autoupdates is allowed to occur.<span class="Apple-converted-space"> </span>In this instance, if file level Filesets are used to deploy the application, self-healing would be completely the wrong choice.

When software autoupdates, files will be altered.<span class="Apple-converted-space"> </span>When a verification occurs, any altered files set for self-healing, will be replaced with the older files.<span class="Apple-converted-space"> </span>Although clearly undesirable, this isn’t the same as downgrading the software, such that it would still function.<span class="Apple-converted-space"> </span>Self-healing will also return any files that were removed by the updater.<span class="Apple-converted-space"> </span>This brings back the condition of files unexpectedly installed, which again could cause the software to act irregular or not even start.<span class="Apple-converted-space"> </span>As such, Ignore at Verify would be the ideal selection.

[![image.png](https://kb.filewave.com/uploads/images/gallery/2024-07/scaled-1680-/VbczMxuzp0TXAj9V-image.png)](https://kb.filewave.com/uploads/images/gallery/2024-07/VbczMxuzp0TXAj9V-image.png)

Ignore at Verify brings about 2 additional items for attention.

### Un-installing.

Un-installers can come in differing forms, one of course is by way of self-healing.<span class="Apple-converted-space"> </span>However, using the allowed auto-updater example, self-healing is not an option.<span class="Apple-converted-space"> </span>This means an alternate method would be required to remove the software.<span class="Apple-converted-space"> </span>Of course, FileWave can be used to achieve this, for example, with un-installer scripts.

### Rollback

Where software is auto updating, the only version available in FileWave will likely be the same version originally pushed (unless updated more recently as a Fileset).<span class="Apple-converted-space"> </span>Therefore, if there was a need to rollback to a prior version, som additional work would be required, which would take time before being deployable.

## Overview

Each method has its own merits, but being aware of the pros and cons and how to deal with these, provides the armoury for successful application management.

# Uninstall Filesets

## What

When software is no longer needed, the removal method depends on how it was originally deployed. This article outlines the common FileWave uninstall paths and where a custom uninstaller is still required.

### Options

#### Self-Healing

If a Fileset uses **Self Healing** and **Download if Missing** for tracked files, disassociating the Fileset removes the files that are part of that Fileset.

#### MSI

Windows MSI Filesets are different because MSI packages can expose an uninstall action. When the Fileset is configured to use that feature, disassociating the Fileset can trigger the MSI uninstaller.

[![image.png](https://kb.filewave.com/uploads/images/gallery/2024-07/scaled-1680-/A4DeyCzIunHDL3Nb-image.png)](https://kb.filewave.com/uploads/images/gallery/2024-07/A4DeyCzIunHDL3Nb-image.png)

#### PKG/EXE

PKG and EXE installers do not provide the same built-in uninstall behavior as MSI packages. In many cases the Fileset only tracks the installer itself, not every file created by the installation. If the software vendor does not provide a separate uninstall PKG, EXE, or script, you will usually need to build your own removal script.

#### Apple VPP &amp; Android Play Store

Disassociating these Filesets sends a command to remove the application.

#### Other Files

Applications often create supporting files after first launch, such as preferences, caches, or user data. If you need to remove those items too, you will normally need a separate cleanup method.

## Why

Removing unused software helps keep devices clean, reduces confusion for users, and can support security and license-management goals.

## When

Knowing how to uninstall software is only half of the job. You also need to decide when the uninstall should run.

At first glance it may seem natural to place a pre- or post-uninstaller script inside the same Fileset as the installer. That can work against you when the application is updated.

As vendors release updates, you may replace the installer with a new Fileset or a new Fileset revision. Self-Healing handles matching files cleanly during that swap, but any uninstall script inside the installer Fileset can also run during the change, which is usually not what you want.

## How

A common way to control this is to separate installation and removal logic by using a Fileset Group.

In the example below, the Fileset Group for Microsoft Defender includes the installer Fileset, related profiles, and a separate uninstaller Fileset. Devices are associated with the Fileset Group, not directly with the uninstaller.

![Pasted Graphic 18.png](https://kb.filewave.com/uploads/images/gallery/2024-07/wkn81POehtbtT2Vm-embedded-image-fwp7qonh.png)

The uninstaller Fileset uses a pre-uninstallation script:

![Pasted Graphic 20.png](https://kb.filewave.com/uploads/images/gallery/2024-07/gF4QjwZ74Db7vFOX-embedded-image-8td8mppf.png)

This makes installer updates straightforward. You can replace the installer Fileset or swap revisions inside the group without firing the uninstall. The uninstall runs only when the Fileset Group itself is disassociated from the device.

### PKG/EXE Uninstallers

If a vendor supplies an uninstall PKG, it is usually cleaner to place that PKG in an otherwise empty Fileset and trigger it from an uninstall script, similar to the Microsoft Defender example above.

Trying to auto-associate a separate uninstall PKG exactly when the original installer is disassociated can be difficult to control reliably.

EXE-based uninstallers have the same issue. A practical pattern is to upload the uninstall EXE to an empty Fileset and call it from a pre- or post-uninstallation script.

![Pasted Graphic 21.png](https://kb.filewave.com/uploads/images/gallery/2024-07/vZtJ7J1YNhhVhwZc-embedded-image-mxxdqfyh.png)

This gives you a dedicated uninstaller Fileset that can be added to a Fileset Group and triggered only when you actually want removal to occur.

# Inventory Items in Scripts

## What

- Each Inventory Items has an Internal Name, including Custom Fields which provide extended inventory
- The Internal Name can be used to reference an Inventory Item in Scripts
- These Internal Names should be added to either the Launch Arguments or Environment Variables of the Script
- This applies to all script types, be that other Custom Fields, Policy Blocker Scripts or Fileset Scripts

## When

Internal Name of an Inventory Item may be located from the Inventory Query Editor.<span class="Apple-converted-space"> </span>Example shows the Internal Name: ‘device\_product\_name’

![Pasted Graphic 29.png](https://kb.filewave.com/uploads/images/gallery/2024-07/QyDepMQgYvuZglej-embedded-image-xszkmtt6.png)

This may then be added into a Script, by way of either a Launch Argument or Environment Variable

![Pasted Graphic 30.png](https://kb.filewave.com/uploads/images/gallery/2024-07/TRdIe9TMcFoJSmKB-embedded-image-apalysf6.png)

But, which should be used?

## How

In some respects it does not matter which is used, however, for easy reference consider the following:

- Launch Arguments are referenced by their numerical position
- Environment Variables are referenced by a chosen name
- Custom Fields have an abbreviated name and a full name.<span class="Apple-converted-space"> </span>Custom Field names could overlap with a built-in Inventory Item.

### Built-In Inventory

In general, recommendation here is that of Environment Variables.<span class="Apple-converted-space"> </span>This makes reading the script easier without having to redefine new names within the script for Launch Argument positions.

For example:

![Pasted Graphic 31.png](https://kb.filewave.com/uploads/images/gallery/2024-07/NiOh6QTMHLrDFc0Y-embedded-image-kz46raaw.png)

Could be referenced in a script as:

<table border="1" id="bkmrk-macos-shell-echo-%241-" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 50%;"></col><col style="width: 50%;"></col></colgroup><tbody><tr><td>macOS shell</td><td>echo $1</td></tr><tr><td>Windows Powershell</td><td>echo $args\[0\]</td></tr></tbody></table>

But to make the parameters more easily recognisable for anyone reading the script, it could be desirable to name them:

<table border="1" id="bkmrk-macos-shell-product_" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 50%;"></col><col style="width: 50%;"></col></colgroup><tbody><tr><td>macOS shell</td><td>```
product_name=“$1”
echo $product_name
```

  
</td></tr><tr><td>Windows Powershell</td><td>```
$product_name=“$args[0]”
echo $product_name
```

  
</td></tr></tbody></table>

References to the provided inventory parameters in the script now makes more sense, but as mentioned, Environment Variables take this a step further:

![Pasted Graphic 32.png](https://kb.filewave.com/uploads/images/gallery/2024-07/KoGxqMx9maNr3KIW-embedded-image-0wpbc2ez.png)

A variable name is already defined and this can be referenced in the script directly

```
echo $product_name
```

### Improvements

#### First Improvement

To improve the readability of the script further, consider setting the variable name to match the value, e.g:

![Pasted Graphic 33.png](https://kb.filewave.com/uploads/images/gallery/2024-07/imU79dXCQajD97tQ-embedded-image-skyqleci.png)

```
echo $device_product_name
```

#### Second Improvement

When referencing a Custom Field in a script, it could be referenced in one of two ways. <span class="Apple-converted-space"> </span>

Example Custom Field: State

![Pasted Graphic 39.png](https://kb.filewave.com/uploads/images/gallery/2024-07/AXJgxl2b8I5M37Ry-embedded-image-npp8tct8.png)

<p class="callout success">Note, the description has been used to indicate this is a Custom Field. Inventory Query editor shows Description.</p>

This could be referenced with:

![Pasted Graphic 41.png](https://kb.filewave.com/uploads/images/gallery/2024-07/JLp6aCbxY4KiXCgt-embedded-image-kw0zkmfs.png)

and

```
echo $state
```

However, there is a built-in Inventory Item called State.<span class="Apple-converted-space"> </span>So there are now two Internal Names of ‘state’

![Pasted Graphic 38.png](https://kb.filewave.com/uploads/images/gallery/2024-07/Nyvh16aHs1cBIANW-embedded-image-a1jju9vm.png)

![Pasted Graphic 37.png](https://kb.filewave.com/uploads/images/gallery/2024-07/O6tCx50PJQq0JT3D-embedded-image-rdtja1oo.png)

The above scripted example for 'state' would actually report the built-in value, not the Custom Field. There is, though, a hidden prefix that can be used. <span class="Apple-converted-space"> </span>

This Custom Field could be referenced as either:

- %state%
- %CustomFields.state%

The latter prevents unexpected collusion with the matching Internal Name.<span class="Apple-converted-space"> </span>Hence, to make the parameters more obvious when reading…

![Pasted Graphic 40.png](https://kb.filewave.com/uploads/images/gallery/2024-07/kbDuPKrYEEkoJFSx-embedded-image-hu3lgfns.png)

```
echo $custom_fields_state
echo $internal_device_product_name
```

<p class="callout info">Notice, despite no prefix existing for built-in Inventory Items, by including a prefix for both variables in the Environment Variables definitions, reading the script will be much clearer.</p>

<p class="callout success">Anyone reading the script is now aware that state is a Custom Field, without having to cross reference anything.<span class="Apple-converted-space"> </span>Likewise, the reader also is aware that the device\_product\_name also comes from Inventory, again, without any cross reference necessary.</p>

### Unknown Inventory

Not all Inventory Items are available as parameters.

<p class="callout warning">The FileWave Client builds out the report of items to inventory and return to server.<span class="Apple-converted-space"> </span>Additionally, all Custom Fields, including those server-side (Administrator Custom Fields), are available to the client.<span class="Apple-converted-space"> </span>However, inventory returned by MDM is not available, since the client is unaware of these values, they are pure server-side.</p>

%CustomFields.location%

# Script Logging

## What

For scripts added to FileWave Filesets using the Script view, logging is enabled by default.

![Pasted Graphic 59.png](https://kb.filewave.com/uploads/images/gallery/2024-07/1rWN8RkMTzf0TUBh-embedded-image-xxke4cmk.png)

## When

Each time a Script (as built above) is actioned on a device, a log file is created or added to, with anything that the script outputs.<span class="Apple-converted-space"> </span>The logs of these Scripts are located in the following directories, within subfolders named after the Fileset ID:

#### macOS

```
# ls -al /private/var/log/fwcld/   
total 0
drwxrwxrwx  17 root  wheel   544 Mar  5 16:01 .
drwxr-xr-x  83 root  wheel  2656 Jul 31 08:27 ..
drwxrwxrwx   3 root  wheel    96 Aug  1  2023 1
drwxrwxrwx   5 root  wheel   160 Sep 25  2023 54231
drwxrwxrwx   6 root  wheel   192 Sep 26  2023 54235
drwxrwxrwx   3 root  wheel    96 Nov  9  2023 54367
drwxrwxrwx   3 root  wheel    96 Nov  9  2023 54368
drwxrwxrwx   3 root  wheel    96 Nov  9  2023 54374
drwxrwxrwx   3 root  wheel    96 Nov  9  2023 54379
drwxrwxrwx   3 root  wheel    96 Nov 10  2023 54384
drwxrwxrwx   3 root  wheel    96 Nov 10  2023 54396
drwxrwxrwx   3 root  wheel    96 Nov 10  2023 54401
drwxrwxrwx   3 root  wheel    96 Nov 10  2023 54406
drwxrwxrwx   3 root  wheel    96 Dec 15  2023 54417
drwxrwxrwx   3 root  wheel    96 Dec 15  2023 54419
drwxrwxrwx   3 root  wheel    96 Dec 15  2023 54421
drwxrwxrwx   3 root  wheel    96 Mar  5 16:01 55188
```

#### Windows

[![image.png](https://kb.filewave.com/uploads/images/gallery/2024-07/scaled-1680-/f4WIleVTNgRKxdmD-image.png)](https://kb.filewave.com/uploads/images/gallery/2024-07/f4WIleVTNgRKxdmD-image.png)

#### Example:

macOS example, but the principle is the same for Windows.

Consider this simple shell script that runs a command to output the username that ran the command:

![Pasted Graphic 60.png](https://kb.filewave.com/uploads/images/gallery/2024-07/YVIYiWjbvmaV5seh-embedded-image-okgwvqkc.png)

On running the command, the user running the command will be reported.<span class="Apple-converted-space"> </span>For example, running this locally on a device might reply:

```
% whoami
sholden
```

Viewing the log generated by FileWave:

```
# cat /private/var/log/fwcld/54421/whoami.sh.log
----------------------- HEADER - Date: (Fri Dec 15 2023) - Time: (16:40:21) -----------------------
root
----------------------- FOOTER - Date: (Fri Dec 15 2023) - Time: (16:40:22) - Exit code: (0) -----------------------
```

The output presents:

- Header and Footer with timestamps
- Footer with exit code value
- Any output from the script between the Header and Footer

### Improvement

The Script may or may not provide output, depending upon the command used.<span class="Apple-converted-space"> </span>However, why not add additional echo commands (or similar) to output extra details to provide more information from the script running.

Here is an example of a Fileset Requirement Script, waiting for confirmation of a Profile to be installed before activating the Fileset:

![Pasted Graphic 61.png](https://kb.filewave.com/uploads/images/gallery/2024-07/9AkfzOL7RG3PDmZY-embedded-image-4exhhdsw.png)

The script is outputting additional information, showing the ID of the Profile, found or not.<span class="Apple-converted-space"> </span>On success, exit 0, else exit 1.

Requirement Scripts will retry every 2 minutes, until successful, unless coded otherwise

```
----------------------- HEADER - Date: (Thu Jul 31 2024) - Time: (11:03:12) -----------------------
Did not find ml1063.local.aa0bd493-960d-4dc0-9631-a3fea189191e.Configuration.aa0bd493-960d-4dc0-9631-a3fea189191e
Did not find ml1063.local.5a57bcb9-7293-4cba-a20b-126eb2660b25.Configuration.5a57bcb9-7293-4cba-a20b-126eb2660b25
----------------------- FOOTER - Date: (Thu Jul 31 2024) - Time: (11:03:12) - Exit code: (1) -----------------------

----------------------- HEADER - Date: (Thu Jul 31 2024) - Time: (11:05:12) -----------------------
Found installed profile:  ml1063.local.aa0bd493-960d-4dc0-9631-a3fea189191e.Configuration.aa0bd493-960d-4dc0-9631-a3fea189191e
----------------------- FOOTER - Date: (Thu Jul 31 2024) - Time: (11:05:12) - Exit code: (0) -----------------------
```

On first attempt, the log shows two Profiles were searched and not found, with the script exiting a value of 1. On second attempt, the first Profile ID is now showing as installed and the script exited with a value of 0.

### No Logs

Some scripts ran through FileWave, e.g. Policy Blocker Scripts, do not provide logs, with some mention in the Client Log alone, that the Script ran.

However, it is entirely possible to choose to create a custom log file within a script, for any script, and echo any output desired to provide additional logging.

<p class="callout success">Consider how the script will grow and how to either overwrite or append appropriately.</p>