= 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]]