diff --git a/.github/workflows/e2e-versions.yml b/.github/workflows/e2e-versions.yml
index 0eabb14..9785530 100644
--- a/.github/workflows/e2e-versions.yml
+++ b/.github/workflows/e2e-versions.yml
@@ -20,8 +20,11 @@ jobs:
       fail-fast: false
       matrix:
         os: [macos-latest, windows-latest, ubuntu-latest]
-        distribution: ['temurin', 'adopt', 'adopt-openj9', 'zulu', 'liberica'] # internally 'adopt-hotspot' is the same as 'adopt'
+        distribution: ['temurin', 'adopt', 'adopt-openj9', 'zulu', 'liberica', 'microsoft' ] # internally 'adopt-hotspot' is the same as 'adopt'
         version: ['8', '11', '16']
+        exclude:
+        - distribution: microsoft
+          version: 8
     steps:
       - name: Checkout
         uses: actions/checkout@v2
@@ -174,16 +177,17 @@ jobs:
         run: bash __tests__/verify-java.sh "${{ matrix.version }}" "${{ steps.setup-java.outputs.path }}"
         shell: bash
 
-  setup-java-custom-architecture:
-    name: ${{ matrix.distribution }} ${{ matrix.version }} (jdk-x86) - ${{ matrix.os }}
+  # Only Liberica and Zulu provide x86
+  setup-java-x86:
+    name: ${{ matrix.distribution }} ${{ matrix.version }} (jdk-${{ matrix.architecture }}) - ${{ matrix.os }}
     needs: setup-java-major-minor-versions
     runs-on: ${{ matrix.os }}
     strategy:
       fail-fast: false
       matrix:
-        # Only Zulu and Liberica provides x86 arch for now and only for windows / ubuntu
+        # x86 is not supported on macOS
         os: [windows-latest, ubuntu-latest]
-        distribution: ['zulu', 'liberica']
+        distribution: ['liberica', 'zulu']
         version: ['11']
     steps:
       - name: Checkout
@@ -194,7 +198,9 @@ jobs:
         with:
           distribution: ${{ matrix.distribution }}
           java-version: ${{ matrix.version }}
-          architecture: x86
+          architecture: 'x86'
       - name: Verify Java
         run: bash __tests__/verify-java.sh "${{ matrix.version }}" "${{ steps.setup-java.outputs.path }}"
         shell: bash
