TFS Release Manager–Website Application Pool Start & Stop

Requirement is to copy the updated files of the website to the target environment (Production, Staging etc.) automatically using copy task in release manager.

It can be easily implemented by using the copy task which is internally a Robocopy operation.

Issue is that the copy task will fail, if some user is already accessing the website and at the same time this task is trying to copy the files.

This problem can be handled by implementing following steps in the given order –

  1. Stop the application pool
  2. Copy the updated web files
  3. Start the application pool

Step 2 above is the available copy task in TFS RM.

Step 1 and 3 can be implemented using a PowerShell script.

Here is the content of the script –

<#

.Synopsis
Start / Stop Application Pool

.Discription
It starts or stops the application pool of a website.

.Example
powershell.exe -file .\AppPoolStopStart.ps1 ApplicationPoolName Start/Stop

. Example
powershell.exe -file .\AppPoolStopStart.ps1 DefaultAppPool Start

#>

param ([parameter(Mandatory=$True,Position=0)]
[string][ValidateNotNullOrEmpty()]$AppPoolName,

[Parameter(Mandatory=$true, Position=1)]
[string][ValidateNotNullOrEmpty()]$Action)


if ($Action -eq "stop")
{
Write-Output "Stoping the Application Pool - ($AppPoolName)......."
import-module WebAdministration
if((Get-WebAppPoolState $AppPoolName).Value -ne 'Stopped')
{
Stop-WebAppPool -Name $AppPoolName
Write-Output "Application Pool - ($AppPoolName) stopped successfully!"
}
}

if ($Action -eq "start")
{
Write-Output "Starting the Application Pool - ($AppPoolName)......."
import-module WebAdministration
if((Get-WebAppPoolState $AppPoolName).Value -ne 'Started')
{
Start-WebAppPool -Name $AppPoolName
Write-Output "Application Pool - ($AppPoolName) started successfully!"
}
}

Its can be executed as -  .\AppPoolStopStart.ps1 DefaultAppPool Start

Now add this to the source code in TFS and publish it in the build artifacts for the release definition.

In release definition, add the following tasks in the below order –

  1. Task to copy this PowerShell from the published artifacts to the target machine.
  2. Task to run PowerShell on Target Machines to execute the above PS script with an arguments as “Application Pool Name and the status as “Stop”. image
  3. Other required Release Manager tasks.
  4. Task to run PowerShell on Target Machines to execute the above PS script with an arguments as “Application Pool Name and the status as “Start”. 

           image

On successful execution of the above release definition, it will –

  1. First stop the application pool. image
  2. After successful execution of other tasks, it will finally start the application pool.image

             ——End of Article——

Advertisements

Windows Server 2016–Docker Container–dockerfile

Requirement is to configure docker image and run IIS based container to install/configure a website using DockerFile.

Here are the steps that needs to be done to implement the above requirement –

  1. Import microsoft/iis image from the Docker secure registry.
  2. Create the dockerfile to do the below activities –

    a. It installs .net features needed by the application.

    b. It copies application published data to the container.

    c. It creates and configures website with application pool.

    d. It sets .Net trust level.

    Note – Using this dockerfile, we can create container anywhere in any windows server 2016 environment.

    Here is the content of the dockerfile –

    ——————

FROM microsoft/iis  

SHELL ["powershell"]

RUN Install-WindowsFeature NET-Framework-45-ASPNET ; \  

    Install-WindowsFeature Web-Asp-Net45

COPY Web C:\\inetpub\\wwwroot\\Web  

RUN Remove-WebSite -Name 'Default Web Site'  

RUN New-Website -Name 'abc' -Port 80 \  

    -PhysicalPath 'C:\inetpub\wwwroot\Web' -ApplicationPool '.NET v4.5'

EXPOSE 80

RUN & c:\windows\system32\inetsrv\appcmd.exe set config /commit:WEBROOT /section:trust /level:Full

 

CMD ["ping", "-t", "localhost"]

Copy the above content into the text file and name it like dockerfile without any extension. Important note is that this file should not have any extension. Keep it in the same folder where you have kept the web folder (containing the published code of your site ‘abc’).

        3.  Built the image using the above dockerfile using the command for the location where you have kept the dockerfile – docker build –t [imageName] .

       4. Above command creates the image and you can access the list using the command – docker images

image

      5. Once image is created successfully, we need to create the container. It can be created using the command – docker run -d -p 80:80 [ImageName] ping -t localhost

It will create the container. You can get the list of running containers using the command – docker container ls

image

Complete flow of step 3,4 and 5 is given below –

image

