master 9d6201b8a3ea cached
37 files
63.8 KB
18.0k tokens
43 symbols
1 requests
Download .txt
Repository: Node-Virtualization/node-virtualbox
Branch: master
Commit: 9d6201b8a3ea
Files: 37
Total size: 63.8 KB

Directory structure:
gitextract_73cbe_5t/

├── .eslintrc
├── .github/
│   ├── dependabot.yml
│   ├── stale.yml
│   └── workflows/
│       └── main.yml
├── .gitignore
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── Vagrantfile
├── code_of_conduct.md
├── lib/
│   ├── scan-codes.js
│   └── virtualbox.js
├── package.json
└── test/
    ├── guestproperty.spec.js
    ├── helpers/
    │   └── logger.js
    └── integration/
        ├── acpipowerbutton.js
        ├── acpisleepbutton.js
        ├── exec.js
        ├── export.js
        ├── getextradata.js
        ├── guestproperty-enumerate.js
        ├── guestproperty.js
        ├── isRunning.js
        ├── keyboardputscancode.js
        ├── list.js
        ├── modify.js
        ├── pause.js
        ├── poweroff.js
        ├── resume.js
        ├── savestate.js
        ├── setextradata.js
        ├── snapshot-delete.js
        ├── snapshot-list.js
        ├── snapshot-restore.js
        ├── snapshot-take.js
        ├── start.js
        └── stop.js

================================================
FILE CONTENTS
================================================

================================================
FILE: .eslintrc
================================================
// {
//   // Settings
//   "esversion"     : 6,
//   "passfail"      : false,  // Stop on first error.
//   "maxerr"        : 100,    // Maximum errors before stopping.

//   // Predefined globals whom JSHint will ignore.
//   "browser"       : true,   // Standard browser globals e.g. `window`, `document`.

//   "node"          : true,
//   "rhino"         : false,
//   "couch"         : false,
//   "wsh"           : false,   // Windows Scripting Host.

//   "jquery"        : false,
//   "prototypejs"   : false,
//   "mootools"      : false,
//   "dojo"          : false,

//   "predef"        : [  // Extra globals.
//     "require",
//     "define",
//     "notify",
//     "expect",
//     "it",
//     "afterEach",
//     "describe",
//     "jest"
//   ],

//   // Development.
//   "debug"         : false,   // Allow debugger statements e.g. browser breakpoints.
//   "devel"         : false,   // Allow development statements e.g. `console.log();`.

//   // EcmaScript 5.
//   "strict"        : true,   // Require `use strict` pragma in every file.
//   "globalstrict"  : false,  // Allow global "use strict" (also enables 'strict').

//   // The Good Parts.
//   "asi"           : false,  // Tolerate Automatic Semicolon Insertion (no semicolons).
//   "laxbreak"      : false,  // Tolerate unsafe line breaks e.g. `return [\n] x` without semicolons.
//   "bitwise"       : true,   // Prohibit bitwise operators (&, |, ^, etc.).
//   "boss"          : false,  // Tolerate assignments inside if, for & while. Usually conditions & loops are for comparison, not assignments.
//   "curly"         : true,   // Require {} for every new block or scope.
//   "eqeqeq"        : false,  // Require triple equals i.e. `===`.
//   "eqnull"        : false,  // Tolerate use of `== null`.
//   "evil"          : true,  // Tolerate use of `eval`.
//   "expr"          : false,  // Tolerate `ExpressionStatement` as Programs.
//   "forin"         : false,   // Tolerate `for in` loops without `hasOwnPrototype`.
//   "immed"         : true,   // Require immediate invocations to be wrapped in parens e.g. `( function(){}() );`
//   "latedef"       : false,  // Prohibit variable use before definition.
//   "loopfunc"      : true,  // Allow functions to be defined within loops.
//   "noarg"         : true,   // Prohibit use of `arguments.caller` and `arguments.callee`.
//   "regexp"        : true,   // Prohibit `.` and `[^...]` in regular expressions.
//   "regexdash"     : false,  // Tolerate unescaped last dash i.e. `[-...]`.
//   "scripturl"     : true,   // Tolerate script-targeted URLs.
//   "shadow"        : false,  // Allows re-define variables later in code e.g. `var x=1; x=2;`.
//   "supernew"      : true,  // Tolerate `new function () { ... };` and `new Object;`.
//   "undef"         : true,   // Require all non-global variables be declared before they are used.

//   // Styling prefrences.
//   "newcap"        : false,  // Require capitalization of all constructor functions e.g. `new F()`.
//   "noempty"       : false,  // Prohibit use of empty blocks.
//   "nonew"         : false,  // Prohibit use of constructors for side-effects.
//   "nomen"         : false,  // Prohibit use of initial or trailing underbars in names.
//   "onevar"        : false,  // Allow only one `var` statement per function.
//   "plusplus"      : false,  // Prohibit use of `++` & `--`.
//   "sub"           : true,   // Tolerate all forms of subscript notation besides dot notation e.g. `dict['key']` instead of `dict.key`.
//   "trailing"      : false,  // Prohibit trailing whitespaces.
//   "white"         : false   // Check against strict whitespace and indentation rules.
// }

{
  "parserOptions": {
    "ecmaVersion": 2018,
  },
  "env": {
    "browser": true,
    "node": true,
    "es6": true,
  },
  "globals": {
    "require": true,
    "define": true,
    "notify": true,
    "expect": true,
    "it": true,
    "afterEach": true,
    "describe": true,
    "jest": true,
  },
  "rules": {
    "no-debugger": "error",
    "no-console": "error",
    "strict": ["error", "global"],
    "no-bitwise": "error",
    "curly": "error",
    "eqeqeq": "off",
    "no-eval": "error",
    "no-undef": "error",
    "no-redeclare": "error",
    "no-caller": "error",
    "no-unused-vars": [
      "error",
      {
        "argsIgnorePattern": "_",
      },
    ],
    "no-empty": "off",
    "no-new": "off",
    "no-underscore-dangle": "off",
    "one-var": "off",
    "no-plusplus": "off",
    "no-sub": "off",
    "no-trailing-spaces": "off",
    "no-tabs": "off",
  },
}


================================================
FILE: .github/dependabot.yml
================================================
# .github/dependabot.yml

version: 2
updates:
  - package-ecosystem: "npm"
    directory: "/"
    schedule:
      interval: "weekly"
    labels:
      - "dependencies"
    assignees:
      - "colonelpopcorn"
    reviewers:
      - "colonelpopcorn"


================================================
FILE: .github/stale.yml
================================================
# Number of days of inactivity before an issue becomes stale
daysUntilStale: 90
# Number of days of inactivity before a stale issue is closed
daysUntilClose: 14
# Issues with these labels will never be considered stale
exemptLabels:
  - pinned
  - security
