Determine Power-CLI Object-Type

Background

If you needed to pass some „Objects“ to a Power-Shell function you need the name of their Types.

Example

Four Parameters need to be passed to the function:

  • two Objects
    1. VI-Server
    2. Virtual-Machine
  • two Strings:
    1. diskName
    2. diskSize
function resizeVMDisk { Param([VMware.VimAutomation.ViCore.Types.V1.VIServer]$server, [VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine]$vm, [string]$diskName, [string]$diskSize)

Algorithm

  1. Find an existing PowerCLI-Function which already uses the Object-Parameter you need.

In my case:

Get-VMHost

2) Pull the MetaData of this Command.

3) Display the „Attributes“ of the relevant Object-Parameter

4) Look for „Target Type List“

Result

„VM“ = [VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine]

„Server“ = [VMware.VimAutomation.ViCore.Types.V1.VIServer]

Example

C:\LAB> $cmd = Get-Command -Module VMware.VimAutomation.Core -Name Get-VMHost
C:\LAB> $meta = New-Object System.Management.Automation.CommandMetadata ($cmd)
C:\LAB> $meta

Name                    : Get-VMHost
CommandType             : VMware.VimAutomation.ViCore.Cmdlets.Commands.GetVMHost
DefaultParameterSetName : Default
SupportsShouldProcess   : False
SupportsPaging          : False
PositionalBinding       : True
SupportsTransactions    : False
HelpUri                 :
RemotingCapability      : PowerShell
ConfirmImpact           : None
Parameters              : {[Name, System.Management.Automation.ParameterMetadata], [NoRecursion, System.Management.Automation.ParameterMetadata], [VM,
                          System.Management.Automation.ParameterMetadata], [ResourcePool, System.Management.Automation.ParameterMetadata]…}


C:\LAB> $meta.Parameters["VM"].Attributes

Position                        : -2147483648
ParameterSetName                : SecondaryParameterSet
ValueFromPipeline               : True
Mandatory                       : False
ExperimentName                  :
ExperimentAction                : None
ValueFromPipelineByPropertyName : False
ValueFromRemainingArguments     : False
HelpMessage                     :
HelpMessageBaseName             :
HelpMessageResourceId           :
DontShow                        : False
TypeId                          : System.Management.Automation.ParameterAttribute

TypeId : System.Management.Automation.ValidateNotNullOrEmptyAttribute

Critical                        : True
ContextPrincipalName            :
ContextOptional                 : False
ContextRelationName             :
TargetTypeList                  : {VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine}
TransformNullOptionalParameters : True
TypeId                          : VMware.VimAutomation.Sdk.Util10Ps.BaseCmdlet.ObnArgumentTransformationAttribute


C:\LAB> $meta.Parameters["Server"].Attributes

Position                        : -2147483648
ParameterSetName                : Default
ValueFromPipeline               : False
Mandatory                       : False
ExperimentName                  :
ExperimentAction                : None
ValueFromPipelineByPropertyName : False
ValueFromRemainingArguments     : False
HelpMessage                     :
HelpMessageBaseName             :
HelpMessageResourceId           :
DontShow                        : False
TypeId                          : System.Management.Automation.ParameterAttribute

Position                        : -2147483648
ParameterSetName                : ById
ValueFromPipeline               : False
Mandatory                       : False
ExperimentName                  :
ExperimentAction                : None
ValueFromPipelineByPropertyName : False
ValueFromRemainingArguments     : False
HelpMessage                     :
HelpMessageBaseName             :
HelpMessageResourceId           :
DontShow                        : False
TypeId                          : System.Management.Automation.ParameterAttribute

Position                        : -2147483648
ParameterSetName                : DistributedSwitch
ValueFromPipeline               : False
Mandatory                       : False
ExperimentName                  :
ExperimentAction                : None
ValueFromPipelineByPropertyName : False
ValueFromRemainingArguments     : False
HelpMessage                     :
HelpMessageBaseName             :
HelpMessageResourceId           :
DontShow                        : False
TypeId                          : System.Management.Automation.ParameterAttribute

Position                        : -2147483648
ParameterSetName                : SecondaryParameterSet
ValueFromPipeline               : False
Mandatory                       : False
ExperimentName                  :
ExperimentAction                : None
ValueFromPipelineByPropertyName : False
ValueFromRemainingArguments     : False
HelpMessage                     :
HelpMessageBaseName             :
HelpMessageResourceId           :
DontShow                        : False
TypeId                          : System.Management.Automation.ParameterAttribute

