Τετάρτη 16 Μαΐου 2018

How to GAC a dll with PowerShell in VSTS

Introduction

When we install an application on a machine, it is necessary to have already installed all required external dependencies. Registering in GAC the dlls is a nice way to deal with this problem. In VSTS where we expect deployment to happen without human intervention, having a way to register those dlls into GAC will give elegance and clearence to our deployment process.
In this article we will explain how to use GAC It!, a VSTS custom extension which registers all dlls in one folder.
 

Core Code

The PowerShell script is built around procedure

System.EnterpriseServices.Internal.Publish.GacInstall(filename)

which registers the given file. 
Unfortunately, in case of an error, it doesn't give back any meaningful message. That's why we have to check whether the dll is indeed registered, by trying to load it.
Generally, gacutil.exe is a better way to GAC dlls but it must be copied first on the target machine and cannot be an integral part of an extension.

How to GAC It!

To call the powershell script is very simple 

Copy all dll files you want into a folder. GAC It! can search recursively into subfolders.

Then add a new Task with GAC It! It gets the following parameters:
  1.  p_DllPath (string, mandatory): the complete path of the folder which contains the dlls
  2. p_FileMask (string, default *.dll): Use filemask if you want to register only the dlls with specific names. It is useful when you want to register just one dll.
  3. p_Recurse (boolean, default true): If we want to include subfolders.

 Example

It follows an example about how to use the task. Enjoy!

Τρίτη 10 Απριλίου 2018

How to publish a custom task in VSTS

Introduction

In this article we will describe how we can publish a task in VSTS (Visual Studio Team Services) and use it in our build and release definitions. The task can be private (available only in our project) or publicly distributed in VSTS Marketplace.
We have used the process described here
 https://docs.microsoft.com/en-gb/vsts/extend/develop/add-build-task?view=vsts


Goal

We will
  1. Create a powershell script which gets an argument and logs the host computer name. 
  2. Create a task in VSTS that uses this powershell script.
  3. Create a release definition which runs this task and shows on VSTS logging, script's output.
  4. Understand the underlying process.

1. Set up the environment

First of all create an account in VSTS https://www.visualstudio.com/team-services/

Create a publishing account from http://aka.ms/vsmarketplace-manage

 Get a text editor. https://code.visualstudio.com/


 Open powershell as administrator and run the next command
 npm i -g tfx-cli

 2. Create your project

Go to the folder where you keep your projects and create a project with the following structure 


Create empty files inside the folders. We will fill them later.

3. Create your powershell script

Create a simple script like below

param(
    [string]$psargument
)

#######################################################
# Returns computer name
#######################################################

Write-Host "GetComputerName.ps1 started on $env:computername with argument $psargument" -Fore Yellow

It gets one argument and writes computer name and the argument.
Save the script under folder buildAndReleaseTask, together with task.json.

4. Prepare the task.json file

Open task.json and copy paste the following code

{
    "id": "ABD573AF-2246-0FAB-13DC-ABDE3872EFCD",
    "name": "GetComputerName",
    "friendlyName": "Get Computer's Name",
    "description": "This is a simple powershell script which returns computer name",
    "helpMarkDown": "Version 1.0",
    "category": "Utility",
    "visibility": [
        "Build",
        "Release"
    ],
    "author": "Christos Giannoukos",
    "version": {
        "Major": 1,
        "Minor": 0,
        "Patch": 0
    },
    "instanceNameFormat": "Echo $(samplestring)",
    "groups": [
        {
            "name": "advanced",
            "displayName": "Advanced",
            "isExpanded": false
        }
    ],
    "inputs": [
        {
            "name": "psargument",
            "type": "string",
            "label": "PowerShell Argument",
            "defaultValue": "",
            "required": false,
            "helpMarkDown": "a simple argument"
        }
    ],
    "execution": {
        "PowerShell": {
            "target": "$(currentDirectory)\\GetComputerName.ps1",
            "argumentFormat":"",
            "workingDirectory": "$(currentDirectory)"
        }
    }
}