Once all above steps are done successfully, you can browse your web application using any browser.

If you want to look inside the container, you can run the below commands and it will open the command prompt (cmd or PowerShell) inside the container and then you can using different commands to view the files –

1) For DOS command  – docker exec –I [ConatinerID] cmd

image 

2) For PowerShell command – docker exec –I [ContainerID] powershell

image

 

———-End of Article———

Docker Container–Windows 2016 Server–With SEP (Symantec Endpoint Protection)

Scenario – You have Windows Server 2016 machine and you have installed and configured Docker. After successful configuration, docker version command can give the information about the installed version.

image

You want to host IIS based website and so you have imported microsoft/iis image from docker secure registry successfully. You now wants to run the container using the command like –

docker run –d –name myFirstIISAap –p 80:80 microsoft/iis

You might get the below error message –

Error response from daemon: container c44wuweuwe323232xxxxx encountered an error during start: failure in a windows system call : This operation returned because the timeout period expired. (0x5b4)

image

Solution –

The following steps were taken:

  1. SEP V14mp1 (14.0.2332.0100) installed with all features – above issue present
  2. Remove SEP completely – no issues. Container created successfully.
  3. Re-install SEP with basic AV features only – no issues. Container created successfully.
  4. Modify SEP installation to include ADC feature – above issue present (at this stage advanced logging was enabled in SEP, error reproduced, and Symantec Diagnostic tool used to compile all logs for support purposes)
  5. Modify SEP installation to remove ADC feature and add IPS (NTP), SONAR (PTP) and Advanced Download Protection features – no issues. Container created successfully.- This could be the recommended solution.

TFS RM–Kill Process before Copy Task

Requirement

We need to copy the application executables and dlls to the XenApp environment or any other environment like Web server using TFS release manager.

Problem

Copying of executable files will fail if it is already in use as a process by some user.

Solution

To copy executable file, we need to ensure that it should not be in use. To ensure it, we need some script that detects it and if the process is running, it should kill it.

Here are the steps that can help to address the issue –

1) PowerShell script to kill the process. Here is the script that will kill the process –

<#
.Synopsis
   Script is to kill notepad* Process.
.DESCRIPTION
   Script is to kill notepad* Process.
#>

#Script Name – KillProcess.ps1
$ProcessName = "notepad*"

$ProcessInfo = get-process | Where-object {$_.ProcessName -Like $ProcessName}
if (@($ProcessInfo).Count -gt 0)
{
    Write-Output "——-Process – $ProcessName —————"
    TASKKILL /F /T /IM $ProcessName
    Write-Output "Process – $ProcessName – killed successfully!" 
    Write-Output "————————————————–" 

}

2) Add this script in TFS application repository.

3) Publish it as an artifact in the application automated build definition so that it will be available for the release automation.

4) In release automation, add below tasks

       a. Task to copy the PowerShell script to the target machine.

       b. Task for “PowerShell on Target Machines”.

      image

Output –

image

 

  ——-End of Article—–

Visual Studio 2017 – vNext Build Automation – .vdproj based installer

Problem – We need to build “.vdproj” (installer) based project in Visual Studio 2017 using vNext Build Automation.

Solution

Follow the below steps –

  1. First step is to configure the build environment.
    1. Install “Microsoft Visual Studio 2017 Installer Projects (InstallerProjects.vsix)”. Download it from https://marketplace.visualstudio.com/items?itemName=VisualStudioProductTeam.MicrosoftVisualStudio2017InstallerProjects.
    2. To install it, double clink on InstallerProjects.vsix and follow the default option to complete the installation.
    3. Add the below highlighted key. To add it,
      1. Add the node 15.0_[User ID]_Config like as shown below 15.0_a71083cb_Config.
      2. Add MSBuild folder (key) in it.
      3. In MSBuild, create new key “EnableOutOfProcBuild” and set its value as 0.

          image

  1. In TFS Build Definition, add task for command line and add the below information –
    1. ToolC:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\Common7\IDE\devenv.com
    2. Arguments$(Build.SourcesDirectory)\Deployment.sln /build $(BuildConfiguration)
  2. Finally, initiate the build and it will build the “.vdproj” files as defined in the solution and will create MSI installer file.

TFS Drop Location Clean Up Utility in PowerShell

In TFS, we do build Automation and the output of the build Automation is kept in some DFS share called the drop location. When you build the application multiple times using the automated build process, it generates the output and keeps it in the drop location. Let’s say, you have application “abc” and you did build of it ten times. It will copy the output to drop location in different folders like –

[DFS Share]\abc\1.0.0.0