Critical                        : True
ContextPrincipalName            :
ContextOptional                 : False
ContextRelationName             :
TargetTypeList                  : {VMware.VimAutomation.ViCore.Types.V1.VIServer}
TransformNullOptionalParameters : True
TypeId                          : VMware.VimAutomation.Sdk.Util10Ps.BaseCmdlet.ObnArgumentTransformationAttribute

VMware ESXi: Generate Self-Signed Certificate for FQDN and retrieve SSL-Thumbprint

Background

VMware wants us to prepopulate an Excel-Sheet with SSH-Keys and SSL-Thumbprints of all ESXi-Hosts, who have been freshly deployed minutes before, which effectivly protects against man-in-the-middle-attacks – maybe a problem in US-datacenters.

Beginning with VMware Cloud Foundation Release VCF 4.2 the Cloud-Builder-App verifies the „CN“ of all ESXi-SSL-Certificates, which is in default-setup set to „localhost“ (to be overwritten when connecting to the vCenter so this is seemed to be no issue) – not accepted, CN has to be set to <server-fqdn>.

VCF PreCheck: SSL Certificate CN Error

Solution

plink.exe

„plink.exe“ from the Putty-Suite allows to be called from PowerShell in automated fashion without interactive Password-Prompt. (In May 2021 there seems to be no other choice for Power-Shell Core 7)

Algorithm

  1. generate „correct“ self-signed certificate with „CN“ set to „fqdn“ not for „localhost“
  2. read the new certificate SSL-sha256-thumbprint
  3. reboot the ESXi-Host to activate the new SSL-Server-Certificate

Result

Correct SSL Server-Certificate

Server SSL-Certificate with correct CN

Log for four ESXi-Hosts

Contains SSL-Thumbprints to get copied into the VCF-Excel-Sheet.

Variables

  • $VMPassword
  • $VMUsername

have to be prepopulated.

PS T:\vmware vcf4> .\esxi_ssl_ssh.ps1
Generate SSL Self-Signed Certificate [ham01-m01-esx01]
Keyboard-interactive authentication prompts from server:
End of keyboard-interactive prompts from server
Fetch SSL-Thumbprint
Generate SSL Self-Signed Certificate [ham01-m01-esx02]
Keyboard-interactive authentication prompts from server:
End of keyboard-interactive prompts from server
Fetch SSL-Thumbprint
Generate SSL Self-Signed Certificate [ham01-m01-esx03]
Keyboard-interactive authentication prompts from server:
End of keyboard-interactive prompts from server
Fetch SSL-Thumbprint
Generate SSL Self-Signed Certificate [ham01-m01-esx04]
Keyboard-interactive authentication prompts from server:
End of keyboard-interactive prompts from server
Fetch SSL-Thumbprint

*** Result ***
172.16.11.101 ham01-m01-esx01
SSL-Thumbprint: D2:6E:01:AD:36:82:3E:D2:AC:F3:66:6E:27:FC:A5:2C:26:99:57:8D:E6:D9:24:E3:42:61:F3:C3:52:65:8C:36
172.16.11.102 ham01-m01-esx02
SSL-Thumbprint: 21:67:3F:11:E4:FE:F3:D2:D9:C6:C2:66:85:7D:3D:3F:02:49:F2:FE:D6:74:86:E1:8E:BE:CC:A2:66:41:72:D2
172.16.11.103 ham01-m01-esx03
SSL-Thumbprint: F6:D3:12:BD:53:36:F0:E5:FD:C9:F9:3C:41:60:80:79:C8:C4:69:30:52:AF:6C:AF:24:C3:C6:DE:2A:75:80:14
172.16.11.104 ham01-m01-esx04
SSL-Thumbprint: AC:0B:D0:E3:6D:03:12:3F:7E:69:5F:0F:75:F0:F5:F2:E1:59:61:46:83:35:1F:AD:2C:15:9D:EB:C1:9D:EF:DE

PowerShell Sourcecode

$NestedESXiHosts = @{
    "ham01-m01-esx01"=@{"vmk0"="172.16.11.101"};
    "ham01-m01-esx02"=@{"vmk0"="172.16.11.102"};
    "ham01-m01-esx03"=@{"vmk0"="172.16.11.103"};
    "ham01-m01-esx04"=@{"vmk0"="172.16.11.104"};
}

