Jump to content

List VirtualBox VMs, filter them to find the one you need, start the VM


rodent1
 Share

Recommended Posts

I have many VMs from past projects that I know I'll have to revisit. VirtualBox can sort them alphabetically, but I have failed to keep a consistent naming system that keeps track of the OS, the language name and the project name. So when I need to look for the VM I used 6 months ago for French and a certain project under Windows 8 using the Oracle VirtualBox Manager, my eyes tend to start glazing... I came up with a solution, and created this simple script to get the list of VMs, display them in a listview, then have a filter where I can type the project name, or the language, or the OS. Only the VMs with a name that contain the filter string are displayed, and I can just select the VM I need from my script UI, and launch it.

It could have added a lot of bells and whistles, and I may add a few in the future. If someone uses this script and adds features, please share.

The code:

 
;Manage VirtualBox VMs


#include <ListViewConstants.au3>
#include <WindowsConstants.au3>
#Include <GuiListView.au3>
#include <guiconstantsex.au3>

#include <AutoItConstants.au3>

Local $ListID
Local $arLVItems

Main()

Func Main()
    Local $sVBFolder = GetVBFolder()    ; read the VirtualBox installation folder from the registry
    if $sVBFolder = -1 then
        MsgBox(0,"","Failed to retrieve the VirtualBox folder from the registry, exiting...")
        Return
    EndIf
    Local $arVMList = GetVMList($sVBFolder) ; use VirtualBox commandline to query the name of existing VMs
    if $arVMList = 0 Then Return    ; none was found, exit
    ShowVMs($arVMList, $sVBFolder)
EndFunc

Func GetVBFolder()
    Local $sFilePath
    if StringInStr(@OSArch, "64")>0 Then
        $sFilePath = RegRead("HKLM64\SOFTWARE\Oracle\VirtualBox","InstallDir")
    Else
        $sFilePath = RegRead("HKLM\SOFTWARE\Oracle\VirtualBox","InstallDir")
    EndIf
    Return $sFilePath
EndFunc

Func GetVMList($sFilePath)
    if StringLen($sFilePath)>0 Then
        Local $iPID = Run(@ComSpec & ' /K "' & $sFilePath & '\vboxmanage" list vms', $sFilePath, @SW_HIDE, $STDOUT_CHILD)
        ProcessWaitClose($iPID) ; Wait until the process has closed.
        Local $sOutput = stringreplace(StdoutRead($iPID), '"', '')  ; Read the Stdout stream
        Local $arVMLst = StringSplit($sOutput, @CRLF,1)
        for $i = 1 to $arVMLst[0]
            if StringInStr($arVMLst[$i], "{")>0 Then
                $arVMLst[$i] = StringLeft($arVMLst[$i], StringInStr($arVMLst[$i], "{") - 2)
            Else
                $arVMLst[$i] = ""
            EndIf
        Next
        Return $arVMLst
    Else
        MsgBox(0,"debug",@error & @LF & @extended)
        Return -1
    EndIf
EndFunc

Func ShowVMs($arVMs, $sFilePath)
    Local $sCurVMSel
    Local $sFilter
    Local $frmMain = GUICreate("Menu Key Tester", 623, 450, 192, 124)
    Local $lblFilter=GUICtrlCreateLabel("Display filter:", 10, 5, 100, 20)
    Local $txtFilterEdit = GUICtrlCreateEdit("", 120, 5, 200, 20)
    Local $btnApplyFilter = GUICtrlCreateButton("Apply Filter", 350, 5, 100, 20)
    GUICtrlSetState($btnApplyFilter, $GUI_DISABLE)
    $ListID = GUICtrlCreateListView("", 10, 27, 590, 390, BitOR($LVS_SORTDESCENDING, $GUI_BKCOLOR_LV_ALTERNATE, 0x00000020))    ;LVS_EX_FULLROWSELECT = 0x00000020
    PopulateVMList($arVMs)
    $btnOK = GUICtrlCreateButton("OK", 10, 420, 180, 25)
    Local $btnStartVM = GUICtrlCreateButton("Start VM",250, 420, 180, 25)
    GUICtrlSetState($btnStartVM, $GUI_DISABLE)
    GUISetState(@SW_SHOW)
    Local $nMsg
    while 1
        $nMsg = GUIGetMsg()
        Switch $nMsg
            Case $GUI_EVENT_CLOSE
                Exit
            case $btnOK
                Exit
            case $btnApplyFilter
                $sFilter = GUICtrlRead($txtFilterEdit)
                PopulateVMList($arVMs, $sFilter)
            case $btnStartVM
                ;MsgBox(262144, 'Debug line ~' & @ScriptLineNumber, 'Selection:' & @CRLF & '$sFilePath & ''\vboxmanage" startvm "'' & $sCurVMSel & ''"''' & @CRLF & @CRLF & 'Return:' & @CRLF & $sFilePath & '\vboxmanage" startvm "' & $sCurVMSel & '"') ;### Debug MSGBOX
                Local $iPID = Run(@ComSpec & ' /K ""' & $sFilePath & 'vboxmanage" startvm "' & $sCurVMSel & '""', $sFilePath, @SW_HIDE, $STDOUT_CHILD)
            case $ListID
            case Else
                ;$sCurVMSel = ""
                for $i = 1 to $arLVItems[0]
                    if $nMsg = $arLVItems[$i] Then
                        $sCurVMSel = GUICtrlRead($arLVItems[$i])
