[{"data":1,"prerenderedAt":2937},["ShallowReactive",2],{"post:\u002F2025\u002F12\u002F10\u002Fpython-discovery-inventory-vmware-hosts-and-vms-via-pyvmomi\u002F":3},{"post":4,"newer":2884,"older":2896,"related":2908,"series":2935},{"id":5,"title":6,"body":7,"canonical":2865,"categories":2866,"date":2869,"description":2870,"extension":2871,"featured":2872,"hero":2873,"image":2873,"meta":2874,"navigation":132,"path":2875,"readingTime":116,"seo":2876,"series":2873,"seriesOrder":2873,"sites":2877,"source":2873,"stem":2878,"tags":2879,"updated":2873,"url":2882,"__hash__":2883},"blog\u002Fblog\u002F2025\u002F12\u002F10\u002Fpython-discovery-inventory-vmware-hosts-and-vms-via-pyvmomi.md","Python: Discovery – Inventory VMware Hosts and VMs via pyVmomi",{"type":8,"value":9,"toc":2858},"minimark",[10,14,23,28,65,69,72,144,147,181,189,192,198,202,2670,2674,2787,2791,2854],[11,12,13],"p",{},"Before a migration, a capacity review, or a license true-up, the first question is always the same: what's actually running in this vCenter, and on what? PowerCLI is the default answer for most Windows-side admins, but it's not always the tool already wired into a pipeline. Plenty of discovery and CMDB tooling lives in Python, and pulling the same data with pyVmomi (VMware's Python SDK for the vSphere Web Services API) means it drops straight into that tooling without a PowerShell hop in the middle. This script connects to a vCenter Server, retrieves host and VM properties through the PropertyCollector, and writes two CSVs: one row per host, one row per VM.",[11,15,16,17,22],{},"It is one of the collectors in the ",[18,19,21],"a",{"href":20},"\u002F2026\u002F07\u002F15\u002Finfrastructure-a-discovery-first-approach-to-documenting-an-undocumented-network\u002F","discovery-first approach to documenting an undocumented network",": the VM CSV gives you names, guest hostnames and IPs for workloads that a subnet sweep alone can't attribute to a hypervisor.",[24,25,27],"h2",{"id":26},"requirements","Requirements",[29,30,31,35,47,55,58],"ul",{},[32,33,34],"li",{},"Python 3.10 or later. Current pyVmomi releases (9.x at the time of writing) state support for Python 3.10+.",[32,36,37,38,42,43,46],{},"The ",[39,40,41],"code",{},"pyvmomi"," package: ",[39,44,45],{},"pip install pyvmomi",". The project states it stays backward compatible with the previous four vSphere releases, so match the SDK to your vCenter generation if you run something old.",[32,48,49,50,54],{},"A vCenter account with the built-in ",[51,52,53],"strong",{},"Read-only"," role on the inventory objects you want to see. Nothing is changed.",[32,56,57],{},"Network reach to the vCenter API on TCP 443.",[32,59,60,61,64],{},"If vCenter still uses its self-signed VMCA certificate, ",[39,62,63],{},"--insecure"," skips verification. Prefer trusting the VMCA root on the machine running the script instead.",[24,66,68],{"id":67},"usage","Usage",[11,70,71],{},"Connect with environment variables set (handy for CI or a scheduled job where the password shouldn't land in shell history):",[73,74,79],"pre",{"className":75,"code":76,"language":77,"meta":78,"style":78},"language-bash shiki shiki-themes github-dark","export VCENTER_HOST=\"vcenter.corp.example\"\nexport VCENTER_USER=\"svc-discovery@vsphere.local\"\nexport VCENTER_PASSWORD=\"\u003Cservice-account-password>\"\n\npython3 vmware_inventory.py\n","bash","",[39,80,81,101,114,127,134],{"__ignoreMap":78},[82,83,86,90,94,97],"span",{"class":84,"line":85},"line",1,[82,87,89],{"class":88},"snl16","export",[82,91,93],{"class":92},"s95oV"," VCENTER_HOST",[82,95,96],{"class":88},"=",[82,98,100],{"class":99},"sU2Wk","\"vcenter.corp.example\"\n",[82,102,104,106,109,111],{"class":84,"line":103},2,[82,105,89],{"class":88},[82,107,108],{"class":92}," VCENTER_USER",[82,110,96],{"class":88},[82,112,113],{"class":99},"\"svc-discovery@vsphere.local\"\n",[82,115,117,119,122,124],{"class":84,"line":116},3,[82,118,89],{"class":88},[82,120,121],{"class":92}," VCENTER_PASSWORD",[82,123,96],{"class":88},[82,125,126],{"class":99},"\"\u003Cservice-account-password>\"\n",[82,128,130],{"class":84,"line":129},4,[82,131,133],{"emptyLinePlaceholder":132},true,"\n",[82,135,137,141],{"class":84,"line":136},5,[82,138,140],{"class":139},"svObZ","python3",[82,142,143],{"class":99}," vmware_inventory.py\n",[11,145,146],{},"Or pass everything on the command line against a lab vCenter with a self-signed certificate (the password is prompted for):",[73,148,150],{"className":75,"code":149,"language":77,"meta":78,"style":78},"python3 vmware_inventory.py --host vcenter.lab.example --user svc-discovery@vsphere.local --insecure --output-prefix lab-inventory\n",[39,151,152],{"__ignoreMap":78},[82,153,154,156,159,163,166,169,172,175,178],{"class":84,"line":85},[82,155,140],{"class":139},[82,157,158],{"class":99}," vmware_inventory.py",[82,160,162],{"class":161},"sDLfK"," --host",[82,164,165],{"class":99}," vcenter.lab.example",[82,167,168],{"class":161}," --user",[82,170,171],{"class":99}," svc-discovery@vsphere.local",[82,173,174],{"class":161}," --insecure",[82,176,177],{"class":161}," --output-prefix",[82,179,180],{"class":99}," lab-inventory\n",[73,182,187],{"className":183,"code":185,"language":186,"meta":78},[184],"language-text","Password for svc-discovery@vsphere.local@vcenter.lab.example:\nWrote 4 row(s) to lab-inventory-hosts.csv.\nWrote 37 row(s) to lab-inventory-vms.csv.\n","text",[39,188,185],{"__ignoreMap":78},[11,190,191],{},"A few rows of the VM file, for a sense of the shape (names and addresses are placeholders):",[73,193,196],{"className":194,"code":195,"language":186,"meta":78},[184],"vm_name,template,power_state,guest_os,guest_hostname,ip_address,host,cpu_count,memory_gb,committed_gb,provisioned_gb,tools_running,tools_version_status,instance_uuid\napp01,False,poweredOn,Microsoft Windows Server 2022 (64-bit),app01.corp.example,10.20.30.41,esx01.lab.example,4,16.0,92.4,120.0,guestToolsRunning,guestToolsCurrent,5003a1c2-...\ntpl-rhel9,True,poweredOff,Red Hat Enterprise Linux 9 (64-bit),,,esx02.lab.example,2,4.0,11.2,40.0,guestToolsNotRunning,guestToolsCurrent,5003b7e9-...\n",[39,197,195],{"__ignoreMap":78},[24,199,201],{"id":200},"script","Script",[73,203,207],{"className":204,"code":205,"language":206,"meta":78,"style":78},"language-python shiki shiki-themes github-dark","\"\"\"\nInventory VMware ESXi hosts and virtual machines through the vSphere API (pyVmomi).\n\nConnects to a vCenter Server and uses the PropertyCollector (RetrievePropertiesEx over a\nContainerView) to fetch only the properties it needs, one paged query per object type.\nWrites one CSV row per host and one per VM. Intended as a lightweight discovery pass\nahead of a migration, capacity review, or license audit.\n\nReads: vCenter connection details from CLI arguments or environment variables.\nWrites: \u003Coutput-prefix>-hosts.csv and \u003Coutput-prefix>-vms.csv.\nRequires: Python 3.10+, pyvmomi, a vCenter account with the Read-only role.\n\"\"\"\n\nimport argparse\nimport csv\nimport getpass\nimport os\nimport sys\n\nfrom pyVim.connect import Disconnect, SmartConnect\nfrom pyVmomi import vim, vmodl\n\nHOST_PROPERTIES = [\n    \"name\",\n    \"parent\",\n    \"runtime.connectionState\",\n    \"runtime.inMaintenanceMode\",\n    \"summary.config.product.version\",\n    \"summary.config.product.build\",\n    \"summary.hardware.vendor\",\n    \"summary.hardware.model\",\n    \"summary.hardware.cpuModel\",\n    \"summary.hardware.numCpuPkgs\",\n    \"summary.hardware.numCpuCores\",\n    \"summary.hardware.memorySize\",\n    \"vm\",\n]\n\nVM_PROPERTIES = [\n    \"name\",\n    \"summary.config.template\",\n    \"summary.config.guestFullName\",\n    \"summary.config.numCpu\",\n    \"summary.config.memorySizeMB\",\n    \"summary.config.instanceUuid\",\n    \"summary.runtime.powerState\",\n    \"summary.runtime.host\",\n    \"summary.storage.committed\",\n    \"summary.storage.uncommitted\",\n    \"summary.guest.hostName\",\n    \"summary.guest.ipAddress\",\n    \"summary.guest.toolsRunningStatus\",\n    \"summary.guest.toolsVersionStatus2\",\n]\n\nGIB = 1024 ** 3\n\n\ndef parse_args():\n    parser = argparse.ArgumentParser(description=\"Inventory VMware hosts and VMs via pyVmomi.\")\n    parser.add_argument(\"--host\", default=os.environ.get(\"VCENTER_HOST\"), help=\"vCenter Server hostname or IP.\")\n    parser.add_argument(\"--user\", default=os.environ.get(\"VCENTER_USER\"), help=\"vCenter user name.\")\n    parser.add_argument(\"--password\", default=os.environ.get(\"VCENTER_PASSWORD\"), help=\"vCenter password (prompted if omitted).\")\n    parser.add_argument(\"--port\", type=int, default=443, help=\"vCenter API port. Defaults to 443.\")\n    parser.add_argument(\"--insecure\", action=\"store_true\", help=\"Skip TLS certificate verification (self-signed vCenter certs).\")\n    parser.add_argument(\"--output-prefix\", default=\"vmware-inventory\", help=\"Prefix for the output CSV files.\")\n    return parser.parse_args()\n\n\ndef connect(args):\n    password = args.password or getpass.getpass(f\"Password for {args.user}@{args.host}: \")\n    return SmartConnect(\n        host=args.host,\n        user=args.user,\n        pwd=password,\n        port=args.port,\n        disableSslCertValidation=args.insecure,\n    )\n\n\ndef collect(content, obj_type, path_set, page_size=500):\n    \"\"\"Yield (managed_object, {property_path: value}) for every obj_type in the inventory.\"\"\"\n    view = content.viewManager.CreateContainerView(content.rootFolder, [obj_type], True)\n    try:\n        traversal = vmodl.query.PropertyCollector.TraversalSpec(\n            name=\"traverseView\", path=\"view\", skip=False, type=vim.view.ContainerView\n        )\n        obj_spec = vmodl.query.PropertyCollector.ObjectSpec(obj=view, skip=True, selectSet=[traversal])\n        prop_spec = vmodl.query.PropertyCollector.PropertySpec(type=obj_type, pathSet=path_set, all=False)\n        filter_spec = vmodl.query.PropertyCollector.FilterSpec(objectSet=[obj_spec], propSet=[prop_spec])\n        options = vmodl.query.PropertyCollector.RetrieveOptions(maxObjects=page_size)\n\n        collector = content.propertyCollector\n        result = collector.RetrievePropertiesEx([filter_spec], options)\n        while result:\n            for obj in result.objects:\n                # Unset properties are simply absent from propSet, so callers use .get().\n                yield obj.obj, {prop.name: prop.val for prop in obj.propSet}\n            if not result.token:\n                break\n            result = collector.ContinueRetrievePropertiesEx(result.token)\n    finally:\n        view.Destroy()\n\n\ndef to_gib(value):\n    return round(value \u002F GIB, 1) if value is not None else \"\"\n\n\ndef inventory_hosts(content):\n    rows = []\n    host_names = {}\n    for host, props in collect(content, vim.HostSystem, HOST_PROPERTIES):\n        host_names[host._moId] = props.get(\"name\", \"\")\n        parent = props.get(\"parent\")\n        # A clustered host's parent is a ClusterComputeResource; a standalone host\n        # sits under a plain ComputeResource that carries the host's own name.\n        cluster = parent.name if isinstance(parent, vim.ClusterComputeResource) else \"\u003Cstandalone>\"\n\n        rows.append({\n            \"host_name\": props.get(\"name\", \"\"),\n            \"cluster\": cluster,\n            \"connection_state\": props.get(\"runtime.connectionState\", \"\"),\n            \"maintenance_mode\": props.get(\"runtime.inMaintenanceMode\", \"\"),\n            \"esxi_version\": props.get(\"summary.config.product.version\", \"\"),\n            \"esxi_build\": props.get(\"summary.config.product.build\", \"\"),\n            \"vendor\": props.get(\"summary.hardware.vendor\", \"\"),\n            \"model\": props.get(\"summary.hardware.model\", \"\"),\n            \"cpu_model\": (props.get(\"summary.hardware.cpuModel\") or \"\").strip(),\n            \"cpu_sockets\": props.get(\"summary.hardware.numCpuPkgs\", \"\"),\n            \"cpu_cores\": props.get(\"summary.hardware.numCpuCores\", \"\"),\n            \"memory_gb\": to_gib(props.get(\"summary.hardware.memorySize\")),\n            \"vm_count\": len(props.get(\"vm\", [])),\n        })\n    return rows, host_names\n\n\ndef inventory_vms(content, host_names):\n    rows = []\n    for _, props in collect(content, vim.VirtualMachine, VM_PROPERTIES):\n        host_ref = props.get(\"summary.runtime.host\")\n        committed = props.get(\"summary.storage.committed\")\n        uncommitted = props.get(\"summary.storage.uncommitted\")\n        memory_mb = props.get(\"summary.config.memorySizeMB\")\n\n        rows.append({\n            \"vm_name\": props.get(\"name\", \"\"),\n            \"template\": props.get(\"summary.config.template\", \"\"),\n            \"power_state\": props.get(\"summary.runtime.powerState\", \"\"),\n            \"guest_os\": props.get(\"summary.config.guestFullName\", \"\"),\n            \"guest_hostname\": props.get(\"summary.guest.hostName\", \"\"),\n            \"ip_address\": props.get(\"summary.guest.ipAddress\", \"\"),\n            \"host\": host_names.get(host_ref._moId, \"\") if host_ref else \"\",\n            \"cpu_count\": props.get(\"summary.config.numCpu\", \"\"),\n            \"memory_gb\": round(memory_mb \u002F 1024, 1) if memory_mb is not None else \"\",\n            \"committed_gb\": to_gib(committed),\n            \"provisioned_gb\": to_gib((committed or 0) + (uncommitted or 0)) if committed is not None else \"\",\n            \"tools_running\": props.get(\"summary.guest.toolsRunningStatus\", \"\"),\n            \"tools_version_status\": props.get(\"summary.guest.toolsVersionStatus2\", \"\"),\n            \"instance_uuid\": props.get(\"summary.config.instanceUuid\", \"\"),\n        })\n    return rows\n\n\ndef write_csv(path, rows):\n    if not rows:\n        print(f\"No rows to write for {path}.\")\n        return\n    with open(path, \"w\", newline=\"\", encoding=\"utf-8\") as handle:\n        writer = csv.DictWriter(handle, fieldnames=list(rows[0].keys()))\n        writer.writeheader()\n        writer.writerows(rows)\n    print(f\"Wrote {len(rows)} row(s) to {path}.\")\n\n\ndef main():\n    args = parse_args()\n    if not args.host or not args.user:\n        print(\"Both --host and --user are required (or VCENTER_HOST \u002F VCENTER_USER).\", file=sys.stderr)\n        sys.exit(1)\n\n    service_instance = connect(args)\n    try:\n        content = service_instance.RetrieveContent()\n        host_rows, host_names = inventory_hosts(content)\n        write_csv(f\"{args.output_prefix}-hosts.csv\", sorted(host_rows, key=lambda r: r[\"host_name\"]))\n        vm_rows = inventory_vms(content, host_names)\n        write_csv(f\"{args.output_prefix}-vms.csv\", sorted(vm_rows, key=lambda r: r[\"vm_name\"]))\n    finally:\n        Disconnect(service_instance)\n\n\nif __name__ == \"__main__\":\n    main()\n","python",[39,208,209,214,219,223,228,233,239,245,250,256,262,268,273,278,287,295,303,311,319,324,338,351,356,368,377,385,393,401,409,417,425,433,441,449,457,465,473,479,484,494,501,509,517,525,533,541,549,557,565,573,581,589,597,605,610,615,632,637,642,654,677,713,743,773,811,840,868,877,882,887,898,945,953,964,975,986,997,1008,1014,1019,1024,1043,1049,1065,1074,1085,1125,1131,1166,1201,1228,1247,1252,1263,1274,1283,1298,1305,1325,1337,1343,1354,1362,1368,1373,1378,1389,1434,1439,1444,1455,1466,1477,1495,1516,1531,1537,1543,1568,1573,1579,1597,1606,1623,1640,1657,1674,1691,1708,1730,1747,1764,1779,1800,1806,1814,1819,1824,1835,1844,1861,1876,1891,1906,1921,1926,1931,1947,1964,1981,1998,2015,2032,2056,2073,2113,2122,2168,2185,2202,2219,2224,2232,2237,2242,2253,2264,2289,2295,2337,2365,2371,2377,2411,2416,2421,2431,2442,2459,2479,2489,2494,2505,2512,2523,2534,2578,2589,2625,2632,2638,2643,2648,2664],{"__ignoreMap":78},[82,210,211],{"class":84,"line":85},[82,212,213],{"class":99},"\"\"\"\n",[82,215,216],{"class":84,"line":103},[82,217,218],{"class":99},"Inventory VMware ESXi hosts and virtual machines through the vSphere API (pyVmomi).\n",[82,220,221],{"class":84,"line":116},[82,222,133],{"emptyLinePlaceholder":132},[82,224,225],{"class":84,"line":129},[82,226,227],{"class":99},"Connects to a vCenter Server and uses the PropertyCollector (RetrievePropertiesEx over a\n",[82,229,230],{"class":84,"line":136},[82,231,232],{"class":99},"ContainerView) to fetch only the properties it needs, one paged query per object type.\n",[82,234,236],{"class":84,"line":235},6,[82,237,238],{"class":99},"Writes one CSV row per host and one per VM. Intended as a lightweight discovery pass\n",[82,240,242],{"class":84,"line":241},7,[82,243,244],{"class":99},"ahead of a migration, capacity review, or license audit.\n",[82,246,248],{"class":84,"line":247},8,[82,249,133],{"emptyLinePlaceholder":132},[82,251,253],{"class":84,"line":252},9,[82,254,255],{"class":99},"Reads: vCenter connection details from CLI arguments or environment variables.\n",[82,257,259],{"class":84,"line":258},10,[82,260,261],{"class":99},"Writes: \u003Coutput-prefix>-hosts.csv and \u003Coutput-prefix>-vms.csv.\n",[82,263,265],{"class":84,"line":264},11,[82,266,267],{"class":99},"Requires: Python 3.10+, pyvmomi, a vCenter account with the Read-only role.\n",[82,269,271],{"class":84,"line":270},12,[82,272,213],{"class":99},[82,274,276],{"class":84,"line":275},13,[82,277,133],{"emptyLinePlaceholder":132},[82,279,281,284],{"class":84,"line":280},14,[82,282,283],{"class":88},"import",[82,285,286],{"class":92}," argparse\n",[82,288,290,292],{"class":84,"line":289},15,[82,291,283],{"class":88},[82,293,294],{"class":92}," csv\n",[82,296,298,300],{"class":84,"line":297},16,[82,299,283],{"class":88},[82,301,302],{"class":92}," getpass\n",[82,304,306,308],{"class":84,"line":305},17,[82,307,283],{"class":88},[82,309,310],{"class":92}," os\n",[82,312,314,316],{"class":84,"line":313},18,[82,315,283],{"class":88},[82,317,318],{"class":92}," sys\n",[82,320,322],{"class":84,"line":321},19,[82,323,133],{"emptyLinePlaceholder":132},[82,325,327,330,333,335],{"class":84,"line":326},20,[82,328,329],{"class":88},"from",[82,331,332],{"class":92}," pyVim.connect ",[82,334,283],{"class":88},[82,336,337],{"class":92}," Disconnect, SmartConnect\n",[82,339,341,343,346,348],{"class":84,"line":340},21,[82,342,329],{"class":88},[82,344,345],{"class":92}," pyVmomi ",[82,347,283],{"class":88},[82,349,350],{"class":92}," vim, vmodl\n",[82,352,354],{"class":84,"line":353},22,[82,355,133],{"emptyLinePlaceholder":132},[82,357,359,362,365],{"class":84,"line":358},23,[82,360,361],{"class":161},"HOST_PROPERTIES",[82,363,364],{"class":88}," =",[82,366,367],{"class":92}," [\n",[82,369,371,374],{"class":84,"line":370},24,[82,372,373],{"class":99},"    \"name\"",[82,375,376],{"class":92},",\n",[82,378,380,383],{"class":84,"line":379},25,[82,381,382],{"class":99},"    \"parent\"",[82,384,376],{"class":92},[82,386,388,391],{"class":84,"line":387},26,[82,389,390],{"class":99},"    \"runtime.connectionState\"",[82,392,376],{"class":92},[82,394,396,399],{"class":84,"line":395},27,[82,397,398],{"class":99},"    \"runtime.inMaintenanceMode\"",[82,400,376],{"class":92},[82,402,404,407],{"class":84,"line":403},28,[82,405,406],{"class":99},"    \"summary.config.product.version\"",[82,408,376],{"class":92},[82,410,412,415],{"class":84,"line":411},29,[82,413,414],{"class":99},"    \"summary.config.product.build\"",[82,416,376],{"class":92},[82,418,420,423],{"class":84,"line":419},30,[82,421,422],{"class":99},"    \"summary.hardware.vendor\"",[82,424,376],{"class":92},[82,426,428,431],{"class":84,"line":427},31,[82,429,430],{"class":99},"    \"summary.hardware.model\"",[82,432,376],{"class":92},[82,434,436,439],{"class":84,"line":435},32,[82,437,438],{"class":99},"    \"summary.hardware.cpuModel\"",[82,440,376],{"class":92},[82,442,444,447],{"class":84,"line":443},33,[82,445,446],{"class":99},"    \"summary.hardware.numCpuPkgs\"",[82,448,376],{"class":92},[82,450,452,455],{"class":84,"line":451},34,[82,453,454],{"class":99},"    \"summary.hardware.numCpuCores\"",[82,456,376],{"class":92},[82,458,460,463],{"class":84,"line":459},35,[82,461,462],{"class":99},"    \"summary.hardware.memorySize\"",[82,464,376],{"class":92},[82,466,468,471],{"class":84,"line":467},36,[82,469,470],{"class":99},"    \"vm\"",[82,472,376],{"class":92},[82,474,476],{"class":84,"line":475},37,[82,477,478],{"class":92},"]\n",[82,480,482],{"class":84,"line":481},38,[82,483,133],{"emptyLinePlaceholder":132},[82,485,487,490,492],{"class":84,"line":486},39,[82,488,489],{"class":161},"VM_PROPERTIES",[82,491,364],{"class":88},[82,493,367],{"class":92},[82,495,497,499],{"class":84,"line":496},40,[82,498,373],{"class":99},[82,500,376],{"class":92},[82,502,504,507],{"class":84,"line":503},41,[82,505,506],{"class":99},"    \"summary.config.template\"",[82,508,376],{"class":92},[82,510,512,515],{"class":84,"line":511},42,[82,513,514],{"class":99},"    \"summary.config.guestFullName\"",[82,516,376],{"class":92},[82,518,520,523],{"class":84,"line":519},43,[82,521,522],{"class":99},"    \"summary.config.numCpu\"",[82,524,376],{"class":92},[82,526,528,531],{"class":84,"line":527},44,[82,529,530],{"class":99},"    \"summary.config.memorySizeMB\"",[82,532,376],{"class":92},[82,534,536,539],{"class":84,"line":535},45,[82,537,538],{"class":99},"    \"summary.config.instanceUuid\"",[82,540,376],{"class":92},[82,542,544,547],{"class":84,"line":543},46,[82,545,546],{"class":99},"    \"summary.runtime.powerState\"",[82,548,376],{"class":92},[82,550,552,555],{"class":84,"line":551},47,[82,553,554],{"class":99},"    \"summary.runtime.host\"",[82,556,376],{"class":92},[82,558,560,563],{"class":84,"line":559},48,[82,561,562],{"class":99},"    \"summary.storage.committed\"",[82,564,376],{"class":92},[82,566,568,571],{"class":84,"line":567},49,[82,569,570],{"class":99},"    \"summary.storage.uncommitted\"",[82,572,376],{"class":92},[82,574,576,579],{"class":84,"line":575},50,[82,577,578],{"class":99},"    \"summary.guest.hostName\"",[82,580,376],{"class":92},[82,582,584,587],{"class":84,"line":583},51,[82,585,586],{"class":99},"    \"summary.guest.ipAddress\"",[82,588,376],{"class":92},[82,590,592,595],{"class":84,"line":591},52,[82,593,594],{"class":99},"    \"summary.guest.toolsRunningStatus\"",[82,596,376],{"class":92},[82,598,600,603],{"class":84,"line":599},53,[82,601,602],{"class":99},"    \"summary.guest.toolsVersionStatus2\"",[82,604,376],{"class":92},[82,606,608],{"class":84,"line":607},54,[82,609,478],{"class":92},[82,611,613],{"class":84,"line":612},55,[82,614,133],{"emptyLinePlaceholder":132},[82,616,618,621,623,626,629],{"class":84,"line":617},56,[82,619,620],{"class":161},"GIB",[82,622,364],{"class":88},[82,624,625],{"class":161}," 1024",[82,627,628],{"class":88}," **",[82,630,631],{"class":161}," 3\n",[82,633,635],{"class":84,"line":634},57,[82,636,133],{"emptyLinePlaceholder":132},[82,638,640],{"class":84,"line":639},58,[82,641,133],{"emptyLinePlaceholder":132},[82,643,645,648,651],{"class":84,"line":644},59,[82,646,647],{"class":88},"def",[82,649,650],{"class":139}," parse_args",[82,652,653],{"class":92},"():\n",[82,655,657,660,662,665,669,671,674],{"class":84,"line":656},60,[82,658,659],{"class":92},"    parser ",[82,661,96],{"class":88},[82,663,664],{"class":92}," argparse.ArgumentParser(",[82,666,668],{"class":667},"s9osk","description",[82,670,96],{"class":88},[82,672,673],{"class":99},"\"Inventory VMware hosts and VMs via pyVmomi.\"",[82,675,676],{"class":92},")\n",[82,678,680,683,686,689,692,694,697,700,703,706,708,711],{"class":84,"line":679},61,[82,681,682],{"class":92},"    parser.add_argument(",[82,684,685],{"class":99},"\"--host\"",[82,687,688],{"class":92},", ",[82,690,691],{"class":667},"default",[82,693,96],{"class":88},[82,695,696],{"class":92},"os.environ.get(",[82,698,699],{"class":99},"\"VCENTER_HOST\"",[82,701,702],{"class":92},"), ",[82,704,705],{"class":667},"help",[82,707,96],{"class":88},[82,709,710],{"class":99},"\"vCenter Server hostname or IP.\"",[82,712,676],{"class":92},[82,714,716,718,721,723,725,727,729,732,734,736,738,741],{"class":84,"line":715},62,[82,717,682],{"class":92},[82,719,720],{"class":99},"\"--user\"",[82,722,688],{"class":92},[82,724,691],{"class":667},[82,726,96],{"class":88},[82,728,696],{"class":92},[82,730,731],{"class":99},"\"VCENTER_USER\"",[82,733,702],{"class":92},[82,735,705],{"class":667},[82,737,96],{"class":88},[82,739,740],{"class":99},"\"vCenter user name.\"",[82,742,676],{"class":92},[82,744,746,748,751,753,755,757,759,762,764,766,768,771],{"class":84,"line":745},63,[82,747,682],{"class":92},[82,749,750],{"class":99},"\"--password\"",[82,752,688],{"class":92},[82,754,691],{"class":667},[82,756,96],{"class":88},[82,758,696],{"class":92},[82,760,761],{"class":99},"\"VCENTER_PASSWORD\"",[82,763,702],{"class":92},[82,765,705],{"class":667},[82,767,96],{"class":88},[82,769,770],{"class":99},"\"vCenter password (prompted if omitted).\"",[82,772,676],{"class":92},[82,774,776,778,781,783,786,788,791,793,795,797,800,802,804,806,809],{"class":84,"line":775},64,[82,777,682],{"class":92},[82,779,780],{"class":99},"\"--port\"",[82,782,688],{"class":92},[82,784,785],{"class":667},"type",[82,787,96],{"class":88},[82,789,790],{"class":161},"int",[82,792,688],{"class":92},[82,794,691],{"class":667},[82,796,96],{"class":88},[82,798,799],{"class":161},"443",[82,801,688],{"class":92},[82,803,705],{"class":667},[82,805,96],{"class":88},[82,807,808],{"class":99},"\"vCenter API port. Defaults to 443.\"",[82,810,676],{"class":92},[82,812,814,816,819,821,824,826,829,831,833,835,838],{"class":84,"line":813},65,[82,815,682],{"class":92},[82,817,818],{"class":99},"\"--insecure\"",[82,820,688],{"class":92},[82,822,823],{"class":667},"action",[82,825,96],{"class":88},[82,827,828],{"class":99},"\"store_true\"",[82,830,688],{"class":92},[82,832,705],{"class":667},[82,834,96],{"class":88},[82,836,837],{"class":99},"\"Skip TLS certificate verification (self-signed vCenter certs).\"",[82,839,676],{"class":92},[82,841,843,845,848,850,852,854,857,859,861,863,866],{"class":84,"line":842},66,[82,844,682],{"class":92},[82,846,847],{"class":99},"\"--output-prefix\"",[82,849,688],{"class":92},[82,851,691],{"class":667},[82,853,96],{"class":88},[82,855,856],{"class":99},"\"vmware-inventory\"",[82,858,688],{"class":92},[82,860,705],{"class":667},[82,862,96],{"class":88},[82,864,865],{"class":99},"\"Prefix for the output CSV files.\"",[82,867,676],{"class":92},[82,869,871,874],{"class":84,"line":870},67,[82,872,873],{"class":88},"    return",[82,875,876],{"class":92}," parser.parse_args()\n",[82,878,880],{"class":84,"line":879},68,[82,881,133],{"emptyLinePlaceholder":132},[82,883,885],{"class":84,"line":884},69,[82,886,133],{"emptyLinePlaceholder":132},[82,888,890,892,895],{"class":84,"line":889},70,[82,891,647],{"class":88},[82,893,894],{"class":139}," connect",[82,896,897],{"class":92},"(args):\n",[82,899,901,904,906,909,912,915,918,921,924,927,930,933,935,938,940,943],{"class":84,"line":900},71,[82,902,903],{"class":92},"    password ",[82,905,96],{"class":88},[82,907,908],{"class":92}," args.password ",[82,910,911],{"class":88},"or",[82,913,914],{"class":92}," getpass.getpass(",[82,916,917],{"class":88},"f",[82,919,920],{"class":99},"\"Password for ",[82,922,923],{"class":161},"{",[82,925,926],{"class":92},"args.user",[82,928,929],{"class":161},"}",[82,931,932],{"class":99},"@",[82,934,923],{"class":161},[82,936,937],{"class":92},"args.host",[82,939,929],{"class":161},[82,941,942],{"class":99},": \"",[82,944,676],{"class":92},[82,946,948,950],{"class":84,"line":947},72,[82,949,873],{"class":88},[82,951,952],{"class":92}," SmartConnect(\n",[82,954,956,959,961],{"class":84,"line":955},73,[82,957,958],{"class":667},"        host",[82,960,96],{"class":88},[82,962,963],{"class":92},"args.host,\n",[82,965,967,970,972],{"class":84,"line":966},74,[82,968,969],{"class":667},"        user",[82,971,96],{"class":88},[82,973,974],{"class":92},"args.user,\n",[82,976,978,981,983],{"class":84,"line":977},75,[82,979,980],{"class":667},"        pwd",[82,982,96],{"class":88},[82,984,985],{"class":92},"password,\n",[82,987,989,992,994],{"class":84,"line":988},76,[82,990,991],{"class":667},"        port",[82,993,96],{"class":88},[82,995,996],{"class":92},"args.port,\n",[82,998,1000,1003,1005],{"class":84,"line":999},77,[82,1001,1002],{"class":667},"        disableSslCertValidation",[82,1004,96],{"class":88},[82,1006,1007],{"class":92},"args.insecure,\n",[82,1009,1011],{"class":84,"line":1010},78,[82,1012,1013],{"class":92},"    )\n",[82,1015,1017],{"class":84,"line":1016},79,[82,1018,133],{"emptyLinePlaceholder":132},[82,1020,1022],{"class":84,"line":1021},80,[82,1023,133],{"emptyLinePlaceholder":132},[82,1025,1027,1029,1032,1035,1037,1040],{"class":84,"line":1026},81,[82,1028,647],{"class":88},[82,1030,1031],{"class":139}," collect",[82,1033,1034],{"class":92},"(content, obj_type, path_set, page_size",[82,1036,96],{"class":88},[82,1038,1039],{"class":161},"500",[82,1041,1042],{"class":92},"):\n",[82,1044,1046],{"class":84,"line":1045},82,[82,1047,1048],{"class":99},"    \"\"\"Yield (managed_object, {property_path: value}) for every obj_type in the inventory.\"\"\"\n",[82,1050,1052,1055,1057,1060,1063],{"class":84,"line":1051},83,[82,1053,1054],{"class":92},"    view ",[82,1056,96],{"class":88},[82,1058,1059],{"class":92}," content.viewManager.CreateContainerView(content.rootFolder, [obj_type], ",[82,1061,1062],{"class":161},"True",[82,1064,676],{"class":92},[82,1066,1068,1071],{"class":84,"line":1067},84,[82,1069,1070],{"class":88},"    try",[82,1072,1073],{"class":92},":\n",[82,1075,1077,1080,1082],{"class":84,"line":1076},85,[82,1078,1079],{"class":92},"        traversal ",[82,1081,96],{"class":88},[82,1083,1084],{"class":92}," vmodl.query.PropertyCollector.TraversalSpec(\n",[82,1086,1088,1091,1093,1096,1098,1101,1103,1106,1108,1111,1113,1116,1118,1120,1122],{"class":84,"line":1087},86,[82,1089,1090],{"class":667},"            name",[82,1092,96],{"class":88},[82,1094,1095],{"class":99},"\"traverseView\"",[82,1097,688],{"class":92},[82,1099,1100],{"class":667},"path",[82,1102,96],{"class":88},[82,1104,1105],{"class":99},"\"view\"",[82,1107,688],{"class":92},[82,1109,1110],{"class":667},"skip",[82,1112,96],{"class":88},[82,1114,1115],{"class":161},"False",[82,1117,688],{"class":92},[82,1119,785],{"class":667},[82,1121,96],{"class":88},[82,1123,1124],{"class":92},"vim.view.ContainerView\n",[82,1126,1128],{"class":84,"line":1127},87,[82,1129,1130],{"class":92},"        )\n",[82,1132,1134,1137,1139,1142,1145,1147,1150,1152,1154,1156,1158,1161,1163],{"class":84,"line":1133},88,[82,1135,1136],{"class":92},"        obj_spec ",[82,1138,96],{"class":88},[82,1140,1141],{"class":92}," vmodl.query.PropertyCollector.ObjectSpec(",[82,1143,1144],{"class":667},"obj",[82,1146,96],{"class":88},[82,1148,1149],{"class":92},"view, ",[82,1151,1110],{"class":667},[82,1153,96],{"class":88},[82,1155,1062],{"class":161},[82,1157,688],{"class":92},[82,1159,1160],{"class":667},"selectSet",[82,1162,96],{"class":88},[82,1164,1165],{"class":92},"[traversal])\n",[82,1167,1169,1172,1174,1177,1179,1181,1184,1187,1189,1192,1195,1197,1199],{"class":84,"line":1168},89,[82,1170,1171],{"class":92},"        prop_spec ",[82,1173,96],{"class":88},[82,1175,1176],{"class":92}," vmodl.query.PropertyCollector.PropertySpec(",[82,1178,785],{"class":667},[82,1180,96],{"class":88},[82,1182,1183],{"class":92},"obj_type, ",[82,1185,1186],{"class":667},"pathSet",[82,1188,96],{"class":88},[82,1190,1191],{"class":92},"path_set, ",[82,1193,1194],{"class":667},"all",[82,1196,96],{"class":88},[82,1198,1115],{"class":161},[82,1200,676],{"class":92},[82,1202,1204,1207,1209,1212,1215,1217,1220,1223,1225],{"class":84,"line":1203},90,[82,1205,1206],{"class":92},"        filter_spec ",[82,1208,96],{"class":88},[82,1210,1211],{"class":92}," vmodl.query.PropertyCollector.FilterSpec(",[82,1213,1214],{"class":667},"objectSet",[82,1216,96],{"class":88},[82,1218,1219],{"class":92},"[obj_spec], ",[82,1221,1222],{"class":667},"propSet",[82,1224,96],{"class":88},[82,1226,1227],{"class":92},"[prop_spec])\n",[82,1229,1231,1234,1236,1239,1242,1244],{"class":84,"line":1230},91,[82,1232,1233],{"class":92},"        options ",[82,1235,96],{"class":88},[82,1237,1238],{"class":92}," vmodl.query.PropertyCollector.RetrieveOptions(",[82,1240,1241],{"class":667},"maxObjects",[82,1243,96],{"class":88},[82,1245,1246],{"class":92},"page_size)\n",[82,1248,1250],{"class":84,"line":1249},92,[82,1251,133],{"emptyLinePlaceholder":132},[82,1253,1255,1258,1260],{"class":84,"line":1254},93,[82,1256,1257],{"class":92},"        collector ",[82,1259,96],{"class":88},[82,1261,1262],{"class":92}," content.propertyCollector\n",[82,1264,1266,1269,1271],{"class":84,"line":1265},94,[82,1267,1268],{"class":92},"        result ",[82,1270,96],{"class":88},[82,1272,1273],{"class":92}," collector.RetrievePropertiesEx([filter_spec], options)\n",[82,1275,1277,1280],{"class":84,"line":1276},95,[82,1278,1279],{"class":88},"        while",[82,1281,1282],{"class":92}," result:\n",[82,1284,1286,1289,1292,1295],{"class":84,"line":1285},96,[82,1287,1288],{"class":88},"            for",[82,1290,1291],{"class":92}," obj ",[82,1293,1294],{"class":88},"in",[82,1296,1297],{"class":92}," result.objects:\n",[82,1299,1301],{"class":84,"line":1300},97,[82,1302,1304],{"class":1303},"sAwPA","                # Unset properties are simply absent from propSet, so callers use .get().\n",[82,1306,1308,1311,1314,1317,1320,1322],{"class":84,"line":1307},98,[82,1309,1310],{"class":88},"                yield",[82,1312,1313],{"class":92}," obj.obj, {prop.name: prop.val ",[82,1315,1316],{"class":88},"for",[82,1318,1319],{"class":92}," prop ",[82,1321,1294],{"class":88},[82,1323,1324],{"class":92}," obj.propSet}\n",[82,1326,1328,1331,1334],{"class":84,"line":1327},99,[82,1329,1330],{"class":88},"            if",[82,1332,1333],{"class":88}," not",[82,1335,1336],{"class":92}," result.token:\n",[82,1338,1340],{"class":84,"line":1339},100,[82,1341,1342],{"class":88},"                break\n",[82,1344,1346,1349,1351],{"class":84,"line":1345},101,[82,1347,1348],{"class":92},"            result ",[82,1350,96],{"class":88},[82,1352,1353],{"class":92}," collector.ContinueRetrievePropertiesEx(result.token)\n",[82,1355,1357,1360],{"class":84,"line":1356},102,[82,1358,1359],{"class":88},"    finally",[82,1361,1073],{"class":92},[82,1363,1365],{"class":84,"line":1364},103,[82,1366,1367],{"class":92},"        view.Destroy()\n",[82,1369,1371],{"class":84,"line":1370},104,[82,1372,133],{"emptyLinePlaceholder":132},[82,1374,1376],{"class":84,"line":1375},105,[82,1377,133],{"emptyLinePlaceholder":132},[82,1379,1381,1383,1386],{"class":84,"line":1380},106,[82,1382,647],{"class":88},[82,1384,1385],{"class":139}," to_gib",[82,1387,1388],{"class":92},"(value):\n",[82,1390,1392,1394,1397,1400,1403,1406,1408,1411,1414,1417,1420,1423,1425,1428,1431],{"class":84,"line":1391},107,[82,1393,873],{"class":88},[82,1395,1396],{"class":161}," round",[82,1398,1399],{"class":92},"(value ",[82,1401,1402],{"class":88},"\u002F",[82,1404,1405],{"class":161}," GIB",[82,1407,688],{"class":92},[82,1409,1410],{"class":161},"1",[82,1412,1413],{"class":92},") ",[82,1415,1416],{"class":88},"if",[82,1418,1419],{"class":92}," value ",[82,1421,1422],{"class":88},"is",[82,1424,1333],{"class":88},[82,1426,1427],{"class":161}," None",[82,1429,1430],{"class":88}," else",[82,1432,1433],{"class":99}," \"\"\n",[82,1435,1437],{"class":84,"line":1436},108,[82,1438,133],{"emptyLinePlaceholder":132},[82,1440,1442],{"class":84,"line":1441},109,[82,1443,133],{"emptyLinePlaceholder":132},[82,1445,1447,1449,1452],{"class":84,"line":1446},110,[82,1448,647],{"class":88},[82,1450,1451],{"class":139}," inventory_hosts",[82,1453,1454],{"class":92},"(content):\n",[82,1456,1458,1461,1463],{"class":84,"line":1457},111,[82,1459,1460],{"class":92},"    rows ",[82,1462,96],{"class":88},[82,1464,1465],{"class":92}," []\n",[82,1467,1469,1472,1474],{"class":84,"line":1468},112,[82,1470,1471],{"class":92},"    host_names ",[82,1473,96],{"class":88},[82,1475,1476],{"class":92}," {}\n",[82,1478,1480,1483,1486,1488,1491,1493],{"class":84,"line":1479},113,[82,1481,1482],{"class":88},"    for",[82,1484,1485],{"class":92}," host, props ",[82,1487,1294],{"class":88},[82,1489,1490],{"class":92}," collect(content, vim.HostSystem, ",[82,1492,361],{"class":161},[82,1494,1042],{"class":92},[82,1496,1498,1501,1503,1506,1509,1511,1514],{"class":84,"line":1497},114,[82,1499,1500],{"class":92},"        host_names[host._moId] ",[82,1502,96],{"class":88},[82,1504,1505],{"class":92}," props.get(",[82,1507,1508],{"class":99},"\"name\"",[82,1510,688],{"class":92},[82,1512,1513],{"class":99},"\"\"",[82,1515,676],{"class":92},[82,1517,1519,1522,1524,1526,1529],{"class":84,"line":1518},115,[82,1520,1521],{"class":92},"        parent ",[82,1523,96],{"class":88},[82,1525,1505],{"class":92},[82,1527,1528],{"class":99},"\"parent\"",[82,1530,676],{"class":92},[82,1532,1534],{"class":84,"line":1533},116,[82,1535,1536],{"class":1303},"        # A clustered host's parent is a ClusterComputeResource; a standalone host\n",[82,1538,1540],{"class":84,"line":1539},117,[82,1541,1542],{"class":1303},"        # sits under a plain ComputeResource that carries the host's own name.\n",[82,1544,1546,1549,1551,1554,1556,1559,1562,1565],{"class":84,"line":1545},118,[82,1547,1548],{"class":92},"        cluster ",[82,1550,96],{"class":88},[82,1552,1553],{"class":92}," parent.name ",[82,1555,1416],{"class":88},[82,1557,1558],{"class":161}," isinstance",[82,1560,1561],{"class":92},"(parent, vim.ClusterComputeResource) ",[82,1563,1564],{"class":88},"else",[82,1566,1567],{"class":99}," \"\u003Cstandalone>\"\n",[82,1569,1571],{"class":84,"line":1570},119,[82,1572,133],{"emptyLinePlaceholder":132},[82,1574,1576],{"class":84,"line":1575},120,[82,1577,1578],{"class":92},"        rows.append({\n",[82,1580,1582,1585,1588,1590,1592,1594],{"class":84,"line":1581},121,[82,1583,1584],{"class":99},"            \"host_name\"",[82,1586,1587],{"class":92},": props.get(",[82,1589,1508],{"class":99},[82,1591,688],{"class":92},[82,1593,1513],{"class":99},[82,1595,1596],{"class":92},"),\n",[82,1598,1600,1603],{"class":84,"line":1599},122,[82,1601,1602],{"class":99},"            \"cluster\"",[82,1604,1605],{"class":92},": cluster,\n",[82,1607,1609,1612,1614,1617,1619,1621],{"class":84,"line":1608},123,[82,1610,1611],{"class":99},"            \"connection_state\"",[82,1613,1587],{"class":92},[82,1615,1616],{"class":99},"\"runtime.connectionState\"",[82,1618,688],{"class":92},[82,1620,1513],{"class":99},[82,1622,1596],{"class":92},[82,1624,1626,1629,1631,1634,1636,1638],{"class":84,"line":1625},124,[82,1627,1628],{"class":99},"            \"maintenance_mode\"",[82,1630,1587],{"class":92},[82,1632,1633],{"class":99},"\"runtime.inMaintenanceMode\"",[82,1635,688],{"class":92},[82,1637,1513],{"class":99},[82,1639,1596],{"class":92},[82,1641,1643,1646,1648,1651,1653,1655],{"class":84,"line":1642},125,[82,1644,1645],{"class":99},"            \"esxi_version\"",[82,1647,1587],{"class":92},[82,1649,1650],{"class":99},"\"summary.config.product.version\"",[82,1652,688],{"class":92},[82,1654,1513],{"class":99},[82,1656,1596],{"class":92},[82,1658,1660,1663,1665,1668,1670,1672],{"class":84,"line":1659},126,[82,1661,1662],{"class":99},"            \"esxi_build\"",[82,1664,1587],{"class":92},[82,1666,1667],{"class":99},"\"summary.config.product.build\"",[82,1669,688],{"class":92},[82,1671,1513],{"class":99},[82,1673,1596],{"class":92},[82,1675,1677,1680,1682,1685,1687,1689],{"class":84,"line":1676},127,[82,1678,1679],{"class":99},"            \"vendor\"",[82,1681,1587],{"class":92},[82,1683,1684],{"class":99},"\"summary.hardware.vendor\"",[82,1686,688],{"class":92},[82,1688,1513],{"class":99},[82,1690,1596],{"class":92},[82,1692,1694,1697,1699,1702,1704,1706],{"class":84,"line":1693},128,[82,1695,1696],{"class":99},"            \"model\"",[82,1698,1587],{"class":92},[82,1700,1701],{"class":99},"\"summary.hardware.model\"",[82,1703,688],{"class":92},[82,1705,1513],{"class":99},[82,1707,1596],{"class":92},[82,1709,1711,1714,1717,1720,1722,1724,1727],{"class":84,"line":1710},129,[82,1712,1713],{"class":99},"            \"cpu_model\"",[82,1715,1716],{"class":92},": (props.get(",[82,1718,1719],{"class":99},"\"summary.hardware.cpuModel\"",[82,1721,1413],{"class":92},[82,1723,911],{"class":88},[82,1725,1726],{"class":99}," \"\"",[82,1728,1729],{"class":92},").strip(),\n",[82,1731,1733,1736,1738,1741,1743,1745],{"class":84,"line":1732},130,[82,1734,1735],{"class":99},"            \"cpu_sockets\"",[82,1737,1587],{"class":92},[82,1739,1740],{"class":99},"\"summary.hardware.numCpuPkgs\"",[82,1742,688],{"class":92},[82,1744,1513],{"class":99},[82,1746,1596],{"class":92},[82,1748,1750,1753,1755,1758,1760,1762],{"class":84,"line":1749},131,[82,1751,1752],{"class":99},"            \"cpu_cores\"",[82,1754,1587],{"class":92},[82,1756,1757],{"class":99},"\"summary.hardware.numCpuCores\"",[82,1759,688],{"class":92},[82,1761,1513],{"class":99},[82,1763,1596],{"class":92},[82,1765,1767,1770,1773,1776],{"class":84,"line":1766},132,[82,1768,1769],{"class":99},"            \"memory_gb\"",[82,1771,1772],{"class":92},": to_gib(props.get(",[82,1774,1775],{"class":99},"\"summary.hardware.memorySize\"",[82,1777,1778],{"class":92},")),\n",[82,1780,1782,1785,1788,1791,1794,1797],{"class":84,"line":1781},133,[82,1783,1784],{"class":99},"            \"vm_count\"",[82,1786,1787],{"class":92},": ",[82,1789,1790],{"class":161},"len",[82,1792,1793],{"class":92},"(props.get(",[82,1795,1796],{"class":99},"\"vm\"",[82,1798,1799],{"class":92},", [])),\n",[82,1801,1803],{"class":84,"line":1802},134,[82,1804,1805],{"class":92},"        })\n",[82,1807,1809,1811],{"class":84,"line":1808},135,[82,1810,873],{"class":88},[82,1812,1813],{"class":92}," rows, host_names\n",[82,1815,1817],{"class":84,"line":1816},136,[82,1818,133],{"emptyLinePlaceholder":132},[82,1820,1822],{"class":84,"line":1821},137,[82,1823,133],{"emptyLinePlaceholder":132},[82,1825,1827,1829,1832],{"class":84,"line":1826},138,[82,1828,647],{"class":88},[82,1830,1831],{"class":139}," inventory_vms",[82,1833,1834],{"class":92},"(content, host_names):\n",[82,1836,1838,1840,1842],{"class":84,"line":1837},139,[82,1839,1460],{"class":92},[82,1841,96],{"class":88},[82,1843,1465],{"class":92},[82,1845,1847,1849,1852,1854,1857,1859],{"class":84,"line":1846},140,[82,1848,1482],{"class":88},[82,1850,1851],{"class":92}," _, props ",[82,1853,1294],{"class":88},[82,1855,1856],{"class":92}," collect(content, vim.VirtualMachine, ",[82,1858,489],{"class":161},[82,1860,1042],{"class":92},[82,1862,1864,1867,1869,1871,1874],{"class":84,"line":1863},141,[82,1865,1866],{"class":92},"        host_ref ",[82,1868,96],{"class":88},[82,1870,1505],{"class":92},[82,1872,1873],{"class":99},"\"summary.runtime.host\"",[82,1875,676],{"class":92},[82,1877,1879,1882,1884,1886,1889],{"class":84,"line":1878},142,[82,1880,1881],{"class":92},"        committed ",[82,1883,96],{"class":88},[82,1885,1505],{"class":92},[82,1887,1888],{"class":99},"\"summary.storage.committed\"",[82,1890,676],{"class":92},[82,1892,1894,1897,1899,1901,1904],{"class":84,"line":1893},143,[82,1895,1896],{"class":92},"        uncommitted ",[82,1898,96],{"class":88},[82,1900,1505],{"class":92},[82,1902,1903],{"class":99},"\"summary.storage.uncommitted\"",[82,1905,676],{"class":92},[82,1907,1909,1912,1914,1916,1919],{"class":84,"line":1908},144,[82,1910,1911],{"class":92},"        memory_mb ",[82,1913,96],{"class":88},[82,1915,1505],{"class":92},[82,1917,1918],{"class":99},"\"summary.config.memorySizeMB\"",[82,1920,676],{"class":92},[82,1922,1924],{"class":84,"line":1923},145,[82,1925,133],{"emptyLinePlaceholder":132},[82,1927,1929],{"class":84,"line":1928},146,[82,1930,1578],{"class":92},[82,1932,1934,1937,1939,1941,1943,1945],{"class":84,"line":1933},147,[82,1935,1936],{"class":99},"            \"vm_name\"",[82,1938,1587],{"class":92},[82,1940,1508],{"class":99},[82,1942,688],{"class":92},[82,1944,1513],{"class":99},[82,1946,1596],{"class":92},[82,1948,1950,1953,1955,1958,1960,1962],{"class":84,"line":1949},148,[82,1951,1952],{"class":99},"            \"template\"",[82,1954,1587],{"class":92},[82,1956,1957],{"class":99},"\"summary.config.template\"",[82,1959,688],{"class":92},[82,1961,1513],{"class":99},[82,1963,1596],{"class":92},[82,1965,1967,1970,1972,1975,1977,1979],{"class":84,"line":1966},149,[82,1968,1969],{"class":99},"            \"power_state\"",[82,1971,1587],{"class":92},[82,1973,1974],{"class":99},"\"summary.runtime.powerState\"",[82,1976,688],{"class":92},[82,1978,1513],{"class":99},[82,1980,1596],{"class":92},[82,1982,1984,1987,1989,1992,1994,1996],{"class":84,"line":1983},150,[82,1985,1986],{"class":99},"            \"guest_os\"",[82,1988,1587],{"class":92},[82,1990,1991],{"class":99},"\"summary.config.guestFullName\"",[82,1993,688],{"class":92},[82,1995,1513],{"class":99},[82,1997,1596],{"class":92},[82,1999,2001,2004,2006,2009,2011,2013],{"class":84,"line":2000},151,[82,2002,2003],{"class":99},"            \"guest_hostname\"",[82,2005,1587],{"class":92},[82,2007,2008],{"class":99},"\"summary.guest.hostName\"",[82,2010,688],{"class":92},[82,2012,1513],{"class":99},[82,2014,1596],{"class":92},[82,2016,2018,2021,2023,2026,2028,2030],{"class":84,"line":2017},152,[82,2019,2020],{"class":99},"            \"ip_address\"",[82,2022,1587],{"class":92},[82,2024,2025],{"class":99},"\"summary.guest.ipAddress\"",[82,2027,688],{"class":92},[82,2029,1513],{"class":99},[82,2031,1596],{"class":92},[82,2033,2035,2038,2041,2043,2045,2047,2050,2052,2054],{"class":84,"line":2034},153,[82,2036,2037],{"class":99},"            \"host\"",[82,2039,2040],{"class":92},": host_names.get(host_ref._moId, ",[82,2042,1513],{"class":99},[82,2044,1413],{"class":92},[82,2046,1416],{"class":88},[82,2048,2049],{"class":92}," host_ref ",[82,2051,1564],{"class":88},[82,2053,1726],{"class":99},[82,2055,376],{"class":92},[82,2057,2059,2062,2064,2067,2069,2071],{"class":84,"line":2058},154,[82,2060,2061],{"class":99},"            \"cpu_count\"",[82,2063,1587],{"class":92},[82,2065,2066],{"class":99},"\"summary.config.numCpu\"",[82,2068,688],{"class":92},[82,2070,1513],{"class":99},[82,2072,1596],{"class":92},[82,2074,2076,2078,2080,2083,2086,2088,2090,2092,2094,2096,2098,2101,2103,2105,2107,2109,2111],{"class":84,"line":2075},155,[82,2077,1769],{"class":99},[82,2079,1787],{"class":92},[82,2081,2082],{"class":161},"round",[82,2084,2085],{"class":92},"(memory_mb ",[82,2087,1402],{"class":88},[82,2089,625],{"class":161},[82,2091,688],{"class":92},[82,2093,1410],{"class":161},[82,2095,1413],{"class":92},[82,2097,1416],{"class":88},[82,2099,2100],{"class":92}," memory_mb ",[82,2102,1422],{"class":88},[82,2104,1333],{"class":88},[82,2106,1427],{"class":161},[82,2108,1430],{"class":88},[82,2110,1726],{"class":99},[82,2112,376],{"class":92},[82,2114,2116,2119],{"class":84,"line":2115},156,[82,2117,2118],{"class":99},"            \"committed_gb\"",[82,2120,2121],{"class":92},": to_gib(committed),\n",[82,2123,2125,2128,2131,2133,2136,2138,2141,2144,2146,2148,2151,2153,2156,2158,2160,2162,2164,2166],{"class":84,"line":2124},157,[82,2126,2127],{"class":99},"            \"provisioned_gb\"",[82,2129,2130],{"class":92},": to_gib((committed ",[82,2132,911],{"class":88},[82,2134,2135],{"class":161}," 0",[82,2137,1413],{"class":92},[82,2139,2140],{"class":88},"+",[82,2142,2143],{"class":92}," (uncommitted ",[82,2145,911],{"class":88},[82,2147,2135],{"class":161},[82,2149,2150],{"class":92},")) ",[82,2152,1416],{"class":88},[82,2154,2155],{"class":92}," committed ",[82,2157,1422],{"class":88},[82,2159,1333],{"class":88},[82,2161,1427],{"class":161},[82,2163,1430],{"class":88},[82,2165,1726],{"class":99},[82,2167,376],{"class":92},[82,2169,2171,2174,2176,2179,2181,2183],{"class":84,"line":2170},158,[82,2172,2173],{"class":99},"            \"tools_running\"",[82,2175,1587],{"class":92},[82,2177,2178],{"class":99},"\"summary.guest.toolsRunningStatus\"",[82,2180,688],{"class":92},[82,2182,1513],{"class":99},[82,2184,1596],{"class":92},[82,2186,2188,2191,2193,2196,2198,2200],{"class":84,"line":2187},159,[82,2189,2190],{"class":99},"            \"tools_version_status\"",[82,2192,1587],{"class":92},[82,2194,2195],{"class":99},"\"summary.guest.toolsVersionStatus2\"",[82,2197,688],{"class":92},[82,2199,1513],{"class":99},[82,2201,1596],{"class":92},[82,2203,2205,2208,2210,2213,2215,2217],{"class":84,"line":2204},160,[82,2206,2207],{"class":99},"            \"instance_uuid\"",[82,2209,1587],{"class":92},[82,2211,2212],{"class":99},"\"summary.config.instanceUuid\"",[82,2214,688],{"class":92},[82,2216,1513],{"class":99},[82,2218,1596],{"class":92},[82,2220,2222],{"class":84,"line":2221},161,[82,2223,1805],{"class":92},[82,2225,2227,2229],{"class":84,"line":2226},162,[82,2228,873],{"class":88},[82,2230,2231],{"class":92}," rows\n",[82,2233,2235],{"class":84,"line":2234},163,[82,2236,133],{"emptyLinePlaceholder":132},[82,2238,2240],{"class":84,"line":2239},164,[82,2241,133],{"emptyLinePlaceholder":132},[82,2243,2245,2247,2250],{"class":84,"line":2244},165,[82,2246,647],{"class":88},[82,2248,2249],{"class":139}," write_csv",[82,2251,2252],{"class":92},"(path, rows):\n",[82,2254,2256,2259,2261],{"class":84,"line":2255},166,[82,2257,2258],{"class":88},"    if",[82,2260,1333],{"class":88},[82,2262,2263],{"class":92}," rows:\n",[82,2265,2267,2270,2273,2275,2278,2280,2282,2284,2287],{"class":84,"line":2266},167,[82,2268,2269],{"class":161},"        print",[82,2271,2272],{"class":92},"(",[82,2274,917],{"class":88},[82,2276,2277],{"class":99},"\"No rows to write for ",[82,2279,923],{"class":161},[82,2281,1100],{"class":92},[82,2283,929],{"class":161},[82,2285,2286],{"class":99},".\"",[82,2288,676],{"class":92},[82,2290,2292],{"class":84,"line":2291},168,[82,2293,2294],{"class":88},"        return\n",[82,2296,2298,2301,2304,2307,2310,2312,2315,2317,2319,2321,2324,2326,2329,2331,2334],{"class":84,"line":2297},169,[82,2299,2300],{"class":88},"    with",[82,2302,2303],{"class":161}," open",[82,2305,2306],{"class":92},"(path, ",[82,2308,2309],{"class":99},"\"w\"",[82,2311,688],{"class":92},[82,2313,2314],{"class":667},"newline",[82,2316,96],{"class":88},[82,2318,1513],{"class":99},[82,2320,688],{"class":92},[82,2322,2323],{"class":667},"encoding",[82,2325,96],{"class":88},[82,2327,2328],{"class":99},"\"utf-8\"",[82,2330,1413],{"class":92},[82,2332,2333],{"class":88},"as",[82,2335,2336],{"class":92}," handle:\n",[82,2338,2340,2343,2345,2348,2351,2353,2356,2359,2362],{"class":84,"line":2339},170,[82,2341,2342],{"class":92},"        writer ",[82,2344,96],{"class":88},[82,2346,2347],{"class":92}," csv.DictWriter(handle, ",[82,2349,2350],{"class":667},"fieldnames",[82,2352,96],{"class":88},[82,2354,2355],{"class":161},"list",[82,2357,2358],{"class":92},"(rows[",[82,2360,2361],{"class":161},"0",[82,2363,2364],{"class":92},"].keys()))\n",[82,2366,2368],{"class":84,"line":2367},171,[82,2369,2370],{"class":92},"        writer.writeheader()\n",[82,2372,2374],{"class":84,"line":2373},172,[82,2375,2376],{"class":92},"        writer.writerows(rows)\n",[82,2378,2380,2383,2385,2387,2390,2393,2396,2398,2401,2403,2405,2407,2409],{"class":84,"line":2379},173,[82,2381,2382],{"class":161},"    print",[82,2384,2272],{"class":92},[82,2386,917],{"class":88},[82,2388,2389],{"class":99},"\"Wrote ",[82,2391,2392],{"class":161},"{len",[82,2394,2395],{"class":92},"(rows)",[82,2397,929],{"class":161},[82,2399,2400],{"class":99}," row(s) to ",[82,2402,923],{"class":161},[82,2404,1100],{"class":92},[82,2406,929],{"class":161},[82,2408,2286],{"class":99},[82,2410,676],{"class":92},[82,2412,2414],{"class":84,"line":2413},174,[82,2415,133],{"emptyLinePlaceholder":132},[82,2417,2419],{"class":84,"line":2418},175,[82,2420,133],{"emptyLinePlaceholder":132},[82,2422,2424,2426,2429],{"class":84,"line":2423},176,[82,2425,647],{"class":88},[82,2427,2428],{"class":139}," main",[82,2430,653],{"class":92},[82,2432,2434,2437,2439],{"class":84,"line":2433},177,[82,2435,2436],{"class":92},"    args ",[82,2438,96],{"class":88},[82,2440,2441],{"class":92}," parse_args()\n",[82,2443,2445,2447,2449,2452,2454,2456],{"class":84,"line":2444},178,[82,2446,2258],{"class":88},[82,2448,1333],{"class":88},[82,2450,2451],{"class":92}," args.host ",[82,2453,911],{"class":88},[82,2455,1333],{"class":88},[82,2457,2458],{"class":92}," args.user:\n",[82,2460,2462,2464,2466,2469,2471,2474,2476],{"class":84,"line":2461},179,[82,2463,2269],{"class":161},[82,2465,2272],{"class":92},[82,2467,2468],{"class":99},"\"Both --host and --user are required (or VCENTER_HOST \u002F VCENTER_USER).\"",[82,2470,688],{"class":92},[82,2472,2473],{"class":667},"file",[82,2475,96],{"class":88},[82,2477,2478],{"class":92},"sys.stderr)\n",[82,2480,2482,2485,2487],{"class":84,"line":2481},180,[82,2483,2484],{"class":92},"        sys.exit(",[82,2486,1410],{"class":161},[82,2488,676],{"class":92},[82,2490,2492],{"class":84,"line":2491},181,[82,2493,133],{"emptyLinePlaceholder":132},[82,2495,2497,2500,2502],{"class":84,"line":2496},182,[82,2498,2499],{"class":92},"    service_instance ",[82,2501,96],{"class":88},[82,2503,2504],{"class":92}," connect(args)\n",[82,2506,2508,2510],{"class":84,"line":2507},183,[82,2509,1070],{"class":88},[82,2511,1073],{"class":92},[82,2513,2515,2518,2520],{"class":84,"line":2514},184,[82,2516,2517],{"class":92},"        content ",[82,2519,96],{"class":88},[82,2521,2522],{"class":92}," service_instance.RetrieveContent()\n",[82,2524,2526,2529,2531],{"class":84,"line":2525},185,[82,2527,2528],{"class":92},"        host_rows, host_names ",[82,2530,96],{"class":88},[82,2532,2533],{"class":92}," inventory_hosts(content)\n",[82,2535,2537,2540,2542,2545,2547,2550,2552,2555,2557,2560,2563,2566,2569,2572,2575],{"class":84,"line":2536},186,[82,2538,2539],{"class":92},"        write_csv(",[82,2541,917],{"class":88},[82,2543,2544],{"class":99},"\"",[82,2546,923],{"class":161},[82,2548,2549],{"class":92},"args.output_prefix",[82,2551,929],{"class":161},[82,2553,2554],{"class":99},"-hosts.csv\"",[82,2556,688],{"class":92},[82,2558,2559],{"class":161},"sorted",[82,2561,2562],{"class":92},"(host_rows, ",[82,2564,2565],{"class":667},"key",[82,2567,2568],{"class":88},"=lambda",[82,2570,2571],{"class":92}," r: r[",[82,2573,2574],{"class":99},"\"host_name\"",[82,2576,2577],{"class":92},"]))\n",[82,2579,2581,2584,2586],{"class":84,"line":2580},187,[82,2582,2583],{"class":92},"        vm_rows ",[82,2585,96],{"class":88},[82,2587,2588],{"class":92}," inventory_vms(content, host_names)\n",[82,2590,2592,2594,2596,2598,2600,2602,2604,2607,2609,2611,2614,2616,2618,2620,2623],{"class":84,"line":2591},188,[82,2593,2539],{"class":92},[82,2595,917],{"class":88},[82,2597,2544],{"class":99},[82,2599,923],{"class":161},[82,2601,2549],{"class":92},[82,2603,929],{"class":161},[82,2605,2606],{"class":99},"-vms.csv\"",[82,2608,688],{"class":92},[82,2610,2559],{"class":161},[82,2612,2613],{"class":92},"(vm_rows, ",[82,2615,2565],{"class":667},[82,2617,2568],{"class":88},[82,2619,2571],{"class":92},[82,2621,2622],{"class":99},"\"vm_name\"",[82,2624,2577],{"class":92},[82,2626,2628,2630],{"class":84,"line":2627},189,[82,2629,1359],{"class":88},[82,2631,1073],{"class":92},[82,2633,2635],{"class":84,"line":2634},190,[82,2636,2637],{"class":92},"        Disconnect(service_instance)\n",[82,2639,2641],{"class":84,"line":2640},191,[82,2642,133],{"emptyLinePlaceholder":132},[82,2644,2646],{"class":84,"line":2645},192,[82,2647,133],{"emptyLinePlaceholder":132},[82,2649,2651,2653,2656,2659,2662],{"class":84,"line":2650},193,[82,2652,1416],{"class":88},[82,2654,2655],{"class":161}," __name__",[82,2657,2658],{"class":88}," ==",[82,2660,2661],{"class":99}," \"__main__\"",[82,2663,1073],{"class":92},[82,2665,2667],{"class":84,"line":2666},194,[82,2668,2669],{"class":92},"    main()\n",[24,2671,2673],{"id":2672},"notes","Notes",[29,2675,2676,2708,2718,2736,2757,2766,2776],{},[32,2677,2678,2685,2686,2688,2689,2692,2693,2695,2696,2699,2700,2703,2704,2707],{},[51,2679,2680,2681,2684],{},"Why the PropertyCollector instead of walking ",[39,2682,2683],{},"vm.summary","."," The first version of this script walked ",[39,2687,2683],{}," object by object, where pyVmomi fetches managed-object properties from the server as you touch them: readable, fine for a lab, slow for a few thousand VMs. ",[39,2690,2691],{},"RetrievePropertiesEx"," fetches only the listed property paths for every object in the ContainerView, in pages of ",[39,2694,1241],{},", and ",[39,2697,2698],{},"ContinueRetrievePropertiesEx"," pulls the next page using the returned token. The older ",[39,2701,2702],{},"RetrieveProperties"," call is deprecated in favour of the ",[39,2705,2706],{},"Ex"," pair.",[32,2709,2710,2713,2714,2717],{},[51,2711,2712],{},"Destroy your views."," The vSphere API keeps a ContainerView alive until it is destroyed or the session ends, so the ",[39,2715,2716],{},"finally: view.Destroy()"," matters for a long-running process that reuses one session.",[32,2719,2720,2723,2724,2727,2728,2731,2732,2735],{},[51,2721,2722],{},"Committed is not provisioned."," ",[39,2725,2726],{},"summary.storage.committed"," is the space actually committed to the VM across all datastores; ",[39,2729,2730],{},"uncommitted"," is the additional space it could potentially use on those datastores, for example thin disks growing to their full size. The script reports both committed and their sum as ",[39,2733,2734],{},"provisioned_gb",", which is the number license and capacity conversations usually want.",[32,2737,2738,2744,2745,2748,2749,2752,2753,2756],{},[51,2739,2740,2743],{},[39,2741,2742],{},"toolsStatus"," is deprecated."," The original version of this script used ",[39,2746,2747],{},"summary.guest.toolsStatus","; the API reference marks it deprecated as of vSphere API 5.0 in favour of ",[39,2750,2751],{},"toolsRunningStatus"," and ",[39,2754,2755],{},"toolsVersionStatus2",", which the script now reads.",[32,2758,2759,2723,2762,2765],{},[51,2760,2761],{},"Guest IPs need VMware Tools.",[39,2763,2764],{},"summary.guest.ipAddress"," is the primary address reported by the guest. A VM with Tools stopped or not installed shows a blank IP even if it's up; cross-reference its MAC (from the VM's network adapter settings; this script doesn't collect MACs) against DHCP leases or a switch forwarding table to place it.",[32,2767,2768,2771,2772,2775],{},[51,2769,2770],{},"Templates are VMs too."," They show up in the VM container view; the ",[39,2773,2774],{},"template"," column lets you filter them out of capacity numbers.",[32,2777,2778,2781,2782,2786],{},[51,2779,2780],{},"Snapshot, not a monitor."," Schedule it and diff successive CSVs to catch drift between passes. The ",[18,2783,2785],{"href":2784},"\u002F2026\u002F03\u002F11\u002Fnode-js-discovery-diffing-two-network-scans-to-flag-new-hosts\u002F","Node.js scan diff"," post shows the same idea for network scans.",[24,2788,2790],{"id":2789},"references","References",[29,2792,2793,2802,2812,2819,2826,2833,2840,2847],{},[32,2794,2795,2801],{},[18,2796,2800],{"href":2797,"rel":2798},"https:\u002F\u002Fpypi.org\u002Fproject\u002Fpyvmomi\u002F",[2799],"nofollow","pyvmomi on PyPI"," (Python support, compatibility policy)",[32,2803,2804],{},[18,2805,2808,2809],{"href":2806,"rel":2807},"https:\u002F\u002Fgithub.com\u002Fvmware\u002Fpyvmomi\u002Fblob\u002Fmaster\u002FpyVim\u002Fconnect.py",[2799],"pyVim\u002Fconnect.py: SmartConnect and ",[39,2810,2811],{},"disableSslCertValidation",[32,2813,2814],{},[18,2815,2818],{"href":2816,"rel":2817},"https:\u002F\u002Fdeveloper.broadcom.com\u002Fxapis\u002Fvsphere-web-services-api\u002Flatest\u002Fvmodl.query.PropertyCollector.html",[2799],"vSphere Web Services API: PropertyCollector",[32,2820,2821],{},[18,2822,2825],{"href":2823,"rel":2824},"https:\u002F\u002Fdeveloper.broadcom.com\u002Fxapis\u002Fvsphere-web-services-api\u002Flatest\u002Fvmodl.query.PropertyCollector.RetrieveOptions.html",[2799],"vSphere Web Services API: RetrieveOptions",[32,2827,2828],{},[18,2829,2832],{"href":2830,"rel":2831},"https:\u002F\u002Fdeveloper.broadcom.com\u002Fxapis\u002Fvsphere-web-services-api\u002Flatest\u002Fvim.view.ViewManager.html",[2799],"vSphere Web Services API: ViewManager.CreateContainerView",[32,2834,2835],{},[18,2836,2839],{"href":2837,"rel":2838},"https:\u002F\u002Fdeveloper.broadcom.com\u002Fxapis\u002Fvsphere-web-services-api\u002Flatest\u002Fvim.vm.Summary.GuestSummary.html",[2799],"vSphere Web Services API: VirtualMachineGuestSummary",[32,2841,2842],{},[18,2843,2846],{"href":2844,"rel":2845},"https:\u002F\u002Fdeveloper.broadcom.com\u002Fxapis\u002Fvsphere-web-services-api\u002Flatest\u002Fvim.vm.Summary.StorageSummary.html",[2799],"vSphere Web Services API: VirtualMachineStorageSummary",[32,2848,2849],{},[18,2850,2853],{"href":2851,"rel":2852},"https:\u002F\u002Fdeveloper.broadcom.com\u002Fxapis\u002Fvsphere-web-services-api\u002Flatest\u002Fvim.host.Summary.HardwareSummary.html",[2799],"vSphere Web Services API: HostHardwareSummary",[2855,2856,2857],"style",{},"html pre.shiki code .snl16, html code.shiki .snl16{--shiki-default:#F97583}html pre.shiki code .s95oV, html code.shiki .s95oV{--shiki-default:#E1E4E8}html pre.shiki code .sU2Wk, html code.shiki .sU2Wk{--shiki-default:#9ECBFF}html pre.shiki code .svObZ, html code.shiki .svObZ{--shiki-default:#B392F0}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sDLfK, html code.shiki .sDLfK{--shiki-default:#79B8FF}html pre.shiki code .s9osk, html code.shiki .s9osk{--shiki-default:#FFAB70}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}",{"title":78,"searchDepth":103,"depth":103,"links":2859},[2860,2861,2862,2863,2864],{"id":26,"depth":103,"text":27},{"id":67,"depth":103,"text":68},{"id":200,"depth":103,"text":201},{"id":2672,"depth":103,"text":2673},{"id":2789,"depth":103,"text":2790},"techcolumnist",[2867,2868],"scripts","engineering","2025-12-10T14:00:00Z","A pyVmomi script that pulls ESXi host and VM inventory from vCenter with one PropertyCollector query per type and writes two CSVs for a discovery pass.","md",false,null,{},"\u002Fblog\u002F2025\u002F12\u002F10\u002Fpython-discovery-inventory-vmware-hosts-and-vms-via-pyvmomi",{"title":6,"description":2870},[2865],"blog\u002F2025\u002F12\u002F10\u002Fpython-discovery-inventory-vmware-hosts-and-vms-via-pyvmomi",[206,2880,2881],"vmware","discovery","\u002F2025\u002F12\u002F10\u002Fpython-discovery-inventory-vmware-hosts-and-vms-via-pyvmomi\u002F","SJSIcOhHs_sN_lYvh3IuV4x24P8wLWA5wRSsw00g7tg",{"title":2885,"description":2886,"date":2887,"url":2888,"categories":2889,"tags":2890,"image":2873,"readingTime":136,"canonical":2865,"sites":2895,"series":2873,"seriesOrder":2873},"Python: Data Warehouse – Incremental Loads from Postgres to BigQuery","A Python script that copies new and changed Postgres rows into BigQuery with one load job and a MERGE, advancing the watermark in the same transaction.","2025-12-17T14:00:00Z","\u002F2025\u002F12\u002F17\u002Fpython-data-warehouse-incremental-loads-from-postgres-to-bigquery\u002F",[2867,2868],[206,2891,2892,2893,2894],"data-warehouse","etl","gcloud","sql",[2865],{"title":2897,"description":2898,"date":2899,"url":2900,"categories":2901,"tags":2903,"image":2873,"readingTime":136,"canonical":2865,"sites":2907,"series":2873,"seriesOrder":2873},"PowerShell: Active Directory – Report Group Membership Sprawl","Rank AD security groups by nesting depth, transitive member count, ownership and staleness for an access review, plus a per-user Kerberos token size estimate.","2025-12-03T14:00:00Z","\u002F2025\u002F12\u002F03\u002Fpowershell-active-directory-report-group-membership-sprawl\u002F",[2902,2867],"ps",[2904,2905,2906],"powershell","active-directory","reporting",[2865],[2909,2919,2927],{"title":2910,"description":2911,"date":2912,"url":2913,"categories":2914,"tags":2915,"image":2873,"readingTime":116,"canonical":2865,"sites":2918,"series":2873,"seriesOrder":2873},"Python: Discovery – Crawling DNS Zones for Orphaned Records","A dnspython script that transfers a zone with AXFR, probes every A\u002FAAAA record for signs of life, flags dangling CNAMEs, and reports orphan cleanup candidates.","2026-01-28T14:00:00Z","\u002F2026\u002F01\u002F28\u002Fpython-discovery-crawling-dns-zones-for-orphaned-records\u002F",[2867,2868],[206,2881,2916,2917],"network","windows",[2865],{"title":2920,"description":2921,"date":2922,"url":2923,"categories":2924,"tags":2925,"image":2873,"readingTime":116,"canonical":2865,"sites":2926,"series":2873,"seriesOrder":2873},"Python: Discovery – Fingerprint Every Device on a Subnet","A Python script that ARP-sweeps a local subnet with Scapy, maps MACs to IEEE vendors, probes common ports for banners, and writes one CSV row per device.","2026-01-07T14:00:00Z","\u002F2026\u002F01\u002F07\u002Fpython-discovery-fingerprint-every-device-on-a-subnet\u002F",[2867,2868],[206,2881,2916],[2865],{"title":2928,"description":2929,"date":2930,"url":20,"categories":2931,"tags":2933,"image":2873,"readingTime":247,"canonical":2865,"sites":2934,"series":2873,"seriesOrder":2873},"Infrastructure: Documenting an Undocumented Network, Discovery First","Document an undocumented network from what it already knows: DHCP leases, AD, ARP and switch MAC tables, then a scoped nmap pass. Scripts included.","2026-07-15T14:00:00Z",[2868,2932],"strategy",[2881,2916,206],[2865],{"doc":2873,"posts":2936},[],1790052513237]