[DFS Share]\abc\1.0.0.1

[DFS Share]\abc\1.0.0.2

….

[DFS Share]\abc\1.0.0.10

In long interval of time, the drop location will hold n number of output folders. Now, think what will happen when we have multiple applications and multiple teams are working on it. It will consume lots of space.

To address this issue, one has to manually manage the drop location. Manual activity is always time consuming and prone to errors.

One has to look for some kind of automation to manage the drop location. Here are the basic requirements –

1.) We need to delete the output folder older then n (say 10 days) number of days.

2.) We need to keep last three output folders even if they are older then n (say 10 days) number of days.

3.) It should send email to the concerned team/person for the notification of the clean-up done.

These two requirements can be easily implemented using PowerShell scripting.

Here is the script content –

Minimum PowerShell version required is v5.

——————————-

   1: <#

   2: .Synopsis

   3:    Script is to delete all the folders with the content from the TFS Drop location which are older then n number of days.

   4: .DESCRIPTION

   5:    Script is to delete all the folders with the content from the TFS Drop location which are older then n number of days.

   6: #>

   7:  

   8: #Updated - First Version

   9:  

  10: $Global:DataForEmailBody

  11:  

  12: Function SendEmail {

  13:  

  14: $Email = New-Object -ComObject "CDO.Message"

  15: $Email.Configuration.Fields.Item("http://schemas.microsoft.com/cdo/configuration/sendusing") = 2

  16: $Email.Configuration.Fields.Item("http://schemas.microsoft.com/cdo/configuration/smtpserver") = 'XXXXX'

  17: $Email.Configuration.Fields.Item("http://schemas.microsoft.com/cdo/configuration/smtpserverport") = 25

  18: $Email.Configuration.Fields.Update()

  19:  

  20: $Email.From="TFSAdmin@xyz.com"

  21: $Email.To="abcd@xyz.com"

  22: $Email.Subject="Utility | Scheduled Job | TFS Drop Location Cleanup Activity"

  23: $Email.HTMLBody = "<font color=""black"" face=""Calibri, Verdana"" size=""3"">

  24:                     <p><b> All, </b></p>

  25:                     <p><mark> fyi....</mark></p>

  26:                     <p><b> </b></p>

  27:                     <p> TFSDropLocationCleanupUtility has cleanup the drop location. Here are the details...</p>

  28:                     <p><b> </b></p>

  29:                     <p>----------------------------------------------</p>

  30:                     <p><b> </b></p>

  31:                     <a> $Global:DataForEmailBody </a>                    

  32:                     <p>----------------------------------------------</p>                                                           

  33:                     <p> Regards, TFS Administration Team </p>

  34:                         <font color=""blue"" face=""Arial, Verdana"" size=""2""

  35:                         <p> This is an auto generated email from the scheduled Job in TFS. If you need more information, contact TFS admin </p>"

  36:  

  37: $Email.Send()

  38: }

  39:  

  40: #Start-Transcript -Path ".\TFSDropLocCleanupUtility.log"

  41: $DayCount = 30 #Folders to be deleted prior to current - this day count

  42:  

  43: $dt = (Get-Date).AddDays(-$DayCount)

  44: $FolderCountsToSkip = 3

  45: $DropLocation = "P:\temp"

  46: $flag = $false

  47:  

  48: $Global:DataForEmailBody = "<p> Batch Started.....</p>"

  49:  

  50: $RootFolder = Get-ChildItem $DropLocation -Directory

  51:  

  52: foreach ($_RootFolder in $RootFolder)

  53: {

  54: #Write-Host $_RootFolder

  55:  

  56:    $FolderFirstLevel = Get-ChildItem $DropLocation\$_RootFolder -directory -recurse -depth 0 | Where-Object {$_.Name -notmatch "^[0-9].(\d+(\.\d+){1,4})"} 

  57:    foreach ($_FolderFirstLevel in $FolderFirstLevel)

  58:     {

  59:        # Write-Host $_FolderFirstLevel.FullName

  60:         

  61:         $FolderInfo = Get-ChildItem $_FolderFirstLevel.FullName | Where{$_.LastWriteTime -lt $dt} | sort { [version]($_.Name -replace '^[0-9].(\d+(\.\d+){1,4})', '$1') } -Descending | Select-Object -skip $FolderCountsToSkip

  62:         foreach ($_FolderInfo in $FolderInfo)

  63:         {

  64:             Write-Host $_FolderInfo.FullName " Deleted!!!"

  65:             Remove-Item $_FolderInfo.FullName -Force -Recurse

  66:             $Global:DataForEmailBody += "<p>" + $_FolderInfo.FullName  + " Deleted!!! </p>"

  67:             $flag = $true

  68:         }

  69:     }

  70:  

  71:  

  72:    $FolderFirstLevel = Get-ChildItem $DropLocation\$_RootFolder -directory -recurse -depth 0 | Where-Object {$_.Name -match "^[0-9].(\d+(\.\d+){1,4})"} | Where{$_.LastWriteTime -lt $dt} | sort { [version]($_.Name -replace '^[0-9].(\d+(\.\d+){1,4})', '$1') } -Descending | Select-Object -skip $FolderCountsToSkip

  73:    foreach ($_FolderFirstLevel in $FolderFirstLevel)

  74:     {

  75:         Write-Host $_FolderFirstLevel.FullName " Deleted!!!"

  76:         Remove-Item $_FolderFirstLevel.FullName -Force -Recurse

  77:         $Global:DataForEmailBody += "<p>" + $_FolderFirstLevel.FullName  + " Deleted!!! </p>"

  78:         $flag = $true

  79:     }

  80: }

  81:  

  82: if($flag)

  83: {

  84:  

  85:     SendEmail 

  86: }

  87: else

  88: {

  89:     $Global:DataForEmailBody += "<p> Drop Location is already upto date. No cleanup required for today!! </p>"

  90:     SendEmail

  91: }

  92:  

  93:  

