diff --git a/Makefile b/Makefile
index 4285a7bb..6041fcd8 100644
--- a/Makefile
+++ b/Makefile
@@ -27,7 +27,10 @@ build: go ocb
build-fips: go ocb
@./scripts/build.sh -d "${DISTRIBUTIONS}" -b ${OTELCOL_BUILDER} -f true
-generate: generate-sources generate-goreleaser
+generate: generate-sources generate-msi generate-goreleaser
+
+generate-msi: go
+ @./scripts/generate-msi.sh -d "${DISTRIBUTIONS}"
generate-goreleaser: go
@./scripts/generate-goreleaser.sh -d "${DISTRIBUTIONS}" -g ${GO}
diff --git a/cmd/msi/main.go b/cmd/msi/main.go
new file mode 100644
index 00000000..cd8d95be
--- /dev/null
+++ b/cmd/msi/main.go
@@ -0,0 +1,111 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+package main
+
+import (
+ "bytes"
+ "encoding/json"
+ "flag"
+ "fmt"
+ "log"
+ "os"
+ "text/template"
+)
+
+type Guids struct {
+ ProductUpgradeCode string `json:"product_upgrade_code"`
+ ComponentGuid string `json:"component_guid"`
+}
+
+type DistGuids struct {
+ Standard Guids `json:"standard"`
+ Fips Guids `json:"fips"`
+}
+
+const (
+ HostDistro = "nrdot-collector-host"
+ K8sDistro = "nrdot-collector-k8s"
+ CoreDistro = "nrdot-collector"
+ templateFilename = "cmd/msi/windows-installer.wxs.tmpl"
+)
+
+var (
+ distFlag = flag.String("d", "", "Collector distributions to build")
+ fipsFlag = flag.Bool("f", false, "FIPS")
+)
+
+func main() {
+ flag.Parse()
+
+ if len(*distFlag) == 0 {
+ log.Fatal("no distribution to template")
+ }
+
+ // Get GUIDs
+
+ // Parse the base template
+ baseTemplate, err := template.New("base").Delims("<<", ">>").ParseFiles(templateFilename)
+ if err != nil {
+ panic(err)
+ }
+
+ guids := getMsiGuids(*distFlag, *fipsFlag)
+
+ // Data for the base template
+ data := map[string]interface{}{
+ "InstallerName": getInstallerName(*distFlag, *fipsFlag),
+ "ProductUpgradeCode": guids.ProductUpgradeCode,
+ "ComponentGUID": guids.ComponentGuid,
+ }
+
+ // Execute the base template to generate a new template
+ var generatedTemplateContent bytes.Buffer
+ err = baseTemplate.ExecuteTemplate(&generatedTemplateContent, "base", data)
+ if err != nil {
+ panic(err)
+ }
+
+ err = baseTemplate.ExecuteTemplate(os.Stdout, "base", data)
+ if err != nil {
+ panic(err)
+ }
+}
+
+func getInstallerName(dist string, fips bool) string {
+ name := ""
+ switch dist {
+ case CoreDistro:
+ name = "Core"
+ case HostDistro:
+ name = "Host"
+ case K8sDistro:
+ name = "K8s"
+ default:
+ log.Fatal("Unknown Distribution:", dist)
+ }
+ if fips {
+ name += " (FIPS)"
+ }
+ return name
+}
+
+func getMsiGuids(dist string, fips bool) Guids {
+ filename := fmt.Sprintf("./distributions/%s/msi-guids.json", *distFlag)
+ data, err := os.ReadFile(filename)
+ if err != nil {
+ panic(err)
+ }
+
+ var distGuids DistGuids
+ err = json.Unmarshal(data, &distGuids)
+ if err != nil {
+ panic(err)
+ }
+
+ if fips {
+ return distGuids.Fips
+ } else {
+ return distGuids.Standard
+ }
+}
diff --git a/cmd/msi/windows-installer.wxs.tmpl b/cmd/msi/windows-installer.wxs.tmpl
new file mode 100644
index 00000000..d26d7b0a
--- /dev/null
+++ b/cmd/msi/windows-installer.wxs.tmpl
@@ -0,0 +1,99 @@
+<< define "base" ->>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ NOT COLLECTOR_SVC_ARGS
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<< end >>
\ No newline at end of file
diff --git a/distributions/README.md b/distributions/README.md
index 26b37ea9..aeedd163 100644
--- a/distributions/README.md
+++ b/distributions/README.md
@@ -75,10 +75,21 @@ done
```
#### Packages
-If a distribution provides linux packages (refer to its README), you can follow the instructions below to install them (using the `host` distribution as an example).
+If a distribution provides windows installers or linux packages (refer to its README), you can follow the instructions below to install them (using the `host` distribution as an example).
> Note: `systemd` is required for automatic service configuration.
+#### MSI Installation
+```powershell
+set collector_distro="nrdot-collector-host"
+set collector_version="1.5.0"
+set collector_arch="x64"
+set license_key="YOUR_LICENSE_KEY"
+
+iwr "https://github.com/newrelic/nrdot-collector-releases/releases/download/${collector_version}/${collector_distro}_${collector_version}_windows_${collector_arch}.msi" -OutFile "collector.msi"
+msiexec /i "collector.msi" NEW_RELIC_LICENSE_KEY="$license_key"
+```
+
##### DEB Installation
```bash
export collector_distro="nrdot-collector-host"
diff --git a/distributions/nrdot-collector-host/msi-guids.json b/distributions/nrdot-collector-host/msi-guids.json
new file mode 100644
index 00000000..652f4cd4
--- /dev/null
+++ b/distributions/nrdot-collector-host/msi-guids.json
@@ -0,0 +1,10 @@
+{
+ "standard": {
+ "product_upgrade_code": "TEMP-PRODUCT-CODE-HOST",
+ "component_guid": "TEMP-COMPONENT-GUID-HOST"
+ },
+ "fips": {
+ "product_upgrade_code": "TEMP-PRODUCT-CODE-HOST-FIPS",
+ "component_guid": "TEMP-COMPONENT-GUID-HOST-FIPS"
+ }
+}
\ No newline at end of file
diff --git a/distributions/nrdot-collector-host/windows-installer-fips.wxs b/distributions/nrdot-collector-host/windows-installer-fips.wxs
new file mode 100644
index 00000000..df2415af
--- /dev/null
+++ b/distributions/nrdot-collector-host/windows-installer-fips.wxs
@@ -0,0 +1,97 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ NOT COLLECTOR_SVC_ARGS
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/distributions/nrdot-collector-host/windows-installer.wxs b/distributions/nrdot-collector-host/windows-installer.wxs
new file mode 100644
index 00000000..afa2b281
--- /dev/null
+++ b/distributions/nrdot-collector-host/windows-installer.wxs
@@ -0,0 +1,97 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ NOT COLLECTOR_SVC_ARGS
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/distributions/nrdot-collector/msi-guids.json b/distributions/nrdot-collector/msi-guids.json
new file mode 100644
index 00000000..607d7de9
--- /dev/null
+++ b/distributions/nrdot-collector/msi-guids.json
@@ -0,0 +1,10 @@
+{
+ "standard": {
+ "product_upgrade_code": "TEMP-PRODUCT-CODE-CORE",
+ "component_guid": "TEMP-COMPONENT-GUID-CORE"
+ },
+ "fips": {
+ "product_upgrade_code": "TEMP-PRODUCT-CODE-CORE-FIPS",
+ "component_guid": "TEMP-COMPONENT-GUID-CORE-FIPS"
+ }
+}
\ No newline at end of file
diff --git a/distributions/nrdot-collector/windows-installer-fips.wxs b/distributions/nrdot-collector/windows-installer-fips.wxs
new file mode 100644
index 00000000..682efaaf
--- /dev/null
+++ b/distributions/nrdot-collector/windows-installer-fips.wxs
@@ -0,0 +1,97 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ NOT COLLECTOR_SVC_ARGS
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/distributions/nrdot-collector/windows-installer.wxs b/distributions/nrdot-collector/windows-installer.wxs
new file mode 100644
index 00000000..7bf9c06e
--- /dev/null
+++ b/distributions/nrdot-collector/windows-installer.wxs
@@ -0,0 +1,97 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ NOT COLLECTOR_SVC_ARGS
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/scripts/generate-msi.sh b/scripts/generate-msi.sh
new file mode 100755
index 00000000..ad26ccc9
--- /dev/null
+++ b/scripts/generate-msi.sh
@@ -0,0 +1,31 @@
+#!/bin/bash
+
+GO=''
+
+while getopts d:g: flag
+do
+ case "${flag}" in
+ d) distributions=${OPTARG};;
+ g) GO=${OPTARG};;
+ *) exit 1;;
+ esac
+done
+
+[[ -n "$GO" ]] || GO='go'
+
+if [[ -z $distributions ]]; then
+ echo "List of distributions to generate .wxs files not provided. Use '-d' to specify the names of the distributions use. Ex.:"
+ echo "$0 -d nrdot-collector-host"
+ exit 1
+fi
+
+echo "Generating .wxs files for distributions: $distributions";
+
+for distribution in $(echo "$distributions" | tr "," "\n")
+do
+ if [[ $distribution = "nrdot-collector-k8s" ]]; then
+ continue
+ fi
+ ${GO} run cmd/msi/main.go -d "${distribution}" > "./distributions/${distribution}/windows-installer.wxs"
+ ${GO} run cmd/msi/main.go -d "${distribution}" -f > "./distributions/${distribution}/windows-installer-fips.wxs"
+done