script to download:
python_hyper-v_topology_grapher.py
The following code retrieves information about virtual switches (VMSwitches) and virtual machine network adapters (VMNetworkAdapters) in Hyper-V. It then builds a graph, where the nodes are the virtual switches and VMs, and the edges represent the connections between these elements. The whole thing is visualised using the Matplotlib library.
The programme consists of several functions that perform various tasks:
def get_vmswitches(): """ Use PowerShell to get Hyper-V virtual switches as JSON. """ cmd = ["powershell", "-Command", "Get-VMSwitch | ConvertTo-Json"] proc = subprocess.run(cmd, capture_output=True, text=True) try: switches = json.loads(proc.stdout) except json.JSONDecodeError as e: print("Error decoding JSON for switches:", e) print("PowerShell output was:", proc.stdout) switches = [] # Ensure the data is a list if isinstance(switches, dict): switches = [switches] return switches
This function uses PowerShell to retrieve information about the virtual switches on the Hyper-V system and then converts the result into JSON format. If the JSON decoding fails, it prints an error message and returns an empty list. If the data is not in list form, the function converts it to a list.
def get_vmnetworkadapters(): """ Use PowerShell to get Hyper-V VM network adapters as JSON. This version pipes all VMs to Get-VMNetworkAdapter to ensure we get data. """ # Updated command to get network adapters from all VMs cmd = ["powershell", "-Command", "Get-VM | Get-VMNetworkAdapter | ConvertTo-Json"] proc = subprocess.run(cmd, capture_output=True, text=True) if proc.stderr: print("PowerShell error output:", proc.stderr) try: adapters = json.loads(proc.stdout) except json.JSONDecodeError as e: print("Error decoding JSON for adapters:", e) print("PowerShell output was:", proc.stdout) adapters = [] # Ensure the data is a list if isinstance(adapters, dict): adapters = [adapters] return adapters
This function works similarly to the previous one, but instead of virtual switches, it fetches data about the network adapters of the virtual machines in Hyper-V. In case of errors during JSON decoding, it prints an error message and returns an empty list.
def build_graph(switches, adapters): """ Build a graph with virtual switches as one type of node and VMs as another. An edge represents a connection between a VM and a virtual switch. """ G = nx.Graph() # Add virtual switch nodes for sw in switches: sw_name = sw.get("Name") if sw_name: G.add_node(sw_name, type="switch") # Add VM nodes and edges based on network adapter connections for adapter in adapters: vm_name = adapter.get("VMName") switch_name = adapter.get("SwitchName") if vm_name: G.add_node(vm_name, type="vm") # Create an edge if the adapter is connected to a switch if switch_name: G.add_edge(vm_name, switch_name) return G
This function creates a graph using the NetworkX library. It adds nodes to the graph representing virtual switches (of type 'switch') and virtual machines (of type 'vm'). The edges of the graph are created between the VMs and the virtual switches if a network adapter is connected to the switch in question.
def draw_graph(G): """ Draw the graph using matplotlib. Switches are drawn as squares (blue) and VMs as circles (green). """ pos = nx.spring_layout(G, k=1.0, iterations=100, seed=42) # For consistent layout # Separate nodes by type for custom styling switch_nodes = [n for n, d in G.nodes(data=True) if d.get("type") == "switch"] vm_nodes = [n for n, d in G.nodes(data=True) if d.get("type") == "vm"] plt.figure(figsize=(10, 8)) nx.draw_networkx_nodes(G, pos, nodelist=switch_nodes, node_color='lightblue', node_shape='s', node_size=1500, label="Virtual Switch") nx.draw_networkx_nodes(G, pos, nodelist=vm_nodes, node_color='lightgreen', node_shape='o', node_size=1500, label="Virtual Machine") nx.draw_networkx_edges(G, pos) nx.draw_networkx_labels(G, pos, font_size=10) plt.title("Hyper-V Topology: Virtual Switches & VMs") plt.axis('off') plt.legend(scatterpoints=1, labelspacing=1.5, handletextpad=1.0, borderaxespad=1.0) plt.tight_layout() plt.show()
This function is responsible for visualising the graph using the Matplotlib library. Nodes representing virtual switches are drawn as blue squares and nodes representing virtual machines are drawn as green circles. The edges of the graph represent the connections between the switches and the virtual machines.
def main(): print("Extracting Hyper-V virtual switches...") switches = get_vmswitches() print(f"Found {len(switches)} switch(es).") print("Extracting Hyper-V VM network adapters...") adapters = get_vmnetworkadapters() print(f"Found {len(adapters)} network adapter(s).") if not switches and not adapters: print("No data retrieved. Ensure Hyper-V is installed and you have proper permissions.") return graph = build_graph(switches, adapters) draw_graph(graph)
The `main` function starts the process of collecting data about the virtual switches and network adapters of the virtual machines, and then builds and draws a graph representing this data. This function is the entry point of the programme and is started when the programme is executed directly.
if __name__ == "__main__": main()
This is the standard way of running a program in Python. If the script is run directly, the `main()` function is called, which starts the whole process.
The code is used to retrieve data about the virtual switches and network adapters of virtual machines in Hyper-V, build a graph representing these elements, and then visualise this graph using the Matplotlib library. It uses PowerShell to retrieve the data and NetworkX to manipulate the graph.