Update – Sept 2021.
– Added a new switch “-mode” [Online | Offline]. Specifies whether you want to pull data live from the server or use existing CSV files.
– Fixed bugs and added more error handling
Keeping a clean and healthy environment is important when managing a large number of devices in Workspace ONE UEM. Over time duplicate and stale device records, especially for Windows 10, can grow and grow. Without regular maintenance, you could potentially have thousands of records that are no longer valid and will affect the reporting of your deployments. This happens due to normal attrition of devices, re-imaging, and device resets. I took an internal script developed by our VMware IT system admins and modified it for external use so that you can easily clean up device records using WS1 REST API. The script is available on Github: Start-UEMMaintenance.ps1. To download it, click “Raw” then right-click and “Save As”.
What the script do?
This script connects to your VMware Workspace ONE UEM environment and gets duplicates, stale records, or problematic devices (devices with invalid serials). It also can get duplicate user accounts. Once you run any of the “get” actions, it will save the data to several csv files located under C:\UEM-Maintenance\[uem server]\[today’s date]. If you run it again on the same day, it will search for valid CSV files first before reaching out again to the server. This is to improve speed, allow for editing of CSVs, and reduce load on the server. If it does not find a valid csv, it will go ahead and reach out to the server. Additionally, it asks for and stores the UEM credentials in an encrypted file (saved C:\UEM-Maintenance\ [uem server]\Logs\Creds.txt) with AES encryption. The key is saved C:\UEM-Maintenance\ [uem server]\Logs\AES.key. This allows the script to be run in an automated fashion by a service account or multiple users on the same internal server. However since the encryption key is on the same system, care must be taken on who can access the system this script is running from. This key can also be saved on a different location for improved security.
Using REST API with Workspace One involves two things: first, you need an API key. This essentially “gets you in the door” and is tied to the Organization Group. However, to actually do anything, such as reading or deleting devices you still need a Workspace One admin account. This can either be a basic account or a service account synced in from Active Directory. The minimum this account needs is REST API access as well as “delete’ device records. The simplest way to achieve it is the grant the account “Airwatch Administrator” access. However, this gives it way more access than it needs so the best practice always is to create a least privileged access role. If you do set it to “Airwatch Administrator”, give it that role during the cleanup and then change the account to “read only” role. This is to ensure no one external ever get the API key and admin credentials.
Additionally, as mentioned above when you run the script the first time (per environment) it will prompt you for those admin credentials and then save them encrypted to C:\UEM-Maintenance\ [uem server]\Logs\Creds.txt. The key to unlock and retrieve the creds is in the same directory so this isn’t a true foolproof encrypted solution. It adds a layer of security but you still need to protect the AES.key file. You can do this several ways: First, delete the file after each time this script is run. If you do this then you will have to input credentials each time you run the script. Second, you can run this on an internal server where only legitimate admins have access. Or you can modify the script to store and retrieve this file from a different file share on your network.
With that out of the way, let’s dig into each function and how they work.
This function first gets all devices and saves them to AllDevices.csv. You can optionally search based on platform. Next, it will count the duplicates based on Serial Number and save to AllDuplicateDevices.csv. It loops through that list and sorts based on “Device Last Seen” and then by “Device ID” so that the most recent device (meaning the “good” device) is excluded. All of these exclusions are sent to DoNotDeleteList.csv. The rest are the true duplicates and should be deleted. This list is DuplicateDevicesToBeDeleted.csv and will be used by the “Delete-Duplicates” function. You can look at these files as well as edit them for accuracy as well as to reduce the final deletion list. I.e. as a test you could delete all rows except one in the DuplicateDevicesToBeDeleted.csv file so that only one device will be deleted. This is a good test to ensure your credentials work properly. Additionally, this can sometimes take some time depending on how large of an environment it is. This function supports two optional parameters:
It excludes devices with invalid serials as those may not be true duplicates. See below for more details on this.
Specifies which platform type you’d like to search duplicates for. Valid options are: ‘Mac’, ‘Win10’, ‘Android’, ‘iOS’, ‘ChromeOS’, ‘Any’. Any is the default if no parameter is specified.
This will delete all devices found in DuplicateDevicesToBeDeleted.csv. If that file is not there, it will then run Get-Duplicates.
This first looks for an AllDevices.csv file and will import it if found. Otherwise, it will run the “Get-DuplicateDevices” command and pull live from the server. Then after all devices are gathered, it will then sort and look for all devices not seen in the last 90 days (default). If you specify a different value in the “day” parameter, then you can adjust how far back you want to filter. After this it will save all stale devices to StaleDevices.csv. Optional parameter supported:
Specifies how many days back the script should check for stale records. Default is 90 days.
This will delete all stale devices found in StaleDevices.csv. If that file is not there, it will then run Get-StaleDevices.
This first looks for an AllDevices.csv file and will import it if found. Otherwise, it will run the “Get-DuplicatesDevices” command and pull live from the server. Then after all devices are gathered, it will then sort based on the $SerialFilter variable at the top of the script. At the time of this writing, I have it set to filter any of these values
'System Serial Number',
'To be filled by O.E.M.',
Devices can have invalid serials for a number of reasons and need to be looked at why the inventory is not working properly. This can sometimes indicate a bad or incomplete enrollment. This function will save all problematic devices found to ProblematicDevices.csv
This will delete all problematic devices found in ProblematicDevices.csv. If that file is not found, it will run Get-ProblematicDevices.
This searches the environment for duplicate users. Duplicate users can exist for a variety of reasons, but the most common is creating basic accounts with the same username at different OGs. You can filter based on user type (Basic, Directory, or Any) or a user list (csv file). Optional parameters supported:
Specify path to a csv file that has a list of usernames (command separated)
Specifies type of search to search for (basic, directory, or Any)
.\Start-UEMMaintenance.ps1 -server myserver.awmdm.com -ApiKey “n0t@re@lK3y” -Action Get-DuplicateUsers -UserList C:\temp\userlist.csv -UserType ‘BasicOnly’ -UserList C:\temp\userlist.csv
Specifies the server you are targeting in format myserver.awmdm.com
Mandatory parameter for the API key that is required for the script to connect via REST API to your server. These keys are per OG and are found under All Settings > System > Advanced > API > REST API.
Mandatory parameter that specifies the action the script should take. Options are: ‘Get-Duplicates’, ‘Delete-Duplicates’, ‘Get-Stale’, ‘Delete-Stale’, ‘Get-Problematic’, ‘Delete-Problematic’.
For more examples, see the readme documentation here.