+
+  # Only Microsoft provides AArch64. However, GitHub-hosted runners do not support this architecture.
\ No newline at end of file
diff --git a/README.md b/README.md
index 0ee64fd..f3cea5d 100644
--- a/README.md
+++ b/README.md
@@ -59,6 +59,7 @@ Currently, the following distributions are supported:
 | `adopt` or `adopt-hotspot` | Adopt OpenJDK Hotspot | [Link](https://adoptopenjdk.net/) | [Link](https://adoptopenjdk.net/about.html) |
 | `adopt-openj9` | Adopt OpenJDK OpenJ9 | [Link](https://adoptopenjdk.net/) | [Link](https://adoptopenjdk.net/about.html) |
 | `liberica` | Liberica JDK | [Link](https://bell-sw.com/) | [Link](https://bell-sw.com/liberica_eula/) |
+| `microsoft` | Microsoft Build of OpenJDK | [Link](https://www.microsoft.com/openjdk) | [Link](https://docs.microsoft.com/java/openjdk/faq)
 
 **NOTE:** The different distributors can provide discrepant list of available versions / supported configurations. Please refer to the official documentation to see the list of supported versions.
 
diff --git a/__tests__/distributors/microsoft-installer.test.ts b/__tests__/distributors/microsoft-installer.test.ts
new file mode 100644
index 0000000..eb77f0e
--- /dev/null
+++ b/__tests__/distributors/microsoft-installer.test.ts
@@ -0,0 +1,88 @@
+import { MicrosoftDistributions } from '../../src/distributions/microsoft/installer';
+
+describe('findPackageForDownload', () => {
+  let distribution: MicrosoftDistributions;
+
+  beforeEach(() => {
+    distribution = new MicrosoftDistributions({
+      version: '',
+      architecture: 'x64',
+      packageType: 'jdk',
+      checkLatest: false
+    });
+  });
+
+  it.each([
+    [
+      '17.x',
+      '17.0.1',
+      'https://aka.ms/download-jdk/microsoft-jdk-17.0.1.12.1-{{OS_TYPE}}-x64.{{ARCHIVE_TYPE}}'
+    ],
+    [
+      '16.0.x',
+      '16.0.2',
+      'https://aka.ms/download-jdk/microsoft-jdk-16.0.2.7.1-{{OS_TYPE}}-x64.{{ARCHIVE_TYPE}}'
+    ],
+    [
+      '11.0.13',
+      '11.0.13',
+      'https://aka.ms/download-jdk/microsoft-jdk-11.0.13.8.1-{{OS_TYPE}}-x64.{{ARCHIVE_TYPE}}'
+    ]
+  ])('version is %s -> %s', async (input, expectedVersion, expectedUrl) => {
+    const result = await distribution['findPackageForDownload'](input);
+    expect(result.version).toBe(expectedVersion);
+    let os: string;
+    let archive: string;
+    switch (process.platform) {
+      case 'darwin':
+        os = 'macos';
+        archive = 'tar.gz';
+        break;
+      case 'win32':
+        os = 'windows';
+        archive = 'zip';
+        break;
+      default:
+        os = process.platform.toString();
+        archive = 'tar.gz';
+        break;
+    }
+    const url = expectedUrl.replace('{{OS_TYPE}}', os).replace('{{ARCHIVE_TYPE}}', archive);
+    expect(result.url).toBe(url);
+  });
+
+  it('should throw an error', async () => {
+    await expect(distribution['findPackageForDownload']('8')).rejects.toThrow(
+      /Could not find satisfied version for SemVer */
+    );
+  });
+});
+
+describe('getPlatformOption', () => {
+  const distributions = new MicrosoftDistributions({
+    architecture: 'x64',
+    version: '11',
+    packageType: 'jdk',
+    checkLatest: false
+  });
+
+  it.each([
+    ['linux', 'tar.gz', 'linux'],
+    ['darwin', 'tar.gz', 'macos'],
+    ['win32', 'zip', 'windows']
+  ])('os version %s -> %s', (input, expectedArchive, expectedOs) => {
+    const actual = distributions['getPlatformOption'](input as NodeJS.Platform);
+
+    expect(actual.archive).toEqual(expectedArchive);
+    expect(actual.os).toEqual(expectedOs);
+  });
+
+  it.each(['aix', 'android', 'freebsd', 'openbsd', 'netbsd', 'solaris', 'cygwin'])(
+    'not support os version %s',
+    input => {
+      expect(() => distributions['getPlatformOption'](input as NodeJS.Platform)).toThrow(
+        /Platform '\w+' is not supported\. Supported platforms: .+/
+      );
+    }
+  );
+});
diff --git a/dist/setup/index.js b/dist/setup/index.js
index 19fd501..855880b 100644
--- a/dist/setup/index.js
+++ b/dist/setup/index.js
@@ -13819,7 +13819,136 @@ exports.XMLCBWriter = XMLCBWriter;
 /* 193 */,
 /* 194 */,
 /* 195 */,
-/* 196 */,
+/* 196 */
+/***/ (function(__unusedmodule, exports, __webpack_require__) {
+
+"use strict";
+
+var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
+    if (k2 === undefined) k2 = k;
+    Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
+}) : (function(o, m, k, k2) {
+    if (k2 === undefined) k2 = k;
+    o[k2] = m[k];
+}));
+var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
+    Object.defineProperty(o, "default", { enumerable: true, value: v });
+}) : function(o, v) {
+    o["default"] = v;
+});
+var __importStar = (this && this.__importStar) || function (mod) {
+    if (mod && mod.__esModule) return mod;
+    var result = {};
+    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
+    __setModuleDefault(result, mod);
+    return result;
+};
+var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
+    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
+    return new (P || (P = Promise))(function (resolve, reject) {
+        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
+        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
+        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
+        step((generator = generator.apply(thisArg, _arguments || [])).next());
+    });
+};
+var __importDefault = (this && this.__importDefault) || function (mod) {
+    return (mod && mod.__esModule) ? mod : { "default": mod };
+};
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.MicrosoftDistributions = void 0;
+const base_installer_1 = __webpack_require__(83);
+const semver_1 = __importDefault(__webpack_require__(876));
+const util_1 = __webpack_require__(322);
+const core = __importStar(__webpack_require__(470));
+const tc = __importStar(__webpack_require__(139));
+const fs_1 = __importDefault(__webpack_require__(747));
+const path_1 = __importDefault(__webpack_require__(622));
+class MicrosoftDistributions extends base_installer_1.JavaBase {
+    constructor(installerOptions) {
+        super('Microsoft', installerOptions);
+    }
+    downloadTool(javaRelease) {
+        return __awaiter(this, void 0, void 0, function* () {
+            core.info(`Downloading Java ${javaRelease.version} (${this.distribution}) from ${javaRelease.url} ...`);
+            const javaArchivePath = yield tc.downloadTool(javaRelease.url);
+            core.info(`Extracting Java archive...`);
+            const extension = util_1.getDownloadArchiveExtension();
+            const extractedJavaPath = yield util_1.extractJdkFile(javaArchivePath, extension);
+            const archiveName = fs_1.default.readdirSync(extractedJavaPath)[0];
+            const archivePath = path_1.default.join(extractedJavaPath, archiveName);
+            const javaPath = yield tc.cacheDir(archivePath, this.toolcacheFolderName, this.getToolcacheVersionName(javaRelease.version), this.architecture);
+            return { version: javaRelease.version, path: javaPath };
+        });
+    }
+    findPackageForDownload(range) {
+        return __awaiter(this, void 0, void 0, function* () {
+            if (this.architecture !== 'x64' && this.architecture !== 'aarch64') {
+                throw new Error(`Unsupported architecture: ${this.architecture}`);
+            }
+            const availableVersionsRaw = yield this.getAvailableVersions();
+            const opts = this.getPlatformOption();
+            const availableVersions = availableVersionsRaw.map(item => ({
+                url: `https://aka.ms/download-jdk/microsoft-jdk-${item.version.join('.')}-${opts.os}-${this.architecture}.${opts.archive}`,
+                version: this.convertVersionToSemver(item)
+            }));
+            const satisfiedVersion = availableVersions
+                .filter(item => util_1.isVersionSatisfies(range, item.version))
+                .sort((a, b) => -semver_1.default.compareBuild(a.version, b.version))[0];
+            if (!satisfiedVersion) {
+                const availableOptions = availableVersions.map(item => item.version).join(', ');
+                const availableOptionsMessage = availableOptions
+                    ? `\nAvailable versions: ${availableOptions}`
+                    : '';
+                throw new Error(`Could not find satisfied version for SemVer ${range}. ${availableOptionsMessage}`);
+            }
+            return satisfiedVersion;
+        });
+    }
+    getAvailableVersions() {
+        return __awaiter(this, void 0, void 0, function* () {
+            // TODO get these dynamically!
+            // We will need Microsoft to add an endpoint where we can query for versions.
+            const jdkVersions = [
+                {
+                    version: [17, 0, 1, 12, 1]
+                },
+                {
+                    version: [16, 0, 2, 7, 1]
+                }
+            ];
+            // M1 is only supported for Java 16 & 17
+            if (process.platform !== 'darwin' || this.architecture !== 'aarch64') {
+                jdkVersions.push({
+                    version: [11, 0, 13, 8, 1]
+                });
+            }
+            return jdkVersions;
+        });
+    }
+    getPlatformOption(platform = process.platform /* for testing */) {
+        switch (platform) {
+            case 'darwin':
+                return { archive: 'tar.gz', os: 'macos' };
+            case 'win32':
+                return { archive: 'zip', os: 'windows' };
+            case 'linux':
+                return { archive: 'tar.gz', os: 'linux' };
+            default:
+                throw new Error(`Platform '${platform}' is not supported. Supported platforms: 'darwin', 'linux', 'win32'`);
+        }
+    }
+    convertVersionToSemver(version) {
+        const major = version.version[0];
+        const minor = version.version[1];
+        const patch = version.version[2];
+        return `${major}.${minor}.${patch}`;
+    }
+}
+exports.MicrosoftDistributions = MicrosoftDistributions;
+
+
+/***/ }),
 /* 197 */
 /***/ (function(__unusedmodule, exports, __webpack_require__) {
 
@@ -56004,6 +56133,7 @@ const installer_2 = __webpack_require__(834);
 const installer_3 = __webpack_require__(584);
 const installer_4 = __webpack_require__(439);
 const installer_5 = __webpack_require__(507);
+const installer_6 = __webpack_require__(196);
 var JavaDistribution;
 (function (JavaDistribution) {
     JavaDistribution["Adopt"] = "adopt";
@@ -56013,6 +56143,7 @@ var JavaDistribution;
     JavaDistribution["Zulu"] = "zulu";
     JavaDistribution["Liberica"] = "liberica";
     JavaDistribution["JdkFile"] = "jdkfile";
+    JavaDistribution["Microsoft"] = "microsoft";
 })(JavaDistribution || (JavaDistribution = {}));
 function getJavaDistribution(distributionName, installerOptions, jdkFile) {
     switch (distributionName) {
@@ -56029,6 +56160,8 @@ function getJavaDistribution(distributionName, installerOptions, jdkFile) {
             return new installer_2.ZuluDistribution(installerOptions);
         case JavaDistribution.Liberica:
             return new installer_5.LibericaDistributions(installerOptions);
+        case JavaDistribution.Microsoft:
+            return new installer_6.MicrosoftDistributions(installerOptions);
         default:
             return null;
     }
diff --git a/src/distributions/distribution-factory.ts b/src/distributions/distribution-factory.ts
index 2ec2421..623bbae 100644
--- a/src/distributions/distribution-factory.ts
+++ b/src/distributions/distribution-factory.ts
@@ -5,6 +5,7 @@ import { ZuluDistribution } from './zulu/installer';
 import { AdoptDistribution, AdoptImplementation } from './adopt/installer';
 import { TemurinDistribution, TemurinImplementation } from './temurin/installer';
 import { LibericaDistributions } from './liberica/installer';
+import { MicrosoftDistributions } from './microsoft/installer';
 
 enum JavaDistribution {
   Adopt = 'adopt',
@@ -13,7 +14,8 @@ enum JavaDistribution {
   Temurin = 'temurin',
   Zulu = 'zulu',
   Liberica = 'liberica',
-  JdkFile = 'jdkfile'
+  JdkFile = 'jdkfile',
+  Microsoft = 'microsoft'
 }
 
 export function getJavaDistribution(
@@ -35,6 +37,8 @@ export function getJavaDistribution(
       return new ZuluDistribution(installerOptions);
     case JavaDistribution.Liberica:
       return new LibericaDistributions(installerOptions);
+    case JavaDistribution.Microsoft:
+      return new MicrosoftDistributions(installerOptions);
     default:
       return null;
   }
diff --git a/src/distributions/microsoft/installer.ts b/src/distributions/microsoft/installer.ts
new file mode 100644
index 0000000..79fffe5
--- /dev/null
+++ b/src/distributions/microsoft/installer.ts
@@ -0,0 +1,115 @@
+import { JavaBase } from '../base-installer';
+import { JavaDownloadRelease, JavaInstallerOptions, JavaInstallerResults } from '../base-models';
+import semver from 'semver';
+import { extractJdkFile, getDownloadArchiveExtension, isVersionSatisfies } from '../../util';
+import * as core from '@actions/core';
+import { MicrosoftVersion, PlatformOptions } from './models';
+import * as tc from '@actions/tool-cache';
+import fs from 'fs';
+import path from 'path';
+
+export class MicrosoftDistributions extends JavaBase {
+  constructor(installerOptions: JavaInstallerOptions) {
+    super('Microsoft', installerOptions);
+  }
+
+  protected async downloadTool(javaRelease: JavaDownloadRelease): Promise<JavaInstallerResults> {
+    core.info(
+      `Downloading Java ${javaRelease.version} (${this.distribution}) from ${javaRelease.url} ...`
+    );
+    const javaArchivePath = await tc.downloadTool(javaRelease.url);
+
+    core.info(`Extracting Java archive...`);
+    const extension = getDownloadArchiveExtension();
+    const extractedJavaPath = await extractJdkFile(javaArchivePath, extension);
+
+    const archiveName = fs.readdirSync(extractedJavaPath)[0];
+    const archivePath = path.join(extractedJavaPath, archiveName);
+
+    const javaPath = await tc.cacheDir(
+      archivePath,
+      this.toolcacheFolderName,
+      this.getToolcacheVersionName(javaRelease.version),
+      this.architecture
+    );
+
+    return { version: javaRelease.version, path: javaPath };
+  }
+
+  protected async findPackageForDownload(range: string): Promise<JavaDownloadRelease> {
+    if (this.architecture !== 'x64' && this.architecture !== 'aarch64') {
+      throw new Error(`Unsupported architecture: ${this.architecture}`);
+    }
+    const availableVersionsRaw = await this.getAvailableVersions();
+
+    const opts = this.getPlatformOption();
+    const availableVersions = availableVersionsRaw.map(item => ({
+      url: `https://aka.ms/download-jdk/microsoft-jdk-${item.version.join('.')}-${opts.os}-${
+        this.architecture
+      }.${opts.archive}`,
+      version: this.convertVersionToSemver(item)
+    }));
+
+    const satisfiedVersion = availableVersions
+      .filter(item => isVersionSatisfies(range, item.version))
+      .sort((a, b) => -semver.compareBuild(a.version, b.version))[0];
+
+    if (!satisfiedVersion) {
+      const availableOptions = availableVersions.map(item => item.version).join(', ');
+      const availableOptionsMessage = availableOptions
+        ? `\nAvailable versions: ${availableOptions}`
+        : '';
+      throw new Error(
+        `Could not find satisfied version for SemVer ${range}. ${availableOptionsMessage}`
+      );
+    }
+
+    return satisfiedVersion;
+  }
+
+  private async getAvailableVersions(): Promise<MicrosoftVersion[]> {
+    // TODO get these dynamically!
+    // We will need Microsoft to add an endpoint where we can query for versions.
+    const jdkVersions = [
+      {
+        version: [17, 0, 1, 12, 1]
+      },
+      {
+        version: [16, 0, 2, 7, 1]
+      }
+    ];
+
+    // M1 is only supported for Java 16 & 17
+    if (process.platform !== 'darwin' || this.architecture !== 'aarch64') {
+      jdkVersions.push({
+        version: [11, 0, 13, 8, 1]
+      });
+    }
+
+    return jdkVersions;
+  }
+
+  private getPlatformOption(
+    platform: NodeJS.Platform = process.platform /* for testing */
+  ): PlatformOptions {
+    switch (platform) {
+      case 'darwin':
+        return { archive: 'tar.gz', os: 'macos' };
+      case 'win32':
+        return { archive: 'zip', os: 'windows' };
+      case 'linux':
+        return { archive: 'tar.gz', os: 'linux' };
+      default:
+        throw new Error(
+          `Platform '${platform}' is not supported. Supported platforms: 'darwin', 'linux', 'win32'`
+        );
+    }
+  }
+
+  private convertVersionToSemver(version: MicrosoftVersion): string {
+    const major = version.version[0];
+    const minor = version.version[1];
+    const patch = version.version[2];
+    return `${major}.${minor}.${patch}`;
+  }
+}
diff --git a/src/distributions/microsoft/models.ts b/src/distributions/microsoft/models.ts
new file mode 100644
index 0000000..361c7db
--- /dev/null
+++ b/src/distributions/microsoft/models.ts
@@ -0,0 +1,12 @@
+type OsVersions = 'linux' | 'macos' | 'windows';
+type ArchiveType = 'tar.gz' | 'zip';
+
+export interface PlatformOptions {
+  archive: ArchiveType;
+  os: OsVersions;
+}
+
+export interface MicrosoftVersion {
+  downloadUrl?: string;
+  version: Array<number>;
+}