Your first DevTest Labs artifact – JSON file

At this point in my Azure DevTest Labs blog post series, I’ve covered just about everything you need to know to start using DevTest Labs and even how to customize the available artifacts you can use by supplying your own from a personal GitHub repo. What I haven’t shown you how to do yet is how to create one of those custom artifacts. So, you guessed, it, that’s what I’ll do in this post. If you’re just joining the party late, you should probably start at the first post in this series to get caught up.

What is a DevTest Labs artifact anyway?

Artifacts are what you use to customize Azure VMs and apps during or after you deploy them in your DevTest Labs setup. There are a ton of default artifacts available from the DevTest Labs public GitHub repo (automatically sync’d with your lab) and you can also add your own personal GitHub repo if you have specialized requirements not met from the publicly available artifacts.

So, you’re probably thinking something like, “sounds like some kind of script”. Yep. At a bare minimum, almost all artifacts contain these two files: a script and a JSON file that describes the artifact and tells DevTest Labs what to do with your script. These are required along with any other files you need to make the script go. For example, you might need source .csv data files or, if you want to use a custom icon for your artifact, a picture file to add some shiny.

Get started making an artifact

Now that you know what an artifact is, it’s time to make one. You don’t need to start from scratch. The easiest way to get started quickly is to simply copy and paste an existing artifact from the public Azure DevTest Labs GitHub repo. Either fork the repo for yourself or grab an artifact straight from the site—just be sure you pick the correct type, either Linux or Windows. You’ll see what I mean when you look in the Artifacts folder on Github, the files for each artifact are kept in a separate folder and named for whether they are targeted for Linux or Windows VMs, but we’re getting ahead of ourselves there. Just go grab an artifact folder and check out the files you find.

Next, copy the artifact folder that you downloaded into your local GitHub repo artifacts directory and rename it something more appropriate (windows-<something> or linux-<something>). To make this artifact your own, you’ll need to tweak the copied JSON file to do your bidding using an editor like the free Visual Studio Code that I use. When you open up the JSON, you’ll see something like this below.

Yes. Yes, I know this screen shot looks like a picture for ants. You can click on it to make it larger, but I wanted you to see the whole thing without line wrapping and I’ll blow it up a piece at a time for you:


I know this looks like a lot of code, but have no fear, even if you aren’t a developer you’re going to be a pro at these by the end of the blog. Technically, only the title, description, target OS type, and the command to run are required. I’ll show you some tips and tricks for the other parts as we go along too.

Note: I’m using one of my own custom artifacts for this example. If you’re really curious about what it does, check out my GitHub repo docs on the subject. How I made that documentation page for my repo might be the subject of a later blog post if anyone is interested.

So, here we go section by section and I’ll tell you what each attribute (element) of the JSON file does. PAY ATTENTION to the syntax and mind your }’s, ,’s, and ’s. JSON validation is very picky. Also, beware of line wrap in these examples. If in doubt, refer to the picture for ants.

The schema line is used to help validate your JSON file. Technically not required, but it never changes so I just leave it as is and move on:

"$schema": "",

The title element (required) provides the name for the artifact and is also what will show up in DevTest Labs when you go to add an artifact:

"title": "Enable directory integration in Azure AD",

Publisher is next. This is optional and can be left blank, but putting in your name will tell DevTest Labs, and the world, who is responsible for creating this artifact. It’s also displayed in DevTest Labs when you go to apply an artifact:

"publisher": "JeffGilb",

Next, description (required) is, well obviously, words that describe what the artifact does:

"description": "Uses global admin credentials to enable directory sync integration in Azure AD in preparation for running Azure AD Connect.",

The iconUri element value is what tells DevTest Labs what image file to associate with your shiny, new artifact. Give a link to it directly like in the example below:

"iconUri": "",

Tip: If you don’t include this line, a standard DevTest Labs icon will be used for your artifact.

Following the icon to use, targetOSType (required) tells DevTest Labs whether this artifact is for Linux or Windows VMs:

"targetOsType": "Windows",

Adding tags helps people filter through the list of artifacts from within the DevTest Labs interface:

"tags": [

Now, this whole parameters section is only necessary if your script requires user input. Otherwise, it’s completely unnecessary to include in your JSON file. However, if you do require user input at script runtime (aka valueFromPipeline=$true in PowerShell speak), this is how you get it. This is also where those text input boxes on artifacts come from that ask you to fill in the script’s blanks:

"parameters": {
  "User": {
    "type": "string",
    "displayName": "Global admin name.",
    "description": "Azure AD tenant global administrator name."
  "Password": {
    "type": "securestring",
    "displayName": "Global admin password.",
    "description": "Azure AD tenant global administrator password."

There’s a couple of things to take note of here after you give your parameter a name–the name that your script is expecting to come from user input. First, notice the type line. That can be string, securestring (which is obfuscated and/or allows you to choose from a saved secret from your DevTest Labs’ Azure Key Vault), int, bool, or array. Personally, I’ve never used anything besides string and securestring here, but your mileage may vary.

The next element, displayName, is the text displayed next to the data entry text box to tell you what kind of information is expected to be entered there.

Finally, the description line of a prompt section is the information that pops-up when the cursor is hovered over the little information icon at the end of the display name.

TIP: Because we’re saying this artifact requires user input (parameters) to run, all the fields that you define here will be * Required. To make a prompted value optional for whatever reason (maybe an If/Else statement in PowerShell doesn’t need all values or something) just provide an empty default value for the item on the next line like “default”: “” or you can add an allow empty line like “allowEmpty”: true if you want to display a default value, but also allow someone to blank it out when the artifact is run.

Finally, it’s time to tell the JSON which script to kick off with the runCommand element (notice how the prompts, and their syntax, are listed after the script name and beware of line wrap. The commandToExecute should be one line, see: picture for ants):

"runCommand": {
  "commandToExecute": "[concat('powershell.exe -ExecutionPolicy bypass \"& ./enableSync.ps1 -User ''', parameters('User'), ''' -Password ''', parameters('Password'), '''')]"

If you didn’t have any prompts for your script, you obviously wouldn’t need that parameters section above and the runCommand line would look more like this to simply run the script:

"commandToExecute": "[concat('powershell.exe -ExecutionPolicy bypass \"& ./enableSync.ps1')]"

And that’s it for the JSON file. Save your artifact files (JSON, script file, and/or image file), commit your local repo changes with GitHub, create and merge a pull request, and then go look in DevTest Labs for your shiny new artifact. In case you’re wondering what this particular artifact looks like in DevTest Labs:


There you go! Hopefully, if you were following along with me, and you’ve got your personal GitHub repo integrated with DevTest Labs, your first custom artifact quickly appeared in DevTest Labs. If not, stick around, I’ll show you some handy artifact troubleshooting tips after we cover some things to know about the script part of the artifact. That’s next.


You’ve seen my blog; want to follow me on Twitter too? @JeffGilb.

 877 total views,  1 views today