VBox.ps1

#https://github.com/ajbrehm/NNVirtualBoxPowerShellModule

if ($null -eq (get-command VBoxManage.exe -errorAction silentlyContinue) ) {
  $env:path = "C:\Program Files\Oracle\VirtualBox;$env:path"
}

#LockType
$LockType_Shared = 1
$LockType_Write = 2

$global:vboxcom

class Box {
  [string] $Name
  [string] $Address
}

function Connect-VBox() {
  param(
    [Parameter(position = 0, mandatory = $True)]
    [string] $Name 
  )

  # get Ip from $Name

  Connect-Ssh -Ip "192.168.56.20"
}

function Get-VBoxProcess {

  <#
  .SYNOPSIS
  Get all VirtualBox related processes
  .DESCRIPTION
  Find all running processes related to VirtualBox.
  .EXAMPLE
  PS C:\> Get-VBoxProcess
  Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName
  ------- ------ ----- ----- ----- ------ -- -----------
      401 56 36272 27956 139 36.63 1876 VBoxHeadless
      754 129 103736 52940 244 76.85 12244 VBoxHeadless
     3444 17 16076 11844 109 1,351.14 8176 VBoxSVC
      193 15 19416 55140 137 1.28 12212 VirtualBox
   
  Get all running VirtualBox related processes
  .NOTES
  NAME : Get-VboxProcess
  VERSION : 0.9
  LAST UPDATED: 6/13/2011
  AUTHOR : Jeffery Hicks
  .LINK
  Get-VirtualBox
  .INPUTS
  None
  .OUTPUTS
  Process object
  #>

  
  [cmdletbinding()]
  Param()
  
  Write-Verbose "Starting $($myinvocation.mycommand)"
  Try {
    $processes = Get-Process -ErrorAction "Stop" | Where { $_.path -match "oracle\\virt" }
    Write-Verbose "Found $($processes | measure-object).Count processes)"
    $processes
  }
  Catch {
    Write-Host "Failed to find any VirtualBox related processes." -ForegroundColor Magenta
  }
  
  Finally {
    Write-Verbose "Ending $($myinvocation.mycommand)"
  }
  
}

function Get-VBox() {

  $vbox = Get-VBoxCom
  $machines = $vbox.Machines
  Write-Host ($machines | Format-Table -GroupBy Name -Property Name, State | Out-String)
}

function Get-VBoxCom {
  if (-Not($global:vboxcom)) {
    $global:vboxcom = New-Object -ComObject "VirtualBox.VirtualBox"
    $status = "VirtualBox v{0} rev.{1}" -f $global:vboxcom.version, $global:vboxcom.revision
    Write-Host $status -ForegroundColor Cyan
  }
  return $global:vboxcom
}

# https://www.virtualbox.org/manual/ch08.html#vboxmanage-dhcpserver
function Get-VBoxHostOnlyAdpater {

  <#
  vboxmanage showvminfo core | grep "NIC 1:" | awk '{print tolower($4)}' | sed 's/.\{2\}/&:/g' | sed 's/.\{2\}$//'
 
arp -a | grep 08:00:27:a5:db:a3 | awk '{print $2}' | tail -c +2 | head -c -2
        #vboxmanage hostonlyif ipconfig $ifname --ip 192.168.56.1 --netmask 255.255.255.0
        #vboxmanage dhcpserver modify --ifname $ifname --disable
 
  #>


  #https://www.virtualbox.org/manual/ch08.html#vboxmanage-dhcpserver

  # ip -o -4 addr
  # IP address for the host 192.168.56.1
  # DHCP-Server Range 192.168.56.101 - 192.168.56.254
  # The IP range limiting the IP addresses that will be provided to the guest systems 192.168.56.2 - 192.168.56.100

  # TODO get name from ComObject

  $if = vboxmanage list hostonlyifs
  $name = $if | Select-String '^Name:\s+(.+)'
  # TODO test
  if (-Not($name)) {
    Write-Error ("host-only interface not found")
    return
  } 

  return $name.matches.groups[1]
}


function Get-VBoxPath {
  param(
    [string] $Name
  )

  $path = Get-BoxPath -Path "vbox"
  if ($Name) {
    $path = Join-Path $path $Name
  }
  return $path
}

function New-VBox() {
  param(
    [Parameter(Mandatory = $true)]
    [string] $Name,
    [switch] $Update
  )

  $box = [Box]::new()
  $box.Name = $Name
  $box.Address = "192.168.56.20/24"

  Write-Host("Creating machine '${Name}' ...")

  # Ubuntu
  # $imagePath = Get-Ubuntu -Path "releases/noble/release" -File "ubuntu-24.04-server-cloudimg-amd64.ova" -Update $Update
  $imagePath = Get-CoreOSImage

  #vboxmanage import $imagePath --vsys 0 --vmname $box.Name --options importtovdi --basefolder (Get-VBoxPath)
  #vboxmanage modifyvm $box.Name --nic1 nat
  #vboxmanage modifyvm $box.Name --nic2 hostonly --hostonlyadapter2 (Get-VBoxHostOnlyAdpater)
  
  # Ubuntu
  # $seedImg = New-CloudInit -Path (Get-VBoxPath -Name $box.Name) -Hostname $box.Name -Address $box.Address
  # vboxmanage storageattach $box.Name --storagectl IDE --port 0 --device 0 --type dvddrive --medium $seedImg

  $config = Get-CoreOSIgnitionConfig -Hostname $box.Name
  
  vboxmanage guestproperty set $box.Name "/Ignition/Config" $config

}