I have used regular expression for finding the folder name in the drop location. In my case, the folder name is based on version in the format like aa.bb.cc.dd. You need to modify the regular express based on the naming convention in your drop location.

Please note the below screenshot for first two requirements.

clip_image001

Schedule the above PowerShell script to the task scheduler or as a TFS job to run it daily.

 

clip_image001[4]

On every successful execution, it will cleanup the drop location based on the number of days and number of folders to keep. Finally it will send the email with the information of the folders that it has deleted.

Email Content will be like below –

Case 1 – Folders deleted and clean up done –

Email Content –

All,

fyi….

TFSDropLocationCleanupUtility has cleanup the drop location. Here are the details…

———————————————-

Batch Started…..

P:\temp\abcd\1.0.0.52 DELETED!!!

P:\temp\abcd\1.0.0.51 DELETED!!!

P:\temp\abcd\1.0.0.46 DELETED!!!

P:\temp\abcd\1.0.0.45 DELETED!!!

P:\temp\xyz\1.0.0.69 DELETED!!!

P:\temp\zzzz\Desktop\1.0.0.36 DELETED!!!

P:\temp\zzzz\Desktop\1.0.0.31 DELETED!!!

———————————————-

Regards, TFS Administration Team

This is an auto generated email from the scheduled Job in TFS. If you need more information, contact TFS admin

————————

Case 2 – Drop location is already up to date –

Email Content –

All,

fyi….

TFSDropLocationCleanupUtility has cleanup the drop location. Here are the details…

———————————————-

Batch Started…..

Drop Location is already upto date. No cleanup required for today!!

———————————————-

Regards, TFS Administration Team

This is an auto generated email from the scheduled Job in TFS. If you need more information, contact TFS admin

——End of the Article—-

Docker–Windows Server 2016

Requirement is to understand how to deploy IIS based website in the container.

To play around, create a Windows Server 2016 based VM in MS Azure.

Steps to follow –

  1. Configure Docker environment in Windows Server 2016:

            Run the below commands –

      • Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force
      • Install-Module -Name DockerMsftProvider –Force
      • Install-Package -Name docker -ProviderName DockerMsftProvider -Force
      • Restart-Computer –Force

 

        2.   To verify, it it is installed correctly, Run the command –

              docker version 

            image

 

        3. Next step is to pull the IIS image from docker secured registry. Run the below command –

            docker pull Microsoft/iis

            This command will take some time to pull and extract the IIS image onto the server. Once completed successfully, run the command “docker images” to list the images pulled from DSR.

 

         clip_image001

 

     4. Run the following command to start the container –

         docker run –d –name myFirstIIS –p 80:80 microsoft/iis

     5. Run the following command to list all the running containers –

         docker ps –a

          Or

         docker container ls

     6. Run the following command to open the command prompt inside the container – docker exec –I myFirstIIS cmd

     7. Write index.html in the inetpub of the IIS in the container as –

      echo "Hello World From a Windows Server Container" > C:\inetpub\wwwroot\index.html

        image

     7. Browse the IIS site as shown below –

        clip_image002

 

All the steps above can be done through DockerFile concept. I will explain it in the next article.

 

                  ——End of the Article—–