;                       MsgBox(262144, 'Debug line ~' & @ScriptLineNumber, 'Selection:' & @CRLF & '$sCurVMSel' & @CRLF & @CRLF & 'Return:' & @CRLF & $sCurVMSel) ;### Debug MSGBOX
                        ExitLoop
;                   Else
;                       MsgBox(262144, 'Debug line ~' & @ScriptLineNumber, 'Selection:' & @CRLF & 'GUICtrlRead($arLVItems[$i])' & @CRLF & @CRLF & 'Return:' & @CRLF & GUICtrlRead($arLVItems[$i])) ;### Debug MSGBOX
                    EndIf
                Next
                if stringlen($sCurVMSel)>0 and BitAND(GUICtrlGetState($btnStartVM), $GUI_DISABLE) = $GUI_DISABLE Then
                    local $res = GUICtrlSetState($btnStartVM, $GUI_ENABLE)
                Elseif stringlen($sCurVMSel)=0 and BitAND(GUICtrlGetState($btnStartVM), $GUI_ENABLE) = $GUI_ENABLE Then
                    ;MsgBox(262144, 'Debug line ~' & @ScriptLineNumber, 'Selection:' & @CRLF & '$sCurVMSel' & @CRLF & @CRLF & 'Return:' & @CRLF & $sCurVMSel) ;### Debug MSGBOX
                    GUICtrlSetState($btnStartVM, $GUI_DISABLE)
                EndIf
                Local $FilterCurrentText = GUICtrlRead($txtFilterEdit)

                if stringlen($FilterCurrentText) = 0 and BitAND(GUICtrlGetState($btnApplyFilter), $GUI_ENABLE) = $GUI_ENABLE Then
                    GUICtrlSetState($btnApplyFilter, $GUI_DISABLE)
                Elseif stringlen($FilterCurrentText) > 0 and BitAND(GUICtrlGetState($btnApplyFilter), $GUI_DISABLE) = $GUI_DISABLE Then
                    GUICtrlSetState($btnApplyFilter, $GUI_ENABLE)
                EndIf
        EndSwitch
    WEnd
EndFunc

Func PopulateVMList($arVMs, $sFiltr = "")
    Local $ItemIDList
    GUICtrlDelete($ListID)
    $ListID = GUICtrlCreateListView("", 10, 27, 600, 390, -1, BitOR($LVS_EX_FULLROWSELECT, $LVS_EX_GRIDLINES))
    GUICtrlSetBkColor(-1, $GUI_BKCOLOR_LV_ALTERNATE)
    GUICtrlSetStyle(-1, $LVS_LIST)
    for $i = 1 to $arVMs[0]
        if StringLen($arVMs[$i])>0 Then
            if StringLen($sFiltr)>0 Then
                if StringInStr(StringUpper($arVMs[$i]), StringUpper($sFiltr))>0 Then
                    $ItemIDList &= GUICtrlCreateListViewItem($arVMs[$i], $ListID) & ","
                EndIf
            Else
                $ItemIDList &= GUICtrlCreateListViewItem($arVMs[$i], $ListID) & ","
            EndIf
            GUICtrlSetBkColor(-1, 0x00E0FFFF)   ; color item light blue
        EndIf
    Next
    if StringLen($ItemIDList) Then
        $ItemIDList = StringLeft($ItemIDList, StringLen($ItemIDList)-1) ; trim final comma
    EndIf
    $arLVItems = StringSplit($ItemIDList, ',')
    GUISetState(@SW_SHOW)
EndFunc

Ā 

Edited by rodent1
Link to comment
Share on other sites

That's odd, since the command to start the VM isĀ 

Run(@ComSpec & ' /K "' & $sFilePath & 'vboxmanage" startvm "' & $sCurVMSel & '"' etc

where the command is enclosed between double quotes. Yet from what you are saying, it looks like the quotes are missing.

My VM host OS is Windows 7, if that has any bearing.

Could you save the command string value, then try it from the command prompt, to see if you find the same problem?

Edited by rodent1
Link to comment
Share on other sites

I have access to a windows 2008 R1 VM server, and reproduced the problem there. After googling and tinkering, I updated the command to start the VM to this, and it works.

Local $iPID = Run(@ComSpec & ' /K ""' & $sFilePath & 'vboxmanage" startvm "' & $sCurVMSel & '""', $sFilePath, @SW_HIDE, $STDOUT_CHILD)

Please let me know if this resolves the issue for you.

Edited by rodent1
Link to comment
Share on other sites

ThanksĀ rodent1, I can't test it at the moment but I believe it should solve the problem, the double quotes are what was needed when passing arguments with spaces in file path. I knew the answer offhand but wanted you to figure it out as it helps with developing debugging skills. :) much appreciated!

Edited by mpower
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...