function New-VboxCoreOS {
  
}

function New-VBoxTmp {

  Write-Verbose "Creating the VirtualBox COM object"
  $vbox = New-Object -ComObject "VirtualBox.VirtualBox"
  $machines = $vbox.Machines
  Write-Host ($machines | Format-List | Out-String)

  # https://gitlab.com/xtec/box/-/blob/acc37ba85b4650806904c50306ecd12962b7090a/box.ps1

  
}


function Remove-VBox() {
  param(
    [Parameter(Position = 0, Mandatory = $True, HelpMessage = "Enter a virtual machine name")]
    [ValidateNotNullorEmpty()]
    [string] $Name 
  )

  try {
    $vbox = Get-VBoxCom
    $vbox.FindMachine($Name) | Out-Null
    Stop-VBox $Name
    Write-Host("Removing machine '${Name}' ...")
    vboxmanage unregistervm $Name --delete
  }
  catch {
    Write-Host -f Yellow $_
  }

  Remove-Item -Path (Get-VBoxPath $Name) -Recurse -Force -ErrorAction Ignore
}

#$json = $vm | ConvertTo-Json
#Write-Host($json)

#https://www.virtualbox.org/sdkref/interface_i_machine.html#af28da645b00a821547d9cb8e92f8b7b0

# https://www.virtualbox.org/sdkref/interface_i_console.html

function Start-VBox() {
  [cmdletbinding()]
  param(
    [Parameter(Position = 0, Mandatory = $True, HelpMessage = "Enter a virtual machine name", ValueFromPipeline = $True, ValueFromPipelineByPropertyName = $True)]
    [ValidateNotNullorEmpty()]
    [string] $Name,
    [switch] $New 
  )

  try {
    $vbox = Get-VBoxCom
    $machine = $vbox.FindMachine($name)
  }
  catch {
    if ($New) {
      New-VBox $Name
    }
    else {
      Write-Host -f Yellow $_
      return
    }
  }

  if ($machine.State -lt 5) {
    
    $session = New-Object -ComObject "VirtualBox.Session"

    Write-Host("Starting machine '${Name}' ...")
    vboxmanage startvm $Name --type headless


    #$machine.GetType() | Out-Host
    # https://www.virtualbox.org/sdkref/interface_i_machine.html#aa75e76da42ef908795d235d995262c6f
    #$machine.GetSerialPort(1) | Out-Host
    #$machine.LockMachine($session, 1)
    #$progress = $machine.LaunchVMProcess($session, "headless", "")
    #Write-Host("Starting VM ...")
    #$progress.WaitForCompletion(-1)
  }
  else {
    Write-Host "I can only start machines that have been stopped." -ForegroundColor Magenta
  }

}

function Stop-VBox() {

  param(
    [Parameter(Position = 0, Mandatory = $True, HelpMessage = "Power off (stop) a running VM.")]
    [ValidateNotNullorEmpty()]
    [string] $Name 
  )   

  try {
    $vbox = Get-VBoxCom
    $machine = $vbox.FindMachine($Name)
  }
  catch {
    Write-Host -f Yellow $_
    return
  }

  # Virtual machine must be Running, Paused or Stuck to be powered down.
  if (@(5, 6, 7) -Contains $machine.State) {
    $session = New-Object -ComObject "VirtualBox.Session"
    $machine.LockMachine($session, $LockType_Shared)
    $progress = $session.Console.PowerDown()
    Write-Host("Stopping machine '${Name}' ...")
    $progress.WaitForCompletion(-1)
    #$session.UnlockMachine()
  }
}



function StateAsString {
  param(
    [int] $State
  )

  
  Switch ($vstate) {
    1 { "Stopped" }
    2 { "Saved" }
    3 { "Teleported" }
    4 { "Aborted" }
    5 { "Running" }
    6 { "Paused" }
    7 { "Stuck" }
    8 { "Snapshotting" }
    9 { "Starting" }
    10 { "Stopping" }
    11 { "Restoring" }
    12 { "TeleportingPausedVM" }
    13 { "TeleportingIn" }
    14 { "FaultTolerantSync" }
    15 { "DeletingSnapshotOnline" }
    16 { "DeletingSnapshot" }
    17 { "SettingUp" }
  }
}

<#
if ($null -eq (get-command VBoxManage.exe -errorAction silentlyContinue) ) {
    $env:path = "C:\Program Files\Oracle\VirtualBox;$env:path"
}
 
#>