diff --git a/lib/cli/index.ts b/lib/cli/index.ts
index fdb079ff..0968116d 100644
--- a/lib/cli/index.ts
+++ b/lib/cli/index.ts
@@ -5,14 +5,16 @@ import * as start from '../cmds/start';
 import * as status from '../cmds/status';
 import * as update from '../cmds/update';
 
-const CHROME = 'chrome';
-const chromeOption: yargs.Options = {
+const CHROMEDRIVER_ALIAS = 'chrome';
+const CHROMEDRIVER = 'chromedriver';
+const chromedriverOption: yargs.Options = {
   describe: 'Install or update chromedriver.',
   default: true,
   type: 'boolean'
 };
-const CHROME_LOGS = 'chrome_logs';
-const chromeLogsOption: yargs.Options = {
+const CHROMEDRIVER_LOGS_ALIAS = 'chrome_logs';
+const CHROMEDRIVER_LOGS = 'chromedriver_logs';
+const chromedriverLogsOption: yargs.Options = {
   describe: 'File path to chrome logs.',
   type: 'string'
 };
@@ -30,8 +32,9 @@ const edgeOption: yargs.Options = {
       '"C:\Program Files (x86)\Microsoft Web Driver\MirosoftWebDriver.exe"',
   type: 'string'
 };
-const GECKO = 'gecko';
-const geckoOption: yargs.Options = {
+const GECKODRIVER_ALIAS = 'gecko';
+const GECKODRIVER = 'geckodriver';
+const geckodriverOption: yargs.Options = {
   describe: 'Install or update geckodriver.',
   default: true,
   type: 'boolean'
@@ -41,8 +44,9 @@ const githubTokenOption: yargs.Options = {
   describe: 'Use a GitHub token to prevent rate limit issues.',
   type: 'string'
 };
+const IEDRIVER_ALIAS = 'ie';
 const IEDRIVER = 'iedriver';
-const ieOption: yargs.Options = {
+const iedriverOption: yargs.Options = {
   describe: 'Install or update ie driver.',
   default: false,
   type: 'boolean'
@@ -58,6 +62,31 @@ const logLevelOption: yargs.Options = {
   default: 'info',
   type: 'string'
 };
+const MAX_VERSIONS_CHROMEDRIVER_ALIAS = 'max_versions.chrome';
+const MAX_VERSIONS_CHROMEDRIVER = 'max_versions.chromedriver';
+const maxVersionsChromedriverOption: yargs.Options = {
+  describe: 'The chromedriver max version used only for update.',
+  type: 'string'
+};
+const MAX_VERSIONS_GECKODRIVER_ALIAS = 'max_versions.gecko';
+const MAX_VERSIONS_GECKODRIVER = 'max_versions.geckodriver';
+const maxVersionsGeckodriverOption: yargs.Options = {
+  describe: 'The geckodriver max version used only for update.',
+  type: 'string'
+};
+const MAX_VERSIONS_IEDRIVER_ALIAS = 'max_versions.ie';
+const MAX_VERSIONS_IEDRIVER = 'max_versions.iedriver';
+const maxVersionsIedriverOption: yargs.Options = {
+  describe: 'The ie driver max version used only for update.',
+  type: 'string'
+};
+const MAX_VERSIONS_SELENIUM_ALIAS = 'max_versions.standalone';
+const MAX_VERSIONS_SELENIUM = 'max_versions.selenium';
+const maxVersionsSeleniumOption: yargs.Options = {
+  describe: 'The selenium server standalone max version used only for update.',
+  type: 'string'
+};
+
 const OUT_DIR = 'out_dir';
 const outDirOption: yargs.Options = {
   describe: 'Location of output.',
@@ -79,34 +108,40 @@ const seleniumLogLevelOption: yargs.Options = {
   describe: 'Set the -Dselenium.LOGGER.level flag when starting the server',
   type: 'string'
 };
-const STANDALONE = 'standalone';
-const standaloneOption: yargs.Options = {
+const SELENIUM_ALIAS = 'standalone';
+const SELENIUM = 'selenium';
+const seleniumOption: yargs.Options = {
   describe: 'Install or update selenium server standalone.',
   default: true,
   type: 'boolean'
 };
-const STANDALONE_NODE = 'standalone_node';
-const standaloneNodeOption: yargs.Options = {
+const SELENIUM_NODE_ALIAS = 'standalone_node';
+const SELENIUM_NODE = 'selenium_node';
+const seleniumNodeOption: yargs.Options = {
   describe: 'Start the selenium server standalone with role set to "node".',
   type: 'boolean'
 };
-const VERSIONS_CHROME = 'versions.chrome';
-const versionsChromeOption: yargs.Options = {
+const VERSIONS_CHROMEDRIVER_ALIAS = 'versions.chrome';
+const VERSIONS_CHROMEDRIVER = 'versions.chromedriver';
+const versionsChromedriverOption: yargs.Options = {
   describe: 'The chromedriver version.',
   type: 'string'
 };
-const VERSIONS_GECKO = 'versions.gecko';
-const versionsGeckoOption: yargs.Options = {
+const VERSIONS_GECKODRIVER_ALIAS = 'versions.gecko';
+const VERSIONS_GECKODRIVER = 'versions.geckodriver';
+const versionsGeckodriverOption: yargs.Options = {
   describe: 'The geckodriver version.',
   type: 'string'
 };
-const VERSIONS_IE = 'versions.ie';
-const versionsIeOption: yargs.Options = {
+const VERSIONS_IEDRIVER_ALIAS = 'versions.ie';
+const VERSIONS_IEDRIVER = 'versions.iedriver';
+const versionsIedriverOption: yargs.Options = {
   describe: 'The ie driver version.',
   type: 'string'
 };
-const VERSIONS_STANDALONE = 'versions.standalone';
-const versionsStandaloneOption: yargs.Options = {
+const VERSIONS_SELENIUM_ALIAS = 'versions.standalone';
+const VERSIONS_SELENIUM = 'versions.selenium';
+const versionsSeleniumOption: yargs.Options = {
   describe: 'The selenium server standalone version.',
   type: 'string'
 };
@@ -133,22 +168,33 @@ yargs
     .command(
         'start', 'Start up the selenium server.',
         (yargs: yargs.Argv) => {
-          return yargs.option(CHROME, chromeOption)
-              .option(CHROME_LOGS, chromeLogsOption)
+          return yargs
+              .option(CHROMEDRIVER, chromedriverOption)
+              .alias(CHROMEDRIVER_ALIAS, CHROMEDRIVER)
+              .option(CHROMEDRIVER_LOGS, chromedriverLogsOption)
+              .alias(CHROMEDRIVER_LOGS_ALIAS, CHROMEDRIVER_LOGS)
               .option(DETACH, detachOption)
               .option(EDGE, edgeOption)
-              .option(GECKO, geckoOption)
-              .option(IEDRIVER, ieOption)
+              .option(GECKODRIVER, geckodriverOption)
+              .alias(GECKODRIVER_ALIAS, GECKODRIVER)
+              .option(IEDRIVER, iedriverOption)
+              .alias(IEDRIVER_ALIAS, IEDRIVER)
               .option(LOG_LEVEL, logLevelOption)
               .option(OUT_DIR, outDirOption)
-              .option(SELENIUM_PORT, seleniumPort)
+              .option(SELENIUM, seleniumOption)
+              .alias(SELENIUM_ALIAS, SELENIUM)
               .option(SELENIUM_LOG_LEVEL, seleniumLogLevelOption)
-              .option(STANDALONE, standaloneOption)
-              .option(STANDALONE_NODE, standaloneNodeOption)
-              .option(VERSIONS_CHROME, versionsChromeOption)
-              .option(VERSIONS_GECKO, versionsGeckoOption)
-              .option(VERSIONS_IE, versionsIeOption)
-              .option(VERSIONS_STANDALONE, versionsStandaloneOption);
+              .option(SELENIUM_NODE, seleniumNodeOption)
+              .alias(SELENIUM_NODE_ALIAS, SELENIUM_NODE)
+              .option(SELENIUM_PORT, seleniumPort)
+              .option(VERSIONS_CHROMEDRIVER, versionsChromedriverOption)
+              .alias(VERSIONS_CHROMEDRIVER_ALIAS, VERSIONS_CHROMEDRIVER)
+              .option(VERSIONS_GECKODRIVER, versionsGeckodriverOption)
+              .alias(VERSIONS_GECKODRIVER_ALIAS, VERSIONS_GECKODRIVER)
+              .option(VERSIONS_IEDRIVER, versionsIedriverOption)
+              .alias(VERSIONS_IEDRIVER_ALIAS, VERSIONS_IEDRIVER)
+              .option(VERSIONS_SELENIUM, versionsSeleniumOption)
+              .alias(VERSIONS_SELENIUM_ALIAS, VERSIONS_SELENIUM);
         },
         (argv: yargs.Arguments) => {
           start.handler(argv);
@@ -166,19 +212,34 @@ yargs
         'update', 'Install or update selected binaries.',
         (yargs: yargs.Argv) => {
           return yargs.option(OUT_DIR, outDirOption)
-              .option(CHROME, chromeOption)
-              .option(GECKO, geckoOption)
+              .option(CHROMEDRIVER, chromedriverOption)
+              .alias(CHROMEDRIVER_ALIAS, CHROMEDRIVER)
+              .option(GECKODRIVER, geckodriverOption)
+              .alias(GECKODRIVER_ALIAS, GECKODRIVER)
               .option(GITHUB_TOKEN, githubTokenOption)
-              .option(IEDRIVER, ieOption)
+              .option(IEDRIVER, iedriverOption)
+              .alias(IEDRIVER_ALIAS, IEDRIVER)
               .option(IGNORE_SSL, ignoreSSLOption)
               .option(LOG_LEVEL, logLevelOption)
+              .option(MAX_VERSIONS_CHROMEDRIVER, maxVersionsChromedriverOption)
+              .alias(MAX_VERSIONS_CHROMEDRIVER_ALIAS, MAX_VERSIONS_CHROMEDRIVER)
+              .option(MAX_VERSIONS_GECKODRIVER, maxVersionsGeckodriverOption)
+              .alias(MAX_VERSIONS_GECKODRIVER_ALIAS, MAX_VERSIONS_GECKODRIVER)
+              .option(MAX_VERSIONS_IEDRIVER, maxVersionsIedriverOption)
+              .alias(MAX_VERSIONS_IEDRIVER_ALIAS, MAX_VERSIONS_IEDRIVER)
+              .option(MAX_VERSIONS_SELENIUM, maxVersionsSeleniumOption)
               .option(OUT_DIR, outDirOption)
               .option(PROXY, proxyOption)
-              .option(STANDALONE, standaloneOption)
-              .option(VERSIONS_CHROME, versionsChromeOption)
-              .option(VERSIONS_GECKO, versionsGeckoOption)
-              .option(VERSIONS_IE, versionsIeOption)
-              .option(VERSIONS_STANDALONE, versionsStandaloneOption);
+              .option(SELENIUM, seleniumOption)
+              .alias(SELENIUM_ALIAS, SELENIUM)
+              .option(VERSIONS_CHROMEDRIVER, versionsChromedriverOption)
+              .alias(VERSIONS_CHROMEDRIVER_ALIAS, VERSIONS_CHROMEDRIVER)
+              .option(VERSIONS_GECKODRIVER, versionsGeckodriverOption)
+              .alias(VERSIONS_GECKODRIVER_ALIAS, VERSIONS_GECKODRIVER)
+              .option(VERSIONS_IEDRIVER, versionsIedriverOption)
+              .alias(VERSIONS_IEDRIVER_ALIAS, VERSIONS_IEDRIVER)
+              .option(VERSIONS_SELENIUM, versionsSeleniumOption)
+              .alias(VERSIONS_SELENIUM_ALIAS, VERSIONS_SELENIUM);
         },
         (argv: yargs.Arguments) => {
           update.handler(argv);
diff --git a/lib/cmds/cmds.spec-e2e.ts b/lib/cmds/cmds.spec-e2e.ts
index decaa5fa..f9a36ecb 100644
--- a/lib/cmds/cmds.spec-e2e.ts
+++ b/lib/cmds/cmds.spec-e2e.ts
@@ -39,8 +39,8 @@ describe('using the cli', () => {
     it('should download the files', async () => {
       const argv = {
         _: ['foobar'],
-        chrome: true,
-        standalone: true,
+        chromedriver: true,
+        selenium: true,
         out_dir: tmpDir,
         '$0': 'bin\\webdriver-manager'
       };
@@ -70,9 +70,9 @@ describe('using the cli', () => {
     it('should start the selenium server standalone in role=node', async () => {
       const argv = {
         _: ['foobar'],
-        chrome: true,
-        standalone: true,
-        standalone_node: true,
+        chromedriver: true,
+        selenium: true,
+        selenium_node: true,
         out_dir: tmpDir,
         '$0': 'bin\\webdriver-manager'
       };
@@ -104,8 +104,8 @@ describe('using the cli', () => {
     it('should start the selenium server standalone', async () => {
       const argv = {
         _: ['foobar'],
-        chrome: true,
-        standalone: true,
+        chromedriver: true,
+        selenium: true,
         out_dir: tmpDir,
         '$0': 'bin\\webdriver-manager'
       };
diff --git a/lib/cmds/options.ts b/lib/cmds/options.ts
index e5ef3a1f..2728e321 100644
--- a/lib/cmds/options.ts
+++ b/lib/cmds/options.ts
@@ -16,14 +16,18 @@ export interface Options {
   githubToken?: string;
 }
 
+export type BrowserDriverName = 'chromedriver'|'geckodriver'|'iedriver';
+
 /**
  * Contains information about a browser driver.
  */
 export interface BrowserDriver {
   // The name of the browser driver.
-  name?: 'chromedriver'|'geckodriver'|'iedriver';
+  name?: BrowserDriverName;
   // The version which does not have to follow semver.
   version?: string;
+  // A max version that either fully or partially matches the version.
+  maxVersion?: string;
 }
 
 /**
@@ -35,6 +39,8 @@ export interface Server {
   name?: 'selenium';
   // The version which does not have to follow semver.
   version?: string;
+  // A max version that either fully or partially matches the version.
+  maxVersion?: string;
   // Run as role = node option.
   runAsNode?: boolean;
   // The relative or full path to the chrome logs file.
diff --git a/lib/cmds/update.ts b/lib/cmds/update.ts
index 3853c828..b7bd95c8 100644
--- a/lib/cmds/update.ts
+++ b/lib/cmds/update.ts
@@ -11,7 +11,7 @@ const log = loglevel.getLogger('webdriver-manager');
  * @param argv The argv from yargs.
  */
 export async function handler(argv: yargs.Arguments) {
-  log.setLevel(argv.log_level);
+  log.setLevel(argv['log_level']);
   const options = convertArgs2Options(argv);
   await update(options);
 }
@@ -35,12 +35,14 @@ export function updateBinary(optionsBinary: OptionsBinary): Promise<void[]> {
   const promises = [];
   if (optionsBinary.browserDrivers) {
     for (const provider of optionsBinary.browserDrivers) {
-      promises.push(provider.binary.updateBinary(provider.version));
+      promises.push(provider.binary.updateBinary(provider.version,
+        provider.maxVersion));
     }
   }
   if (optionsBinary.server && optionsBinary.server.binary) {
     promises.push(
-        optionsBinary.server.binary.updateBinary(optionsBinary.server.version));
+        optionsBinary.server.binary.updateBinary(optionsBinary.server.version,
+          optionsBinary.server.maxVersion));
   }
   return Promise.all(promises);
 }
\ No newline at end of file
diff --git a/lib/cmds/utils.spec-unit.ts b/lib/cmds/utils.spec-unit.ts
index 96ea951e..a30ef832 100644
--- a/lib/cmds/utils.spec-unit.ts
+++ b/lib/cmds/utils.spec-unit.ts
@@ -6,7 +6,7 @@ describe('utils', () => {
       const argv = {
         _: ['foobar'],
         proxy: 'http://some.proxy.com',
-        versions: {gecko: '0.16.0', chrome: '2.20'},
+        versions: {geckodriver: '0.16.0', chromedriver: '2.20'},
         out_dir: 'foobar_download',
         ignore_ssl: false,
         '$0': 'bin\\webdriver-manager'
@@ -14,22 +14,8 @@ describe('utils', () => {
       const options = convertArgs2AllOptions(argv);
       expect(options.browserDrivers).toBeTruthy();
       expect(options.browserDrivers.length).toBe(3);
-      for (const provider of options.browserDrivers) {
-        if (provider.name === 'geckodriver') {
-          expect(provider.version).toBe('0.16.0');
-        }
-        if (provider.name === 'chromedriver') {
-          expect(provider.version).toBe('2.20');
-        }
-        if (provider.name === 'iedriver') {
-          expect(provider.version).toBeUndefined();
-        }
-      }
       expect(options.server).toBeTruthy();
       expect(options.server.name).toBe('selenium');
-      expect(options.server.version).toBeUndefined();
-      expect(options.proxy).toBe('http://some.proxy.com');
-      expect(options.ignoreSSL).toBeFalsy();
       expect(options.outDir).toBe('foobar_download');
     });
   });
@@ -38,10 +24,10 @@ describe('utils', () => {
     it('should create the default providers', () => {
       const argv = {
         _: ['foobar'],
-        chrome: true,
-        gecko: true,
-        standalone: true,
-        versions: {gecko: '0.16.0', chrome: '2.20'},
+        chromedriver: true,
+        geckodriver: true,
+        selenium: true,
+        versions: {geckodriver: '0.16.0', chromedriver: '2.20'},
         out_dir: 'foobar_download',
         '$0': 'bin\\webdriver-manager'
       };
diff --git a/lib/cmds/utils.ts b/lib/cmds/utils.ts
index 8cf391ff..a1a880c8 100644
--- a/lib/cmds/utils.ts
+++ b/lib/cmds/utils.ts
@@ -5,7 +5,7 @@ import {IEDriver} from '../provider/iedriver';
 import {ProviderConfig} from '../provider/provider';
 import {SeleniumServer, SeleniumServerProviderConfig} from '../provider/selenium_server';
 
-import {Options} from './options';
+import {BrowserDriver, BrowserDriverName, Options} from './options';
 import {OptionsBinary} from './options_binary';
 
 /**
@@ -49,41 +49,25 @@ export function addOptionsBinary(options: Options): OptionsBinary {
 }
 
 /**
- * Create the options with all providers. Used for clean and status commands.
+ * For the clean and status commands ONLY.
+ * Create the options with all providers.
  * @param argv
  */
 export function convertArgs2AllOptions(argv: yargs.Arguments): Options {
-  let versionsChrome, versionsGecko, versionsIe, versionsStandalone = undefined;
-  if (argv.versions) {
-    versionsChrome = argv.versions.chrome as string;
-    versionsGecko = argv.versions.gecko as string;
-    versionsIe = argv.versions.ie as string;
-    versionsStandalone = argv.versions.standalone as string;
-  }
   return {
     browserDrivers: [
-      {name: 'chromedriver', version: versionsChrome},
-      {name: 'geckodriver', version: versionsGecko},
-      {name: 'iedriver', version: versionsIe}
+      {name: 'chromedriver'},
+      {name: 'geckodriver'},
+      {name: 'iedriver'}
     ],
-    server: {
-      name: 'selenium',
-      version: versionsStandalone,
-      runAsNode: argv.standalone_node as boolean,
-      runAsDetach: argv.detach as boolean,
-      chromeLogs: argv.chrome_logs as string,
-      edge: argv.edge as string,
-    },
-    ignoreSSL: argv.ignore_ssl as boolean,
-    outDir: argv.out_dir as string,
-    proxy: argv.proxy as string,
-    githubToken: argv.github_token as string,
+    server: {name: 'selenium'},
+    outDir: argv['out_dir'] as string
   };
 }
 
 /**
- * Create the options with providers depending on argv's. Used for update and
- * start commands.
+ * For the update and start commands ONLY.
+ * Create the options with providers depending on argv's.
  * @param argv
  */
 export function convertArgs2Options(argv: yargs.Arguments): Options {
@@ -96,33 +80,39 @@ export function convertArgs2Options(argv: yargs.Arguments): Options {
     githubToken: argv.github_token as string,
   };
 
-  let versionsChrome, versionsGecko, versionsIe, versionsStandalone = undefined;
-  if (argv.versions) {
-    versionsChrome = argv.versions.chrome as string;
-    versionsGecko = argv.versions.gecko as string;
-    versionsIe = argv.versions.ie as string;
-    versionsStandalone = argv.versions.standalone as string;
-  }
-  if (argv.chrome as boolean) {
-    options.browserDrivers.push(
-        {name: 'chromedriver', version: versionsChrome});
+  if (argv['chromedriver'] as boolean) {
+    setVersions('chromedriver', argv, options.browserDrivers);
   }
-  if (argv.gecko as boolean) {
-    options.browserDrivers.push({name: 'geckodriver', version: versionsGecko});
+  if (argv['geckodriver'] as boolean) {
+    setVersions('geckodriver', argv, options.browserDrivers);
   }
-  if (argv.iedriver as boolean) {
-    options.browserDrivers.push({name: 'iedriver', version: versionsIe});
+  if (argv['iedriver'] as boolean) {
+    setVersions('iedriver', argv, options.browserDrivers);
   }
-  if (argv.standalone as boolean) {
+  if (argv['selenium']) {
     options.server = {};
     options.server.name = 'selenium';
-    options.server.runAsNode = argv.standalone_node as boolean;
+    options.server.runAsNode = argv['selenium_node'] as boolean;
     options.server.runAsDetach = argv.detach as boolean;
-    options.server.version = versionsStandalone;
+    options.server.version = argv['versions'] && argv['versions']['selenium'] ?
+      argv['versions']['selenium'] as string : undefined;
+    options.server.maxVersion = argv['max_versions']
+      && argv['max_versions']['selenium'] ?
+      argv['versions']['selenium'] as string : undefined;
     options.server.chromeLogs = argv.chrome_logs as string;
     options.server.edge = argv.edge as string;
     options.server.port = argv.seleniumPort as number;
     options.server.logLevel = argv.seleniumLogLevel as string;
   }
   return options;
+}
+
+function setVersions(name: BrowserDriverName,
+    argv: yargs.Arguments, browserDrivers: BrowserDriver[]): BrowserDriver[] {
+  const version = argv['versions'] && argv['versions'][name] ?
+    argv['versions'][name] as string : undefined;
+  const maxVersion = argv['max_versions'] && argv['max_versions'][name] ?
+    argv['max_versions'][name] as string : undefined;
+  browserDrivers.push({name, version, maxVersion});
+  return browserDrivers;
 }
\ No newline at end of file
diff --git a/lib/provider/chromedriver.ts b/lib/provider/chromedriver.ts
index 403ef842..95c96973 100644
--- a/lib/provider/chromedriver.ts
+++ b/lib/provider/chromedriver.ts
@@ -18,6 +18,8 @@ export class ChromeDriver extends ProviderClass implements ProviderInterface {
   proxy: string = null;
   requestUrl = 'https://chromedriver.storage.googleapis.com/';
   seleniumFlag = '-Dwebdriver.chrome.driver';
+  version: string = null;
+  maxVersion: string = null;
 
   constructor(config?: ProviderConfig) {
     super();
@@ -29,14 +31,23 @@ export class ChromeDriver extends ProviderClass implements ProviderInterface {
     this.outDir = this.setVar('outDir', this.outDir, config);
     this.proxy = this.setVar('proxy', this.proxy, config);
     this.requestUrl = this.setVar('requestUrl', this.requestUrl, config);
+    this.version = this.setVar('version', this.version, config);
+    this.maxVersion = this.setVar('maxVersion', this.maxVersion, config);
   }
 
   /**
    * Should update the cache and download, find the version to download,
    * then download that binary.
    * @param version Optional to provide the version number or latest.
+   * @param maxVersion Optional to provide the max version.
    */
-  async updateBinary(version?: string): Promise<void> {
+  async updateBinary(version?: string, maxVersion?: string): Promise<void> {
+    if (!version) {
+      version = this.version;
+    }
+    if (!maxVersion) {
+      maxVersion = this.maxVersion;
+    }
     await updateXml(this.requestUrl, {
       fileName: path.resolve(this.outDir, this.cacheFileName),
       ignoreSSL: this.ignoreSSL,
@@ -48,7 +59,7 @@ export class ChromeDriver extends ProviderClass implements ProviderInterface {
         semanticVersionParser);
     const versionObj = getVersion(
         versionList, osHelper(this.osType, this.osArch),
-        formatVersion(version));
+        formatVersion(version), maxVersion);
 
     const chromeDriverUrl = this.requestUrl + versionObj.url;
     const chromeDriverZip = path.resolve(this.outDir, versionObj.name);
diff --git a/lib/provider/geckodriver.ts b/lib/provider/geckodriver.ts
index 9ecc93d9..a6db54e7 100644
--- a/lib/provider/geckodriver.ts
+++ b/lib/provider/geckodriver.ts
@@ -23,6 +23,8 @@ export class GeckoDriver extends ProviderClass implements ProviderInterface {
   proxy: string = null;
   requestUrl = 'https://api.github.com/repos/mozilla/geckodriver/releases';
   seleniumFlag = '-Dwebdriver.gecko.driver';
+  version: string = null;
+  maxVersion: string = null;
 
   constructor(config?: GeckoDriverProviderConfig) {
     super();
@@ -35,14 +37,23 @@ export class GeckoDriver extends ProviderClass implements ProviderInterface {
     this.proxy = this.setVar('proxy', this.proxy, config);
     this.requestUrl = this.setVar('requestUrl', this.requestUrl, config);
     this.oauthToken = this.setVar('oauthToken', this.oauthToken, config);
+    this.version = this.setVar('version', this.version, config);
+    this.maxVersion = this.setVar('maxVersion', this.version, config);
   }
 
   /**
    * Should update the cache and download, find the version to download,
    * then download that binary.
    * @param version Optional to provide the version number or latest.
+   * @param maxVersion Optional to provide the max version.
    */
-  async updateBinary(version?: string): Promise<void> {
+  async updateBinary(version?: string, maxVersion?: string): Promise<void> {
+    if (!version) {
+      version = this.version;
+    }
+    if (!maxVersion) {
+      maxVersion = this.maxVersion;
+    }
     await updateJson(
         this.requestUrl, {
           fileName: path.resolve(this.outDir, this.cacheFileName),
@@ -54,7 +65,8 @@ export class GeckoDriver extends ProviderClass implements ProviderInterface {
     const versionList =
         convertJsonToVersionList(path.resolve(this.outDir, this.cacheFileName));
     const versionObj =
-        getVersion(versionList, osHelper(this.osType, this.osArch), version);
+        getVersion(versionList, osHelper(this.osType, this.osArch), version,
+        maxVersion);
 
     const geckoDriverUrl = versionObj.url;
     const geckoDriverCompressed = path.resolve(this.outDir, versionObj.name);
diff --git a/lib/provider/iedriver.ts b/lib/provider/iedriver.ts
index 94fdc04b..c50f2c08 100644
--- a/lib/provider/iedriver.ts
+++ b/lib/provider/iedriver.ts
@@ -18,6 +18,8 @@ export class IEDriver extends ProviderClass implements ProviderInterface {
   proxy: string = null;
   requestUrl = 'https://selenium-release.storage.googleapis.com/';
   seleniumFlag = '-Dwebdriver.ie.driver';
+  version: string = null;
+  maxVersion: string = null;
 
   constructor(config?: ProviderConfig) {
     super();
@@ -29,14 +31,23 @@ export class IEDriver extends ProviderClass implements ProviderInterface {
     this.outDir = this.setVar('outDir', this.outDir, config);
     this.proxy = this.setVar('proxy', this.proxy, config);
     this.requestUrl = this.setVar('requestUrl', this.requestUrl, config);
+    this.version = this.setVar('version', this.version, config);
+    this.maxVersion = this.setVar('maxVersion', this.maxVersion, config);
   }
 
   /**
    * Should update the cache and download, find the version to download,
    * then download that binary.
    * @param version Optional to provide the version number or latest.
+   * @param maxVersion Optional to provide the max version.
    */
-  async updateBinary(version?: string): Promise<void> {
+  async updateBinary(version?: string, maxVersion?: string): Promise<void> {
+    if (!version) {
+      version = this.version;
+    }
+    if (!maxVersion) {
+      maxVersion = this.maxVersion;
+    }
     await updateXml(this.requestUrl, {
       fileName: path.resolve(this.outDir, this.cacheFileName),
       ignoreSSL: this.ignoreSSL,
@@ -46,7 +57,8 @@ export class IEDriver extends ProviderClass implements ProviderInterface {
         path.resolve(this.outDir, this.cacheFileName), '.zip', versionParser,
         semanticVersionParser);
     const versionObj =
-        getVersion(versionList, osHelper(this.osType, this.osArch), version);
+        getVersion(versionList, osHelper(this.osType, this.osArch), version,
+        maxVersion);
 
     const chromeDriverUrl = this.requestUrl + versionObj.url;
     const chromeDriverZip = path.resolve(this.outDir, versionObj.name);
diff --git a/lib/provider/provider.ts b/lib/provider/provider.ts
index f3f9dc21..5c11fc8b 100644
--- a/lib/provider/provider.ts
+++ b/lib/provider/provider.ts
@@ -11,10 +11,11 @@ export interface ProviderInterface {
   cleanFiles?: () => string;
   getBinaryPath?: (version?: string) => string | null;
   getStatus?: () => string | null;
-  updateBinary: (version?: string) => Promise<void>;
+  updateBinary: (version?: string, maxVersion?: string) => Promise<void>;
   seleniumFlag?: string;
   osType?: string;
-  versionConfig?: string;
+  version?: string;
+  maxVersion?: string;
 }
 
 /**
@@ -69,8 +70,10 @@ export interface ProviderConfig {
   proxy?: string;
   // Set the requests to ignore SSL (optional).
   ignoreSSL?: boolean;
-  // Allow to pass a config for the max versions to download (optional).
-  versionConfig?: string;
+  // The version number (optional).
+  version?: string;
+  // The max version number. Partially match is okay (optional).
+  maxVersion?: string;
   // Catch all for other things.
   [key: string]: string|boolean|number;
 }
diff --git a/lib/provider/selenium_server.ts b/lib/provider/selenium_server.ts
index 28fb1f41..e56996cd 100644
--- a/lib/provider/selenium_server.ts
+++ b/lib/provider/selenium_server.ts
@@ -35,6 +35,8 @@ export class SeleniumServer extends ProviderClass implements ProviderInterface {
   runAsDetach = false;
   logLevel: string = null;
   javaOpts: {[key: string]: string} = {};
+  version: string = null;
+  maxVersion: string = null;
 
   constructor(config?: SeleniumServerProviderConfig) {
     super();
@@ -52,6 +54,8 @@ export class SeleniumServer extends ProviderClass implements ProviderInterface {
     if (this.runAsDetach) {
       this.runAsNode = true;
     }
+    this.version = this.setVar('version', this.version, config);
+    this.maxVersion = this.setVar('maxVersion', this.maxVersion, config);
     this.logLevel = this.setVar('logLevel', this.logLevel, config);
     if (this.logLevel) {
       this.setJavaFlag('-Dselenium.LOGGER.level', this.logLevel);
@@ -62,8 +66,15 @@ export class SeleniumServer extends ProviderClass implements ProviderInterface {
    * Should update the cache and download, find the version to download,
    * then download that binary.
    * @param version Optional to provide the version number or latest.
+   * @param maxVersion Optional to provide the max version.
    */
-  async updateBinary(version?: string): Promise<void> {
+  async updateBinary(version?: string, maxVersion?: string): Promise<void> {
+    if (!version) {
+      version = this.version;
+    }
+    if (!maxVersion) {
+      maxVersion = this.maxVersion;
+    }
     await updateXml(this.requestUrl, {
       fileName: path.resolve(this.outDir, this.cacheFileName),
       ignoreSSL: this.ignoreSSL,
@@ -72,7 +83,7 @@ export class SeleniumServer extends ProviderClass implements ProviderInterface {
     const versionList = convertXmlToVersionList(
         path.resolve(this.outDir, this.cacheFileName),
         'selenium-server-standalone', versionParser, semanticVersionParser);
-    const versionObj = getVersion(versionList, '', version);
+    const versionObj = getVersion(versionList, '', version, maxVersion);
 
     const seleniumServerUrl = this.requestUrl + versionObj.url;
     const seleniumServerJar = path.resolve(this.outDir, versionObj.name);
diff --git a/lib/provider/utils/version_list.spec-unit.ts b/lib/provider/utils/version_list.spec-unit.ts
index e07aee9e..eb3b33e4 100644
--- a/lib/provider/utils/version_list.spec-unit.ts
+++ b/lib/provider/utils/version_list.spec-unit.ts
@@ -48,6 +48,19 @@ describe('version_list', () => {
       expect(version['foo_win32']['size']).toBe(10101);
       expect(version['foo_linux64']['size']).toBe(10102);
     });
+
+    it('should return the max version for "2."', () => {
+      const version = getVersionObjs(versionList, null, '2.');
+      expect(Object.keys(version).length).toBe(3);
+      expect(version['foo_mac32']['size']).toBe(20100);
+      expect(version['foo_win32']['size']).toBe(20101);
+      expect(version['foo_linux64']['size']).toBe(20102);
+    });
+
+    it('should return undefined with a max version of "4."', () => {
+      const version = getVersionObjs(versionList, null, '4.');
+      expect(version).toBeUndefined();
+    });
   });
 
   describe('getVersionObj', () => {
diff --git a/lib/provider/utils/version_list.ts b/lib/provider/utils/version_list.ts
index b869e62a..942e9123 100644
--- a/lib/provider/utils/version_list.ts
+++ b/lib/provider/utils/version_list.ts
@@ -39,12 +39,13 @@ export interface VersionObj {
  * @param versionList The version list object.
  * @param osMatch The OS name and architecture.
  * @param version Optional field for the semver version number or latest.
- * * @returns Either a VersionObj or null.
+ * @param maxVersion Optional field to find the max version matching a value.
+ * @returns Either a VersionObj or null.
  */
 export function getVersion(
-    versionList: VersionList, osMatch: string, version?: string): VersionObj|
-    null {
-  const versionObjs = getVersionObjs(versionList, version);
+    versionList: VersionList, osMatch: string, version?: string,
+    maxVersion?: string): VersionObj| null {
+  const versionObjs = getVersionObjs(versionList, version, maxVersion);
   return getVersionObj(versionObjs, osMatch);
 }
 
@@ -55,21 +56,37 @@ export function getVersion(
  * @returns The object with paritial urls associated with the binary size.
  */
 export function getVersionObjs(
-    versionList: VersionList, version?: string): {[key: string]: VersionObj} {
+    versionList: VersionList, version?: string, maxVersion?: string
+    ): {[key: string]: VersionObj} {
   if (version && version !== 'latest') {
+    // Exact matches are easy.
     return versionList[version];
   } else {
-    let latestVersion = null;
+    // Either we want the latest or we want to match with the max version.
+    let retVersion = null;
     for (const versionKey of Object.keys(versionList)) {
-      if (!latestVersion) {
-        latestVersion = versionKey;
+      if (maxVersion) {
+        // Only find the greatest of the max version.
+        // An example:
+        //   maxVersion = 0.1 might match 0.13, 0.1, 0.14, result is 0.14.
+        //   if the user wants 0.1., then the maxVersion should be "0.1."
+        if (versionKey.startsWith(maxVersion)) {
+          if (!retVersion) {
+            retVersion = versionKey;
+          } else if (semver.gt(versionKey, retVersion)) {
+            retVersion = versionKey;
+          }
+        }
       } else {
-        if (semver.gt(versionKey, latestVersion)) {
-          latestVersion = versionKey;
+        // Always find the latest.
+        if (!retVersion) {
+          retVersion = versionKey;
+        } else if (semver.gt(versionKey, retVersion)) {
+          retVersion = versionKey;
         }
       }
     }
-    return versionList[latestVersion];
+    return versionList[retVersion];
   }
 }