Microsoft Windows
You can build and test a Microsoft Windows application using a Windows platform on Harness Cloud or a self-managed Kubernetes cluster build infrastructure.
This guide assumes you've created a Harness CI pipeline.
Specify architecture
- Harness Cloud
- Self-managed
stages:
  - stage:
      name: build
      identifier: build
      type: CI
      spec:
        cloneCodebase: true
        platform:
          os: Windows
          arch: Amd64
        runtime:
          type: Cloud
          spec: {}
There are several self-managed build infrastructure options. This example uses a Kubernetes cluster build infrastructure. For instructions and important information, go to Run Windows builds in a Kubernetes cluster build infrastructure.
stages:
  - stage:
      name: build
      identifier: build
      description: ""
      type: CI
      spec:
        cloneCodebase: true
        infrastructure:
          type: KubernetesDirect
          spec:
            connectorRef: YOUR_K8S_CLUSTER_CONNECTOR_ID
            namespace: YOUR_K8S_NAMESPACE
            automountServiceAccountToken: true
            nodeSelector:
              kubernetes.io/os: windows
            os: Windows
Install dependencies
- Harness Cloud
- Self-managed
Harness Cloud runners include pre-installed libraries and tools, and you can use Run steps to install additional dependencies or additional versions. For details about pre-installed tools and versions, go to Platforms and image specifications.
- step:
    type: Run
    identifier: dependencies
    name: Dependencies
    spec:
      shell: Powershell
      command: |-
        dotnet add package Newtonsoft.json --version 12.0.1
You can use Run steps to install dependencies.
- step:
    type: Run
    identifier: dependencies
    name: Dependencies
    spec:
      connectorRef: YOUR_IMAGE_REGISTRY_CONNECTOR
      image: mcr.microsoft.com/dotnet/sdk:7.0
      shell: Powershell
      command: |-
        dotnet add package Newtonsoft.json --version 12.0.1
Cache dependencies
Add caching to your Build stage.
- Cache Intelligence
- Save and Restore Cache steps
Cache your Windows app dependencies with Cache Intelligence. Add caching to your stage.spec and specify the paths to cache:
- stage:
    spec:
      caching:
        enabled: true
        key: cache-{{ checksum "packages.lock.json" }}
        paths:
          - C:\%LocalAppData%\NuGet\Cache
      sharedPaths:
        - C:\%LocalAppData%\NuGet\Cache
You can use built-in steps to:
YAML example: Save and restore cache steps
Here's an example of a pipeline with Save Cache to S3 and Restore Cache from S3 steps.
            steps:
              - step:
                  type: RestoreCacheS3
                  name: Restore Cache From S3
                  identifier: Restore_Cache_From_S3
                  spec:
                    connectorRef: YOUR_AWS_CONNECTOR_ID
                    region: us-east-1
                    bucket: YOUR_S3_BUCKET
                    key: cache-{{ checksum "packages.lock.json" }}
                    archiveFormat: Tar
              - step:
                  type: Run
                  ...
              - step:
                  type: BuildAndPushDockerRegistry
                  ...
              - step:
                  type: SaveCacheS3
                  name: Save Cache to S3
                  identifier: Save_Cache_to_S3
                  spec:
                    connectorRef: YOUR_AWS_CONNECTOR_ID
                    region: us-east-1
                    bucket: YOUR_S3_BUCKET
                    key: cache-{{ checksum "packages.lock.json" }}
                    sourcePaths:
                      - C:\%LocalAppData%\NuGet\Cache
                    archiveFormat: Tar
Build and run tests
Add Run steps to build and run your tests.
- Harness Cloud
- Self-managed
- step:
    type: Run
    identifier: build_dotnet_app
    name: Build DotNet App
    spec:
      shell: Powershell
      command: |-
        dotnet restore
        dotnet build --no-restore
        dotnet test C:\path\to\project.tests.csproj --no-build --verbosity normal
- step:
    type: Run
    identifier: build_dotnet_app
    name: Build DotNet App
    spec:
      connectorRef: YOUR_IMAGE_REGISTRY_CONNECTOR
      image: mcr.microsoft.com/dotnet/sdk:6.0
      shell: Powershell
      command: |-
        dotnet restore
        dotnet build --no-restore
        dotnet test C:\path\to\project.tests.csproj --no-build --verbosity normal
For some languages, you can leverage Harness' Test Intelligence feature to reduce unit test time.
Harness CI also supports test splitting (parallelism) for both Run and Test steps.
Visualize test results
You can view test results on the Tests tab of your pipeline executions. Test results must be in JUnit XML format.
For your pipeline to produce test reports, you need to modify the Run step that runs your tests. Make sure the command generates JUnit XML reports and add the reports specification.
If your test tool doesn't produce JUnit XML formatted reports by default, you can use a converter to output compatible JUnit XML reports, such as NUnit to JUnit or .NET trx2JUnit.
- Harness Cloud
- Self-managed
- step:
    type: Run
    identifier: install_converter
    name: install converter
    spec:
      shell: Powershell
      command: |-
        dotnet tool install -g trx2junit
        export PATH="C:\Users\USER\.dotnet\tools"
