The Wiert Corner – irregular stream of stuff

Jeroen W. Pluimers on .NET, C#, Delphi, databases, and personal interests

  • My badges

  • Twitter Updates

  • My Flickr Stream

  • Pages

  • All categories

  • Enter your email address to subscribe to this blog and receive notifications of new posts by email.

    Join 4,262 other subscribers

Archive for April 29th, 2021

VMware ESXi console: viewing all VMs, suspending and waking them up: part 4

Posted by jpluimers on 2021/04/29

Yesterday we ended with an overview of available and unavailable vim-cmd vmsvc commands and the promise to try running the various power commands on all relevant VMs.

Let’s start with a summary of the commands, so it will be easier to make a list of scripts to run them on relevant VMs.

Available commands

  • vim-cmd vmsvc/power.getstate vmid
  • vim-cmd vmsvc/power.hibernate vmid
  • vim-cmd vmsvc/power.off vmid
  • vim-cmd vmsvc/power.on vmid
  • vim-cmd vmsvc/power.reboot vmid
  • vim-cmd vmsvc/power.reset vmid
  • vim-cmd vmsvc/power.shutdown vmid
  • vim-cmd vmsvc/power.suspend vmid
  • vim-cmd vmsvc/power.suspendResume vmid

Unavailable commands

  • vim-cmd vmsvc/power.startup vmid
  • vim-cmd vmsvc/power.resume vmid
  • vim-cmd vmsvc/power.wakeup vmid

List the vmid values, power status and name of all VMs

Getting the vmid

Yesterday I showed a small statement that gives the list of vmid values on an ESXi system:

vim-cmd vmsvc/getallvms | sed -n -E -e "s/^([[:digit:]]+)s+((S.+S)?)s+([S+])s+(.+.vmx)s+(S+)s+(vmx-[[:digit:]]+)s*?((S.+)?)$/1/p"

What I ideally want is not just the vmid and name for each VM from vim-cmd vmsvc/getallvms, but also get the power state information from vim-cmd vmsvc/power.getstate vmid.

For that, we need to parse the output of vim-cmd vmsvc/power.getstate vmid, which can be three outputs:

  • Retrieved runtime info
    Powered off
  • Retrieved runtime info
    Powered on
  • Retrieved runtime info
    Suspended

So basically it involves deleting the first line which was covered in part 2 of this installment, for example on my system:

# vim-cmd vmsvc/power.getstate 10 | sed '1d'
Powered on

Getting VM name

Extracting both vmid and name from vim-cmd vmsvc/getallvms at the same time is not easy, heck even impossible, so I decided to go the vim-cmd vmsvc/get.config vmid way.

Getting multiple values out of some output is already very hard in bash, where usually the less difficult way is to use arrays. Since Busybox has an ash shell (see Busybox sh (actually ash derivative dash): checking exit codes), and ash does not do arrays, that route is gone.

To give you an idea how hard this is in bash and how to sort of workaround the lack of array support in ash:

This partial vim-cmd vmsvc/get.config vmid sample output on one of my VMs that shows how to use head -n 31 to get just the first 31 lines of output:

# vim-cmd vmsvc/get.config 10 | head -n 31
Configuration:

