diff --git a/lib/commands/execute.js b/lib/commands/execute.js
new file mode 100644
index 00000000..e4fcfb07
--- /dev/null
+++ b/lib/commands/execute.js
@@ -0,0 +1,27 @@
+import _ from 'lodash';
+import { errors } from 'appium-base-driver';
+
+let extensions = {};
+
+extensions.execute = async function (script, args) {
+  if (script.match(/^mobile\:/)) {
+    script = script.replace(/^mobile\:/, '').trim();
+    return await this.executeMobile(script, _.isArray(args) ? args[0] : args);
+  }
+
+  throw new errors.NotImplementedError();
+};
+
+extensions.executeMobile = async function (mobileCommand, opts = {}) {
+  const mobileCommandsMapping = {
+    shell: async (x) => await this.mobileShell(x),
+  };
+
+  if (!_.has(mobileCommandsMapping, mobileCommand)) {
+    throw new errors.UnknownCommandError(`Unknown mobile command "${mobileCommand}". ` +
+                                         `Only ${_.keys(mobileCommandsMapping)} commands are supported.`);
+  }
+  return await mobileCommandsMapping[mobileCommand](opts);
+};
+
+export default extensions;
diff --git a/lib/commands/index.js b/lib/commands/index.js
index a77acee2..51e7755d 100644
--- a/lib/commands/index.js
+++ b/lib/commands/index.js
@@ -10,6 +10,8 @@ import networkCmds from './network';
 import coverageCmds from './coverage';
 import recordscreenCmds from './recordscreen';
 import performanceCmds from './performance';
+import executeCmds from "./execute";
+import shellCmds from "./shell";
 
 let commands = {};
 Object.assign(
@@ -25,7 +27,9 @@ Object.assign(
   networkCmds,
   coverageCmds,
   recordscreenCmds,
-  performanceCmds
+  performanceCmds,
+  executeCmds,
+  shellCmds,
   // add other command types here
 );
 
diff --git a/lib/commands/shell.js b/lib/commands/shell.js
new file mode 100644
index 00000000..88fcf54f
--- /dev/null
+++ b/lib/commands/shell.js
@@ -0,0 +1,28 @@
+import log from '../logger';
+import _ from 'lodash';
+import { util } from 'appium-support';
+
+let commands = {};
+
+commands.mobileShell = async function (opts = {}) {
+  if (!this.relaxedSecurityEnabled) {
+    log.errorAndThrow(`Appium server must have relaxed security flag set in order to run any shell commands`);
+  }
+
+  if (!_.isString(opts.command)) {
+    log.errorAndThrow(`The 'command' argument is mandatory'`);
+  }
+  let args = opts.args;
+  if (util.hasValue(args)) {
+    if (!_.isArray(args)) {
+      args = [args];
+    }
+  } else {
+    args = [];
+  }
+
+  return await this.adb.shell([opts.command, ...args]);
+};
+
+export { commands };
+export default commands;
diff --git a/test/functional/commands/execute-e2e-specs.js b/test/functional/commands/execute-e2e-specs.js
new file mode 100644
index 00000000..a08b0a55
--- /dev/null
+++ b/test/functional/commands/execute-e2e-specs.js
@@ -0,0 +1,58 @@
+import chai from 'chai';
+import chaiAsPromised from 'chai-as-promised';
+import AndroidDriver from '../../..';
+import _ from 'lodash';
+import DEFAULT_CAPS from '../desired';
+
+
+chai.should();
+chai.use(chaiAsPromised);
+
+let driver;
+let caps = _.defaults({
+  appPackage: 'io.appium.android.apis',
+  appActivity: '.view.TextFields'
+}, DEFAULT_CAPS);
+
+describe('execute', function () {
+  before(async function () {
+    driver = new AndroidDriver();
+    await driver.createSession(caps);
+  });
+  after(async function () {
+    await driver.deleteSession();
+  });
+
+  it('should fail if one tries to execute non-mobile command in native context', async function () {
+    await driver.execute('blabla').should.eventually.be.rejected;
+  });
+
+  it('should fail if one tries to execute an unknown mobile command in native context', async function () {
+    await driver.execute('mobile: blabla').should.eventually.be.rejectedWith(/Unknown mobile command/);
+  });
+
+  it('should fail if one tries to execute a shell command without relaxed security flag set', async function () {
+    await driver.execute('mobile: shell', {command: 'pm', args: ['list']})
+      .should.eventually.be.rejectedWith(/must have relaxed security flag set/);
+  });
+
+  it('should fail if no command argument is provided to shell call', async function () {
+    driver.relaxedSecurityEnabled = true;
+    try {
+      await driver.execute('mobile: shell', {comand: 'pm', args: ['list']})
+        .should.eventually.be.rejectedWith(/argument is mandatory/);
+    } finally {
+      driver.relaxedSecurityEnabled = undefined;
+    }
+  });
+
+  it('should return a result if correct shell command is provided', async function () {
+    driver.relaxedSecurityEnabled = true;
+    try {
+      (await driver.execute('mobile: shell', {command: 'echo', args: 'hello'}))
+        .should.not.be.empty;
+    } finally {
+      driver.relaxedSecurityEnabled = undefined;
+    }
+  });
+});