$NestedESXiHosts.GetEnumerator() | Sort-Object -Property key | Foreach-Object {
	$VMName = $_.Key
	$VMIPAddress = $_.Value.vmk0
	
	write-host -ForegroundColor Green "Generate SSL Self-Signed Certificate [$VMName]"
	#
	$SSLThumbPrint = echo y | plink -ssh -pw $VMPassword $VMUsername@$VMIPAddress "/sbin/generate-certificates;openssl x509 -in /etc/vmware/ssl/rui.crt -fingerprint -sha256 -noout;reboot;"
    #
	write-host -ForegroundColor Green "Fetch SSL-Thumbprint"
	#
	$SSLThumbPrint = $SSLThumbPrint.split("=")[1]
	$_.Value.SSL = $SSLThumbPrint
}

write-host
write-host -ForegroundColor Green "*** Result ***"

$NestedESXiHosts.GetEnumerator() | Sort-Object -Property key | Foreach-Object {
	$VMName = $_.Key
	$VMIPAddress = $_.Value.vmk0
	$VMSSL = $_.Value.SSL
	write-host -ForegroundColor Green "$VMIPAddress $VMName"
	write-host "SSL-Thumbprint: $VMSSL"
}              

Firefox: Allow Restricted TCP-Ports

Disclaimer

I don’t think, „hiding“ a webserver behind a non-standard TCP-Port is a security feature („security by obscurity“) but on the other hand restricting access to non-standard Ports seems to not increase the personal security measure, it just wastes time of anybody who needs to access such a service – and – it’s absolutely allowed to run a web-server on any port which isn’t used by another service 😉

Solution (if you (think, you) know what you’re doing)

As always

about:config

Add as „String“ if it’s missing:

network.security.ports.banned.override

Add the Service you want to acccess

8081,8082,8083

Disclaimer

Since i’m trying to get rid of Evernote, too anoying too often, i’ll start to document non-private-stuff here.

Virtual Machine with direct Storage Access

Business Case

My QNAP-NAS (TS-431X2) is slow

  • this must not be QNAPs fault, maybe the drives (4 disks, RAID5, between 147..167 MB/second for sequential read) are the root cause
  • adding a SSD-Cache didn’t improve performance when I had a 3-disk RAID 5
    • many people around the world are troubleshooting this without success

so I decided to

  1. use the QNAP-NAS as a Virtual-Tape-Library for Backup-Purposes etc
  2. use my ESXi-Host as Storage-Server

„Storage Server“ VM

I regularily use „Nested ESXi“-Hosts for Lab Environments which should access the storage, so I decided to first give NFS a try – ESXi has no built in NFS-Server, so a small VM using Free-NAS, True-NAS, I didn’t decide yet, should provide „feature parity“ to the QNAP System.

RDM is no option

Adding my former „QNAP Cache SSD“ to the ESXi-Host showed that it was impossible (as expected) to passthrough this disk to a VM.

RDM is no option since it doesn’t allow direct hardware access, eg. SMART-Counters or other statistics.

PCIe SATA-Controller: Dell PERC H310

A PERC H310 can get used as a passthrough device for a VM which will get full hardware access for up to 8 disks.

  • as far I remember, this hardware has been released in 2011, but it might still be fast enough to be no bottleneck

IT Firmware

There’s nothing wrong with the original H310-RAID-Firmware, but since I won’t need those features i’d prefer the „IT“-Firmware, which offers much larger buffers to handle bursts easily.

This firmware has to be programmed, a lot of guides for this exist – I had to combine https://www.vladan.fr/flash-dell-perc-h310-with-it-firmware/ providing a link to a nice Dell-Firmware („6gbpsas.fw“) and a precise description what to do – but the „megarec.exe“ found in the archive didn’t work at my Asus mainboard („Error 8192“) so I found another megarec-release https://www.taste-of-it.de/flash-dell-perc-h310-mit-lsi-9211-8i-it-mode/ here.

