How to deploy to IIS using Azure DevOps YAML pipelines
Tags: azure, devops, microsoft, iis
Published: 2021-08-19 12:05:32

This blog is intended as a practical guide on how to deploy to IIS on a virtual machine using Azure DevOps YAML pipelines. If you want to read more about Azure DevOps and the benefits of DevOps check this out:
https://docs.microsoft.com/en-us/azure/devops/pipelines/?view=azure-devops

## Some assumptions before we start:
* You have access to the server you want to deploy on and admin 
  access to PowerShell.
* You have access to the internet on the remote server you want to 
  deploy on.
* You have admin access to install the .net core hosting bundle on 
  the server.
* You can create environments, push code to your repo and create 
  pipelines.
* You have a .net core API to deploy.

## Creating Environment

1. Go to Pipelines, and then select Environments.

2. Select Create environment.

3. Type the name of the environment, enter the description and 
   select Virtual machines and click next.

![New environment creation dialog example image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ezr6e49y65i1v4aru5cl.png)

4. Then select the Generic provider in the dropdown and select 
   Windows as the operating system. You can then copy the 
   registration script using the copy icon.

![Example of new environment creation dialog](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w7bznjiwqqdomsaglrjy.png)

5. Open an Administrative Powershell terminal on the windows 
   machine you want to deploy to, paste the registration script in 
   the terminal, and run the script. This step usually takes a 
   while.

6. When the agent is done downloading you will be prompted if you 
   want to add a tag to the machine. This is not required if there 
   is a single machine in the environment but you will need to add 
   the associated tags if you have multiple machines in the 
   environment.

7. You will then be prompted to ask if you want to unzip for each 
   task, which is not required — so you can say no.

8. You will then be prompted to enter a user account for the agent 
   running on the machine. You can leave it as default or create a 
   new service account under which the agent will run.

![Azure pipeline agent install console](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vhkjarrmeu3oupym0jmw.png)

When your agent creation succeeds you will be able to go back to Azure DevOps and see your virtual machine added as a resource in the environment!

## Creating build stage

1. Go to Pipelines, and then select Pipelines.

2. Select Create Pipeline and connect to your application's source 
   code.

![repo selection dialogue ](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/szprmpmzhgpj2a3ei46f.png)

3. Choose to show more on the configure pipeline step then select 
   ASP.NET Core.

![Image where configuration step is selectd](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/txodzccq749msba0yakm.png)

4. You will then have a base pipeline for ASP.NET Core applications, you can then add the build stage by adding the following code snippet:

``` YAML
trigger:
- master

pool:
  vmImage: ubuntu-latest

variables:
  buildConfiguration: 'Release'

  #Replace these variables to suit your application
  projectName: 'WeatherService'
  websiteName: 'WeatherService'
  appPoolName: 'WeatherService'

stages:
- stage: 'Build'
  displayName: 'Build'
  jobs:
     - job: 
       steps:  
        - task: DotNetCoreCLI@2
          displayName: 'dotnet restore'
          inputs:
            command: 'restore'
            projects: '*.sln'

        - task: DotNetCoreCLI@2
          displayName: Build
          inputs:
            command: 'build'
            projects: '*.sln'
            arguments: --configuration Release

        - task: DotNetCoreCLI@2
          displayName: Test
          inputs:
            command: test
            projects: '*.sln'
            arguments: '--configuration $(BuildConfiguration)'
       
        - task: DotNetCoreCLI@2
          displayName: 'Publish the project - $(buildConfiguration)'
          inputs:
            command: 'publish'
            projects: '**/*.csproj'
            publishWebProjects: false
            arguments: '--no-build --configuration $(buildConfiguration) --output $(Build.ArtifactStagingDirectory)/$(buildConfiguration)'
            zipAfterPublish: true

        - publish: '$(Build.ArtifactStagingDirectory)'
          artifact: drop
```

5. Replace the variables at the top to suit your application by 
   replacing the app pool name, website name, and project name 
   with your project’s details.
6. You can then click Save and run to have a pipeline to build 
   that creates your application.

## Create release pipeline

1. Go to Pipelines and select Pipelines.
2. You will see the pipeline that you have created, on the left- 
   hand side of your pipeline select more options and then select 
   edit.
3. Your pipeline will load then you can append the following YAML 
   code to your pipeline:

