Automate the Cleanup of Deregistered Endpoints

September 12, 2023

How to ensure a Clean Inventory in Carbon Black Cloud? Automate the Cleanup of Deregistered Endpoints

In today's fast-paced cybersecurity landscape, maintaining a clean inventory of your security solutions' endpoints is essential. This is especially critical in large virtual desktop infrastructure (VDI) environments, where non-persistent VDI clones often clutter the inventory page. VMware Carbon Black Cloud (CBC) administrators may also face this challenge. This article discusses an automated solution for cleaning up deregistered endpoints in VMware Carbon Black Cloud using PowerShell.

The Problem: Cluttered Inventory in High VDI Footprint

Customers operating in environments with large VDI footprints often face a unique set of challenges, primarily related to endpoint management and inventory visibility. Let's take a deep dive to understand how non-persistent clones work and how the Carbon Black cloud integrates with VDI.

How Non-Persistent Clones Work in VDI

In a VDI environment, a "golden image" serves as the template for creating VDI clones. These clones are called "non-persistent" because they are ephemeral; they exist for the duration of a user's session and are destroyed when the user logs off. When a clone is spawned from the golden image, it registers with the Carbon Black Cloud (CBC) to obtain a unique device ID. This re-registration is critical; otherwise, the clone and golden image would share the same device ID, causing backend problems in CBC.

While a user is logged in, the sensor on the VDI clone communicates with CBC just like any normal endpoint. It maintains its unique device ID and host name for that session. After the user logs off, the non-persistent clone is typically turned off and destroyed. In the context of CBC, these clones transition to a "deregistered" state based on the policy settings applied to VDI endpoints.

The Cycle Repeats, The Problem Intensifies

Here's where things get tricky. When a new clone is created from the golden image, the hostname of the previously deleted clone often becomes available again. This new clone goes through the same lifecycle - re-registration, user session, and eventual destruction. As this process repeats, administrators end up with multiple deregistered  endpoints in their CBC inventory, all with the same host name but different device IDs.

The Limitation of Carbon Black Cloud's Deletion Policy

By default, Carbon Black Cloud provides automatic deregistration and automatic deletion of deregistered assets, but only after a minimum of 24 hours. First, as a best practice, deregistration should be enabled in the specific VDI endpoint policy, as shown in the figure below.  A screenshot of a computer</p>
<p>Description automatically generated

Figure 1: Auto-deregister function of VDI Clone sensors after a specific time of inactivity.

Deletion of unregistered assets can be set on the Inventory page by clicking the Sensor Options button > Manage Sensor Settings in the upper right corner.

A screenshot of a computer</p>
<p>Description automatically generated

Figure 2: Sensor Deletion option on the Inventory page for deregisterered assets.

In environments with high VDI clone turnover, this delay can quickly lead to a cluttered and confusing inventory. It also creates a significant challenge for administrators when triaging alerts for a specific hostname, as it becomes unclear which device triggered the alert.

The delayed purge and repeated use of identical hostnames creates a layer of administrative overhead. It also complicates the process of triaging and responding to alerts. Automating the remediation of deregistered endpoints is not just a convenience, it is a necessity to maintain operational efficiency and security effectiveness.

The Solution: A Deregistered (VDI) Endpoint Deletion Script