- step:
    type: Run
    identifier: build_dotnet_app
    name: Build DotNet App
    spec:
      shell: Powershell
      command: |-
        dotnet restore
        dotnet build
        dotnet test C:\path\to\project.tests.csproj --no-build --verbosity normal
        trx2junit results.trx
      reports:
        type: JUnit
        spec:
          paths:
            - results.xml
- step:
    type: Run
    identifier: install_converter
    name: install converter
    spec:
      connectorRef: YOUR_IMAGE_REGISTRY_CONNECTOR
      image: mcr.microsoft.com/dotnet/sdk:6.0
      shell: Powershell
      command: |-
        dotnet tool install -g trx2junit
        export PATH="C:\Users\USER\.dotnet\tools"
- step:
    type: Run
    identifier: build_dotnet_app
    name: Build DotNet App
    spec:
      connectorRef: YOUR_IMAGE_REGISTRY_CONNECTOR
      image: mcr.microsoft.com/dotnet/sdk:6.0
      shell: Powershell
      command: |-
        dotnet restore
        dotnet build
        dotnet test C:\path\to\project.tests.csproj --no-build --verbosity normal
        trx2junit results.trx
      reports:
        type: JUnit
        spec:
          paths:
            - results.xml
Install Visual Studio
- Harness Cloud
- Self-managed
Visual Studio 2019 Enterprise is pre-installed on Hosted Cloud runners. For details about all available tools and versions, go to Platforms and image specifications.
You can use a Run step to install a different version or edition of Visual Studio.
- step:
    type: Run
    identifier: install_vs2022
    name: install vs2022
    spec:
      connectorRef: YOUR_IMAGE_REGISTRY_CONNECTOR
      image: mcr.microsoft.com/windows/servercore:ltsc2019
      shell: Powershell
      command: |-
        winget install --id Microsoft.VisualStudio.2022.Enterprise
If not already included on your build machine, you can specify a container image that has the necessary binaries or use a Run step to install Visual Studio.
- step:
    type: Run
    identifier: install_vs2022
    name: install vs2022
    spec:
      connectorRef: YOUR_IMAGE_REGISTRY_CONNECTOR
      image: mcr.microsoft.com/windows/servercore:ltsc2019
      shell: Powershell
      command: |-
        winget install --id Microsoft.VisualStudio.2019.Enterprise
Specify shell
- Harness Cloud
- Self-managed
In steps that allow you to supply your own commands, such as Run steps and Background steps, you specify the shell in the step's settings.
- step:
    type: Run
    identifier: dotnet restore
    name: dotnet restore
    spec:
      shell: Powershell ## Set to Bash, Powershell, Pwsh (PowerShell Core), Python, or Sh.
      command: |- ## Enter your script as you would in a command line shell.
        dotnet restore
Several shell binaries are pre-installed on Hosted Cloud runners, including Bash and PowerShell. For details about all available tools and versions, go to Platforms and image specifications.
You can also use Run steps to install different shell tools into the build environment, or specify a container image that has the necessary binaries for the command you want to run.
In steps that allow you to supply your own commands, such as Run steps and Background steps, you specify the shell in the step's settings.
- step:
    type: Run
    identifier: build_dotnet_app
    name: Build DotNet App
    spec:
      connectorRef: YOUR_IMAGE_REGISTRY_CONNECTOR
      image: mcr.microsoft.com/dotnet/sdk:6.0
      shell: Powershell ## Set to Bash, Powershell, Pwsh (PowerShell Core), Python, or Sh.
      command: |- ## Enter your script as you would in a command line shell.
        dotnet restore