``` YAML
- stage: 'Dev'
  displayName: 'Dev'
  dependsOn: 'Build'
  condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/master'))
  jobs:
   - deployment: Dev
     displayName: Dev
     environment: 
       name: 'Dev'    
       resourceType: VirtualMachine
     variables:
     - name: websitePhysicalPath
       value: '%SystemDrive%\inetpub\wwwroot\$(websiteName)'

     strategy:
      runOnce:
        deploy:
          steps: 
          - task: IISWebAppManagementOnMachineGroup@0
            inputs:            
              IISDeploymentType: 'IISWebsite'
              ActionIISWebsite: 'CreateOrUpdateWebsite'
              WebsiteName: '$(websiteName)'
              WebsitePhysicalPath: '$(websitePhysicalPath)'
              WebsitePhysicalPathAuth: 'WebsiteUserPassThrough'
              CreateOrUpdateAppPoolForWebsite: true
              AppPoolNameForWebsite: '$(appPoolName)'
              DotNetVersionForWebsite: 'No Managed Code'
              PipeLineModeForWebsite: 'Integrated'
              AppPoolIdentityForWebsite: 'ApplicationPoolIdentity'
              AddBinding: true
              Bindings: |
                  {
                      bindings:[
                          {
                              "protocol":"http",
                              "ipAddress":"",
                              "hostname":"",
                              "port":"80",
                              "sslThumbprint":"",
                              "sniFlag":false
                          }
                      ]
                  }
          - task: IISWebAppDeploymentOnMachineGroup@0
            inputs:
              WebSiteName: '$(websiteName)'
              Package: '$(Pipeline.Workspace)/drop/$(buildConfiguration)/$(projectName).zip'

```
4. After adding the script select Save and run you will be able to 
   release it to the environment you created earlier.

## Recap

When you are done your script it should look something like this:

``` YAML
trigger:
- master

pool:
  vmImage: ubuntu-latest

variables:
  buildConfiguration: 'Release'
  projectName: 'WeatherService'
  websiteName: 'WeatherService'
  appPoolName: 'WeatherService'

stages:
- stage: 'Build'
  displayName: 'Build'
  jobs:
     - job: 
       steps:  
        - task: DotNetCoreCLI@2
          displayName: 'dotnet restore'
          inputs:
            command: 'restore'
            projects: '*.sln'

        - task: DotNetCoreCLI@2
          displayName: Build
          inputs:
            command: 'build'
            projects: '*.sln'
            arguments: --configuration Release

        - task: DotNetCoreCLI@2
          displayName: Test
          inputs:
            command: test
            projects: '*.sln'
            arguments: '--configuration $(BuildConfiguration)'
       
        - task: DotNetCoreCLI@2
          displayName: 'Publish the project - $(buildConfiguration)'
          inputs:
            command: 'publish'
            projects: '**/*.csproj'
            publishWebProjects: false
            arguments: '--no-build --configuration $(buildConfiguration) --output $(Build.ArtifactStagingDirectory)/$(buildConfiguration)'
            zipAfterPublish: true

        - publish: '$(Build.ArtifactStagingDirectory)'
          artifact: drop

- stage: 'Dev'
  displayName: 'Dev'
  dependsOn: 'Build'
  condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/master'))
  jobs:
   - deployment: Dev
     displayName: Dev
     environment: 
       name: 'Dev'    
       resourceType: VirtualMachine
     variables:
     - name: websitePhysicalPath
       value: '%SystemDrive%\inetpub\wwwroot\$(websiteName)'

     strategy:
      runOnce:
        deploy:
          steps: 
          - task: IISWebAppManagementOnMachineGroup@0
            inputs:            
              IISDeploymentType: 'IISWebsite'
              ActionIISWebsite: 'CreateOrUpdateWebsite'
              WebsiteName: '$(websiteName)'
              WebsitePhysicalPath: '$(websitePhysicalPath)'
              WebsitePhysicalPathAuth: 'WebsiteUserPassThrough'
              CreateOrUpdateAppPoolForWebsite: true
              AppPoolNameForWebsite: '$(appPoolName)'
              DotNetVersionForWebsite: 'No Managed Code'
              PipeLineModeForWebsite: 'Integrated'
              AppPoolIdentityForWebsite: 'ApplicationPoolIdentity'
              AddBinding: true
              Bindings: |
                  {
                      bindings:[
                          {
                              "protocol":"http",
                              "ipAddress":"",
                              "hostname":"",
                              "port":"80",
                              "sslThumbprint":"",
                              "sniFlag":false
                          }
                      ]
                  }
          - task: IISWebAppDeploymentOnMachineGroup@0
            inputs:
              WebSiteName: '$(websiteName)'
              Package: '$(Pipeline.Workspace)/drop/$(buildConfiguration)/$(projectName).zip'

```
You should also have an environment to deploy your pipeline to called Dev.

![Example of environment](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mgvbpkgcj2kcob8kbul2.png)

When you navigate to pipelines it should look something like this:

![Example of pipelines](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ys3gi0yv6h1kuupvy1gp.png)

You can have a look at this example repository as well:
https://github.com/Bassonrichard/azure-devops-iis-deploy

![Example of pipeline stages ready to deploy](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/z4uwpy373th7ntu3pn59.png)

When you release this you will have a DevOps pipeline setup using YAML pipelines, making your solution ready for the future with the ease of deployment of your solution.