[root@esx:~] esxcli hardware pci list | egrep -B8 -A26 "Device Name: Dell"
0000:06:00.0
   Address: 0000:06:00.0
   Segment: 0x0000
   Bus: 0x06
   Slot: 0x00
   Function: 0x0
   VMkernel Name: vmhba2
   Vendor Name: LSI Logic / Symbios Logic
   Device Name: Dell 6Gbps SAS HBA Adapter
   Configured Owner: VMkernel
   Current Owner: VMkernel
   Vendor ID: 0x1000
   Device ID: 0x0072
   SubVendor ID: 0x1028
   SubDevice ID: 0x1f1c
   Device Class: 0x0107
   Device Class Name: Serial Attached SCSI controller
   Programming Interface: 0x00
   Revision ID: 0x03
   Interrupt Line: 0x05
   IRQ: 5
   Interrupt Vector: 0x35
   PCI Pin: 0x00
   Spawned Bus: 0x00
   Flags: 0x3201
   Module ID: 4161
   Module Name: mpt2sas
   Chassis: 0
   Physical Slot: 1
   Slot Description: PCIE1
   Passthru Capable: true
   Parent Device: PCI 0:0:28:0
   Dependent Device: PCI 0:6:0:0
   Reset Method: Function reset
   FPT Sharable: true

[root@esx:~] esxcli device driver list
Device   Driver    Status  KB Article
-------  --------  ------  ----------
vmnic0   igbn      normal
vmhba2   mpt2sas   normal
vmnic2   ixgben    normal
vmhba1   vmw_ahci  normal
vmhba32  vmkusb    normal
vmnic1   igbn      normal
vmhba0   vmw_ahci  normal

[root@esx:~] esxtop
 4:48:13pm up 19 min, 852 worlds, 5 VMs, 17 vCPUs; CPU load average: 0.03, 0.03, 0.12

 ADAPTR PATH                 NPTH AQLEN   CMDS/s  READS/s WRITES/s MBREAD/s MBWRTN/s DAVG/cmd KAVG/cmd GAVG/cmd QAVG/cmd
 vmhba0 -                       1   992     0.77     0.19     0.58     0.00     0.00     0.71     0.03     0.74     0.01
 vmhba1 -                       1   992     0.00     0.00     0.00     0.00     0.00     0.00     0.00     0.00     0.00
 vmhba2 -                       1   600     0.00     0.00     0.00     0.00     0.00     0.00     0.00     0.00     0.00
vmhba64 -                       0  1024     0.00     0.00     0.00     0.00     0.00     0.00     0.00     0.00     0.00

PCIe-Passthrough

Passthrough has to be enabled manually, reboot the host and voila:

Dell PERC H310 IT-Firmware: Passthrough active

Now this device can get added to _one_ VM:

Add other device: PCI device
New PCI Device: Controller Passthrough

The (Ubuntu 20.04 Server-)VM seems to be fine with this setup:

Disk as seen by the VM

Azure Regions on Request

According to https://docs.microsoft.com/en-us/azure/best-practices-availability-paired-regions there is a Regional-Pair to „Germany West Central“ called „Germany North“ which is missing at https://azure.microsoft.com/en-us/global-infrastructure/geographies since access is restricted to support specific customer scenarios, for example in-country disaster recovery. These regions are available only upon request by creating a new support request in the Azure portal