You can also use Run steps to install different shell tools into the build environment, or specify a container image that has the necessary binaries for the command you want to run.
Setup .NET SDK
For details about building and testing .NET with Harness CI, including how to setup different versions of the .NET SDK, go to the C# (.NET Core) guide.
Full pipeline examples
The following full pipeline examples are based on the partial examples above.
- Harness Cloud
- Self-managed
If you copy this example, replace the placeholder values with appropriate values for your code repo connector and repository name. Depending on your project and organization, you may also need to replace projectIdentifier and orgIdentifier.
pipeline:
  name: default
  identifier: default
  projectIdentifier: default
  orgIdentifier: default
  tags: {}
  properties:
    ci:
      codebase:
        connectorRef: YOUR_CODE_REPO_CONNECTOR_ID
        repoName: YOUR_REPO_NAME
        build: <+input>
  stages:
    - stage:
        name: build and test
        identifier: build_and_test
        type: CI
        spec:
          cloneCodebase: true
          caching:
            enabled: true
            key: cache-{{ checksum "packages.lock.json" }}
            paths:
              - C:\%LocalAppData%\NuGet\Cache
          execution:
            steps:
              - step:
                  type: Run
                  identifier: dependencies
                  name: Dependencies
                  spec:
                    shell: Powershell
                    command: |-
                      dotnet add package Newtonsoft.json --version 12.0.1
              - step:
                  type: Run
                  identifier: install_converter
                  name: install converter
                  spec:
                    shell: Powershell
                    command: |-
                      dotnet tool install -g trx2junit
                      export PATH="C:\Users\USER\.dotnet\tools"
              - step:
                  type: Run
                  identifier: build_dotnet_app
                  name: Build DotNet App
                  spec:
                    shell: Powershell
                    command: |-
                      dotnet restore
                      dotnet build
                      dotnet test C:\path\to\project.tests.csproj --no-build --verbosity normal
                      trx2junit results.trx
                    reports:
                      type: JUnit
                      spec:
                        paths:
                          - results.xml
          sharedPaths:
            - C:\%LocalAppData%\NuGet\Cache
          platform:
            os: Windows
            arch: Amd64
          runtime:
            type: Cloud
            spec: {}
If you copy this example, replace the placeholder values with appropriate values for your code repo connector, Kubernetes cluster connector, Kubernetes namespace, and repository name. Depending on your project and organization, you may also need to replace projectIdentifier and orgIdentifier.
pipeline:
  name: default
  identifier: default
  projectIdentifier: default
  orgIdentifier: default
  properties:
    ci:
      codebase:
        connectorRef: YOUR_CODE_REPO_CONNECTOR_ID
        repoName: YOUR_REPO_NAME
        build: <+input>
  tags: {}
pipeline:
  name: default
  identifier: default
  projectIdentifier: default
  orgIdentifier: default
  properties:
    ci:
      codebase:
        connectorRef: YOUR_CODE_REPO_CONNECTOR_ID
        repoName: YOUR_REPO_NAME
        build: <+input>
  tags: {}
  stages:
    - stage:
        name: build and test
        identifier: build_and_test
        type: CI
        spec:
          cloneCodebase: true
          execution:
            steps:
              - step:
                  type: RestoreCacheS3
                  name: Restore Cache From S3
                  identifier: Restore_Cache_From_S3
                  spec:
                    connectorRef: YOUR_AWS_CONNECTOR_ID
                    region: us-east-1
                    bucket: YOUR_S3_BUCKET
                    key: cache-{{ checksum "packages.lock.json" }}
                    archiveFormat: Tar
              - step:
                  type: Run
                  identifier: dependencies
                  name: Dependencies
                  spec:
                    connectorRef: YOUR_IMAGE_REGISTRY_CONNECTOR
                    image: mcr.microsoft.com/dotnet/sdk:7.0
                    shell: Powershell
                    command: |-
                      dotnet add package Newtonsoft.json --version 12.0.1
              - step:
                  type: Run
                  identifier: install_converter
                  name: install converter
                  spec:
                    connectorRef: YOUR_IMAGE_REGISTRY_CONNECTOR
                    image: mcr.microsoft.com/dotnet/sdk:6.0
                    shell: Powershell
                    command: |-
                      dotnet tool install -g trx2junit
                      export PATH="C:\Users\USER\.dotnet\tools"
              - step:
                  type: Run
                  identifier: build_dotnet_app
                  name: Build DotNet App
                  spec:
                    connectorRef: YOUR_IMAGE_REGISTRY_CONNECTOR
                    image: mcr.microsoft.com/dotnet/sdk:6.0
                    shell: Powershell
                    command: |-
                      dotnet restore
                      dotnet build
                      dotnet test C:\path\to\project.tests.csproj --no-build --verbosity normal
                      trx2junit results.trx
                    reports:
                      type: JUnit
                      spec:
                        paths:
                          - results.xml
              - step:
                  type: SaveCacheS3
                  name: Save Cache to S3
                  identifier: Save_Cache_to_S3
                  spec:
                    connectorRef: YOUR_AWS_CONNECTOR_ID
                    region: us-east-1
                    bucket: YOUR_S3_BUCKET
                    key: cache-{{ checksum "packages.lock.json" }}
                    sourcePaths:
                      - C:\%LocalAppData%\NuGet\Cache
                    archiveFormat: Tar
          infrastructure:
            type: KubernetesDirect
            spec:
              connectorRef: YOUR_K8S_CLUSTER_CONNECTOR_ID
              namespace: YOUR_K8S_NAMESPACE
              automountServiceAccountToken: true
              nodeSelector:
                kubernetes.io/os: windows
              os: Windows
Next steps
Now that you have created a pipeline that builds and tests a Windows app, you could:
- Create triggers to automatically run your pipeline.
- Add steps to build and upload artifacts.
- Add a step to build and push an image to a Docker registry.