Study carefully this code as it describes the whole project.
First of all, give a proper ID. Follow the above format and change the hexadecimal digits as you like.
Else you are going to get id errors when uploading the extension (see section 7).
Another important section is inputs. Here you have to define the input parameters of your script.
Last, execution describes which script to run. $(currentDirectory) is the directory of the task.json file.
Target points to the file that must be executed.


5. Prepare the extension manifest file

 Open vss-extension.json and copy paste the next code. Change the ids and names


{
    "manifestVersion": 1,
    "id": "get-my-computer-name",
    "name": "GetMyComputerName",
    "version": "1.0.0",
    "publisher": "ChristosGiannoukos",
    "targets": [
        {
            "id": "Microsoft.VisualStudio.Services"
        }
    ],   
    "description": "Tools for building/releasing. Includes one build/release task.",
    "categories": [
        "Build and release"
    ],
    "icons": {
        "default": "images/extension-icon.png"       
    },
    "files": [
        {
            "path": "buildAndReleaseTask"
        }
    ],
    "contributions": [
        {
            "id": "GetComputerName",
            "type": "ms.vss-distributed-task.task",
            "targets": [
                "ms.vss-distributed-task.tasks"
            ],
            "properties": {
                "name": "buildAndReleaseTask"
            }
        }
    ]
}


Be careful for the publisher (5th setting). It must match your name in VS Publisher web page.

6. Packaging the extension

It is time to package the extension and upload it to VSTS
Open powershell, go to extension's directory and run

tfx extension create --manifest-globs vss-extension.json

After a while a *.vsix file will be created under extension's directory. vsix files are zip files which can be opened using tools like winzip or 7zip. Feel free to open it and understand which files it contains.32


7. Upload the extension

Go to your publishing account http://aka.ms/vsmarketplace-manage 
 In the web page you can see all existing published extensions and also your details.

Do you see the red triangle next to your name? This means that you are not registered to publish in VSTS MarketPlace. This extension can be used privately, only inside your VSTS accounts.

Click on New Extension->Visual Studio Team Services.

Select the vsix file and upload it.

Wait for some seconds until the file is verified.

 If you get an error

"Extension validation error
The task.json for contribution buildAndReleaseTask could not be deserialized.Error converting value "xxxxxxxx" to type 'System.Guid'. Path 'id', line 2, position 56."
means that your id has not the correct format. Fix it as described above. 

Another common error is

"Upload Error

Publisher ID 'Christos Giannoukos' provided in the extension manifest should match the publisher ID 'ChristosGiannoukos' under which you are trying to publish this extension."

this means that your name in VS publishing page does not match with the publisher in vss-extension.json


{
"manifestVersion": 1,
"id": "restart-biztalk-host",
"name": "Restart BizTalk Host Instance",
"version": "1.0.1",
"publisher": "ChristosGiannoukos",


change it and retry.

8. Share the extension

Click on the three dots at the right of the extension name and select Share/Unshare

Add the name of your Visual Studio account (without the .visualstudio.com) and press enter.



Go to your Visual Studio account, open the project and go to Manage extensions, top right, where the shopping bag is.


You can see all available extensions. Select the extension

In the next window, click on Get it free and finally install it in the VSTS account you want.

Done! Let's go now and create a simple release definition.

9. Create release definition

In VSTS, go to Releases.

Create an empty Release Definition



Open Environment 1 (or any name given)

In Agent phase select the Agent queue that corresponds to your machine. If you haven't installed an agent yet, click on the gear at the center of the blue menu and then Agent Queues.



click on the + of Agent Phase



By searching, you can find your extension. Add it and configure it. There is no need to write the path as VSTS will put it in the working folder. Fill only the arguments and any additional options.


Save release definition and add new release. Go to the log to see the results.


SUCCESS!!!!!

Understanding the process

When you add a new release, the agent which runs on your machine does among the others, two things:
  1. copies the extension to c:\agent\_work\_tasks\  (default path).
  2. Follows the instructions given inside the task.json file.
If you open the path, you can see your extension's name and id from task.json. Inside it, just under folder with version number, you can find the task.json and the powershell script.