{"id":14,"date":"2025-09-25T16:24:49","date_gmt":"2025-09-25T16:24:49","guid":{"rendered":"https:\/\/xn--o3cah8a1fre.com\/wordpress\/?p=14"},"modified":"2025-09-30T16:17:30","modified_gmt":"2025-09-30T16:17:30","slug":"duplicate-computer-name","status":"publish","type":"post","link":"https:\/\/xn--o3cah8a1fre.com\/wordpress\/2025\/09\/25\/duplicate-computer-name\/","title":{"rendered":"Duplicate Computer name"},"content":{"rendered":"\n<figure class=\"wp-block-image aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"755\" height=\"544\" src=\"https:\/\/xn--o3cah8a1fre.com\/wordpress\/wp-content\/uploads\/2025\/09\/image-1.png\" alt=\"\" class=\"wp-image-20\" srcset=\"https:\/\/xn--o3cah8a1fre.com\/wordpress\/wp-content\/uploads\/2025\/09\/image-1.png 755w, https:\/\/xn--o3cah8a1fre.com\/wordpress\/wp-content\/uploads\/2025\/09\/image-1-300x216.png 300w\" sizes=\"auto, (max-width: 755px) 100vw, 755px\" \/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>There is no fully automated built-in feature to remove duplicates solely based on computer name, as GravityZone relies on unique identifiers.<\/p>\n\n\n\n<p><br>If two endpoints have the same computer name but different HWIDs or MAC addresses, GravityZone treats them as separate entities, each consuming a license seat.<\/p>\n\n\n\n<p>However, <br><br>1 You can set up rules for deleting unused or offline endpoints:<br>&nbsp;&nbsp;&nbsp;&nbsp;\u2022&nbsp;&nbsp; Go to Configuration &amp; Network Settings.<br>&nbsp;&nbsp;&nbsp;&nbsp;\u2022&nbsp;&nbsp; Under the Offline machines cleanup section, create rules to automatically delete endpoints that have not connected for a specified period.<br>&nbsp;&nbsp;&nbsp;&nbsp;\u2022&nbsp;&nbsp; This helps clean up stale or duplicate entries that are no longer active.<br><a href=\"https:\/\/www.bitdefender.com\/business\/support\/en\/77211-155208-configuration.html\">https:\/\/www.bitdefender.com\/business\/support\/en\/77211-155208-configuration.html<\/a><\/p>\n\n\n\n<p>2 Preparing for duplication a Sysprep-Generalized Windows image with&nbsp;BEST&nbsp;installed.<br><a href=\"https:\/\/www.bitdefender.com\/business\/support\/en\/77209-87466-troubleshooting.html\">https:\/\/www.bitdefender.com\/business\/support\/en\/77209-87466-troubleshooting.html<\/a><\/p>\n\n\n\n<p>3 Using Below Script to export duplicate computer name as csv<br><br><code>python getComputerlist.r3.py --api-key <strong>\"PASTE_YOUR_KEY\"<\/strong> --output \".\/exports\/\" --debug<\/code><br><br><strong>Example Duplicate Computer name as csv file<\/strong><br><br>name,fqdn,machineType,operatingSystemVersion,ip,macs,ssid,managedWithBest,lastSeen,loggedInUser<br>DUPLICATE,duplicate,2,Windows 10 Pro,192.168.31.72,0050569708e3,,True,,<br>DUPLICATE,duplicate,2,Windows 10 Pro,192.168.31.100,0050569759eb,,True,,<br>DUPLICATE,duplicate,2,Windows 10 Pro,192.168.31.5,00505697a612,,True,,<\/p>\n\n\n\n<p><a href=\"https:\/\/github.com\/darklite404\/Bitdefender_Gravityzone\/blob\/main\/getComputerlist.r3.py\">https:\/\/github.com\/darklite404\/Bitdefender_Gravityzone\/blob\/main\/getComputerlist.r3.py<\/a><\/p>\n\n\n\n<p>3.1 You can get your API Key by <a href=\"https:\/\/www.bitdefender.com\/business\/support\/en\/77209-125277-public-api.html#UUID-2a74c3b5-6159-831d-4f8a-ca42797ce3b0_section-idm4640169987334432655171029621\">https:\/\/www.bitdefender.com\/business\/support\/en\/77209-125277-public-api.html#UUID-2a74c3b5-6159-831d-4f8a-ca42797ce3b0_section-idm4640169987334432655171029621<\/a><\/p>\n\n\n\n<p>To generate API keys:<a><\/a><\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Log in to&nbsp;<code>https:\/\/gravityzone.bitdefender.com\/<\/code>&nbsp;using an administrator account. Your account must have the following rights:&nbsp;<strong>Manage Networks<\/strong>,&nbsp;<strong>Manage Users<\/strong>,&nbsp;<strong>Manage Company<\/strong>, and&nbsp;<strong>View and analyze data<\/strong>.<\/li>\n\n\n\n<li>Click your username in the upper right side of the console and select&nbsp;<strong>My Account<\/strong>:<img decoding=\"async\" src=\"https:\/\/www.bitdefender.com\/business\/support\/en\/image\/uuid-0852d418-1dd5-f7d6-72f3-3da24223506b.png\" alt=\"console_my_account_121716_en.png\"><\/li>\n\n\n\n<li>Go to the&nbsp;<strong>API keys<\/strong>&nbsp;section and click the&nbsp;<strong>Add<\/strong>&nbsp;button:<br><img decoding=\"async\" src=\"https:\/\/www.bitdefender.com\/business\/support\/en\/image\/uuid-51c968dd-9d54-6e6c-ca88-1f0042bd968d.png\" alt=\"console_my_account_add_API_key121716_en.png\"><\/li>\n\n\n\n<li>Type in a description for the key and select the APIs you want to enable for use with this key:<br><img decoding=\"async\" src=\"https:\/\/xn--o3cah8a1fre.com\/wordpress\/wp-content\/uploads\/2025\/09\/image.png\" alt=\"\"><\/li>\n\n\n\n<li>Click&nbsp;<strong>Generate<\/strong>.NoteA window will be displayed with the newly generated API key and a warning stating that the key is only available for you to read while the window is open. After closing the window you will no longer be able to view the key anywhere in&nbsp;GravityZone.<img decoding=\"async\" src=\"https:\/\/www.bitdefender.com\/business\/support\/en\/image\/uuid-4e599938-8b9c-cf1e-9211-1021e63b0aa5.png\" alt=\"console_my_account_display_API_key_121716_en.png\"><\/li>\n\n\n\n<li>Click the&nbsp;<img decoding=\"async\" src=\"https:\/\/www.bitdefender.com\/business\/support\/en\/image\/uuid-060909dd-7942-2ef7-21d8-78db7e2cd64e.png\" alt=\"copy_to_clipboard_121716_en.png\">&nbsp;button to copy the key to clipboard and save it in a safe location.<\/li>\n\n\n\n<li>Close the&nbsp;<strong>API key<\/strong>&nbsp;window.<\/li>\n<\/ol>\n\n\n\n<p>The new key is added under the&nbsp;<strong>API keys<\/strong>&nbsp;section in an obfuscated format along with its description and creation date, and a list of enabled APIs.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/www.bitdefender.com\/business\/support\/en\/image\/uuid-6d478fba-0821-fe7a-a590-71c6e1f3db6d.png\" alt=\"console_my_account_add_API_key_result_121716_en.png\"\/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Important<\/h3>\n\n\n\n<p>By using the API keys, developers can access sensitive information such as packages and inventory. Please do not share or distribute your own generated API keys, in order to prevent the leaking of sensitive information!<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p><strong>Full Code<\/strong> : <strong>getComputerlist.r3.py<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#!\/usr\/bin\/env python3\nr\"\"\"\nVersion: 1.3.0 (2024-06-19)\nEditor: Pichet Jarunithi\nFetch Bitdefender GravityZone endpoints, find duplicate endpoint names, and export duplicates to CSV.\n\nWhat this script does\n- Calls GravityZone JSON-RPC API (network) and fetches:\n  - getEndpointsList: main list of endpoints.\n  - getNetworkInventoryItems: inventory items (may contain nested details).\n- Finds endpoints that share the same name (case-insensitive) from getEndpointsList only.\n- Exports duplicates to a timestamped CSV.\n- Optionally prints all endpoints\/inventory to console and\/or exports all to CSV(s).\n- Auto-updates prerequisites (requests, certifi, packaging) and restarts if updates were applied.\n- Supports EU (cloud), US (cloudgz) and AP (cloudap) API endpoints.\n- Detailed logging with --debug.\n\nCSV columns (duplicates and \"export all\")\n- name,fqdn,machineType,operatingSystemVersion,ip,macs,ssid,managedWithBest,lastSeen,loggedInUser\n\nRequirements\n- Python 3.8+ recommended.\n- Outbound HTTPS to GravityZone endpoints.\n- Bitdefender GravityZone API key with permissions to query endpoints.\n- The script can auto-update required packages (requests, certifi, packaging) and will restart itself when it does.\n\nAPI key\n- Pass with --api-key \"YOUR_KEY\"\n- Or set environment variable BITDEFENDER_API_KEY\n  - Windows (PowerShell):  setx BITDEFENDER_API_KEY \"YOUR_KEY\"\n  - Windows (CMD):         setx BITDEFENDER_API_KEY \"YOUR_KEY\"\n  - Linux\/macOS (bash):    export BITDEFENDER_API_KEY=\"YOUR_KEY\"\n- If neither is provided, the script exits with code 2.\n\nRegions and endpoints\n- --region ap:               https:\/\/cloudap.gravityzone.bitdefender.com\/api\/v1.0\/jsonrpc\/network\n- --region eu:               https:\/\/cloud.gravityzone.bitdefender.com\/api\/v1.0\/jsonrpc\/network\n- --region us:               https:\/\/cloudgz.gravityzone.bitdefender.com\/api\/v1.0\/jsonrpc\/network\n- Pick the region that matches your GravityZone console. If unsure, try the default first.\n\nSecurity note\n- Use --insecure only as a last resort when corporate MITM\/proxies break TLS validation. It disables certificate verification.\n\nOutput files and naming\n- Duplicates CSV:\n  - Controlled by --output. The script always names files with a timestamp prefix: YYYYMMDD_HHMM.csv.\n  - If --output is a directory or ends with a path separator, the file is written inside that directory.\n  - If --output is a file path, the parent directory is used; the filename is still timestamped (the literal name is not used).\n- Export all CSVs (when --export-all is provided):\n  - Writes two files with timestamp in the selected directory:\n    - &lt;timestamp&gt;_endpoints.csv\n    - &lt;timestamp&gt;_inventory.csv\n\nLogging\n- Default: INFO to stdout.\n- --debug: verbose diagnostics, including sample payload structures and derived fields.\n- --log-file &lt;path&gt;: also writes detailed logs to the specified file.\n\nExit codes\n- 0: success\n- 1: runtime error (network\/API\/other)\n- 2: missing API key\n- On first run it may auto-update packages and restart.\n\nCommand-line options (quick)\n- --api-key: API key (or use BITDEFENDER_API_KEY).\n- --region: \"ap\" (alias: \"non-eu\"), \"eu\", or \"us\". Default: \"non-eu\".\n- --output: target directory or path to influence where the timestamped duplicates CSV is written.\n- --list-all: print all endpoints and inventory to console.\n- --export-all: directory or path (parent directory is used) for writing all endpoints\/inventory CSVs.\n- --debug: verbose logs.\n- --insecure: disable TLS certificate verification (not recommended).\n- --log-file: optional log file path.\n\nExamples\n\nWindows (PowerShell)\n1) Using environment variable and defaults (non-EU region):\n   setx BITDEFENDER_API_KEY \"PASTE_YOUR_KEY_HERE\"\n   python getComputerlist.r3.py\n\n2) Specify region and write outputs to a folder:\n   python getComputerlist.r3.py `\n     --region eu `\n     --output \"C:\\Exports\\\" `\n     --export-all \"C:\\Exports\\\" `\n     --log-file \"C:\\Exports\\gz_run.log\" `\n     --debug\n\n3) Provide API key on the command line:\n   python getComputerlist.r3.py --api-key \"PASTE_YOUR_KEY\" --output \".\/exports\/\" --debug\n   python getComputerlist.r3.py --api-key \"PASTE_YOUR_KEY\" --region ap --output \".\/exports\/\" --debug\n\nOperational notes\n- Duplicate detection is based on name (case-insensitive) from getEndpointsList results only.\n- The inventory call is mostly for additional visibility and optional export; it is not used for de-duplication.\n- For proxies: requests uses HTTPS_PROXY\/HTTP_PROXY environment variables if set.\n- If you receive 401\/403 errors, verify your API key and GravityZone permissions.\n- If you see SSL errors, leave --insecure off unless you fully understand the risk; instead, fix trust store (certifi) or configure your proxy.\n\nTroubleshooting\n- \"No API key provided\": set BITDEFENDER_API_KEY or pass --api-key.\n- \"API error: ...\": re-check region and permissions; confirm endpoint is reachable.\n- SSL\/TLS validation failure: corporate proxy inspection could be at fault; try updating certifi, adding your proxy\u2019s CA to the system store, or use --insecure as a last resort.\n- Timeouts: check network egress, firewall, or corporate proxy rules.\n\nFields exported (best-effort)\n- name, fqdn, machineType, operatingSystemVersion, ip, macs, ssid, managedWithBest, lastSeen, loggedInUser\n- Some fields may be empty or derived from nested structures (best effort).\n\n\"\"\"\nimport os\nimport sys\nimport csv\nimport json\nimport base64\nimport argparse\nimport logging\nfrom uuid import uuid4\nfrom typing import List, Dict, Any, Optional\nfrom datetime import datetime\n\n# --- Bootstrap: ensure latest packages and restart if updated ---\ndef ensure_latest_packages(packages: List&#91;str], logger: logging.Logger) -&gt; None:\n    import subprocess\n    import importlib\n    from importlib import metadata\n    from urllib.request import urlopen\n    from urllib.error import URLError, HTTPError\n\n    # Ensure 'packaging' exists first (needed for proper version comparison)\n    try:\n        from packaging.version import parse as vparse  # noqa: F401\n    except Exception:\n        logger.info(\"Installing\/Updating prerequisite: packaging\")\n        subprocess.run(&#91;sys.executable, \"-m\", \"pip\", \"install\", \"--upgrade\", \"packaging\"], check=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE)\n        # Try importing again in the same process\n        try:\n            from packaging.version import parse as vparse  # noqa: F401\n        except Exception:\n            logger.error(\"Failed to import 'packaging'. Please install it manually.\")\n            sys.exit(1)\n\n    from packaging.version import parse as vparse\n\n    updated_any = False\n    for pkg in packages:\n        try:\n            installed_ver = metadata.version(pkg)\n        except metadata.PackageNotFoundError:\n            installed_ver = None\n\n        latest_ver = None\n        try:\n            with urlopen(f\"https:\/\/pypi.org\/pypi\/{pkg}\/json\", timeout=15) as resp:\n                data = json.load(resp)\n                latest_ver = data.get(\"info\", {}).get(\"version\")\n        except (URLError, HTTPError, json.JSONDecodeError) as e:\n            logger.warning(f\"Could not check latest version for {pkg}: {e}\")\n            continue\n\n        if latest_ver is None:\n            continue\n\n        needs_update = installed_ver is None or vparse(installed_ver) &lt; vparse(latest_ver)\n        if needs_update:\n            logger.info(f\"Updating {pkg} from {installed_ver or 'not installed'} to {latest_ver}\")\n            result = subprocess.run(&#91;sys.executable, \"-m\", \"pip\", \"install\", \"--upgrade\", pkg], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)\n            if result.returncode != 0:\n                logger.error(f\"Failed to update {pkg}: {result.stderr.strip()}\")\n                continue\n            updated_any = True\n\n    if updated_any:\n        # Restart the script with same args\n        logger.info(\"Updates applied. Restarting script...\")\n        os.execv(sys.executable, &#91;sys.executable] + sys.argv)\n\n# --- Argument parsing and logging setup ---\ndef parse_args() -&gt; argparse.Namespace:\n    parser = argparse.ArgumentParser(description=\"Find duplicate endpoint names via Bitdefender GravityZone API and export details to CSV.\")\n    parser.add_argument(\"--api-key\", help=\"Bitdefender API key. If omitted, reads from BITDEFENDER_API_KEY env var.\", default=os.getenv(\"BITDEFENDER_API_KEY\"))\n    parser.add_argument(\n        \"--region\",\n        choices=&#91;\"ap\", \"eu\", \"us\", \"non-eu\"],\n        default=\"non-eu\",\n        help=\"API region: ap (alias: non-eu), eu, or us. Default: non-eu (maps to ap).\"\n    )\n    parser.add_argument(\"--output\", default=\"duplicates_endpoints.csv\", help=\"CSV output filepath\")\n    parser.add_argument(\"--debug\", action=\"store_true\", help=\"Enable detailed debug logs\")\n    parser.add_argument(\"--insecure\", action=\"store_true\", help=\"Allow insecure HTTPS (disable certificate verification). Not recommended.\")\n    parser.add_argument(\"--log-file\", default=None, help=\"Optional path to write detailed logs.\")\n    parser.add_argument(\"--list-all\", action=\"store_true\", help=\"Print all endpoints to console.\")\n    parser.add_argument(\"--export-all\", default=None, help=\"Optional CSV path to export all endpoints.\")\n    return parser.parse_args()\n\ndef setup_logger(debug: bool, log_file: Optional&#91;str] = None) -&gt; logging.Logger:\n    logger = logging.getLogger(\"gzdup\")\n    logger.setLevel(logging.DEBUG if debug else logging.INFO)\n    if logger.handlers:\n        logger.handlers.clear()\n\n    formatter = logging.Formatter(\"&#91;%(asctime)s] %(levelname)s - %(message)s\")\n\n    ch = logging.StreamHandler(sys.stdout)\n    ch.setLevel(logging.DEBUG if debug else logging.INFO)\n    ch.setFormatter(formatter)\n    logger.addHandler(ch)\n\n    if log_file:\n        fh = logging.FileHandler(log_file, encoding=\"utf-8\")\n        fh.setLevel(logging.DEBUG)\n        fh.setFormatter(formatter)\n        logger.addHandler(fh)\n        logger.info(f\"Logging to file: {log_file}\")\n\n    return logger\n\n# --- API helpers ---\ndef get_endpoint_url(region: str) -&gt; str:\n    if region == \"eu\":\n        return \"https:\/\/cloud.gravityzone.bitdefender.com\/api\/v1.0\/jsonrpc\/network\"\n    if region == \"us\":\n        return \"https:\/\/cloudgz.gravityzone.bitdefender.com\/api\/v1.0\/jsonrpc\/network\"\n    # treat both \"ap\" and legacy \"non-eu\" as AP\n    return \"https:\/\/cloudap.gravityzone.bitdefender.com\/api\/v1.0\/jsonrpc\/network\"\n\ndef make_auth_header(api_key: str) -&gt; str:\n    token = base64.b64encode(f\"{api_key}:\".encode(\"utf-8\")).decode(\"utf-8\")\n    return f\"Basic {token}\"\n\ndef fetch_all_endpoints(api_url: str, auth_header: str, insecure: bool, logger: logging.Logger, method: str = \"getEndpointsList\") -&gt; List&#91;Dict&#91;str, Any]]:\n    import requests\n\n    headers = {\n        \"Content-Type\": \"application\/json\",\n        \"Authorization\": auth_header,\n    }\n\n    items: List&#91;Dict&#91;str, Any]] = &#91;]\n    page = 1\n    per_page = 100\n\n    verify = not insecure\n    if not verify:\n        try:\n            import urllib3\n            urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)\n        except Exception:\n            pass\n\n    while True:\n        payload = {\n            \"jsonrpc\": \"2.0\",\n            \"method\": method,\n            \"params\": {\n                \"filters\": {\n                    \"depth\": {\"allItemsRecursively\": True}\n                },\n                \"page\": page,\n                \"perPage\": per_page,\n            },\n            \"id\": str(uuid4()),\n        }\n\n        logger.debug(f\"Requesting page {page} with perPage {per_page}\")\n        resp = requests.post(api_url, json=payload, headers=headers, timeout=60, verify=verify)\n        resp.raise_for_status()\n        data = resp.json()\n\n        if \"error\" in data:\n            raise RuntimeError(f\"API error: {data&#91;'error']}\")\n\n        result = data.get(\"result\", {})\n        page_items = result.get(\"items\", &#91;])\n        # Extra DEBUG for first page to see structure differences\n        if page == 1 and logger.isEnabledFor(logging.DEBUG):\n            logger.debug(f\"&#91;{method}] result keys: {list(result.keys())}\")\n            if page_items:\n                try:\n                    logger.debug(f\"&#91;{method}] first item sample: {json.dumps(page_items&#91;0], ensure_ascii=False)&#91;:4000]}\")\n                except Exception:\n                    logger.debug(f\"&#91;{method}] first item (repr): {repr(page_items&#91;0])&#91;:4000]}\")\n\n        items.extend(page_items)\n\n        total = result.get(\"total\", 0)\n        pages_count = result.get(\"pagesCount\", 1)\n        logger.debug(f\"Fetched {len(page_items)} items (total so far: {len(items)} of {total}); pagesCount={pages_count}\")\n\n        if page &gt;= pages_count:\n            break\n        page += 1\n\n    logger.info(f\"Fetched total items with method {method}: {len(items)}\")\n    return items\n\n# --- Duplicate detection and CSV export ---\ndef group_duplicates_by_name(items: List&#91;Dict&#91;str, Any]], logger: logging.Logger) -&gt; Dict&#91;str, List&#91;Dict&#91;str, Any]]]:\n    groups: Dict&#91;str, List&#91;Dict&#91;str, Any]]] = {}\n    for it in items:\n        name = (it.get(\"name\") or \"\").strip()\n        if not name:\n            continue\n        key = name.casefold()\n        groups.setdefault(key, &#91;]).append(it)\n    dupes = {k: v for k, v in groups.items() if len(v) &gt; 1}\n    logger.info(f\"Duplicate groups found: {len(dupes)}\")\n    return dupes\n\ndef pick_logged_in_user(item: Dict&#91;str, Any]) -&gt; Any:\n    for k in &#91;\"loggedInUser\", \"lastLoggedInUser\", \"loggedUser\", \"user\", \"loginUser\"]:\n        if k in item:\n            return item.get(k)\n    return \"\"\n\ndef export_duplicates_to_csv(dupes: Dict&#91;str, List&#91;Dict&#91;str, Any]]], output_path: str, logger: logging.Logger) -&gt; None:\n    fieldnames = &#91;\n        \"name\",\n        \"fqdn\",\n        \"machineType\",\n        \"operatingSystemVersion\",\n        \"ip\",\n        \"macs\",\n        \"ssid\",\n        \"managedWithBest\",\n        \"lastSeen\",\n        \"loggedInUser\",\n    ]\n    rows = &#91;]\n    for key, items in dupes.items():\n        for it in items:\n            rows.append({\n                \"name\": it.get(\"name\", \"\"),\n                \"fqdn\": it.get(\"fqdn\", \"\"),\n                \"machineType\": it.get(\"machineType\", \"\"),\n                \"operatingSystemVersion\": it.get(\"operatingSystemVersion\", \"\"),\n                \"ip\": it.get(\"ip\", \"\"),\n                \"macs\": \"|\".join(it.get(\"macs\", &#91;]) or &#91;]),\n                \"ssid\": it.get(\"ssid\", \"\"),\n                \"managedWithBest\": it.get(\"managedWithBest\", \"\"),\n                \"lastSeen\": it.get(\"lastSeen\", \"\"),\n                \"loggedInUser\": pick_logged_in_user(it),\n            })\n\n    if not rows:\n        logger.info(\"No duplicates found. CSV will not be created.\")\n        return\n\n    with open(output_path, \"w\", encoding=\"utf-8-sig\", newline=\"\") as f:\n        writer = csv.DictWriter(f, fieldnames=fieldnames)\n        writer.writeheader()\n        writer.writerows(rows)\n\n    logger.info(f\"Wrote {len(rows)} duplicate endpoint rows to {output_path}\")\n\n# Helpers to diagnose and extract fields from nested inventory structures\ndef _find_first_key_recursive(obj: Any, candidate_keys: List&#91;str], max_depth: int = 4) -&gt; Optional&#91;Any]:\n    \"\"\"Depth-limited recursive search for first existing key in candidate_keys.\"\"\"\n    from collections import deque\n    if obj is None:\n        return None\n    seen = set()\n    dq = deque(&#91;(obj, 0)])\n    cand_set = set(k.casefold() for k in candidate_keys)\n    while dq:\n        cur, depth = dq.popleft()\n        if id(cur) in seen:\n            continue\n        seen.add(id(cur))\n        if isinstance(cur, dict):\n            # Direct hit\n            for k, v in cur.items():\n                if k.casefold() in cand_set and v not in (None, \"\", &#91;]):\n                    return v\n            # Traverse deeper if allowed\n            if depth &lt; max_depth:\n                for v in cur.values():\n                    dq.append((v, depth + 1))\n        elif isinstance(cur, list):\n            if depth &lt; max_depth:\n                for v in cur:\n                    dq.append((v, depth + 1))\n    return None\n\ndef _normalize_list_or_scalar(value: Any) -&gt; str:\n    if value is None:\n        return \"\"\n    if isinstance(value, (list, tuple, set)):\n        # flatten one level of dicts\/values\n        flat: List&#91;str] = &#91;]\n        for x in value:\n            if isinstance(x, dict):\n                # try common id-like or address-like keys\n                flat.append(str(\n                    _find_first_key_recursive(x, &#91;\"value\", \"address\", \"ip\", \"mac\", \"id\", \"name\"], max_depth=1) or x\n                ))\n            else:\n                flat.append(str(x))\n        return \"|\".join(map(str, flat))\n    if isinstance(value, dict):\n        # try some common fields if dict\n        return str(_find_first_key_recursive(value, &#91;\"value\", \"address\", \"ip\", \"mac\", \"id\", \"name\"], max_depth=1) or \"\")\n    return str(value)\n\ndef extract_common_fields(item: Dict&#91;str, Any]) -&gt; Dict&#91;str, str]:\n    \"\"\"\n    Try to extract common fields from either endpoint list or network inventory items.\n    Falls back to recursive search for inventory responses where fields are nested.\n    \"\"\"\n    # Candidate key lists\n    name_keys = &#91;\"name\", \"hostname\", \"displayName\", \"computerName\", \"vmName\", \"title\", \"label\"]\n    fqdn_keys = &#91;\"fqdn\", \"dnsName\", \"hostFqdn\", \"fullyQualifiedName\", \"domainName\", \"dns\", \"hostName\"]\n    os_keys = &#91;\"operatingSystemVersion\", \"osName\", \"os\", \"operatingSystem\", \"platform\"]\n    ip_keys = &#91;\"ip\", \"ipAddress\", \"primaryIpAddress\", \"ipv4\", \"ipv4Address\", \"address\"]\n    mac_keys = &#91;\"macs\", \"mac\", \"macAddress\", \"macAddresses\"]\n    machine_type_keys = &#91;\"machineType\", \"type\", \"deviceType\", \"endpointType\"]\n\n    # Direct values\n    name = item.get(\"name\") or _find_first_key_recursive(item, name_keys)\n    fqdn = item.get(\"fqdn\") or _find_first_key_recursive(item, fqdn_keys)\n    osv = item.get(\"operatingSystemVersion\") or _find_first_key_recursive(item, os_keys)\n    ip = item.get(\"ip\") or _find_first_key_recursive(item, ip_keys)\n    macs = item.get(\"macs\") or _find_first_key_recursive(item, mac_keys)\n    machine_type = item.get(\"machineType\") or _find_first_key_recursive(item, machine_type_keys)\n\n    return {\n        \"name\": _normalize_list_or_scalar(name),\n        \"fqdn\": _normalize_list_or_scalar(fqdn),\n        \"machineType\": _normalize_list_or_scalar(machine_type),\n        \"operatingSystemVersion\": _normalize_list_or_scalar(osv),\n        \"ip\": _normalize_list_or_scalar(ip),\n        \"macs\": _normalize_list_or_scalar(macs),\n    }\n\ndef debug_dump_item_structure(method: str, items: List&#91;Dict&#91;str, Any]], logger: logging.Logger, sample: int = 5) -&gt; None:\n    \"\"\"\n    Extra diagnostics: show keys, sample JSON, and what we can extract for name\/fqdn\/ip from nested structures.\n    \"\"\"\n    if not logger.isEnabledFor(logging.DEBUG) or not items:\n        return\n    logger.debug(f\"&#91;{method}] diagnostic dump of first {min(sample, len(items))} items\")\n    for idx, it in enumerate(items&#91;:sample], start=1):\n        try:\n            logger.debug(f\"&#91;{method}] item #{idx} top-level keys: {sorted(list(it.keys()))}\")\n        except Exception:\n            pass\n        try:\n            logger.debug(f\"&#91;{method}] item #{idx} raw (truncated): {json.dumps(it, ensure_ascii=False)&#91;:4000]}\")\n        except Exception:\n            logger.debug(f\"&#91;{method}] item #{idx} raw (repr truncated): {repr(it)&#91;:4000]}\")\n        # Derived fields via recursive extraction\n        derived = extract_common_fields(it)\n        logger.debug(f\"&#91;{method}] item #{idx} derived fields -&gt; name={derived.get('name')!r}, fqdn={derived.get('fqdn')!r}, ip={derived.get('ip')!r}, os={derived.get('operatingSystemVersion')!r}\")\n\ndef log_all_endpoints(items: List&#91;Dict&#91;str, Any]], logger: logging.Logger, level: int = logging.INFO) -&gt; None:\n    for it in items:\n        # Use recursive extraction to surface fields even for inventory items\n        fields = extract_common_fields(it)\n        logger.log(\n            level,\n            \"Endpoint: name=%s, fqdn=%s, machineType=%s, os=%s, ip=%s, macs=%s, ssid=%s, managedWithBest=%s, lastSeen=%s, loggedInUser=%s\",\n            fields.get(\"name\", \"\") or it.get(\"name\", \"\"),\n            fields.get(\"fqdn\", \"\") or it.get(\"fqdn\", \"\"),\n            fields.get(\"machineType\", \"\") or it.get(\"machineType\", \"\"),\n            fields.get(\"operatingSystemVersion\", \"\") or it.get(\"operatingSystemVersion\", \"\"),\n            fields.get(\"ip\", \"\") or it.get(\"ip\", \"\"),\n            fields.get(\"macs\", \"\") or \"|\".join(it.get(\"macs\", &#91;]) or &#91;]),\n            it.get(\"ssid\", \"\"),\n            it.get(\"managedWithBest\", \"\"),\n            it.get(\"lastSeen\", \"\"),\n            pick_logged_in_user(it),\n        )\n\ndef export_all_to_csv(items: List&#91;Dict&#91;str, Any]], output_path: str, logger: logging.Logger) -&gt; None:\n    fieldnames = &#91;\n        \"name\",\n        \"fqdn\",\n        \"machineType\",\n        \"operatingSystemVersion\",\n        \"ip\",\n        \"macs\",\n        \"ssid\",\n        \"managedWithBest\",\n        \"lastSeen\",\n        \"loggedInUser\",\n    ]\n    with open(output_path, \"w\", encoding=\"utf-8-sig\", newline=\"\") as f:\n        writer = csv.DictWriter(f, fieldnames=fieldnames)\n        writer.writeheader()\n        for it in items:\n            writer.writerow({\n                \"name\": it.get(\"name\", \"\"),\n                \"fqdn\": it.get(\"fqdn\", \"\"),\n                \"machineType\": it.get(\"machineType\", \"\"),\n                \"operatingSystemVersion\": it.get(\"operatingSystemVersion\", \"\"),\n                \"ip\": it.get(\"ip\", \"\"),\n                \"macs\": \"|\".join(it.get(\"macs\", &#91;]) or &#91;]),\n                \"ssid\": it.get(\"ssid\", \"\"),\n                \"managedWithBest\": it.get(\"managedWithBest\", \"\"),\n                \"lastSeen\": it.get(\"lastSeen\", \"\"),\n                \"loggedInUser\": pick_logged_in_user(it),\n            })\n    logger.info(f\"Wrote all {len(items)} endpoints to {output_path}\")\n\ndef resolve_timestamped_csv_path(preferred: Optional&#91;str], suffix: Optional&#91;str], logger: logging.Logger) -&gt; str:\n    ts = datetime.now().strftime(\"%Y%m%d_%H%M\")\n    filename = f\"{ts}{suffix or ''}.csv\"\n    dirpath: Optional&#91;str] = None\n\n    if preferred:\n        if preferred.endswith(os.sep) or os.path.isdir(preferred):\n            dirpath = preferred\n        else:\n            parent = os.path.dirname(preferred)\n            if parent:\n                dirpath = parent\n\n    if not dirpath:\n        dirpath = os.getcwd()\n\n    path = os.path.join(dirpath, filename)\n    logger.debug(f\"Resolved CSV path: {path}\")\n    return path\n\n# --- Main ---\ndef main() -&gt; None:\n    args = parse_args()\n    logger = setup_logger(args.debug, args.log_file)\n\n    if not args.api_key:\n        logger.error(\"No API key provided. Use --api-key or set BITDEFENDER_API_KEY environment variable.\")\n        sys.exit(2)\n\n    ensure_latest_packages(&#91;\"requests\", \"certifi\", \"packaging\"], logger)\n\n    api_url = get_endpoint_url(args.region)\n    logger.debug(f\"Using API endpoint: {api_url} (region: {args.region})\")\n\n    auth_header = make_auth_header(args.api_key)\n    logger.debug(\"Authorization header prepared.\")\n\n    try:\n        logger.info(\"Scanning with method: getEndpointsList\")\n        items_endpoints = fetch_all_endpoints(api_url, auth_header, args.insecure, logger, method=\"getEndpointsList\")\n\n        logger.info(\"Scanning with method: getNetworkInventoryItems\")\n        items_inventory = fetch_all_endpoints(api_url, auth_header, args.insecure, logger, method=\"getNetworkInventoryItems\")\n\n        # Extra diagnostics: dump item structure when --debug\n        if args.debug:\n            debug_dump_item_structure(\"getEndpointsList\", items_endpoints, logger, sample=3)\n            debug_dump_item_structure(\"getNetworkInventoryItems\", items_inventory, logger, sample=5)\n\n        if args.list_all:\n            logger.info(\"Endpoints (getEndpointsList):\")\n            log_all_endpoints(items_endpoints, logger, level=logging.INFO)\n            logger.info(\"Inventory (getNetworkInventoryItems):\")\n            log_all_endpoints(items_inventory, logger, level=logging.INFO)\n        elif args.debug:\n            logger.debug(\"Endpoints (getEndpointsList):\")\n            log_all_endpoints(items_endpoints, logger, level=logging.DEBUG)\n            logger.debug(\"Inventory (getNetworkInventoryItems):\")\n            log_all_endpoints(items_inventory, logger, level=logging.DEBUG)\n\n        duplicates_out = resolve_timestamped_csv_path(args.output, None, logger)\n\n        if args.export_all is not None:\n            all_out_endpoints = resolve_timestamped_csv_path(args.export_all, \"_endpoints\", logger)\n            all_out_inventory = resolve_timestamped_csv_path(args.export_all, \"_inventory\", logger)\n            export_all_to_csv(items_endpoints, all_out_endpoints, logger)\n            export_all_to_csv(items_inventory, all_out_inventory, logger)\n\n        dupes = group_duplicates_by_name(items_endpoints, logger)\n        export_duplicates_to_csv(dupes, duplicates_out, logger)\n\n    except Exception as e:\n        logger.error(f\"Failure: {e}\")\n        sys.exit(1)\n\nif __name__ == \"__main__\":\n    main()<\/code><\/pre>\n\n\n\n<p><br><strong>Remarks<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>IF you cannot delete duplicate computer, We assume that the frequent hwid changes happen due to corruptions of WMI database \n<ul class=\"wp-block-list\">\n<li>We recommend recreating the WMI database and monitor wheher the issue persists.\n<ul class=\"wp-block-list\">\n<li>Steps:\n<ol class=\"wp-block-list\">\n<li>Stop WMI service <br>services.msc -&gt; select &#8216;Windows Management Service&#8217; -&gt; Stop<\/li>\n\n\n\n<li>Rename WMI DB folder (from c:\\Windows\\System32\\wbem\\Repository\\ to c:\\Windows\\System32\\wbem\\Repository.old)<\/li>\n\n\n\n<li>Start WMI service<br>services.msc -&gt; select &#8216;Windows Management Service&#8217; -&gt; Start<\/li>\n\n\n\n<li>Restart machine<\/li>\n<\/ol>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>There is no fully automated built-in feature to remove duplicates solely based on computer name, as GravityZone relies on unique identifiers. If two endpoints have the same computer name but different HWIDs or MAC addresses, GravityZone treats them as separate entities, each consuming a license seat. However, 1 You can set up rules for deleting [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2],"tags":[15],"class_list":["post-14","post","type-post","status-publish","format-standard","hentry","category-gravityzone","tag-troubleshooting"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.4 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Duplicate Computer name - Bitdefender Thailand Knowledge Base<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/xn--o3cah8a1fre.com\/wordpress\/2025\/09\/25\/duplicate-computer-name\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Duplicate Computer name - Bitdefender Thailand Knowledge Base\" \/>\n<meta property=\"og:description\" content=\"There is no fully automated built-in feature to remove duplicates solely based on computer name, as GravityZone relies on unique identifiers. If two endpoints have the same computer name but different HWIDs or MAC addresses, GravityZone treats them as separate entities, each consuming a license seat. However, 1 You can set up rules for deleting [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/xn--o3cah8a1fre.com\/wordpress\/2025\/09\/25\/duplicate-computer-name\/\" \/>\n<meta property=\"og:site_name\" content=\"Bitdefender Thailand Knowledge Base\" \/>\n<meta property=\"article:published_time\" content=\"2025-09-25T16:24:49+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-09-30T16:17:30+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/xn--o3cah8a1fre.com\/wordpress\/wp-content\/uploads\/2025\/09\/image-1.png\" \/>\n\t<meta property=\"og:image:width\" content=\"755\" \/>\n\t<meta property=\"og:image:height\" content=\"544\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"misterarm\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"misterarm\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"18 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/xn--o3cah8a1fre.com\\\/wordpress\\\/2025\\\/09\\\/25\\\/duplicate-computer-name\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/xn--o3cah8a1fre.com\\\/wordpress\\\/2025\\\/09\\\/25\\\/duplicate-computer-name\\\/\"},\"author\":{\"name\":\"misterarm\",\"@id\":\"https:\\\/\\\/xn--o3cah8a1fre.com\\\/wordpress\\\/#\\\/schema\\\/person\\\/11264a5bc2f47b69cbd854ec32443e43\"},\"headline\":\"Duplicate Computer name\",\"datePublished\":\"2025-09-25T16:24:49+00:00\",\"dateModified\":\"2025-09-30T16:17:30+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/xn--o3cah8a1fre.com\\\/wordpress\\\/2025\\\/09\\\/25\\\/duplicate-computer-name\\\/\"},\"wordCount\":546,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/xn--o3cah8a1fre.com\\\/wordpress\\\/#\\\/schema\\\/person\\\/11264a5bc2f47b69cbd854ec32443e43\"},\"image\":{\"@id\":\"https:\\\/\\\/xn--o3cah8a1fre.com\\\/wordpress\\\/2025\\\/09\\\/25\\\/duplicate-computer-name\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/xn--o3cah8a1fre.com\\\/wordpress\\\/wp-content\\\/uploads\\\/2025\\\/09\\\/image-1.png\",\"keywords\":[\"troubleshooting\"],\"articleSection\":[\"Gravityzone\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/xn--o3cah8a1fre.com\\\/wordpress\\\/2025\\\/09\\\/25\\\/duplicate-computer-name\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/xn--o3cah8a1fre.com\\\/wordpress\\\/2025\\\/09\\\/25\\\/duplicate-computer-name\\\/\",\"url\":\"https:\\\/\\\/xn--o3cah8a1fre.com\\\/wordpress\\\/2025\\\/09\\\/25\\\/duplicate-computer-name\\\/\",\"name\":\"Duplicate Computer name - Bitdefender Thailand Knowledge Base\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/xn--o3cah8a1fre.com\\\/wordpress\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/xn--o3cah8a1fre.com\\\/wordpress\\\/2025\\\/09\\\/25\\\/duplicate-computer-name\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/xn--o3cah8a1fre.com\\\/wordpress\\\/2025\\\/09\\\/25\\\/duplicate-computer-name\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/xn--o3cah8a1fre.com\\\/wordpress\\\/wp-content\\\/uploads\\\/2025\\\/09\\\/image-1.png\",\"datePublished\":\"2025-09-25T16:24:49+00:00\",\"dateModified\":\"2025-09-30T16:17:30+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/xn--o3cah8a1fre.com\\\/wordpress\\\/2025\\\/09\\\/25\\\/duplicate-computer-name\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/xn--o3cah8a1fre.com\\\/wordpress\\\/2025\\\/09\\\/25\\\/duplicate-computer-name\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/xn--o3cah8a1fre.com\\\/wordpress\\\/2025\\\/09\\\/25\\\/duplicate-computer-name\\\/#primaryimage\",\"url\":\"https:\\\/\\\/xn--o3cah8a1fre.com\\\/wordpress\\\/wp-content\\\/uploads\\\/2025\\\/09\\\/image-1.png\",\"contentUrl\":\"https:\\\/\\\/xn--o3cah8a1fre.com\\\/wordpress\\\/wp-content\\\/uploads\\\/2025\\\/09\\\/image-1.png\",\"width\":755,\"height\":544},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/xn--o3cah8a1fre.com\\\/wordpress\\\/2025\\\/09\\\/25\\\/duplicate-computer-name\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/xn--o3cah8a1fre.com\\\/wordpress\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Duplicate Computer name\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/xn--o3cah8a1fre.com\\\/wordpress\\\/#website\",\"url\":\"https:\\\/\\\/xn--o3cah8a1fre.com\\\/wordpress\\\/\",\"name\":\"\u0e1a\u0e34\u0e17\u0e44\u0e17\u0e22\",\"description\":\"This website is independently operated by the site owner and is not affiliated with or endorsed by Bitdefender.\",\"publisher\":{\"@id\":\"https:\\\/\\\/xn--o3cah8a1fre.com\\\/wordpress\\\/#\\\/schema\\\/person\\\/11264a5bc2f47b69cbd854ec32443e43\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/xn--o3cah8a1fre.com\\\/wordpress\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\\\/\\\/xn--o3cah8a1fre.com\\\/wordpress\\\/#\\\/schema\\\/person\\\/11264a5bc2f47b69cbd854ec32443e43\",\"name\":\"misterarm\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/463b3f82a83d77d05b64504e381e9dbf48d8bdea9238d4bd6b80105dedbc116c?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/463b3f82a83d77d05b64504e381e9dbf48d8bdea9238d4bd6b80105dedbc116c?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/463b3f82a83d77d05b64504e381e9dbf48d8bdea9238d4bd6b80105dedbc116c?s=96&d=mm&r=g\",\"caption\":\"misterarm\"},\"logo\":{\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/463b3f82a83d77d05b64504e381e9dbf48d8bdea9238d4bd6b80105dedbc116c?s=96&d=mm&r=g\"},\"url\":\"https:\\\/\\\/xn--o3cah8a1fre.com\\\/wordpress\\\/author\\\/misterarm\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Duplicate Computer name - Bitdefender Thailand Knowledge Base","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/xn--o3cah8a1fre.com\/wordpress\/2025\/09\/25\/duplicate-computer-name\/","og_locale":"en_US","og_type":"article","og_title":"Duplicate Computer name - Bitdefender Thailand Knowledge Base","og_description":"There is no fully automated built-in feature to remove duplicates solely based on computer name, as GravityZone relies on unique identifiers. If two endpoints have the same computer name but different HWIDs or MAC addresses, GravityZone treats them as separate entities, each consuming a license seat. However, 1 You can set up rules for deleting [&hellip;]","og_url":"https:\/\/xn--o3cah8a1fre.com\/wordpress\/2025\/09\/25\/duplicate-computer-name\/","og_site_name":"Bitdefender Thailand Knowledge Base","article_published_time":"2025-09-25T16:24:49+00:00","article_modified_time":"2025-09-30T16:17:30+00:00","og_image":[{"width":755,"height":544,"url":"https:\/\/xn--o3cah8a1fre.com\/wordpress\/wp-content\/uploads\/2025\/09\/image-1.png","type":"image\/png"}],"author":"misterarm","twitter_card":"summary_large_image","twitter_misc":{"Written by":"misterarm","Est. reading time":"18 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/xn--o3cah8a1fre.com\/wordpress\/2025\/09\/25\/duplicate-computer-name\/#article","isPartOf":{"@id":"https:\/\/xn--o3cah8a1fre.com\/wordpress\/2025\/09\/25\/duplicate-computer-name\/"},"author":{"name":"misterarm","@id":"https:\/\/xn--o3cah8a1fre.com\/wordpress\/#\/schema\/person\/11264a5bc2f47b69cbd854ec32443e43"},"headline":"Duplicate Computer name","datePublished":"2025-09-25T16:24:49+00:00","dateModified":"2025-09-30T16:17:30+00:00","mainEntityOfPage":{"@id":"https:\/\/xn--o3cah8a1fre.com\/wordpress\/2025\/09\/25\/duplicate-computer-name\/"},"wordCount":546,"commentCount":0,"publisher":{"@id":"https:\/\/xn--o3cah8a1fre.com\/wordpress\/#\/schema\/person\/11264a5bc2f47b69cbd854ec32443e43"},"image":{"@id":"https:\/\/xn--o3cah8a1fre.com\/wordpress\/2025\/09\/25\/duplicate-computer-name\/#primaryimage"},"thumbnailUrl":"https:\/\/xn--o3cah8a1fre.com\/wordpress\/wp-content\/uploads\/2025\/09\/image-1.png","keywords":["troubleshooting"],"articleSection":["Gravityzone"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/xn--o3cah8a1fre.com\/wordpress\/2025\/09\/25\/duplicate-computer-name\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/xn--o3cah8a1fre.com\/wordpress\/2025\/09\/25\/duplicate-computer-name\/","url":"https:\/\/xn--o3cah8a1fre.com\/wordpress\/2025\/09\/25\/duplicate-computer-name\/","name":"Duplicate Computer name - Bitdefender Thailand Knowledge Base","isPartOf":{"@id":"https:\/\/xn--o3cah8a1fre.com\/wordpress\/#website"},"primaryImageOfPage":{"@id":"https:\/\/xn--o3cah8a1fre.com\/wordpress\/2025\/09\/25\/duplicate-computer-name\/#primaryimage"},"image":{"@id":"https:\/\/xn--o3cah8a1fre.com\/wordpress\/2025\/09\/25\/duplicate-computer-name\/#primaryimage"},"thumbnailUrl":"https:\/\/xn--o3cah8a1fre.com\/wordpress\/wp-content\/uploads\/2025\/09\/image-1.png","datePublished":"2025-09-25T16:24:49+00:00","dateModified":"2025-09-30T16:17:30+00:00","breadcrumb":{"@id":"https:\/\/xn--o3cah8a1fre.com\/wordpress\/2025\/09\/25\/duplicate-computer-name\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/xn--o3cah8a1fre.com\/wordpress\/2025\/09\/25\/duplicate-computer-name\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/xn--o3cah8a1fre.com\/wordpress\/2025\/09\/25\/duplicate-computer-name\/#primaryimage","url":"https:\/\/xn--o3cah8a1fre.com\/wordpress\/wp-content\/uploads\/2025\/09\/image-1.png","contentUrl":"https:\/\/xn--o3cah8a1fre.com\/wordpress\/wp-content\/uploads\/2025\/09\/image-1.png","width":755,"height":544},{"@type":"BreadcrumbList","@id":"https:\/\/xn--o3cah8a1fre.com\/wordpress\/2025\/09\/25\/duplicate-computer-name\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/xn--o3cah8a1fre.com\/wordpress\/"},{"@type":"ListItem","position":2,"name":"Duplicate Computer name"}]},{"@type":"WebSite","@id":"https:\/\/xn--o3cah8a1fre.com\/wordpress\/#website","url":"https:\/\/xn--o3cah8a1fre.com\/wordpress\/","name":"\u0e1a\u0e34\u0e17\u0e44\u0e17\u0e22","description":"This website is independently operated by the site owner and is not affiliated with or endorsed by Bitdefender.","publisher":{"@id":"https:\/\/xn--o3cah8a1fre.com\/wordpress\/#\/schema\/person\/11264a5bc2f47b69cbd854ec32443e43"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/xn--o3cah8a1fre.com\/wordpress\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":["Person","Organization"],"@id":"https:\/\/xn--o3cah8a1fre.com\/wordpress\/#\/schema\/person\/11264a5bc2f47b69cbd854ec32443e43","name":"misterarm","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/463b3f82a83d77d05b64504e381e9dbf48d8bdea9238d4bd6b80105dedbc116c?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/463b3f82a83d77d05b64504e381e9dbf48d8bdea9238d4bd6b80105dedbc116c?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/463b3f82a83d77d05b64504e381e9dbf48d8bdea9238d4bd6b80105dedbc116c?s=96&d=mm&r=g","caption":"misterarm"},"logo":{"@id":"https:\/\/secure.gravatar.com\/avatar\/463b3f82a83d77d05b64504e381e9dbf48d8bdea9238d4bd6b80105dedbc116c?s=96&d=mm&r=g"},"url":"https:\/\/xn--o3cah8a1fre.com\/wordpress\/author\/misterarm\/"}]}},"_links":{"self":[{"href":"https:\/\/xn--o3cah8a1fre.com\/wordpress\/wp-json\/wp\/v2\/posts\/14","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/xn--o3cah8a1fre.com\/wordpress\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/xn--o3cah8a1fre.com\/wordpress\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/xn--o3cah8a1fre.com\/wordpress\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/xn--o3cah8a1fre.com\/wordpress\/wp-json\/wp\/v2\/comments?post=14"}],"version-history":[{"count":4,"href":"https:\/\/xn--o3cah8a1fre.com\/wordpress\/wp-json\/wp\/v2\/posts\/14\/revisions"}],"predecessor-version":[{"id":21,"href":"https:\/\/xn--o3cah8a1fre.com\/wordpress\/wp-json\/wp\/v2\/posts\/14\/revisions\/21"}],"wp:attachment":[{"href":"https:\/\/xn--o3cah8a1fre.com\/wordpress\/wp-json\/wp\/v2\/media?parent=14"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/xn--o3cah8a1fre.com\/wordpress\/wp-json\/wp\/v2\/categories?post=14"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/xn--o3cah8a1fre.com\/wordpress\/wp-json\/wp\/v2\/tags?post=14"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}