# Label to use when marking an issue as stale
staleLabel: stale
# Comment to post when marking an issue as stale. Set to `false` to disable
markComment: >
  This issue has been automatically marked as stale because it has not received
  any attention in 90 days. It will be closed in 14 days if no further activity occurs.
  Thank you for your contribution!
  (I'm a bot.)
# Comment to post when closing a stale issue. Set to `false` to disable
closeComment: >
  This issue has been automatically closed due to inactivity.
  (I'm a bot.)


================================================
FILE: .github/workflows/main.yml
================================================
# GitHub Actions (.github/workflows/main.yml)
name: Node.js CI
on:
  pull_request:
    branches:
      - main
      - master
  workflow_dispatch:

jobs:
  build:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        node-version: ["22", "21", "20", "19", "18"]
    steps:
      - name: Checkout repository
        uses: actions/checkout@v2
      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          node-version: ${{ matrix.node-version }}
      - name: Install project dependencies
        run: npm install
      - name: Run tests
        run: npm test
      - name: Run linting
        run: npm run lint


================================================
FILE: .gitignore
================================================
######################
# OS-generated files
######################
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
ehthumbs.db
Thumbs.db

######################
# IDE & Tools files
######################
# IntelliJ IDEA, WebStorm, phpStorm
.idea/
*.iml
*.iws

# Eclipse
.classpath
.project
.settings/

# Sublime Text
*.sublime-project
*.sublime-workspace

# vi buffers
*~
*.swp
*.swo

# Emacs buffers
\#*
.\#*

# TextMate
*.tmproj
tmtags

# Build & testing tools
node_modules
.vagrant

######################
# Logs and databases
######################
*.log
*.sql
*.sqlite

######################
# Projects checked out to this root
######################

\.vscode/


================================================
FILE: CONTRIBUTING.md
================================================
# CONTRIBUTING

Please familiarize yourself with the [Contributor Code of Conduct](https://github.com/Node-Virtualization/node-virtualbox/blob/master/code_of_conduct.md)

## Filing Issues

- Please file issues using the issue templates.

- Please follow the issue template exactly and provide as much meaningful detail as you can.

## Testing Your Work

Please test your work thoroughly before submitting a PR.

Understand that Node-Virtualbox is used on a wide variety of platforms; avoid code that applies only to one host operating system and make it as generic as possible.

## Submitting Pull Requests

1. Pull requests *must* be tied to an issue. If no issue exists, please file one (see above).
1. Before starting work, please claim the issue by commenting on it and letting _everyone_ know you'll be working on it. This helps prevent duplicate PRs.
1. Please try to let us know if you abandon an issue so we can remove the `in-progress` label.
1. Mention the issue number in a commit.
1. Fix any issues in the automated PR checks, or explain why they're not relevant.

## Code Quality Tools

Checking tools are there as guidance. Use your judgement.


================================================
FILE: LICENSE
================================================
The MIT License (MIT)

Copyright (c) 2014 Azer Koçulu, Michael Sanford

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: README.md
================================================
# node-virtualbox

![NPM version](https://badge.fury.io/js/virtualbox.svg)
[![Build Status](https://travis-ci.org/Node-Virtualization/node-virtualbox.svg?branch=master)](https://travis-ci.org/Node-Virtualization/node-virtualbox)
[![DepShield Badge](https://depshield.sonatype.org/badges/Node-Virtualization/node-virtualbox/depshield.svg)](https://depshield.github.io)

A JavaScript library to interact with [VirtualBox](https://www.virtualbox.org/) virtual machines.

# Table of Contents

- [Installation](#installation)
- [Controlling Power and State](#controlling-power-and-state) - [Starting a cold machine: Two ways](#starting-a-cold-machine-two-ways) - [Stopping a machine](#stopping-a-machine) - [Pausing, Saving and Resuming a machine](#pausing-saving-and-resuming-a-machine)
- [Import a Machine](#import-a-machine)
- [Export a Machine](#export-a-machine)
- [Snapshot Manage](#snapshot-manage)
- [Cloning a VM](#cloning-vms)
- [Storage](#storage) - [Manage the IDE controller](#manage-the-ide-controller) - [Attach a disk image file](#attach-a-disk-image-file)
- [Controlling the guest OS](#controlling-the-guest-os) - [A note about security :warning:](#a-note-about-security) - [Running programs in the guest](#running-programs-in-the-guest) - [Executing commands as Administrators on Windows guests](#executing-commands-as-administrators-on-windows-guests) - [Killing programs in the guest](#killing-programs-in-the-guest) - [Sending keystrokes to a virtual machine](#sending-keystrokes-to-a-virtual-machine)
- [Meta information about machine](#meta-information-about-machine)
- [Putting it all together](#putting-it-all-together)
- [Available Methods](#available-methods)
- [Troubleshooting](#troubleshooting)
- [More Examples](#more-examples)
- [License (MIT)](#license)
- [Contributing](#contributing)
  - [Testing](#testing)

# Installation

Obtain the package

```bash
$ npm install virtualbox [--save] [-g]
```

and then use it

```javascript
var virtualbox = require('virtualbox');
```

The general formula for commands is:

> virtualbox. **API command** ( "**registered vm name**", **[parameters]**, **callback** );

Available API commands are listed at the end of this document.

# Controlling Power and State

`node-virtualbox` provides convenience methods to command the guest machine's power state in the customary ways.

## Starting a cold machine: Two ways

Virtual machines will _start headless by default_, but you can pass a boolean parameter to start them with a GUI:

```javascript
virtualbox.start('machine_name', true, function start_callback(error) {
  if (error) throw error;
  console.log('Virtual Machine has started WITH A GUI!');
});
```

So as not to break pre-0.1.0 implementations, the old method still works (which also defaults to headless):

```javascript
virtualbox.start('machine_name', function start_callback(error) {
  if (error) throw error;
  console.log('Virtual Machine has started HEADLESS!');
});
```

## Stopping a machine

**Note:** For historical reasons, `.stop` is an alias to `.savestate`.

```javascript
virtualbox.stop('machine_name', function stop_callback(error) {
  if (error) throw error;
  console.log('Virtual Machine has been saved');
});
```

To halt a machine completely, you can use `poweroff` or `acpipowerbutton`:

```javascript
virtualbox.poweroff('machine_name', function poweroff_callback(error) {
  if (error) throw error;
  console.log('Virtual Machine has been powered off!');
});
```

```javascript
virtualbox.acpipowerbutton('machine_name', function acpipower_callback(error) {
  if (error) throw error;
  console.log("Virtual Machine's ACPI power button was pressed.");
});
```

## Pausing, Saving and Resuming a machine

Noting the caveat above that `.stop` is actually an alias to `.savestate`...

```javascript
virtualbox.pause('machine_name', function pause_callback(error) {
  if (error) throw error;
  console.log('Virtual Machine is now paused!');
});
```

```javascript
virtualbox.savestate('machine_name', function save_callback(error) {
  if (error) throw error;
  console.log('Virtual Machine is now paused!');
});
```

And, in the same family, `acpisleepbutton`:

```javascript
virtualbox.acpisleepbutton('machine_name', function acpisleep_callback(error) {
  if (error) throw error;
  console.log("Virtual Machine's ACPI sleep button signal was sent.");
});
```

Note that you should probably _resume_ a machine which is in one of the above three states.

```javascript
virtualbox.resume('machine_name', function resume_callback(error) {
  if (error) throw error;
  console.log('Virtual Machine is now paused!');
});
```

And, of course, a reset button method:

```javascript
virtualbox.reset('machine_name', function reset_callback(error) {
  if (error) throw error;
  console.log("Virtual Machine's reset button was pressed!");
});
```

## Import a machine

You can import an OVA or OVF file with the `vmImport` method:

```javascript
virtualbox.vmImport('ova_file_path', options, function import_callback(error) {
  if (error) throw error;
  console.log('Virtual Machine was imported!');
});
```

The options object may contain optional parameters:
* `vmname`: the name of the new VM.
* `cpus`: the number of CPUs.
* `memory`: the amount of memory in megabytes.

## Export a machine

You can export with `vmExport` method:

```javascript
virtualbox.vmExport('machine_name', 'output', function export_callback(error) {
  if (error) throw error;
  console.log('Virtual Machine was exported!');
});
```

## Snapshot Manage

You can show snapshot list with `snapshotList` method:

```javascript
virtualbox.snapshotList('machine_name', function (
  error,
  snapshotList,
  currentSnapshotUUID
) {
  if (error) throw error;
  if (snapshotList) {
    console.log(
      JSON.stringify(snapshotList),
      JSON.stringify(currentSnapshotUUID)
    );
  }
});
```

And, you can take a snapshot:

```javascript
virtualbox.snapshotTake('machine_name', 'snapshot_name', function (
  error,
  uuid
) {
  if (error) throw error;
  console.log('Snapshot has been taken!');
  console.log('UUID: ', uuid);
});
```

Or, delete a snapshot:

```javascript
virtualbox.snapshotDelete('machine_name', 'snapshot_name', function (error) {
  if (error) throw error;
  console.log('Snapshot has been deleted!');
});
```

Or, restore a snapshot:

```javascript
virtualbox.snapshotRestore('machine_name', 'snapshot_name', function (error) {
  if (error) throw error;
  console.log('Snapshot has been restored!');
});
```

## Cloning VMs

Make a full clone (duplicate virtual hard drive) of a machine:

```javascript
virtualbox.clone('source_machine_name', 'new_machine_name', function (error) {
  if (error) throw error;
  console.log('Done fully cloning the virtual machine!');
});
```

Make a linked clone (interdependent-differentially stored virtual hard drive) of a machine:

```javascript
virtualbox.snapshotTake('machine_name', 'snapshot_name', function (
  error,
  uuid
) {
  if (error) throw error;
  console.log('Snapshot has been taken!');
  console.log('UUID: ', uuid);
  virtualbox.clone(
    'machine_name',
    'new_machine_name',
    'snapshot_name',
    function (error) {
      if (error) throw error;
      console.log('Done making a linked clone of the virtual machine!');
    }
  );
});
```

## Storage

### Manage the IDE controller

In case the VM doesn't have an IDE controller you can use the storagectl command to add one:

```javascript
virtualbox.storage.addCtl(
  {
    vm: 'machine_name',
    perhiperal_name: 'IDE', //optional
    type: 'ide', //optional
  },
  function () {
    console.log('Controller has been added!');
  }
);
```

### Attach a disk image file

Mount an ISO file to the added controller:

```javascript
virtualbox.storage.attach(
  {
    vm: 'machine_name',
    perhiperal_name: 'IDE', //optional
    port: '0', //optional
    device: '0', //optional
    type: 'dvddrive', //optional
    medium: 'X:Foldercontaining\the.iso',
  },
  function () {
    console.log('Image has been mounted!');
  }
);
```

The _medium_ parameter of the options object can be set to the **none** value to unmount.

# Controlling the guest OS

## A note about security :warning:

`node-virtualbox` is not opinionated: we believe that _you know best_ what _you_ need to do with _your_ virtual machine. Maybe that includes issuing `sudo rm -rf /` for some reason.

To that end, the `virtualbox` APIs provided by this module _take absolutely no steps_ to prevent you shooting yourself in the foot.

:warning: Therefore, if you accept user input and pass it to the virtual machine, you should take your own steps to filter input before it gets passed to `virtualbox`.

For more details and discussion, see [issue #29](https://github.com/Node-Virtualization/node-virtualbox/issues/29).

## Running programs in the guest

This method takes an options object with the name of the virtual machine, the path to the binary to be executed and any parameters to pass:

```javascript
var options = {
  vm: 'machine_name',
  cmd: 'C:\\Program Files\\Internet Explorer\\iexplore.exe',
  params: 'https://google.com',
};

virtualbox.exec(options, function exec_callback(error, stdout) {
  if (error) throw error;
  console.log('Started Internet Explorer...');
});
```

### Executing commands as Administrators on Windows guests

Pass username and password information in an `options` object:

```javascript
var options = {
  vm: 'machine_name',
  user: 'Administrator',
  password: '123456',
  cmd: 'C:\\Program Files\\Internet Explorer\\iexplore.exe',
  params: 'https://google.com',
};
```

## Killing programs in the guest

Tasks can be killed in the guest as well. In Windows guests this calls `taskkill.exe /im` and on Linux, BSD and OS X (Darwin) guests, it calls `sudo killall`:

```javascript
virtualbox.kill(
  {
    vm: 'machine_name',
    cmd: 'iexplore.exe',
  },
  function kill_callback(error) {
    if (error) throw error;
    console.log('Terminated Internet Explorer.');
  }
);
```

## Sending keystrokes to a virtual machine

Keyboard scan code sequences can be piped directly to a virtual machine's console:

```javascript
var SCAN_CODES = virtualbox.SCAN_CODES;
var sequence = [
  { key: 'SHIFT', type: 'make', code: SCAN_CODES['SHIFT'] },
  { key: 'A', type: 'make', code: SCAN_CODES['A'] },
  { key: 'SHIFT', type: 'break', code: SCAN_CODES.getBreakCode('SHIFT') },
  { key: 'A', type: 'break', code: SCAN_CODES.getBreakCode('A') },
];

virtualbox.keyboardputscancode(
  'machine_name',
  sequence,
  function keyscan_callback(err) {
    if (error) throw error;
    console.log('Sent SHIFT A');
  }
);
```

# Meta information about machine

List all registered machines, returns an array:

```javascript
virtualbox.list(function list_callback(machines, error) {
  if (error) throw error;
  // Act on machines
});
```

Obtaining a guest property by [key name](https://www.virtualbox.org/manual/ch04.html#guestadd-guestprops):

```javascript
var options = {
  vm: 'machine_name',
  key: '/VirtualBox/GuestInfo/Net/0/V4/IP',
};

virtualbox.guestproperty.get(options, function guestproperty_callback(machines, error) {
  if (error) throw error;
  // Act on machines
});
```

Obtaining an extra property by key name:

```javascript
var options = {
  vm: 'machine_name',
  key: 'GUI/Fullscreen',
};

virtualbox.extradata.get(options, function extradataget_callback(error, value) {
  if (error) throw error;
  console.log(
    'Virtual Machine "%s" extra "%s" value is "%s"',
    options.vm,
    options.key,
    value
  );
});
```

Writing an extra property by key name:

```javascript
var options = {
  vm: 'machine_name',
  key: 'GUI/Fullscreen',
  value: 'true',
};

virtualbox.extradata.set(options, function extradataset_callback(error) {
  if (error) throw error;
  console.log(
    'Set Virtual Machine "%s" extra "%s" value to "%s"',
    options.vm,
    options.key,
    options.value
  );
});
```

_Note: some properties are only available/effective if the Guest OS has the (https://www.virtualbox.org/manual/ch04.html)[Guest Additions] installed and running._

# Putting it all together

```javascript
var virtualbox = require('virtualbox');

virtualbox.start('machine_name', function start_callback(error) {
  if (error) throw error;

  console.log('VM "w7" has been successfully started');

  virtualbox.exec(
    {
      vm: 'machine_name',
      cmd: 'C:\\Program Files\\Internet Explorer\\iexplore.exe',
      params: 'http://google.com',
    },
    function (error) {
      if (error) throw error;
      console.log('Running Internet Explorer...');
    }
  );
});
```

# Available Methods

`virtualbox`

- `.pause({vm:"machine_name"}, callback)`
- `.reset({vm:"machine_name"}, callback)`
- `.resume({vm:"machine_name"}, callback)`
- `.start({vm:"machine_name"}, callback)` and `.start({vm:"machine_name"}, true, callback)`
- `.stop({vm:"machine_name"}, callback)`
- `.savestate({vm:"machine_name"}, callback)`
- `.vmImport({input: "input"}, {options: "options"}, callback)`
- `.vmExport({vm:"machine_name"}, {output: "output"}, callback)`
- `.poweroff({vm:"machine_name"}, callback)`
- `.acpisleepbutton({vm:"machine_name"}, callback)`
- `.acpipowerbutton({vm:"machine_name"}, callback)`
- `.guestproperty.get({vm:"machine_name", property: "propname"}, callback)`
- `.exec(){vm: "machine_name", cmd: "C:\\Program Files\\Internet Explorer\\iexplore.exe", params: "http://google.com"}, callback)`
- `.exec(){vm: "machine_name", user:"Administrator", password: "123456", cmd: "C:\\Program Files\\Internet Explorer\\iexplore.exe", params: "http://google.com"}, callback)`
- `.keyboardputscancode("machine_name", [scan_codes], callback)`
- `.kill({vm:"machine_name"}, callback)`
- `.list(callback)`
- `.isRunning({vm:"machine_name"}, callback)`
- `.snapshotList({vm:"machine_name"}, callback)`
- `.snapshotTake({vm:"machine_name"}, {vm:"snapshot_name"}, callback)`
- `.snapshotDelete({vm:"machine_name"}, {vm:"snapshot_UUID"}, callback)`
- `.snapshotRestore({vm:"machine_name"}, {vm:"snapshot_UUID"}, callback)`
- `.clone({vm:"machine_name"}, {vm:"new_machine_name"}, callback)`
- `.storage.addCtl({vm: "machine_name", perhiperal_name: "IDE", type: "ide"}, callback)`
- `.storage.attach({vm: "machine_name", perhiperal_name: "IDE", port: "0", device: "0", type: "dvddrive", medium: "X:\Folder\containing\the.iso"}, callback)`
- `.extradata.get({vm:"machine_name", key:"keyname"}, callback)`
- `.extradata.set({vm:"machine_name", key:"keyname", value:"val"}, callback)`

# Troubleshooting

- Make sure that Guest account is enabled on the VM.
- Make sure your linux guest can `sudo` with `NOPASSWD` (at least for now).
- VMs start headlessly by default: if you're having trouble with executing a command, start the VM with GUI and observe the screen after executing same command.
- To avoid having "Concurrent guest process limit is reached" error message, execute your commands as an administrator.
- Don't forget that this whole thing is asynchronous, and depends on the return of `vboxmanage` _not_ the actual running state/runlevel of services within the guest. See <https://github.com/Node-Virtualization/node-virtualbox/issues/9>

# More Examples

- [npm tests](https://github.com/Node-Virtualization/node-virtualbox/tree/master/test)

# License

[MIT](https://github.com/Node-Virtualization/node-virtualbox/blob/master/LICENSE)

# Contributing

Please do!

- [File an issue](https://github.com/Node-Virtualization/node-virtualbox/issues)
- [Fork](https://github.com/Node-Virtualization/node-virtualbox#fork-destination-box) and send a pull request.

Please abide by the [Contributor Code of Conduct](https://github.com/Node-Virtualization/node-virtualbox/blob/master/code_of_conduct.md).

## Testing

We currently do not have a complete unit testing suite. However, example scripts and a Vagrantfile are provided. Test your changes by writing a new script and/or running through all the test scripts to make sure they behave as expected. To do this [install vagrant](https://www.vagrantup.com/docs/installation) and run `vagrant up` in this repository's root directory. Then run the example scripts by using node: `node test/integration/<script-name>.js`. Please be ready to provide test output upon opening a pull request.


================================================
FILE: Vagrantfile
================================================
Vagrant.configure("2") do |config|
  config.vm.box = "generic/alpine38"
  config.vm.provider "virtualbox" do |vbox|
    vbox.name = "node-virtualbox-test-machine"
  end
end


================================================
FILE: code_of_conduct.md
================================================
# Contributor Covenant Code of Conduct

## Our Pledge

In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, gender identity and expression, level of experience,
nationality, personal appearance, race, religion, or sexual identity and
orientation.

## Our Standards

Examples of behavior that contributes to creating a positive environment
include:

* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members

Examples of unacceptable behavior by participants include:

* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
  address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
  professional setting

## Our Responsibilities

Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.

Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.

## Scope

This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.

## Enforcement

Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.

Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.

## Attribution

This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at [http://contributor-covenant.org/version/1/4][version]

[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/


================================================
FILE: lib/scan-codes.js
================================================
"use strict";

var codes;

codes = {
  ESCAPE: [0x01],
  NUMBER_1: [0x02],
  NUMBER_2: [0x03],
  NUMBER_3: [0x04],
  NUMBER_4: [0x05],
  NUMBER_5: [0x06],
  NUMBER_6: [0x07],
  NUMBER_7: [0x08],
  NUMBER_8: [0x09],
  NUMBER_9: [0x0a],
  NUMBER_0: [0x0b],
  MINUS: [0x0c],
  EQUAL: [0x0d],
  BACKSPACE: [0x0e],
  TAB: [0x0f],
  Q: [0x10],
  W: [0x11],
  E: [0x12],
  R: [0x13],
  T: [0x14],
  Y: [0x15],
  U: [0x16],
  I: [0x17],
  O: [0x18],
  P: [0x19],
  LEFTBRACKET: [0x1a],
  RIGHTBRACKET: [0x1b],
  ENTER: [0x1c],
  CTRL: [0x1d],
  A: [0x1e],
  S: [0x1f],
  D: [0x20],
  F: [0x21],
  G: [0x22],
  H: [0x23],
  J: [0x24],
  K: [0x25],
  L: [0x26],
  SEMICOLON: [0x27],
  QUOTE: [0x28],
  BACKQUOTE: [0x29],
  SHIFT: [0x2a],
  BACKSLASH: [0x2b],
  Z: [0x2c],
  X: [0x2d],
  C: [0x2e],
  V: [0x2f],
  B: [0x30],
  N: [0x31],
  M: [0x32],
  COMMA: [0x33],
  PERIOD: [0x34],
  SLASH: [0x35],
  R_SHIFT: [0x36],
  PRT_SC: [0x37],
  ALT: [0x38],
  SPACE: [0x39],
  CAPS_LOCK: [0x3a],
  F1: [0x3b],
  F2: [0x3c],
  F3: [0x3d],
  F4: [0x3e],
  F5: [0x3f],
  F6: [0x40],
  F7: [0x41],
  F8: [0x42],
  F9: [0x43],
  F10: [0x44],
  NUM_LOCK: [0x45], // May be [0x45, 0xC5],
  SCROLL_LOCK: [0x46],
  NUMPAD_7: [0x47],
  NUMPAD_8: [0x48],
  NUMPAD_9: [0x49],
  NUMPAD_SUBTRACT: [0x4a],
  NUMPAD_4: [0x4b],
  NUMPAD_5: [0x4c],
  NUMPAD_6: [0x4d],
  NUMPAD_ADD: [0x4e],
  NUMPAD_1: [0x4f],
  NUMPAD_2: [0x50],
  NUMPAD_3: [0x51],
  NUMPAD_0: [0x52],
  NUMPAD_DECIMAL: [0x53],
  F11: [0x57],
  F12: [0x58],
  // Same as other Enter key
  // 'NUMBER_Enter'    : [0xE0, 0x1C],
  R_CTRL: [0xe0, 0x1d],
  NUMBER_DIVIDE: [0xe0, 0x35],
  // 'NUMBER_*'        : [0xE0, 0x37],
  R_ALT: [0xe0, 0x38],
  HOME: [0xe0, 0x47],
  UP: [0xe0, 0x48],
  PAGE_UP: [0xe0, 0x49],
  LEFT: [0xe0, 0x4b],
  RIGHT: [0xe0, 0x4d],
  END: [0xe0, 0x4f],
  DOWN: [0xe0, 0x50],
  PAGE_DOWN: [0xe0, 0x51],
  INSERT: [0xe0, 0x52],
  DELETE: [0xe0, 0x53],
  WINDOW: [0xe0, 0x5b],
  R_WINDOW: [0xe0, 0x5c],
  MENU: [0xe0, 0x5d],
  PAUSE: [0xe1, 0x1d, 0x45, 0xe1, 0x9d, 0xc5],
};

codes.getBreakCode = function (key) {
  var makeCode = codes[key];
  if (makeCode === undefined) {
    throw new Error("Undefined key: " + key);
  }

  if (key === "PAUSE") {
    return [];
  }

  if (makeCode[0] === 0xe0) {
    return [0xe0, makeCode[1] + 0x80];
  } else {
    return [makeCode[0] + 0x80];
  }
};

module.exports = codes;


================================================
FILE: lib/virtualbox.js
================================================
"use strict";

const execFile = require("child_process").execFile,
  log4js = require("log4js"),
  host_platform = process.platform,
  known_OS_types = {
    WINDOWS: "windows",
    MAC: "mac",
    LINUX: "linux",
  },
  defaultExecutor = (bin, cmd) => {
    return new Promise((resolve, reject) => {
      if (!allowedBinaries.includes(bin)) {
        reject(new Error("Not an allowed binary"));
      } else {
        execFile(bin, cmd, function (err, stdout, stderr) {
          if (
            !err &&
            stderr &&
            cmd.indexOf("pause") !== -1 &&
            cmd.indexOf("savestate") !== -1
          ) {
            reject(new Error(stderr));
          }

          resolve({ err, stdout, stderr });
        });
      }
    });
  },
  defaultLoggingConfig = {
    appenders: {
      out: {
        type: "stdout",
        layout: {
          type: "pattern",
          pattern: "%[[%d{yyyy-MM-dd hh:mm:ss.SSS}] [%p] %c - %]%m",
        },
      },
    },
    categories: { default: { appenders: ["out"], level: "info" } },
  },
  defaultLoggerFn = () => {
    log4js.configure(defaultLoggingConfig);
    return log4js.getLogger("VirtualBox");
  },
  defaultLogger = defaultLoggerFn(),
  defaultvboxmanage = function (cmd, callback) {
    try {
      this._executor(this._vBoxManageBinary, cmd)
        .then(({ err, stdout, stderr }) => callback(err, stdout, stderr))
        .catch(defaultErrorHandler);
    } catch (err) {
      this._logging.error(err);
    }
  },
  defaultErrorHandler = (err) => {
    defaultLogger.error(err);
  },
  allowedBinaries = ["VBoxControl"];

class Virtualbox {
  constructor(logging = defaultLogger, executor = defaultExecutor) {
    this._logging = logging;
    this._executor = executor;
    this._setVboxManageBinary();
    allowedBinaries.push(this._vBoxManageBinary);
    this._logging.debug(allowedBinaries);
    this._detectVboxVersion();
    this.storage = new VboxStorage(
      this._logging,
      this._executor,
      this._vBoxManageBinary
    );
    this.guestproperty = new VboxGuestProperty(
      this._logging,
      this._executor,
      this._vBoxManageBinary
    );
    this.extradata = new VboxExtraData(
      this._logging,
      this._executor,
      this._vBoxManageBinary
    );
    this.vboxmanage = defaultvboxmanage;
    this.SCAN_CODES = require("./scan-codes");
  }

  static create(logging, executor) {
    const logger = !!logging ? logging : defaultLogger;
    return new Virtualbox(logger, executor);
  }

  pause(vmname, callback) {
    this._logging.info('Pausing VM "%s"', vmname);
    this.vboxmanage(["controlvm", vmname, "pause"], function (error, _) {
      callback(error);
    });
  }

  list(callback) {
    const parse_listdata = (raw_data) => {
      var _raw = raw_data.split(/\r?\n/g);
      var _data = {};
      if (_raw.length > 0) {
        for (var _i = 0; _i < _raw.length; _i += 1) {
          var _line = _raw[_i];
          if (_line === "") {
            continue;
          }
          // "centos6" {64ec13bb-5889-4352-aee9-0f1c2a17923d}
          var rePattern = /^"(.+)" \{(.+)\}$/;
          var arrMatches = _line.match(rePattern);
          // {'64ec13bb-5889-4352-aee9-0f1c2a17923d': 'centos6'}
          if (arrMatches && arrMatches.length === 3) {
            _data[arrMatches[2].toString()] = {
              name: arrMatches[1].toString(),
            };
          }
        }
      }
      return _data;
    };

    this._logging.info("Listing VMs");
    this.vboxmanage(["list", "runningvms"], (_, stdout) => {
      var _runningvms = parse_listdata(stdout);
      this.vboxmanage(["list", "vms"], function (error, fullStdout) {
        var _all = parse_listdata(fullStdout);
        var _keys = Object.keys(_all);
        for (var _i = 0; _i < _keys.length; _i += 1) {
          var _key = _keys[_i];
          if (_runningvms[_key]) {
            _all[_key].running = true;
          } else {
            _all[_key].running = false;
          }
        }
        callback(_all, error);
      });
    });
  }

  reset(vmname, callback) {
    this._logging.info('Resetting VM "%s"', vmname);
    this.vboxmanage(["controlvm", vmname, "reset"], function (error, _) {
      callback(error);
    });
  }

  resume(vmname, callback) {
    this._logging.info('Resuming VM "%s"', vmname);
    this.vboxmanage(["controlvm", vmname, "resume"], function (error, _) {
      callback(error);
    });
  }

  start(vmname, useGui, callback) {
    if (typeof useGui === "function") {
      callback = useGui;
      useGui = false;
    }
    var vmType = useGui ? "gui" : "headless";

    this._logging.info('Starting VM "%s" with options: ', vmname, vmType);

    this.vboxmanage(
      ["-nologo", "startvm", vmname, "--type", vmType],
      function (error, _) {
        if (error && /VBOX_E_INVALID_OBJECT_STATE/.test(error.message)) {
          error = undefined;
        }
        callback(error);
      }
    );
  }

  stop(vmname, callback) {
    this._logging.info('Stopping VM "%s"', vmname);
    this.vboxmanage(["controlvm", vmname, "savestate"], function (error, _) {
      callback(error);
    });
  }

  savestate(vmname, callback) {
    this._logging.info('Saving State (alias to stop) VM "%s"', vmname);
    this.stop(vmname, callback);
  }

  vmExport(vmname, output, callback) {
    this._logging.info('Exporting VM "%s"', vmname);
    this.vboxmanage(
      ["export", vmname, "--output", output],
      function (error, _) {
        callback(error);
      }
    );
  }

  vmImport(input, options, callback) {
    if (typeof options === "function") {
      callback = options;
      options = {};
    }

    var cmd = ["import", "--vsys", "0"];

    if (options.vmname !== undefined) {
      cmd.push("--vmname");
      cmd.push(options.vmname);
    }

    if (options.cpus !== undefined) {
      cmd.push("--cpus");
      cmd.push(options.cpus.toString());
    }

    if (options.memory !== undefined) {
      cmd.push("--memory");
      cmd.push(options.memory.toString());
    }

    cmd.push(input);

    this._logging.info('Importing VM "%s"', input);
    this.vboxmanage(cmd, function (error, _) {
      callback(error);
    });
  }

  poweroff(vmname, callback) {
    this._logging.info('Powering off VM "%s"', vmname);
    this.vboxmanage(["controlvm", vmname, "poweroff"], function (error, _) {
      callback(error);
    });
  }

  acpipowerbutton(vmname, callback) {
    this._logging.info('ACPI power button VM "%s"', vmname);
    this.vboxmanage(["controlvm", vmname, "acpipowerbutton"], function (error) {
      callback(error);
    });
  }

  acpisleepbutton(vmname, callback) {
    this._logging.info('ACPI sleep button VM "%s"', vmname);
    this.vboxmanage(
      ["controlvm", vmname, "acpisleepbutton"],
      function (error, _) {
        callback(error);
      }
    );
  }

  modify(vname, properties, callback) {
    this._logging.info("Modifying VM %s", vname);
    var args = [vname];

    for (var property in properties) {
      if (properties.hasOwnProperty(property)) {
        var value = properties[property];
        args.push("--" + property);

        if (Array.isArray(value)) {
          Array.prototype.push.apply(args, value);
        } else {
          args.push(value.toString());
        }
      }
    }

    this.vboxmanage(["modifyvm", ...args], function (error, _) {
      callback(error);
    });
  }

  snapshotList(vmname, callback) {
    this._logging.info('Listing snapshots for VM "%s"', vmname);
    this.vboxmanage(
      ["snapshot", vmname, "list", "--machinereadable"],
      function (error, stdout) {
        if (error) {
          callback(error);
          return;
        }

        var s;
        var snapshots = [];
        var currentSnapshot;
        var lines = (stdout || "").split(require("os").EOL);

        lines.forEach(function (line) {
          line
            .trim()
            .replace(
              /^(CurrentSnapshotUUID|SnapshotName|SnapshotUUID).*\="(.*)"$/,
              function (l, k, v) {
                if (k === "CurrentSnapshotUUID") {
                  currentSnapshot = v;
                } else if (k === "SnapshotName") {
                  s = {
                    name: v,
                  };
                  snapshots.push(s);
                } else {
                  s.uuid = v;
                }
              }
            );
        });

        callback(null, snapshots, currentSnapshot);
      }
    );
  }

  snapshotTake(
    vmname,
    name,
    /*optional*/ description,
    /*optional*/ live,
    callback
  ) {
    this._logging.info('Taking snapshot for VM "%s"', vmname);

    if (typeof description === "function") {
      callback = description;
      description = undefined;
    } else if (typeof live === "function") {
      callback = live;
      live = false;
    }

    var cmd = ["snapshot", vmname, "take", name];

    if (description) {
      cmd.push("--description");
      cmd.push(description);
    }

    if (live === true) {
      cmd.push("--live");
    }

    this.vboxmanage(cmd, function (error, stdout) {
      var uuid;
      stdout.trim().replace(/UUID\: ([a-f0-9\-]+)$/, function (l, u) {
        uuid = u;
      });
      callback(error, uuid);
    });
  }

  snapshotDelete(vmname, uuid, callback) {
    this._logging.info('Deleting snapshot "%s" for VM "%s"', uuid, vmname);
    this.vboxmanage(["snapshot", vmname, "delete", uuid], callback);
  }

  snapshotRestore(vmname, uuid, callback) {
    this._logging.info('Restoring snapshot "%s" for VM "%s"', uuid, vmname);
    this.vboxmanage(["snapshot", vmname, "restore", uuid], callback);
  }

  clone(vmname, clonevmname, /*optional*/ snapshot, callback) {
    this._logging.info('Cloning machine "%s" to "%s"', vmname, clonevmname);
    var cmd = ["clonevm", vmname, "--name", clonevmname, "--register"];
    if (typeof snapshot === "function") {
      callback = snapshot;
      snapshot = undefined;
    } else {
      cmd.push("--options");
      cmd.push("link");
      cmd.push("--snapshot");
      cmd.push(snapshot);
    }
    this.vboxmanage(cmd, callback);
  }

  isRunning(vmname, callback) {
    this.vboxmanage(["list", "runningvms"], (error, stdout) => {
      this._logging.info(
        'Checking virtual machine "%s" is running or not',
        vmname
      );
      if (stdout.indexOf(vmname) === -1) {
        callback(error, false);
      } else {
        callback(error, true);
      }
    });
  }

  keyboardputscancode(vmname, codes, callback) {
    var codeStr = codes
      .map(function (code) {
        var s = code.toString(16);

        if (s.length === 1) {
          s = "0" + s;
        }
        return s;
      })
      .join(" ");
    this._logging.info(
      'Sending VM "%s" keyboard scan codes "%s"',
      vmname,
      codeStr
    );
    this.vboxmanage(
      ["controlvm", vmname, "keyboardputscancode", codeStr],
      function (error, stdout) {
        callback(error, stdout);
      }
    );
  }

  exec(options, callback) {
    var vm = options.vm || options.name || options.vmname || options.title,
      username = options.user || options.username || "Guest",
      password = options.pass || options.passwd || options.password,
      path =
        options.path ||
        options.cmd ||
        options.command ||
        options.exec ||
        options.execute ||
        options.run,
      params = options.params || options.parameters || options.args;

    if (Array.isArray(params)) {
      params = params.join(" ");
    }

    if (params === undefined) {
      params = "";
    }

    const getOSTypeCb = (os_type) => {
      var cmd = ["guestcontrol", vm];
      var runcmd = this._vboxVersion > 5 ? ["run"] : ["execute", "--image"];
      cmd = [...cmd, ...runcmd];
      switch (os_type) {
        case known_OS_types.WINDOWS:
          path = path.replace(/\\/g, "\\\\");
          cmd.push("cmd.exe", "--username", username);
          break;
        case known_OS_types.MAC:
          cmd.push("/usr/bin/open", "-a", "--username", username);
          break;
        case known_OS_types.LINUX:
          cmd.push("/bin/sh", "--username", username);
          break;
        default:
          break;
      }

      if (password) {
        cmd.push("--password", password);
      }
      cmd.push("--", "/c", path, params);

      this._logging.info(
        'Executing command "vboxmanage %s" on VM "%s" detected OS type "%s"',
        cmd,
        vm,
        os_type
      );

      this.vboxmanage(cmd, function (error, stdout) {
        callback(error, stdout);
      });
    };

    this.guestproperty.os(vm, getOSTypeCb);
  }

  kill(options, callback) {
    options = options || {};
    var vm = options.vm || options.name || options.vmname || options.title,
      path =
        options.path ||
        options.cmd ||
        options.command ||
        options.exec ||
        options.execute ||
        options.run,
      image_name = options.image_name || path;

    this.guestproperty.os(vm, (os_type) => {
      switch (os_type) {
        case known_OS_types.WINDOWS:
          this._executor(
            {
              vm: vm,
              user: options.user,
              password: options.password,
              path: "C:\\Windows\\System32\\taskkill.exe /im ",
              params: image_name,
            },
            callback
          );
          break;
        case known_OS_types.MAC:
        case known_OS_types.LINUX:
          this._executor(
            {
              vm: vm,
              user: options.user,
              password: options.password,
              path: "sudo killall ",
              params: image_name,
            },
            callback
          );
          break;
      }
    });
  }

  _setVboxManageBinary() {
    this._logging.info(host_platform);
    if (/^win/.test(host_platform)) {
      // Path may not contain VBoxManage.exe but it provides this environment variable
      const vBoxInstallPath =
        process.env.VBOX_INSTALL_PATH || process.env.VBOX_MSI_INSTALL_PATH;
      this._vBoxManageBinary = `${vBoxInstallPath}VBoxManage.exe`;
    } else if (/^darwin/.test(host_platform) || /^linux/.test(host_platform)) {
      // Mac OS X and most Linux use the same binary name, in the path
      this._vBoxManageBinary = "vboxmanage";
    } else {
      // Otherwise (e.g., SunOS) hope it's in the path
      this._vBoxManageBinary = "vboxmanage";
    }
  }

  _detectVboxVersion() {
    this._executor(this._vBoxManageBinary, ["--version"]).then(
      ({ error, stdout }) => {
        if (error) {
          throw error;
        } else {
          this._vboxVersion = stdout.split(".")[0];
          this._logging.info(
            "Virtualbox version detected as %s",
            this._vboxVersion
          );
        }
      }
    );
  }
}

class VboxStorage {
  constructor(logging, executor, vBoxManageBinary) {
    this._logging = logging;
    this._executor = executor;
    this._vBoxManageBinary = vBoxManageBinary;
    this.vboxmanage = defaultvboxmanage;
  }

  addCtl(options, callback) {
    var vm = options.vm || options.name || options.vmname || options.title,
      device_name = options.perhiperal_name || "IDE",
      type = options.type || "ide";
    this._logging.info(
      'Adding "%s" controller named "%s" to %s',
      type,
      device_name,
      vm
    );
    var cmd = ["storagectl", vm, "--name", device_name, "--add", type];
    this.vboxmanage(cmd, callback);
  }

  attach(options, callback) {
    var vm = options.vm || options.name || options.vmname || options.title,
      device_name = options.perhiperal_name || "IDE",
      port = options.port || "0",
      device = options.device || "0",
      type = options.type || "dvddrive",
      medium = options.medium;
    this._logging.info(
      'Mounting "%s" to controller named "%s" on %s',
      medium,
      device_name,
      vm
    );
    var cmd = [
      "storageattach",
      vm,
      "--storagectl",
      device_name,
      "--port",
      port,
      "--device",
      device,
      "--type",
      type,
      "--medium",
      medium,
    ];
    this.vboxmanage(cmd, callback);
  }
}

class VboxGuestProperty {
  constructor(logging, executor, vBoxManageBinary) {
    this._logging = logging;
    this._executor = executor;
    this._vBoxManageBinary = vBoxManageBinary;
    this.os_type = null;
    this.vboxmanage = defaultvboxmanage;
  }

  get(options, callback) {
    var vm = options.vm || options.name || options.vmname || options.title,
      key = options.key,
      defaultValue = options.defaultValue || options.value;

    this.os(vm, (_) => {
      this.vboxmanage(
        ["guestproperty", "get", vm, key],
        function (error, stdout) {
          var value;
          if (error) {
            throw error;
          }
          try {
            value = stdout.substr(stdout.indexOf(":") + 1).trim();
          } catch (ex) {
            this._logging.error(ex);
            callback(defaultValue);
          }
          if (value === "No value set!") {
            value = defaultValue || undefined;
          }
          callback(value);
        }
      );
    });
  }

  os(vmname, callback) {
    if (this.os_type) {
      return callback(this.os_type);
    }

    try {
      this.vboxmanage(
        ["showvminfo", "--machinereadable", vmname],
        (error, stdout, _) => {
          if (error) {
            throw error;
          }

          // The ostype is matched against the ID attribute of 'vboxmanage list ostypes'
          if (stdout.indexOf('ostype="Windows') !== -1) {
            this.os_type = known_OS_types.WINDOWS;
          } else if (
            ['ostype="MacOS', 'ostype="Mac OS machine'].includes(stdout)
          ) {
            this.os_type = known_OS_types.MAC;
          } else {
            this.os_type = known_OS_types.LINUX;
          }
          this._logging.debug("Detected guest OS as: " + this.os_type);
          callback(this.os_type);
        }
      );
    } catch (e) {
      this._logging.error(e);
      this._logging.info("Could not showvminfo for %s", vmname);
    }
  }

  /**
   * Function to return an array of this object:
   * {
   *    "key": "ResumeCounter",
   *    "value": 0,
   *    "namespace": "VMInfo",
   *    "timestamp": 1596902741176896000,
   *    "flags": ["TRANSIENT", "RDONLYGUEST"]
   * }
   * @param {String} vmname The name of the VM to enumerate guest properties on.
   * @param {Function} callback The callback to handle the output.
   * @returns {void} The output of stdout will be an array of properties objects.
   */
  enumerate(vmname, callback) {
    this.vboxmanage(
      ["guestproperty", "enumerate", vmname],
      (err, stdout, _) => {
        if (err) {
          throw err;
        }
        const arrOfProps = stdout.split("\n");
        const nameRegex = /(?<=Name: ).+?(?=\,)/;
        const valueRegex = /(?<=value: ).+?(?=\,)/;
        const timestampRegex = /(?<=timestamp: ).+?(?=\,)/;
        const flagsRegex = /(?<=flags: ).*/;

        const arrOfPropsParsed = [];
        arrOfProps
          .filter((prop) => !!prop)
          .forEach((prop) => {
            const nameMatch = prop.match(nameRegex).shift(),
              value = prop.match(valueRegex).shift(),
              timestamp = prop.match(timestampRegex).shift(),
              flags = prop
                .match(flagsRegex)
                .shift()
                .split(",")
                .map((flag) => flag.replace(" ", "")),
              nameMatchSplit = nameMatch
                .split("/")
                .filter((name) => name !== ""),
              key = nameMatchSplit[2],
              namespace = nameMatchSplit[1];
            arrOfPropsParsed.push({
              key,
              value,
              namespace,
              timestamp,
              flags,
            });
          });
        callback(err, arrOfPropsParsed);
      }
    );
  }
}

class VboxExtraData {
  constructor(logging, executor, vBoxManageBinary) {
    this._logging = logging;
    this._executor = executor;
    this._vBoxManageBinary = vBoxManageBinary;
    this.vboxmanage = defaultvboxmanage;
  }

  get(options, callback) {
    var vm = options.vm || options.name || options.vmname || options.title,
      key = options.key,
      defaultValue = options.defaultValue || options.value;

    this.vboxmanage(["getextradata", vm, key], function (error, stdout) {
      var value;
      if (error) {
        callback(error);
        return;
      }
      try {
        value = stdout.substr(stdout.indexOf(":") + 1).trim();
      } catch (ex) {
        this._logging.error(ex);
        callback(ex, defaultValue);
      }
      if (value === "No value set!") {
        value = defaultValue || undefined;
      }
      callback(null, value);
    });
  }

  set(options, callback) {
    var vm = options.vm || options.name || options.vmname || options.title,
      key = options.key,
      value = options.defaultValue || options.value;

    var cmd = ["setextradata", vm, key, value];
    this.vboxmanage(cmd, function (error, _) {
      callback(error);
    });
  }
}

// module.exports = {
//   'exec': vmExec,
//   'kill': vmKill,
//   'list': list,
//   'pause': pause,
//   'reset': reset,
//   'resume': resume,
//   'start': start,
//   'stop': stop,
//   'savestate': savestate,
//   'import': vmImport,
//   'export': vmExport,
//   'poweroff': poweroff,
//   'acpisleepbutton': acpisleepbutton,
//   'acpipowerbutton': acpipowerbutton,
//   'modify': modify,
//   'guestproperty': guestproperty,
//   'keyboardputscancode': keyboardputscancode,
//   'snapshotList': snapshotList,
//   'snapshotTake': snapshotTake,
//   'snapshotDelete': snapshotDelete,
//   'snapshotRestore': snapshotRestore,
//   'isRunning': isRunning,
//   'extradata': extradata,
//   'clone': clone,
//   'storage': storage,

//   'SCAN_CODES': require('./scan-codes')
// };

module.exports = new Virtualbox();
module.exports.create = Virtualbox.create;
module.exports.Virtualbox = Virtualbox;


================================================
FILE: package.json
================================================
{
  "name": "virtualbox",
  "version": "1.1.2",
  "description": "A library to interact with VirtualBox.",
  "author": "Azer Koculu <azer@kodfabrik.com>",
  "license": "MIT",
  "bugs": "https://github.com/Node-Virtualization/node-virtualbox/issues",
  "contributors": [
    {
      "name": "Azer Koculu",
      "url": "http://azer.bike",
      "email": "azer@kodfabrik.com"
    },
    {
      "name": "Michael Sanford",
      "url": "http://accidentalbeard.com"
    },
    {
      "name": "Jonathan Ling",
      "url": "https://jonathanling.net"
    },
    {
      "name": "Steffen Roegner",
      "url": "http://www.sroegner.org"
    },
    {
      "name": "Jakub Lekstan",
      "url": "https://github.com/kuebk"
    },
    {
      "name": "Christopher'chief' Najewicz",
      "url": "http://chiefy.github.io"
    },
    {
      "name": "Cédric Belin",
      "url": "http://belin.io"
    },
    {
      "name": "bschaepper",
      "url": "https://github.com/bschaepper"
    },
    {
      "name": "2roy999",
      "url": "https://github.com/2roy999"
    },
    {
      "name": "Felipe Miranda",
      "url": "https://github.com/felipemdrs"
    }
  ],
  "keywords": [
    "virtualbox",
    "vboxmanage",
    "vboxheadless"
  ],
  "directories": {
    "lib": "./lib"
  },
  "scripts": {
    "test": "jest ./test/*.spec.js",
    "lint": "eslint ./lib ./test"
  },
  "main": "./lib/virtualbox",
  "repository": {
    "type": "git",
    "url": "https://github.com/Node-Virtualization/node-virtualbox.git"
  },
  "devDependencies": {
    "async": "^3.2.5",
    "eslint": "^8.57.0",
    "jest": "^26.0.1",
    "jsdoc": "^4.0.2",
    "prettier": "^3.2.5"
  },
  "engines": {
    "engine": "node >= 18"
  },
  "dependencies": {
    "log4js": "^6.9.1"
  }
}


================================================
FILE: test/guestproperty.spec.js
================================================
'use strict';

const { logger } = require('./helpers/logger');
const { create } = require('../lib/virtualbox');

describe('Virtualbox#guestproperty', () => {
  it('should not throw an error when getting a guest property with ostype of MacOS', (done) => {
    const executor = jest
      .fn()
      .mockReturnValueOnce(
        new Promise((resolve) =>
          resolve({ err: null, stdout: 'somevalue', stderr: '' })
        )
      )
      .mockReturnValueOnce(
        new Promise((resolve) =>
          resolve({ err: null, stdout: 'ostype="MacOS', stderr: '' })
        )
      )
      .mockReturnValueOnce(
        new Promise((resolve) =>
          resolve({
            err: null,
            stdout: 'somevalue',
            stderr: '',
          })
        )
      );
    const virtualbox = create(logger, executor);
    virtualbox.guestproperty.get(
      { vm: 'testmachine', key: 'someProperty' },
      function (value) {
        expect(value).toBeTruthy();
        expect(virtualbox.guestproperty.os_type).toBe('mac');
        done();
      }
    );
  });

  it('should not throw an error when getting a guest property with ostype of Mac OS machine', (done) => {
    const executor = jest
      .fn()
      .mockReturnValueOnce(
        new Promise((resolve) =>
          resolve({
            err: null,
            stdout: 'somevalue',
            stderr: '',
          })
        )
      )
      .mockReturnValueOnce(
        new Promise((resolve) =>
          resolve({
            err: null,
            stdout: 'ostype="Mac OS machine',
            stderr: '',
          })
        )
      )
      .mockReturnValueOnce(
        new Promise((resolve) =>
          resolve({
            err: null,
            stdout: 'somevalue',
            stderr: '',
          })
        )
      );
    const virtualbox = create(logger, executor);
    virtualbox.guestproperty.get(
      { vm: 'testmachine', key: 'someProperty' },
      function (value) {
        expect(value).toBeTruthy();
        expect(virtualbox.guestproperty.os_type).toBe('mac');
        done();
      }
    );
  });
});


================================================
FILE: test/helpers/logger.js
================================================
"use strict";
const log4js = require("log4js"),
  defaultLoggingConfig = {
    appenders: {
      out: {
        type: "stdout",
        layout: {
          type: "pattern",
          pattern: "%[[%d{yyyy-MM-dd hh:mm:ss.SSS}] [%p] %c - %]%m",
        },
      },
    },
    categories: { default: { appenders: ["out"], level: "debug" } },
  };

log4js.configure(defaultLoggingConfig);

module.exports.logger = log4js.getLogger("VboxTestLogger");


================================================
FILE: test/integration/acpipowerbutton.js
================================================
'use strict';

const virtualbox = require('../../lib/virtualbox'),
  vmName = 'node-virtualbox-test-machine';

virtualbox.acpipowerbutton(vmName, function (error) {
  if (error) {
    throw error;
  }
});


================================================
FILE: test/integration/acpisleepbutton.js
================================================
'use strict';

const virtualbox = require('../../lib/virtualbox'),
  vmName = 'node-virtualbox-test-machine';

virtualbox.acpisleepbutton(vmName, function (error) {
  if (error) {
    throw error;
  }
});


================================================
FILE: test/integration/exec.js
================================================
"use strict";

const virtualbox = require("../../lib/virtualbox"),
  vm = "node-virtualbox-test-machine",
  user = "vagrant",
  pass = "vagrant",
  { logger } = require("../helpers/logger"),
  ostype = virtualbox.guestproperty.os(vm);
let path;

if (ostype === "windows") {
  path = "C:\\Program Files\\Internet Explorer\\iexplore.exe";
} else if (ostype === "mac") {
  path = "Safari.app";
} else {
  path = "ping";
}

virtualbox.start(vm, function () {
  virtualbox.exec(
    {
      vm: vm,
      user: user,
      passwd: pass,
      path: path,
      params: ["http://google.com"],
    },
    function (error, stdout) {
      if (error) {
        throw error;
      }
      logger.debug(stdout);
    }
  );
});


================================================
FILE: test/integration/export.js
================================================
'use strict';

var virtualbox = require('../../lib/virtualbox'),
  vmName = 'node-virtualbox-test-machine';

virtualbox.export(vmName, 'test-export', function (error) {
  if (error) {
    throw error;
  }
});


================================================
FILE: test/integration/getextradata.js
================================================
"use strict";

var virtualbox = require("../../lib/virtualbox"),
  vmname = "node-virtualbox-test-machine",
  { logger } = require("../helpers/logger"),
  key = "some-data-key";

virtualbox.extradata.get({ vmname, key }, function (error, value) {
  if (error) {
    throw error;
  }

  logger.debug(
    'Virtual Machine "%s" extra "%s" value is "%s"',
    vmname,
    key,
    value
  );
});


================================================
FILE: test/integration/guestproperty-enumerate.js
================================================
"use strict";

const virtualbox = require("../../lib/virtualbox"),
  { logger } = require("../helpers/logger"),
  vm = "node-virtualbox-test-machine";

virtualbox.guestproperty.enumerate(vm, (err, arr) => {
  logger.debug(arr);
});


================================================
FILE: test/integration/guestproperty.js
================================================
"use strict";

const virtualbox = require("../../lib/virtualbox"),
  { logger } = require("../helpers/logger"),
  options = {
    vm: "node-virtualbox-test-machine",
    key: "/VirtualBox/GuestInfo/Net/0/V4/IP",
  };

virtualbox.guestproperty.get(options, (error, stdout, _) => {
  if (error) {
    throw error;
  }
  logger.debug(error, stdout, _);
  logger.debug(stdout);
});


================================================
FILE: test/integration/isRunning.js
================================================
"use strict";

var virtualbox = require("../../lib/virtualbox"),
  { logger } = require("../helpers/logger"),
  vm = "node-virtualbox-test-machine";

virtualbox.isRunning(vm, function (error, isRunning) {
  if (error) {
    throw error;
  }
  if (isRunning) {
    logger.log('Virtual Machine "%s" is Running', vm);
  } else {
    logger.log('Virtual Machine "%s" is Poweroff', vm);
  }
});


================================================
FILE: test/integration/keyboardputscancode.js
================================================
"use strict";

var virtualbox = require("../../lib/virtualbox"),
  { logger } = require("../helpers/logger"),
  async = require("async"),
  args = process.argv.slice(2),
  vm = "node-virtualbox-test-machine",
  key = args.length > 1 && args[1],
  delay = 250,
  sequence;

var SCAN_CODES = virtualbox.SCAN_CODES;

var fns = [];

/**
 *
 * Uncomment the following if you want to
 * test a particular key down/up (make/break)
 * sequence.
 *
 **/

// SHIFT + A Sequence
sequence = [
  { key: "SHIFT", type: "make", code: SCAN_CODES["SHIFT"] },
  { key: "A", type: "make", code: SCAN_CODES["A"] },
  { key: "SHIFT", type: "break", code: SCAN_CODES.getBreakCode("SHIFT") },
  { key: "A", type: "break", code: SCAN_CODES.getBreakCode("A") },
];

function onResponse(err) {
  if (err) {
    throw err;
  }
}

function generateFunc(key, type, code) {
  return function (cb) {
    setTimeout(function () {
      logger.info("Sending %s %s code", key, type);
      virtualbox.keyboardputscancode(vm, code, function (err) {
        onResponse(err);
        cb();
      });
    }, delay);
  };
}

function addKeyFuncs(key) {
  var makeCode = SCAN_CODES[key];
  var breakCode = SCAN_CODES.getBreakCode(key);

  if (makeCode && makeCode.length) {
    fns.push(generateFunc(key, "make", makeCode));

    if (breakCode && breakCode.length) {
      fns.push(generateFunc(key, "break", breakCode));
    }
  }
}

if (sequence) {
  fns = sequence.map(function (s) {
    return generateFunc(s.key, s.type, s.code);
  });
} else if (key) {
  addKeyFuncs(key);
} else {
  for (var codeKey in SCAN_CODES) {
    if (codeKey === "getBreakCode") {
      continue;
    }
    addKeyFuncs(key);
  }
}

async.series(fns, function () {
  logger.info("Keyboard Put Scan Code Test Complete");
});


================================================
FILE: test/integration/list.js
================================================
'use strict';

var util = require('util');
var virtualbox = require('../../lib/virtualbox');

virtualbox.list(function (list_data, error) {
  if (error) {
    throw error;
  }

  if (list_data) {
    virtualbox._logging.log(util.inspect(list_data));
    //logger.log(list_data);
  }
});


================================================
FILE: test/integration/modify.js
================================================
'use strict';

var virtualbox = require('../../lib/virtualbox'),
  vmName = 'node-virtualbox-test-machine';

virtualbox.modify(vmName, { memory: 64 }, function (error) {
  if (error) {
    throw error;
  }
});


================================================
FILE: test/integration/pause.js
================================================
'use strict';

const virtualbox = require('../../lib/virtualbox'),
  vmName = 'node-virtualbox-test-machine';

virtualbox.pause(vmName, function (error) {
  if (error) {
    throw error;
  }
});


================================================
FILE: test/integration/poweroff.js
================================================
'use strict';

var virtualbox = require('../../lib/virtualbox'),
  vmName = 'node-virtualbox-test-machine';

virtualbox.poweroff(vmName, function (error) {
  if (error) {
    throw error;
  }
});


================================================
FILE: test/integration/resume.js
================================================
'use strict';

const virtualbox = require('../../lib/virtualbox'),
  vmName = 'node-virtualbox-test-machine';

virtualbox.resume(vmName, function (error) {
  if (error) {
    throw error;
  }
});


================================================
FILE: test/integration/savestate.js
================================================
'use strict';

var virtualbox = require('../../lib/virtualbox'),
  vmName = 'node-virtualbox-test-machine';

virtualbox.savestate(vmName, function (error) {
  if (error) {
    throw error;
  }
});


================================================
FILE: test/integration/setextradata.js
================================================
'use strict';

var virtualbox = require('../../lib/virtualbox'),
  vmname = 'node-virtualbox-test-machine',
  key = 'some_value',
  value = 'kind of value';

virtualbox.extradata.set({ vmname, key, value }, function (error, result) {
  if (error) {
    throw error;
  }

  virtualbox._logging.log(
    'Set Virtual Machine "%s" extra "%s" value to "%s"; result is "%s"',
    vmname,
    key,
    value,
    result
  );
});


================================================
FILE: test/integration/snapshot-delete.js
================================================
'use strict';

var virtualbox = require('../../lib/virtualbox'),
  vm = 'node-virtualbox-test-machine',
  uuid = '44f96692-854f-4358-b246-d455bc403e16';

virtualbox.snapshotDelete(vm, uuid, function (error) {
  if (error) {
    throw error;
  }
});


================================================
FILE: test/integration/snapshot-list.js
================================================
'use strict';

var virtualbox = require('../../lib/virtualbox'),
  vm = 'node-virtualbox-test-machine';

virtualbox.snapshotList(vm, function (
  error,
  snapshotList,
  currentSnapshotUUID
) {
  if (error) {
    throw error;
  }

  if (snapshotList) {
    virtualbox._logging.log(
      JSON.stringify(snapshotList),
      JSON.stringify(currentSnapshotUUID)
    );
  }
});


================================================
FILE: test/integration/snapshot-restore.js
================================================
'use strict';

var virtualbox = require('../../lib/virtualbox'),
  vm = 'node-virtualbox-test-machine',
  uuid = '44f96692-854f-4358-b246-d455bc403e16';

virtualbox.snapshotRestore(vm, uuid, function (error) {
  if (error) {
    throw error;
  }

  virtualbox._logging.log('Virtual machine has been restored');
});


================================================
FILE: test/integration/snapshot-take.js
================================================
'use strict';

var virtualbox = require('../../lib/virtualbox'),
  vmname = 'node-virtualbox-test-machine',
  exportName = 'test-export';

virtualbox.snapshotTake(vmname, exportName, function (error, uuid) {
  if (error) {
    throw error;
  }
  if (uuid) {
    virtualbox._logging.log('UUID: ' + uuid);
  }
});


================================================
FILE: test/integration/start.js
================================================
'use strict';

const virtualbox = require('../../lib/virtualbox'),
  vmName = 'node-virtualbox-test-machine';

virtualbox.start(vmName, function (error) {
  if (error) {
    throw error;
  }
});


================================================
FILE: test/integration/stop.js
================================================
'use strict';

var virtualbox = require('../../lib/virtualbox'),
  vmName = 'node-virtualbox-test-machine';

virtualbox.stop(vmName, function (error) {
  if (error) {
    throw error;
  }
});
Download .txt
gitextract_73cbe_5t/

├── .eslintrc
├── .github/
│   ├── dependabot.yml
│   ├── stale.yml
│   └── workflows/
│       └── main.yml
├── .gitignore
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── Vagrantfile
├── code_of_conduct.md
├── lib/
│   ├── scan-codes.js
│   └── virtualbox.js
├── package.json
└── test/
    ├── guestproperty.spec.js
    ├── helpers/
    │   └── logger.js
    └── integration/
        ├── acpipowerbutton.js
        ├── acpisleepbutton.js
        ├── exec.js
        ├── export.js
        ├── getextradata.js
        ├── guestproperty-enumerate.js
        ├── guestproperty.js
        ├── isRunning.js
        ├── keyboardputscancode.js
        ├── list.js
        ├── modify.js
        ├── pause.js
        ├── poweroff.js
        ├── resume.js
        ├── savestate.js
        ├── setextradata.js
        ├── snapshot-delete.js
        ├── snapshot-list.js
        ├── snapshot-restore.js
        ├── snapshot-take.js
        ├── start.js
        └── stop.js
Download .txt
SYMBOL INDEX (43 symbols across 2 files)

FILE: lib/virtualbox.js
  class Virtualbox (line 62) | class Virtualbox {
    method constructor (line 63) | constructor(logging = defaultLogger, executor = defaultExecutor) {
    method create (line 89) | static create(logging, executor) {
    method pause (line 94) | pause(vmname, callback) {
    method list (line 101) | list(callback) {
    method reset (line 144) | reset(vmname, callback) {
    method resume (line 151) | resume(vmname, callback) {
    method start (line 158) | start(vmname, useGui, callback) {
    method stop (line 178) | stop(vmname, callback) {
    method savestate (line 185) | savestate(vmname, callback) {
    method vmExport (line 190) | vmExport(vmname, output, callback) {
    method vmImport (line 200) | vmImport(input, options, callback) {
    method poweroff (line 231) | poweroff(vmname, callback) {
    method acpipowerbutton (line 238) | acpipowerbutton(vmname, callback) {
    method acpisleepbutton (line 245) | acpisleepbutton(vmname, callback) {
    method modify (line 255) | modify(vname, properties, callback) {
    method snapshotList (line 277) | snapshotList(vmname, callback) {
    method snapshotTake (line 317) | snapshotTake(
    method snapshotDelete (line 354) | snapshotDelete(vmname, uuid, callback) {
    method snapshotRestore (line 359) | snapshotRestore(vmname, uuid, callback) {
    method clone (line 364) | clone(vmname, clonevmname, /*optional*/ snapshot, callback) {
    method isRunning (line 379) | isRunning(vmname, callback) {
    method keyboardputscancode (line 393) | keyboardputscancode(vmname, codes, callback) {
    method exec (line 417) | exec(options, callback) {
    method kill (line 477) | kill(options, callback) {
    method _setVboxManageBinary (line 520) | _setVboxManageBinary() {
    method _detectVboxVersion (line 536) | _detectVboxVersion() {
  class VboxStorage (line 553) | class VboxStorage {
    method constructor (line 554) | constructor(logging, executor, vBoxManageBinary) {
    method addCtl (line 561) | addCtl(options, callback) {
    method attach (line 575) | attach(options, callback) {
  class VboxGuestProperty (line 606) | class VboxGuestProperty {
    method constructor (line 607) | constructor(logging, executor, vBoxManageBinary) {
    method get (line 615) | get(options, callback) {
    method os (line 643) | os(vmname, callback) {
    method enumerate (line 689) | enumerate(vmname, callback) {
  class VboxExtraData (line 733) | class VboxExtraData {
    method constructor (line 734) | constructor(logging, executor, vBoxManageBinary) {
    method get (line 741) | get(options, callback) {
    method set (line 765) | set(options, callback) {

FILE: test/integration/keyboardputscancode.js
  function onResponse (line 32) | function onResponse(err) {
  function generateFunc (line 38) | function generateFunc(key, type, code) {
  function addKeyFuncs (line 50) | function addKeyFuncs(key) {
Condensed preview — 37 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (71K chars).
[
  {
    "path": ".eslintrc",
    "chars": 4579,
    "preview": "// {\n//   // Settings\n//   \"esversion\"     : 6,\n//   \"passfail\"      : false,  // Stop on first error.\n//   \"maxerr\"    "
  },
  {
    "path": ".github/dependabot.yml",
    "chars": 248,
    "preview": "# .github/dependabot.yml\n\nversion: 2\nupdates:\n  - package-ecosystem: \"npm\"\n    directory: \"/\"\n    schedule:\n      interv"
  },
  {
    "path": ".github/stale.yml",
    "chars": 795,
    "preview": "# Number of days of inactivity before an issue becomes stale\ndaysUntilStale: 90\n# Number of days of inactivity before a "
  },
  {
    "path": ".github/workflows/main.yml",
    "chars": 644,
    "preview": "# GitHub Actions (.github/workflows/main.yml)\nname: Node.js CI\non:\n  pull_request:\n    branches:\n      - main\n      - ma"
  },
  {
    "path": ".gitignore",
    "chars": 670,
    "preview": "######################\n# OS-generated files\n######################\n.DS_Store\n.DS_Store?\n._*\n.Spotlight-V100\n.Trashes\neht"
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 1158,
    "preview": "# CONTRIBUTING\n\nPlease familiarize yourself with the [Contributor Code of Conduct](https://github.com/Node-Virtualizatio"
  },
  {
    "path": "LICENSE",
    "chars": 1095,
    "preview": "The MIT License (MIT)\n\nCopyright (c) 2014 Azer Koçulu, Michael Sanford\n\nPermission is hereby granted, free of charge, to"
  },
  {
    "path": "README.md",
    "chars": 16240,
    "preview": "# node-virtualbox\n\n![NPM version](https://badge.fury.io/js/virtualbox.svg)\n[![Build Status](https://travis-ci.org/Node-V"
  },
  {
    "path": "Vagrantfile",
    "chars": 173,
    "preview": "Vagrant.configure(\"2\") do |config|\n  config.vm.box = \"generic/alpine38\"\n  config.vm.provider \"virtualbox\" do |vbox|\n    "
  },
  {
    "path": "code_of_conduct.md",
    "chars": 3204,
    "preview": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, w"
  },
  {
    "path": "lib/scan-codes.js",
    "chars": 2373,
    "preview": "\"use strict\";\n\nvar codes;\n\ncodes = {\n  ESCAPE: [0x01],\n  NUMBER_1: [0x02],\n  NUMBER_2: [0x03],\n  NUMBER_3: [0x04],\n  NUM"
  },
  {
    "path": "lib/virtualbox.js",
    "chars": 22051,
    "preview": "\"use strict\";\n\nconst execFile = require(\"child_process\").execFile,\n  log4js = require(\"log4js\"),\n  host_platform = proce"
  },
  {
    "path": "package.json",
    "chars": 1750,
    "preview": "{\n  \"name\": \"virtualbox\",\n  \"version\": \"1.1.2\",\n  \"description\": \"A library to interact with VirtualBox.\",\n  \"author\": \""
  },
  {
    "path": "test/guestproperty.spec.js",
    "chars": 2105,
    "preview": "'use strict';\n\nconst { logger } = require('./helpers/logger');\nconst { create } = require('../lib/virtualbox');\n\ndescrib"
  },
  {
    "path": "test/helpers/logger.js",
    "chars": 446,
    "preview": "\"use strict\";\nconst log4js = require(\"log4js\"),\n  defaultLoggingConfig = {\n    appenders: {\n      out: {\n        type: \""
  },
  {
    "path": "test/integration/acpipowerbutton.js",
    "chars": 205,
    "preview": "'use strict';\n\nconst virtualbox = require('../../lib/virtualbox'),\n  vmName = 'node-virtualbox-test-machine';\n\nvirtualbo"
  },
  {
    "path": "test/integration/acpisleepbutton.js",
    "chars": 205,
    "preview": "'use strict';\n\nconst virtualbox = require('../../lib/virtualbox'),\n  vmName = 'node-virtualbox-test-machine';\n\nvirtualbo"
  },
  {
    "path": "test/integration/exec.js",
    "chars": 716,
    "preview": "\"use strict\";\n\nconst virtualbox = require(\"../../lib/virtualbox\"),\n  vm = \"node-virtualbox-test-machine\",\n  user = \"vagr"
  },
  {
    "path": "test/integration/export.js",
    "chars": 209,
    "preview": "'use strict';\n\nvar virtualbox = require('../../lib/virtualbox'),\n  vmName = 'node-virtualbox-test-machine';\n\nvirtualbox."
  },
  {
    "path": "test/integration/getextradata.js",
    "chars": 393,
    "preview": "\"use strict\";\n\nvar virtualbox = require(\"../../lib/virtualbox\"),\n  vmname = \"node-virtualbox-test-machine\",\n  { logger }"
  },
  {
    "path": "test/integration/guestproperty-enumerate.js",
    "chars": 232,
    "preview": "\"use strict\";\n\nconst virtualbox = require(\"../../lib/virtualbox\"),\n  { logger } = require(\"../helpers/logger\"),\n  vm = \""
  },
  {
    "path": "test/integration/guestproperty.js",
    "chars": 378,
    "preview": "\"use strict\";\n\nconst virtualbox = require(\"../../lib/virtualbox\"),\n  { logger } = require(\"../helpers/logger\"),\n  option"
  },
  {
    "path": "test/integration/isRunning.js",
    "chars": 390,
    "preview": "\"use strict\";\n\nvar virtualbox = require(\"../../lib/virtualbox\"),\n  { logger } = require(\"../helpers/logger\"),\n  vm = \"no"
  },
  {
    "path": "test/integration/keyboardputscancode.js",
    "chars": 1764,
    "preview": "\"use strict\";\n\nvar virtualbox = require(\"../../lib/virtualbox\"),\n  { logger } = require(\"../helpers/logger\"),\n  async = "
  },
  {
    "path": "test/integration/list.js",
    "chars": 287,
    "preview": "'use strict';\n\nvar util = require('util');\nvar virtualbox = require('../../lib/virtualbox');\n\nvirtualbox.list(function ("
  },
  {
    "path": "test/integration/modify.js",
    "chars": 210,
    "preview": "'use strict';\n\nvar virtualbox = require('../../lib/virtualbox'),\n  vmName = 'node-virtualbox-test-machine';\n\nvirtualbox."
  },
  {
    "path": "test/integration/pause.js",
    "chars": 195,
    "preview": "'use strict';\n\nconst virtualbox = require('../../lib/virtualbox'),\n  vmName = 'node-virtualbox-test-machine';\n\nvirtualbo"
  },
  {
    "path": "test/integration/poweroff.js",
    "chars": 196,
    "preview": "'use strict';\n\nvar virtualbox = require('../../lib/virtualbox'),\n  vmName = 'node-virtualbox-test-machine';\n\nvirtualbox."
  },
  {
    "path": "test/integration/resume.js",
    "chars": 196,
    "preview": "'use strict';\n\nconst virtualbox = require('../../lib/virtualbox'),\n  vmName = 'node-virtualbox-test-machine';\n\nvirtualbo"
  },
  {
    "path": "test/integration/savestate.js",
    "chars": 197,
    "preview": "'use strict';\n\nvar virtualbox = require('../../lib/virtualbox'),\n  vmName = 'node-virtualbox-test-machine';\n\nvirtualbox."
  },
  {
    "path": "test/integration/setextradata.js",
    "chars": 423,
    "preview": "'use strict';\n\nvar virtualbox = require('../../lib/virtualbox'),\n  vmname = 'node-virtualbox-test-machine',\n  key = 'som"
  },
  {
    "path": "test/integration/snapshot-delete.js",
    "chars": 249,
    "preview": "'use strict';\n\nvar virtualbox = require('../../lib/virtualbox'),\n  vm = 'node-virtualbox-test-machine',\n  uuid = '44f966"
  },
  {
    "path": "test/integration/snapshot-list.js",
    "chars": 376,
    "preview": "'use strict';\n\nvar virtualbox = require('../../lib/virtualbox'),\n  vm = 'node-virtualbox-test-machine';\n\nvirtualbox.snap"
  },
  {
    "path": "test/integration/snapshot-restore.js",
    "chars": 315,
    "preview": "'use strict';\n\nvar virtualbox = require('../../lib/virtualbox'),\n  vm = 'node-virtualbox-test-machine',\n  uuid = '44f966"
  },
  {
    "path": "test/integration/snapshot-take.js",
    "chars": 312,
    "preview": "'use strict';\n\nvar virtualbox = require('../../lib/virtualbox'),\n  vmname = 'node-virtualbox-test-machine',\n  exportName"
  },
  {
    "path": "test/integration/start.js",
    "chars": 195,
    "preview": "'use strict';\n\nconst virtualbox = require('../../lib/virtualbox'),\n  vmName = 'node-virtualbox-test-machine';\n\nvirtualbo"
  },
  {
    "path": "test/integration/stop.js",
    "chars": 192,
    "preview": "'use strict';\n\nvar virtualbox = require('../../lib/virtualbox'),\n  vmName = 'node-virtualbox-test-machine';\n\nvirtualbox."
  }
]

About this extraction

This page contains the full source code of the Node-Virtualization/node-virtualbox GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 37 files (63.8 KB), approximately 18.0k tokens, and a symbol index with 43 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!