Germany North could be found in the list (https://azure.microsoft.com/en-us/global-infrastructure/geographies/#new-regions) so it might be coming soon for general availability.

List available Azure-Locations

C:\RH> az account list-locations --query "[].{name:name}" -o table
Name
-------------------
eastus
eastus2
southcentralus
westus2
australiaeast
southeastasia
northeurope
uksouth
westeurope
centralus
northcentralus
westus
southafricanorth
centralindia
eastasia
japaneast
jioindiawest
koreacentral
canadacentral
francecentral
germanywestcentral
norwayeast
switzerlandnorth
uaenorth
brazilsouth
centralusstage
eastusstage
eastus2stage
northcentralusstage
southcentralusstage
westusstage
westus2stage
asia
asiapacific
australia
brazil
canada
europe
global
india
japan
uk
unitedstates
eastasiastage
southeastasiastage
centraluseuap
eastus2euap
westcentralus
westus3
southafricawest
australiacentral
australiacentral2
australiasoutheast
japanwest
koreasouth
southindia
westindia
canadaeast
francesouth
germanynorth
norwaywest
switzerlandwest
ukwest
uaecentral
brazilsoutheast

Visio Diagrams with Python: Resize to fit

Resize Page to Fit Contents, Set Zoom to Fit Page

When the drawing is ready, the size of the page will be too large or too small – „fit to contents“ might be the solution.

Additionally, I prefer the Zoom of the active Window to be set that it shows the whole drawing.

page.ResizeToFitContents()      #https://docs.microsoft.com/de-de/office/vba/api/visio.page.resizetofitcontents
window = visio.ActiveWindow     #https://docs.microsoft.com/de-de/office/vba/api/visio.application.activewindow
window.ViewFit=1                #https://docs.microsoft.com/de-de/office/vba/api/visio.window.viewfit

Result

Visio Diagrams with Python: Colors

24 Colors to choose from.

„Cells“ contain all „Shape-Format“-Properties

Details: https://docs.microsoft.com/en-us/office/client-developer/visio/cells-visio-shapesheet-reference

# Line-Color
# https://docs.microsoft.com/de-de/office/client-developer/visio/linecolor-cell-line-format-section
oval2.Cells("LineColor").FormulaForce = 3

# Fill-Color
# https://docs.microsoft.com/de-de/office/client-developer/visio/fillforegnd-cell-fill-format-section
rect1.Cells("FillForegnd").FormulaForce=3

# Fill-Pattern "0" - no fill
# https://docs.microsoft.com/de-de/office/client-developer/visio/fillpattern-cell-fill-format-section
rect2.Cells("FillPattern").FormulaForce=0

# Fill-Pattern "3"

# yellow background
# https://docs.microsoft.com/de-de/office/client-developer/visio/fillbkgnd-cell-fill-format-section
#
# light-blue foreground
#
oval1.Cells("FillPattern").FormulaForce = 3
oval1.Cells("FillBkgnd").FormulaForce = 5
oval1.Cells("FillForegnd").FormulaForce = 7

Result

Visio Diagrams with Python: Connectors

Connect two existing Shapes

The API is somehow weird, since it creates an (Shape-)Object, but it doesn’t return it.

  • you’ll have to fetch the last object in the shapes-List
#https://docs.microsoft.com/en-us/office/vba/api/visio.shape.autoconnect
rect1.AutoConnect(rect2,0)
#
#https://docs.microsoft.com/en-us/office/vba/api/visio.shapes.itemu
connector1=shapes.ItemU(len(shapes))
#
connector1.Text = "Connector1"
# 
#https://docs.microsoft.com/de-de/office/client-developer/visio/linecolor-cell-line-format-section
# * color "3" is "light green"
connector1.Cells("LineColor").FormulaForce = 3
#
#https://docs.microsoft.com/de-de/office/client-developer/visio/conlinerouteext-cell-shape-layout-section
# * ConLineRouteExt "2" is "Curved"
connector1.Cells("ConLineRouteExt").FormulaForce = 2

Result

>>> len(shapes)
6

Visio Diagrams with Python: Stencils

Stencils and Stencil-Files

Stencils are stored in „VSSX“-Files

server_stencils_filename = "C:\Program Files (x86)\Microsoft Office\root\Office16\Visio Content\1031\SERVER_M.VSSX"

#64 means “open hidden”
server_stencils = visio.Documents.OpenEx(server_stencils_filename,64)

ftp_stencil=server_stencils.Masters("FTP-Server")

Page-Object

Add a FTP-Server to the page

ftp1 = page.Drop(ftp_stencil,3,3)
ftp1.Text = "FTP-Server#1"

Result

>>> len(shapes)
5

Visio Diagrams with Python using COM

Visualize Data from Python in Visio

I needed to illustrate some data discovered by a python script in Microsoft Visio.

As a starting-point i found two sources of infomation in the Internet:

(1) Python => COM => MS Excel

How to access a Windows COM-Application from Python: https://pbpython.com/windows-com.html

  • MS Excel not Visio
  • but 50% of the information needed

(2) PowerShell => COM => MS Visio

How to access Microsoft Visio using the COM-Interface https://www.powershellstation.com/2016/01/20/powershell-and-visio-1

  • PowerShell
  • the other 50% needed.

Result: „Python => COM => MS Visio“

Putting both pieces together, will allow a Python-Script to control MS Visio.

(3) MS Visio „Object Model“

Without the original documentation provided by Microsoft: https://docs.microsoft.com/en-us/office/vba/api/overview/visio there is _no chance_ to get anything to work.

  • the next 50% 😉

The Basics

(1) Python „PyWin32“

Install „PyWin32“-Library

C:\RH>pip install pywin32
Collecting pywin32
  Downloading pywin32-300-cp38-cp38-win_amd64.whl (9.3 MB)
     |████████████████████████████████| 9.3 MB 2.2 MB/s
Installing collected packages: pywin32
Successfully installed pywin32-300

Access Windows/COM from Python

  • open the Visio-Application
    • „visio“-object: stores a pointer to access application-Level functions
  • add a document
    • „document“-object
  • fetch the active Visio-Page
    • „page“-object
  • fetch the list of all Shapes at this page
    • „shapes“-object
import win32com.client as win32
#
visio = win32.gencache.EnsureDispatch('Visio.Application')
document = visio.Documents.Add("")
#
page = visio.ActivePage
#
shapes = page.Shapes

(2) Explore the Visio-Object-Model

Methods

Object-Methods could get discovered using the Python „dir“, notice for example

  • DrawOval
  • DrawRectangle
>>> dir(page)
['AddDataVisualization', 'AddGuide', 'AutoConnectMany', 'AutoSizeDrawing', 'AvoidPageBreaks', 'BoundingBox', 'CLSID', 'CenterDrawing', 'CreateDataVisualizerDiagram', 'CreateSelection', 'Delete', 'DrawArcByThreePoints', 'DrawBezier', 'DrawCircularArc', 'DrawLine', 'DrawNURBS', 'DrawOval', 'DrawPolyline', 'DrawQuarterArc', 'DrawRectangle', 'DrawSpline', 'Drop', 'DropCallout', 'DropConnected', 'DropContainer', 'DropIntoList', 'DropLegend', 'DropLinked', 'DropMany', 'DropManyLinkedU', 'DropManyU', 'Duplicate', 'Export', 'GetCallouts', 'GetContainers', 'GetFormulas', 'GetFormulasU', 'GetResults', 'GetShapesLinkedToData', 'GetShapesLinkedToDataRow', 'GetTheme', 'GetThemeVariant', 'Import', 'InsertFromFile', 'InsertObject', 'Layout', 'LayoutChangeDirection', 'LayoutIncremental', 'LinkShapesToDataRows', 'OpenDrawWindow', 'Paste', 'PasteSpecial', 'PasteToLocation', 'Print', 'PrintTile', 'ResizeToFitContents', 'SetFormulas', 'SetResults', 'SetTheme', 'SetThemeVariant', 'ShapeIDsToUniqueIDs', 'SpatialSearch', 'SplitConnector', 'UniqueIDsToShapeIDs', 'VisualBoundingBox', '_ApplyTypes_', '__call__', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattr__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__int__', '__iter__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_get_good_object_', '_get_good_single_object_', '_oleobj_', '_prop_map_get_', '_prop_map_put_', 'coclass_clsid', 'old_Paste', 'old_PasteSpecial']

Properties

But Object-Parameters won’t and if you don’t want to guess required parameters of Object-Methods, it’s time to bookmark the original documentation provided by Microsoft: https://docs.microsoft.com/en-us/office/vba/api/overview/visio

Start drawing

Page-Object

A good starting point might be the „Page“-Object: https://docs.microsoft.com/en-us/office/vba/api/visio.page

Well add „Shapes“ to the „Page“(-Object) using Methods of the Page-Object:

https://docs.microsoft.com/en-us/office/vba/api/visio.page.drawrectangle or https://docs.microsoft.com/en-us/office/vba/api/visio.page.drawoval – both Methods will return an „Shape“-Object.

#https://docs.microsoft.com/en-us/office/vba/api/visio.page.drawrectangle
rect1 = page.DrawRectangle(1,1,2,2)
rect2 = page.DrawRectangle(4,4,5,5)
#
#https://docs.microsoft.com/en-us/office/vba/api/visio.page.drawoval
oval1 = page.DrawOval(1,4,2,5)
oval2 = page.DrawOval(4,1,5,2)

Shape Object

Look at https://docs.microsoft.com/en-us/office/vba/api/visio.shape – there’s a „Text“-Property:

#https://docs.microsoft.com/en-us/office/vba/api/visio.shape
#https://docs.microsoft.com/en-us/office/vba/api/visio.shape.text
rect1.Text="Rect1"
rect2.Text="Rect2"
oval1.Text="Oval1"
oval2.Text="Oval2"

Result

>>> len(shapes)
4