Last active
September 11, 2025 20:12
-
-
Save rajan-chari/8b1c4d8c54609a8c89c42bf7cfef3d02 to your computer and use it in GitHub Desktop.
Invoke CreateTunnel and Provision from powershell command line
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env pwsh | |
# teams-dev.ps1 - CLI wrapper for teams-dev-functions.ps1 | |
# Usage: teams-dev.ps1 <subcommand> [options] | |
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path | |
# Teams Development Functions for PowerShell | |
# PowerShell equivalents of the custom shell functions for Teams app development | |
function Create-Tunnel { | |
<# | |
.SYNOPSIS | |
Creates a new devtunnel with the specified name and port, configured for anonymous access. | |
.DESCRIPTION | |
This function creates a persistent devtunnel that can be reused across development sessions, | |
avoiding the need to recreate tunnels and update bot endpoints on every launch. | |
.PARAMETER TunnelName | |
The name of the tunnel to create | |
.PARAMETER Port | |
The port number to map in the tunnel | |
.EXAMPLE | |
Create-Tunnel -TunnelName "my-teams-app" -Port 3978 | |
#> | |
param( | |
[Parameter(Mandatory = $true)] | |
[string]$TunnelName, | |
[Parameter(Mandatory = $true)] | |
[int]$Port | |
) | |
try { | |
Write-Host "Creating devtunnel: $TunnelName" -ForegroundColor Green | |
# Create the tunnel | |
devtunnel create $TunnelName | |
if ($LASTEXITCODE -ne 0) { | |
throw "Failed to create tunnel" | |
} | |
# Create the port mapping | |
Write-Host "Creating port mapping for port: $Port" -ForegroundColor Green | |
devtunnel port create $TunnelName -p $Port | |
if ($LASTEXITCODE -ne 0) { | |
throw "Failed to create port mapping" | |
} | |
# Set up anonymous access | |
Write-Host "Setting up anonymous access" -ForegroundColor Green | |
devtunnel access create $TunnelName -p $Port --anonymous | |
if ($LASTEXITCODE -ne 0) { | |
throw "Failed to set up anonymous access" | |
} | |
Write-Host "✅ Tunnel '$TunnelName' created successfully with port $Port and anonymous access" -ForegroundColor Green | |
} | |
catch { | |
Write-Error "❌ Failed to create tunnel: $_" | |
return 1 | |
} | |
} | |
function Invoke-ProvisionTtkLocal { | |
<# | |
.SYNOPSIS | |
Provisions a Teams Toolkit project for local development. | |
.DESCRIPTION | |
This function handles environment configuration and bot registration for Teams Toolkit projects. | |
It creates the necessary .env.local file, prompts for bot endpoint configuration, and runs | |
the provision commands. | |
.EXAMPLE | |
Invoke-ProvisionTtkLocal | |
#> | |
try { | |
# Check if env folder exists | |
if (-not (Test-Path "env")) { | |
Write-Error "❌ 'env' folder not found. Are you sure this is a TTK enabled project?" | |
return 1 | |
} | |
# Create env/.env.local if it doesn't exist | |
if (-not (Test-Path "env/.env.local")) { | |
New-Item -Path "env/.env.local" -ItemType File | Out-Null | |
Write-Host "✨ Created env/.env.local" -ForegroundColor Green | |
} | |
# Check and update BOT_ENDPOINT if needed | |
$envContent = Get-Content "env/.env.local" -ErrorAction SilentlyContinue | |
$botEndpointExists = $envContent | Where-Object { $_ -match "^BOT_ENDPOINT=" } | |
if (-not $botEndpointExists) { | |
Write-Host "BOT_ENDPOINT not found in env/.env.local" -ForegroundColor Yellow | |
$botEndpoint = Read-Host "Please enter the BOT_ENDPOINT value (e.g., https://example.com)" | |
if ([string]::IsNullOrEmpty($botEndpoint)) { | |
Write-Error "❌ BOT_ENDPOINT is required" | |
return 1 | |
} | |
# Validate URL format | |
if ($botEndpoint -notmatch "^https?://") { | |
Write-Error "❌ BOT_ENDPOINT must start with http:// or https://" | |
return 1 | |
} | |
# Extract domain by removing protocol | |
$botDomain = $botEndpoint -replace "^https?://", "" | |
# Remove any existing BOT_ENDPOINT and BOT_DOMAIN entries | |
$filteredContent = $envContent | Where-Object { | |
$_ -notmatch "^BOT_ENDPOINT=" -and $_ -notmatch "^BOT_DOMAIN=" | |
} | |
# Add the new values | |
$newContent = $filteredContent + @("BOT_ENDPOINT=$botEndpoint", "BOT_DOMAIN=$botDomain") | |
$newContent | Set-Content "env/.env.local" | |
Write-Host "✅ Added BOT_ENDPOINT and BOT_DOMAIN to env/.env.local" -ForegroundColor Green | |
} | |
# Run teamsapp provision | |
Write-Host "🚀 Running teamsapp provision..." -ForegroundColor Blue | |
atk provision --env=local | |
if ($LASTEXITCODE -ne 0) { | |
Write-Error "❌ Provisioning failed" | |
return 1 | |
} | |
Write-Host "✅ Provision completed successfully" -ForegroundColor Green | |
return 0 | |
} | |
catch { | |
Write-Error "❌ An error occurred during provisioning: $_" | |
return 1 | |
} | |
} | |
# Export functions for use in other scripts (only when loaded as a module) | |
if ($null -ne $PSModuleInfo) { | |
Export-ModuleMember -Function Create-Tunnel, Invoke-ProvisionTtkLocal | |
} | |
Write-Host "Teams Development Functions loaded successfully!" -ForegroundColor Green | |
Write-Host "Available functions:" -ForegroundColor Cyan | |
Write-Host " - Create-Tunnel" -ForegroundColor White | |
Write-Host " - Invoke-ProvisionTtkLocal" -ForegroundColor White | |
$VERSION = '0.1.0' | |
function Show-GeneralHelp { | |
param() | |
Write-Host "teams-dev.ps1 v$VERSION" -ForegroundColor Cyan | |
Write-Host "" | |
Write-Host "Usage:" -ForegroundColor Yellow | |
Write-Host " teams-dev.ps1 <command> [options]" | |
Write-Host "" | |
Write-Host "Commands:" -ForegroundColor Yellow | |
Write-Host " create-tunnel (crt) Create a devtunnel" -ForegroundColor White | |
Write-Host " provision (prov) Provision TTK project for local development" -ForegroundColor White | |
Write-Host " help (h) Show help" -ForegroundColor White | |
Write-Host " version (v) Show version" -ForegroundColor White | |
Write-Host "" | |
Write-Host "Examples:" -ForegroundColor Yellow | |
Write-Host ' teams-dev.ps1 create-tunnel --name my-app --port 3978' -ForegroundColor White | |
Write-Host ' teams-dev.ps1 crt -n my-app -p 3978' -ForegroundColor White | |
Write-Host ' teams-dev.ps1 provision' -ForegroundColor White | |
} | |
function Show-SubHelp-CreateTunnel { | |
Write-Host "create-tunnel / crt" -ForegroundColor Cyan | |
Write-Host "" | |
Write-Host "Usage:" -ForegroundColor Yellow | |
Write-Host " teams-dev.ps1 create-tunnel --name <name> --port <port>" -ForegroundColor White | |
Write-Host "" | |
Write-Host "Options:" -ForegroundColor Yellow | |
Write-Host " -n, --name Tunnel name (required)" -ForegroundColor White | |
Write-Host " -p, --port Port number (required)" -ForegroundColor White | |
Write-Host " -h, --help Show this help" -ForegroundColor White | |
} | |
function Show-SubHelp-Provision { | |
Write-Host "provision / prov" -ForegroundColor Cyan | |
Write-Host "" | |
Write-Host "Usage:" -ForegroundColor Yellow | |
Write-Host " teams-dev.ps1 provision" -ForegroundColor White | |
Write-Host "" | |
Write-Host "Options:" -ForegroundColor Yellow | |
Write-Host " -h, --help Show this help" -ForegroundColor White | |
} | |
# helper to parse args for create-tunnel | |
function Parse-CreateTunnelArgs { | |
param( | |
[Parameter(ValueFromRemainingArguments=$true)] | |
[string[]]$Args | |
) | |
$result = @{ Name = $null; Port = $null; Help = $false } | |
for ($i=0; $i -lt $Args.Count; $i++) { | |
$a = $Args[$i] | |
switch ($a) { | |
'-n' { | |
if ($i+1 -lt $Args.Count) { $result.Name = $Args[$i+1]; $i++ } else { Write-Error "Missing value for $a"; exit 3 } | |
break | |
} | |
'--name' { | |
if ($i+1 -lt $Args.Count) { $result.Name = $Args[$i+1]; $i++ } else { Write-Error "Missing value for $a"; exit 3 } | |
break | |
} | |
'-p' { | |
if ($i+1 -lt $Args.Count) { $result.Port = $Args[$i+1]; $i++ } else { Write-Error "Missing value for $a"; exit 3 } | |
break | |
} | |
'--port' { | |
if ($i+1 -lt $Args.Count) { $result.Port = $Args[$i+1]; $i++ } else { Write-Error "Missing value for $a"; exit 3 } | |
break | |
} | |
'-h' { | |
$result.Help = $true; break | |
} | |
'--help' { | |
$result.Help = $true; break | |
} | |
default { | |
Write-Error "Unknown option: $a"; exit 3 | |
} | |
} | |
} | |
return $result | |
} | |
# Main dispatch | |
if ($args.Count -eq 0) { | |
Show-GeneralHelp | |
exit 0 | |
} | |
$cmd = $args[0].ToLower() | |
$subArgs = @() | |
if ($args.Count -gt 1) { $subArgs = $args[1..($args.Count-1)] } | |
switch ($cmd) { | |
'create-tunnel' { $cmdKey = 'create-tunnel' } | |
'crt' { $cmdKey = 'create-tunnel' } | |
'provision' { $cmdKey = 'provision' } | |
'prov' { $cmdKey = 'provision' } | |
'help' { $cmdKey = 'help' } | |
'h' { $cmdKey = 'help' } | |
'version' { $cmdKey = 'version' } | |
'v' { $cmdKey = 'version' } | |
default { | |
Write-Error "Unknown command: $cmd" | |
Show-GeneralHelp | |
exit 3 | |
} | |
} | |
switch ($cmdKey) { | |
'create-tunnel' { | |
$parsed = Parse-CreateTunnelArgs -Args $subArgs | |
if ($parsed.Help) { Show-SubHelp-CreateTunnel; exit 0 } | |
if (-not $parsed.Name) { Write-Error "Tunnel name is required (-n, --name)"; exit 4 } | |
if (-not $parsed.Port) { Write-Error "Port is required (-p, --port)"; exit 4 } | |
if ($parsed.Port -notmatch '^\d+$') { Write-Error "Port must be an integer"; exit 4 } | |
try { | |
Create-Tunnel -TunnelName $parsed.Name -Port ([int]$parsed.Port) | |
exit $LASTEXITCODE | |
} catch { | |
Write-Error "Failed to create tunnel: $_" | |
exit 1 | |
} | |
} | |
'provision' { | |
if ($subArgs -and ($subArgs -contains '-h' -or $subArgs -contains '--help')) { Show-SubHelp-Provision; exit 0 } | |
try { | |
Invoke-ProvisionTtkLocal | |
exit $LASTEXITCODE | |
} catch { | |
Write-Error "Provision failed: $_" | |
exit 1 | |
} | |
} | |
'help' { | |
if ($subArgs.Count -gt 0) { | |
switch ($subArgs[0].ToLower()) { | |
'create-tunnel' { Show-SubHelp-CreateTunnel; exit 0 } | |
'crt' { Show-SubHelp-CreateTunnel; exit 0 } | |
'provision' { Show-SubHelp-Provision; exit 0 } | |
'prov' { Show-SubHelp-Provision; exit 0 } | |
default { Show-GeneralHelp; exit 0 } | |
} | |
} else { | |
Show-GeneralHelp; exit 0 | |
} | |
} | |
'version' { | |
Write-Host $VERSION | |
exit 0 | |
} | |
default { | |
Show-GeneralHelp; exit 0 | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
PS C:> teams-dev
Teams Development Functions loaded successfully!
Available functions:
teams-dev.ps1 v0.1.0
Usage:
teams-dev.ps1 [options]
Commands:
create-tunnel (crt) Create a devtunnel
provision (prov) Provision TTK project for local development
help (h) Show help
version (v) Show version
Examples:
teams-dev.ps1 create-tunnel --name my-app --port 3978
teams-dev.ps1 crt -n my-app -p 3978
teams-dev.ps1 provision