= VS Code Tasks =
**Summary**: I've been using [[vscode|VSCode]] for years now and I keep on finding new options to improve my productivity using the tool. On this page I'll show you how I use VSCode tasks to automate small scripts that I use on a daily basis. \\
**Date**: 2 January 2025 \\
{{tag>vscode powershell bash azure kubernetes}}
The tasks below are used on a Windows 11 machine. Powershell is the main shell, so by default the tasks are executed in a Powershell terminal.
== What are VSCode Tasks ==
Tasks are mainly used in VSCode to help developers to automate their workflow. You can use tasks to run scripts, compile code, run tests, etc. I found them also very useful to automate small scripts that you use as a sysadmin. On this page I'll show you how to manage tasks, use different shells and overall how to improve your productivity.
== How to create a task ==
To create a task, you need to create a file called 'tasks.json' in the '.vscode' folder in the root of your project. Here is an example of a 'tasks.json' file:
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"label": "Login to Azure",
"type": "shell",
"command": [
"Write-Host 'Start login to Azure' -ForegroundColor Green;",
"az login;"
],
"presentation": {
"reveal": "always",
"panel": "new"
},
"dependsOrder": "sequence",
"problemMatcher": []
}
]
}
This is just one task and on it's own not that useful. But you can add multiple tasks to the 'tasks' array. You can also add a 'group' to group tasks together.
== Group tasks ==
If you need specific tasks to run in order you can create multiple tasks and a group to define the order.
=== Example: Start a connection to a Azure Jumpbox through a Bastion ===
In the example below I'm using tasks to start multiple browsers and setup a connection to a kubernetes cluster:
* The first is a group because it has a 'dependsOn' property that refers to the other tasks. The other tasks are executed in sequence.
* The second one uses a powershell script (see below) to login to Azure.
* As you can see in the script, you can use any normal powershell command. I especially like to use scripts if I need to provide instructions to myself (or others, as these are set in a git repository).
* The third one uses the Azure CLI in a powershell to setup a tunnel to a Bastion in Azure.
* The fourth one starts Chrome with a specific URL. Note that I use a different browser from my default one so I can use multiple azure identities without having to use incognito/private mode.
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"type": "shell",
"label": "Connect to Dev",
"detail": "Starts chrome for PIM groups; login to azure; setup the connection to the Bastion in the dev spoke.",
"dependsOrder": "sequence",
"dependsOn": [
"Chrome PIM Groups",
"Prepare Bastion",
"Bastion Tunnel to Dev"
],
"problemMatcher": []
},
{
"label": "Prepare Bastion",
"type": "shell",
"command": [
"./.vscode/tasks/bastion-prepare.ps1;"
],
"presentation": {
"reveal": "always",
"panel": "new"
},
"dependsOrder": "sequence",
"problemMatcher": []
},
{
"label": "Bastion Tunnel to Dev",
"type": "shell",
"command": [
"Write-Host 'Start tunnel to DEVELOPMENT' -ForegroundColor Green;",
"az network bastion tunnel --name bas-001 --resource-group rg-bastion --target-resource-id /subscriptions/aa123456-a123-a123-a123-abcd12345678/resourceGroups/rg-cluster/providers/Microsoft.Compute/virtualMachines/vm-jumpbox --resource-port 22 --port 50022;"
],
"presentation": {
"reveal": "always",
"panel": "new"
},
"dependsOrder": "sequence",
"problemMatcher": []
},
{
"label": "Chrome PIM Groups",
"type": "shell",
"windows": {
"command": "start"
},
"osx": {
"command": "open"
},
"args": [
"C:\\Program Files\\Google\\Chrome\\Application\\chrome 'https://portal.azure.com/?feature.msaljs=true#view/Microsoft_Azure_PIMCommon/ActivationMenuBlade/~/aadgroup/provider/aadgroup'"
],
"problemMatcher": []
}
]
}
This is the powershell script that I use to login to Azure:
Write-Host "Make sure you have activated the correct PIM group: https://portal.azure.com/#view/Microsoft_Azure_PIMCommon/ActivationMenuBlade/~/aadgroup"
Write-Host "Login to azure (use 'az logout' in case of problems)"
# Using az login because Connect-AzAccount opens login dialog in the background
# Connect-AzAccount -SubscriptionId aa123456-a123-a123-a123-abcd12345678
az login
Write-Host "Set subscription to hub subscription which has the bastion"
Set-AzContext -Subscription aa123456-a123-a123-a123-abcd12345678 | Out-Null
az account set --subscription aa123456-a123-a123-a123-abcd12345678
# Remove the known hosts file, these are environment specific
$daysToKeepKnownHosts = 28
$limit = (Get-Date).AddDays(-$daysToKeepKnownHosts)
$knownHostsPath = 'C:\Users\sjoer\.ssh'
$knownHostsFile = 'known_hosts'
Write-Host "Rename and remove known_hosts file: $knownHostsPath\$knownHostsFile"
if (Test-Path $knownHostsPath\$knownHostsFile){
Get-ChildItem $knownHostsPath\$knownHostsFile | Rename-Item -NewName { $_.BaseName + (Get-Date -Format "yyyyMMdd-HHmm") + $_.Extension } -Verbose
Get-ChildItem $knownHostsPath | Where-Object { ($_.CreationTime -lt $limit) -AND ($_.Name -like "$knownHostsFile*") } | Remove-Item -Force -Verbose
} else {
Write-Host "The file $knownHostsPath\$knownHostsFile does not exist."
}
$subscription = Get-AzContext
Write-Host "Done, you are now in $($subscription.Subscription.Name). Use one of the other tasks to continue." -foregroundcolor green
Write-Host "Subscription Name: $($subscription.Subscription.Name)" -foregroundcolor green
Write-Host "Subscription Id : $($subscription.Subscription.Id)" -foregroundcolor green
Write-Host "Tenant Name : $($subscription.Tenant.Name)" -foregroundcolor green
Write-Host "Tenant Id : $($subscription.Tenant.Id)" -foregroundcolor green
Write-Host "Once the tunnel is open, you can connect to the jumpbox and K8S in VS Code:"
Write-Host "Jumpbox : In VS Code, open the Remote Explorer extension from the activity bar"
Write-Host " -> SSH Targets -> Open 127.0.0.1 (linux) in a new window"
Write-Host "K8S cluster: In VS Code, from the just new opened window,"
Write-Host " open the Kubernetes extension (might need to be installed for ssh:127.0.0.1) from the activity bar"
Write-Host " -> Set Kubeconfig -> Select kubeconfig from /home/azadmin/.kube/config"
=== Example: Start a connection to a AKS K8S Cluster ===
This is another example of a group task to connect to a Argo CD pod in a Kubernetes cluster:
* The first is a group because it has a 'dependsOn' property that refers to the other tasks. The other tasks are executed in sequence.
* The second one uses the Azure CLI to login to Azure and get the AKS credentials.
* The third one uses the Azure CLI to setup a port forward to the Argo CD pod. It also displays the Argo CD user and password from a kubernetes secret.
* The fourth one starts a tab to connect to the Argo CD web interface which is now available through the port forward.
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"type": "shell",
"label": "Connect to ArgoCD",
"detail": "Login to azure; Connect to k8s; Setup port forwarding for argoCD; Start browser.",
"dependsOrder": "sequence",
"dependsOn": [
"Connect K8S",
"Open ArgoCD",
"Port Forward to ArgoCD"
],
"problemMatcher": []
},
{
"label": "Connect K8S",
"type": "shell",
"command": [
"echo 'Login to azure';",
"az logout;",
"az login;",
"echo 'Set the subscription';",
"az account set --subscription aa123456-a123-a123-a123-abcd12345678;",
"az account show;",
"echo 'Get AKS credentials';",
"az aks get-credentials --resource-group rg-cluster --name aks-cluster --overwrite-existing;",
"echo 'Use kubelogin plugin for authentication';",
"kubelogin convert-kubeconfig -l azurecli;",
"echo 'You can now close this and continue using the K8S plugin to connect to k8s or start a new terminal to work on the commandline.'"
],
"presentation": {
"reveal": "always",
"panel": "new",
"showReuseMessage": true,
"clear": true
},
"dependsOrder": "sequence",
"problemMatcher": []
},
{
"label": "Port Forward to ArgoCD",
"type": "shell",
"command": [
"Write-Host 'ArgoCD User: admin';",
"kubectl get secret argocd-initial-admin-secret --namespace ops -o json | ConvertFrom-Json | select -ExpandProperty data | % { $_.PSObject.Properties | % { $_.Name + [System.Environment]::NewLine + [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($_.Value)) + [System.Environment]::NewLine + [System.Environment]::NewLine } };",
"Write-Host 'ArgoCD Port: 8080';",
"kubectl port-forward deployment/argo-cd-argocd-server 8080 --namespace ops"
],
"presentation": {
"reveal": "always",
"panel": "new",
"showReuseMessage": true,
"clear": true
},
"dependsOrder": "sequence",
"problemMatcher": []
},
{
"label": "Open ArgoCD",
"type": "shell",
"windows": {
"command": "start"
},
"osx": {
"command": "open"
},
"args": [
"http://localhost:8080"
],
"problemMatcher": []
}
]
}
== A task using the Git Bash shell ==
If you're using git on Windows you might want to use the Git Bash shell, which is automatically installed with git. You can use the following task to run a script in the Git Bash shell:
> Note that using all options listed below are very important. Each one is necessary to make the task work. Using git-bash.exe directly will start the git bash in it's own window and not in the terminal of VSCode. Using the -c option allows to start the bash script and the -l option starts the bash shell as a login shell.
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"label": "AKS - Delete all jobs",
"type": "shell",
"command": [
".vscode/tasks/delete-k8s-jobs.sh"
],
"options": {
"shell": {
"executable": "C:\\Program Files\\Git\\git-cmd.exe",
"args": [
"--command=usr/bin/bash.exe",
"-l",
"-c"
]
}
},
"isBackground": true,
"problemMatcher": [],
"presentation": {
"echo": true,
"reveal": "always",
"focus": false,
"panel": "new",
"showReuseMessage": true
}
}
]
}
This is the script that is started by the task:
# Delete all jobs starting with shift in a namespace
export NAMESPACE=shiftops
echo "Deleting all jobs in namespace $NAMESPACE"
# Check
kubectl get jobs -n $NAMESPACE -o name | grep shift-
# Delete all the jobs
kubectl get jobs -n $NAMESPACE -o name | grep shift- |
while read job; do
# Note that the output specified the type so no need for 'delete job', just 'delete' is enough
kubectl delete $job -n $NAMESPACE
done
== Starting tasks ==
When you're in the editor you can start a task by pressing {{{ctrl + shift + p}}} and then type 'Run Task'. You can now select the task you want to run. \\
\\
If you have a lot of tasks I'd use the VSCode extension 'iulian-radu-at.vscode-tasks-sidebar' to show the tasks in the sidebar. This makes it easier to start a task.
== Useful Links ==
* [[https://code.visualstudio.com/docs/editor/tasks|VSCode Tasks]]
* [[https://marketplace.visualstudio.com/items?itemName=iulian-radu-at.vscode-tasks-sidebar|VSCode Tasks Sidebar]]