To address the problem of cluttered inventory due to frequent turnover of non-persistent VDI clones in Carbon Black Cloud (CBC), we can implement an automated solution. A PowerShell script (available here on GitHub) was developed to identify and delete these ephemeral VDI clones that have been deregistered. First, let's get a basic understanding of the key components of the script:

  1. Environment Variables: The script loads API credentials and the organization key from an auth.env file.

  2. Authentication: A token is generated using API secrets and ID.

  3. Deregistered Time Threshold: A time frame is defined, considering endpoints deregistered for more than 5 minutes.

  4. API Calls: The script invokes API endpoints for device search and deletion using the constructed token and body content.

  5. Logging: Outputs are generated to show which endpoints are deregistered and actions taken. 

    Now, let’s dive into the VDI clone deletion script to get a basic understanding how it works:

    1. Environment Variables: First things first, the script needs to know how to access a CBC tenant via the Carbon Black Cloud OpenAPI. The script first reads environment variables from an auth.env file, that must be created in advance. This file includes API credentials and the organization key, which are used to authenticate API calls.
      $envFile = Get-Content -Path "./auth.env" | ConvertFrom-StringData 
    2. Authentication Token: A unique authentication token is constructed using the API ID and API Secret from the environment variables.

      $authToken = "$apiSecret/$apiId"
    3. Time Criteria: It calculates the current time minus one hour, to focus on the most recent deregistered devices.
       $currentTimeMinus1Hour = (Get-Date).AddHours(-1).ToString("yyyy-MM-ddTHH:mm:ssZ")
      Note: To modify the script to target deregistered devices within the last 30 minutes instead of the last hour, you would change the line to something like that:

      $currentTimeMinus30Minutes = (Get-Date).AddMinutes(-30).ToString("yyyy-MM-ddTHH:mm:ssZ")
      Don’t forget, that after making this change, renaming the variable from  $currentTimeMinus1Hour to $currentTimeMinus30Minutes must be consistent throughout the script.

    4. API Endpoint URLs: URLs for device search and device action are constructed. This part is important as it’s the basic API route we must go to search and modify device information in CBC.
      $searchEndpointUrl = "$orgUrl/appservices/v6/orgs/$orgKey/devices/_search"

      $actionEndpointUrl = "$orgUrl/appservices/v6/orgs/$orgKey/device_actions"
    5. Request Body: The script builds a JSON request body with search criteria. It looks for devices that are both deregistered and are not golden devices. The time is also set to focus on the most recent ones.

      $searchRequestBody = @{ ... } | ConvertTo-Json

      Let's break down each component to understand how we can work with the devices API of Carbon Black Cloud:

      • criteria: This is the primary object that contains all the search conditions.
      • status = @("DEREGISTERED"): Only devices that are deregistered are considered. This is essential as we want to eliminate only those devices that are no longer active.
      • deployment_type = @("VDI"): This filters the devices specifically for those deployed in a Virtual Desktop Infrastructure (VDI). It ensures that non-VDI devices are excluded from deletion.
      • golden_device_status = @("NOT_GOLDEN_DEVICE"): This filters out any golden devices (master templates for VDI). It is crucial as deleting a golden device would be catastrophic for the VDI deployment.
      • deregistered_time: This is an object containing a time range condition
      • from = $currentTimeMinus1Hour: Sets the lower boundary for the deregistered time to the current time minus one hour. This ensures you're only considering recently deregistered devices.
      • range = "gte": The time condition is "greater than or equal to," meaning it will consider devices deregistered from the time specified up to the current moment.
      • rows = 50: This specifies the maximum number of records to return. You can adjust this number based on your environment's needs.
      • start = 0: This is the starting index for the returned records. Essentially, it means the script will start looking from the first record.
      • sort: This is an array that specifies the sorting order for the returned devices.
      • field = "name": Sorts the devices by their name.
      • order = "asc": Specifies the sort order as ascending.

    6. API Calls: It invokes API calls to search for devices matching the criteria. If it finds any, it performs another API call to delete them.

$searchResponse = Invoke-RestMethod -Uri $searchEndpointUrl -Method Post -Headers @{...} -Body $searchRequestBody
    7. Extracting Device IDs: After the script has invoked the device search API and received the response, it extracts the device IDs from the returned results. These IDs are essential for identifying which endpoints to delete.

      $deviceIds = $

    8. Conditional Deletion: The script then checks if any device IDs were returned. If yes, it proceeds with the deletion process; otherwise, it outputs that no devices matched the criteria.

      if ($deviceIds.Count -gt 0) { ... }
      else {
          Write-Host "No devices found matching the criteria."

    9. Deletion Request Body: Assuming there are devices to be deleted, the script constructs a JSON request body for this action. The action type is specified as "DELETE_SENSOR" and the device IDs that were previously extracted are included.

      $deleteRequestBody = @{
          "action_type" = "DELETE_SENSOR"
          "device_id" = $deviceIds }
      | ConvertTo-Json
    10.  Invoke Deletion API: Another API call is made, this time to the device action endpoint. The request includes the deletion request body and the necessary headers for authentication.

      $deleteResponse = Invoke-RestMethod -Uri $actionEndpointUrl -Method Post -Headers @{ ... } -Body $deleteRequestBody

    11. Output and Error Handling:The script outputs the API response to give a status on the deletion process. This is useful for auditing and debugging purposes. The script also includes a catch block to capture and output any errors that occur during the API calls. If there's an exception, the script will output the error message and, if available, the response content for further investigation.

    How to Use the Script

    See the project's README page for an overview of the project, a description of each script, a guide to setting the correct API access levels to adhere to the principle of least privilege, and a guide to setting up the auth.env file for working authentication against your Carbon Black Cloud tenant. 

    I also developed a second script (called endpoint-deleter.ps1) that is more focused on the overall endpoint inventory. I tweaked the criteria a bit so that all endpoints with the status: DEREGISTERED are considered for automatic removal.


    Automating the remediation of deregistered endpoints in the VMware Carbon Black Cloud not only saves valuable time, but also significantly improves your ability to focus on real security threats. Maintaining a clean inventory gives you the clarity you need to take decisive action in a landscape where every second counts.  


    This project is licensed under the MIT License. See the LICENSE file for details.


    Use of the script in any environment, including both production and testing environments, is at your own risk. The script has been tested in the author’s lab environment, but it may contain errors or bugs. VMware Carbon Black make no warranties or guarantees regarding the functionality, accuracy, or reliability of the script. Before deploying the script in a production environment, it is strongly recommended to perform thorough testing with a small group of devices to ensure its proper functionality and compatibility with your specific setup. VMware, Inc. shall not be held liable for any damages, losses, or issues arising from the use of the script. By using the script, you acknowledge and accept the risks involved and agree to release VMware, Inc. from any liability related to its use.

Filter Tags