(vim.vm.ConfigInfo) {
   changeVersion = "2021-04-07T22:08:30.548274Z", 
   modified = "1970-01-01T00:00:00Z", 
   name = "X9SRI-3F-W10P-EN-MEDIA", 
   guestFullName = "Microsoft Windows 10 (64-bit)", 
   version = "vmx-14", 
   uuid = "564d51ac-f6cf-e40b-b686-2f53a28a4bea", 
   createDate = "2019-05-17T21:37:11.408173Z", 
   instanceUuid = "52403d0e-7ccd-48da-bb21-7e966defccf7", 
   npivNodeWorldWideName = , 
   npivPortWorldWideName = , 
   npivWorldWideNameType = , 
   npivDesiredNodeWwns = , 
   npivDesiredPortWwns = , 
   npivTemporaryDisabled = true, 
   npivOnNonRdmDisks = , 
   locationId = "564d6b18-ecd1-2261-0127-146b3f3bc636", 
   template = false, 
   guestId = "windows9_64Guest", 
   alternateGuestName = "", 
   annotation = "", 
   files = (vim.vm.FileInfo) {
      vmPathName = "[EVO860_500GB] VM/X9SRI-3F-W10P-EN-MEDIA/X9SRI-3F-W10P-EN-MEDIA.vmx", 
      snapshotDirectory = "[EVO860_500GB] VM/X9SRI-3F-W10P-EN-MEDIA", 
      suspendDirectory = "[EVO860_500GB] VM/X9SRI-3F-W10P-EN-MEDIA", 
      logDirectory = "[EVO860_500GB] VM/X9SRI-3F-W10P-EN-MEDIA", 
      ftMetadataDirectory = 
   }, 
   tools = (vim.vm.ToolsConfigInfo) {

The reason to go the vim-cmd vmsvc/get.config vmid way is that it contains all the configuration info in a kind of JSON format (except the first two lines) and should be relatively easy to parse. Or so at least I hoped.

Basically I am interested in the value of name = "X9SRI-3F-W10P-EN-MEDIA", however, there are multiple name fields in the total configuration:

# vim-cmd vmsvc/get.config 10 | sed -n -E '/name =/p'
   name = "X9SRI-3F-W10P-EN-MEDIA", 
         name = "EVO860_500GB",

So what I really want is the value of name = "X9SRI-3F-W10P-EN-MEDIA", in between the (vim.vm.ConfigInfo) { and files = (vim.vm.FileInfo) { parts.

This can be done using sed as it allows to specify a range using a start and end value using addresses:

  • [Wayback] sed: Addresses in sed

    An address is either a decimal number that counts input lines cumulatively across files, a '$' character that addresses the last line of input, or a context address (which consists of a BRE, as described in Regular Expressions in sed , preceded and followed by a delimiter, usually a slash).

    An editing command with no addresses shall select every pattern space.

    An editing command with one address shall select each pattern space that matches the address.

    An editing command with two addresses shall select the inclusive range from the first pattern space that matches the first address through the next pattern space that matches the second. (If the second address is a number less than or equal to the line number first selected, only one line shall be selected.) Starting at the first line following the selected range, sed shall look again for the first address. Thereafter, the process shall be repeated. Omitting either or both of the address components in the following form produces undefined results:

    [address[,address]]
  • Range Addresses (sed, a stream editor)[Wayback] Range Addresses (sed, a stream editor)

    An address range can be specified by specifying two addresses separated by a comma (,). An address range matches lines starting from where the first address matches, and continues until the second address matches (inclusively):

    $ seq 10 | sed -n '4,6p'
    4
    5
    6
    

    If the second address is a regexp, then checking for the ending match will start with the line following the line which matched the first address: a range will always span at least two lines (except of course if the input stream ends).

  • [Wayback] Regexp Addresses (sed, a stream editor)

For example (with some characters escaped because of [Wayback] ERE syntax (sed, a stream editor)):

# vim-cmd vmsvc/get.config 10 | sed -n -E -e '/\(vim.vm.ConfigInfo\) \{/,/files = \(vim.vm.FileInfo\) \{/p'
(vim.vm.ConfigInfo) {
   changeVersion = "2021-04-07T22:08:30.548274Z", 
   modified = "1970-01-01T00:00:00Z", 
   name = "X9SRI-3F-W10P-EN-MEDIA", 
   guestFullName = "Microsoft Windows 10 (64-bit)", 
   version = "vmx-14", 
   uuid = "564d51ac-f6cf-e40b-b686-2f53a28a4bea", 
   createDate = "2019-05-17T21:37:11.408173Z", 
   instanceUuid = "52403d0e-7ccd-48da-bb21-7e966defccf7", 
   npivNodeWorldWideName = , 
   npivPortWorldWideName = , 
   npivWorldWideNameType = , 
   npivDesiredNodeWwns = , 
   npivDesiredPortWwns = , 
   npivTemporaryDisabled = true, 
   npivOnNonRdmDisks = , 
   locationId = "564d6b18-ecd1-2261-0127-146b3f3bc636", 
   template = false, 
   guestId = "windows9_64Guest", 
   alternateGuestName = "", 
   annotation = "", 
   files = (vim.vm.FileInfo) { 

With [Wayback] BRE syntax (sed, a stream editor) the filter part would be easier: vim-cmd vmsvc/get.config 10 | sed -n -e '/(vim.vm.ConfigInfo) {/,/files = (vim.vm.FileInfo) {/p', but the print part would be more difficult:

  • # vim-cmd vmsvc/get.config 10 | sed -n -E -e '/\(vim.vm.ConfigInfo\) \{/,/files = \(vim.vm.FileInfo\) \{/ s/^ +name = "(.*)",.*?/1/p'
    X9SRI-3F-W10P-EN-MEDIA
    
  • # vim-cmd vmsvc/get.config 10 | sed -n -e '/(vim.vm.ConfigInfo) {/,/files = (vim.vm.FileInfo) {/ s/^ +name = "(.*)",.*?/1/p'
    X9SRI-3F-W10P-EN-MEDIA

Since I am used to extended regular expressions (ERE) over basica regular expressions (BRE), I prefer the first solution.

So getting the name in a variable now becomes this:

# name=`vim-cmd vmsvc/get.config 10 | sed -n -e '/(vim.vm.ConfigInfo) {/,/files = (vim.vm.FileInfo) {/ s/^ +name = "(.*)",.*?/1/p'`
# echo ${name}
X9SRI-3F-W10P-EN-MEDIA

List the vmid values, power status and name of all VMs

Back to the listing script vim-cmd-list-all-VMs.sh:

#!/bin/sh
# https://wiert.me/2021/04/29/vmware-esxi-console-viewing-all-vms-suspending-and-waking-them-up-part-4/
vmids=`vim-cmd vmsvc/getallvms | sed -n -E -e "s/^([[:digit:]]+)\s+((\S.+\S)?)\s+(\[\S+\])\s+(.+\.vmx)\s+(\S+)\s+(vmx-[[:digit:]]+)\s*?((\S.+)?)$/\1/p"`
for vmid in ${vmids} ; do
    powerState=`vim-cmd vmsvc/power.getstate ${vmid} | sed '1d'`
    name=`vim-cmd vmsvc/get.config ${vmid} | sed -n -E -e '/\(vim.vm.ConfigInfo\) \{/,/files = \(vim.vm.FileInfo\) \{/ s/^ +name = "(.*)",.*?/\1/p'`
    vmPathName=`vim-cmd vmsvc/get.config ${vmid} | sed -n -E -e '/files = \(vim.vm.FileInfo\) \{/,/tools = \(vim.vm.ToolsConfigInfo\) \{/ s/^ +vmPathName = "(.*)",.*?/\1/p'`
    echo "VM with id ${vmid} has power state ${powerState} (name = ${name}; vmPathName = ${vmPathName})."
done

As a bonus, next to powerState, the script also figures out vmPathName in a similar way to name.

–jeroen

Posted in *nix, *nix-tools, ash/dash, ash/dash development, Development, ESXi6, ESXi6.5, ESXi6.7, ESXi7, head, Power User, Scripting, sed, sed script, Software Development, tee, Virtualization, VMware, VMware ESXi | Leave a Comment »

Huurprijswijzigingen die voor 1 juli 2021 ingaan berekenen

Posted by jpluimers on 2021/04/29

Voor mijn link-archief:

 

–jeroen

Posted in About, Personal | Leave a Comment »

Some links on Delphi and CHM help files

Posted by jpluimers on 2021/04/29

I hardly use help files, but some older systems do, and when porting really old Delphi code, often odd implementations of accessing them through HHCTRL.OCX are used.

Since I tend to forget the correct way using the HtmlHelpViewer unit, here are some links:

Very old code involving the OCX file:

Quote from the first link [WayBack] How to Connect HTML Help with your Delphi Application:

Linking HTML Help (CHM) Files

You should add the “HTMLHelpViewer” unit to the “Uses” clause in the main form of your application. Then set the full path to your CHM file to Application.HelpFile property. To do so, you can add the following line to the main form’s “On Create” event handler:

Application.HelpFile := ExtractFilePath(Application.ExeName) + 'HelpFile.chm';

where “HelpFile.chm” is the actual name of your HTML Help file, located in the same directory as your application’s executable file.

Using HTML Help from Code

When you need to display your help file or a specific help topic, or perform others actions, you can use the following calls:

Displaying a help topic

Application.HelpContext(IDH_TOPIC);

where IDH_TOPIC is the ContextId value of the topic to display.

Displaying the Table of Contents tab

HtmlHelp(0, Application.HelpFile, HH_DISPLAY_TOC, 0);

Displaying the Index tab

HtmlHelp(0, Application.HelpFile, HH_DISPLAY_INDEX, DWORD(PWideChar('Test')));

Displaying the Search tab

var
  Query: THH_Fts_QueryW;
begin
  with Query do
  begin
    cbStruct := SizeOf(THH_Fts_QueryW);
    fUniCodeStrings := True;
    pszSearchQuery := '';
    iProximity := 0;
    fStemmedSearch := True;
    fTitleOnly := False;
    fExecute := True;
    pszWindow := nil;
  end;
  HtmlHelp(0, Application.HelpFile, HH_DISPLAY_SEARCH, DWORD(@Query));
end;

Performing Keyword Lookup

Application.HelpKeyword('Test');

Providing Help for Controls

You can link specific help topics with any controls located on the form. In this case a control will automatically display the corresponding help topic when the user focuses it and presses F1. Also, you can add the standard [?] button to the caption area of the form: using the Object Inspector, set the form’s BorderStyle property as bsDialog and biHelp member of the BorderIcons property to True. Then set the controls’ HelpContext properties that should correspond to the topic ContextId values as defined in your help project.

–jeroen

Read the rest of this entry »

Posted in Delphi, Development, Software Development | Leave a Comment »