Preparation for the AZ-204 exam (CLI and PS Commands)
Search Command
PS /home/ramiro> get-command *AzWebApp
CommandType Name Version Source
----------- ---- ------- ------
Cmdlet Get-AzWebApp 2.11.2 Az.Websites
Cmdlet New-AzWebApp 2.11.2 Az.Websites
Cmdlet Publish-AzWebApp 2.11.2 Az.Websites
Cmdlet Remove-AzWebApp 2.11.2 Az.Websites
Cmdlet Restart-AzWebApp 2.11.2 Az.Websites
Cmdlet Set-AzWebApp 2.11.2 Az.Websites
Cmdlet Start-AzWebApp 2.11.2 Az.Websites
Cmdlet Stop-AzWebApp 2.11.2 Az.Websites
Activate sandbox
For Console
https://portal.azure.com/learn.docs.microsoft.com
Resource Group
PS /home/ramiro> az group create --name lab1-rg --location eastus
{
"id": "/subscriptions/12345/resourceGroups/lab1-rg",
"location": "eastus",
"name": "lab1-rg",
"properties": {
"provisioningState": "Succeeded"
},
"type": "Microsoft.Resources/resourceGroups"
}
> az group delete --name lab1-rg --no-wait --yes
Create VM
with PS
PS /home/ramiro> Get-AzVm
PS /home/ramiro> New-AzResourceGroup -Name ps-rg -Location westus2
ResourceGroupName : ps-rg
Location : westus2
ProvisioningState : Succeeded
Tags :
ResourceId : /subscriptions/354d5e5b-ad8d-4e29-a2b4-e8e7038d7207/resourceGroups/ps-rg
PS /home/ramiro> New-AzVm -ResourceGroupName ps-rg -Name aznewvm -Location westus2 -VirtualNetworkName "mynewVNet" -SubnetName "default" -SecurityGroupName "mynewNSG" -PublicIpAddressName "mypublicip" -OpenPorts 80,3389
cmdlet New-AzVM at command pipeline position 1
Supply values for the following parameters:
Credential
User: testuser
Password for user testuser: **********
No Size value has been provided. The VM will be created with the default size Standard_D2s_v3.
Creating Azure resources [2% /
PS /home/ramiro> Remove-AzResourceGroup -Name cli-uk-rg
with Cli
PS /home/ramiro> az group create --name cli-uk-rg --location ukwest
{
"id": "/subscriptions/354d5e5b-ad8d-4e29-a2b4-e8e7038d7207/resourceGroups/cli-uk-rg",
"location": "ukwest",
"name": "cli-uk-rg",
"properties": {
"provisioningState": "Succeeded"
},
"type": "Microsoft.Resources/resourceGroups"
}
PS /home/ramiro> az vm create --resource cli-uk-rg --name aznewvm2 --image win2016datacenter --size Standard_B2s --public-ip-sku Standard --admin-user testuser
Admin Password:
Confirm Admin Password:
It is recommended to use parameter "--public-ip-sku Standard" to create new VM with Standard public IP. Please note that the default public IP used for VM creation will be changed from Basic to Standard in the future.
{
"fqdns": "",
"id": "/subscriptions/354d5e5b-ad8d-4e29-a2b4-e8e7038d7207/resourceGroups/cli-uk-rg/providers/Microsoft.Compute/virtualMachines/aznewvm2",
"location": "ukwest",
"macAddress": "00-22-48-C5-C1-6F",
"powerState": "VM running",
"privateIpAddress": "10.0.0.4",
"publicIpAddress": "51.142.142.46",
"resourceGroup": "cli-uk-rg",
"zones": ""
}
Create a Web App
PS /home/ramiro> New-AzResourceGroup -Name "ps-webapp-rg" -Location "EastUS"
ResourceGroupName : ps-webapp-rg
Location : eastus
ProvisioningState : Succeeded
Tags :
ResourceId : /subscriptions/354d5e5b-ad8d-4e29-a2b4-e8e7038d7207/resourceGroups/ps-webapp-rg
PS /home/ramiro> New-AzAppServicePlan -ResourceGroupName "ps-webapp-rg" -Name "aznewasp123" -Location "EastUS" -Tier "Free"
Name State ResourceGroup EnabledHostNames Location
---- ----- ------------- ---------------- --------
aznewasp123 ps-webapp-rg EastUS
PS /home/ramiro> New-AzWebApp -ResourceGroupName "ps-webapp-rg" -Name "webapp1-ramirobedoya" -Location "EastUS" -AppServicePlan "aznewasp123"
Name State ResourceGroup EnabledHostNames Location
---- ----- ------------- ---------------- --------
webapp1-ramirobedoya Running ps-webapp-rg {webapp1-ramirobedoya.azurewebsites.net, webapp1-… EastUS
With CLI
PS /home/ramiro> az group create --name cli-webapp-rg --location eastus
{
"id": "/subscriptions/354d5e5b-ad8d-4e29-a2b4-e8e7038d7207/resourceGroups/cli-webapp-rg",
"location": "eastus",
"name": "cli-webapp-rg",
"properties": {
"provisioningState": "Succeeded"
},
"type": "Microsoft.Resources/resourceGroups"
}
PS /home/ramiro> az appservice plan create -g cli-webapp-rg -n aznewasp4566
{
"geoRegion": "East US",
"id": "/subscriptions/354d5e5b-ad8d-4e29-a2b4-e8e7038d7207/resourceGroups/cli-webapp-rg/providers/Microsoft.Web/serverfarms/aznewasp4566",
"kind": "app",
"location": "eastus",
"maximumElasticWorkerCount": 1,
"maximumNumberOfWorkers": 0,
"name": "aznewasp4566",
"numberOfSites": 0,
"provisioningState": "Succeeded",
"resourceGroup": "cli-webapp-rg",
"sku": {
"capacity": 1,
"family": "B",
"name": "B1",
"size": "B1",
"tier": "Basic"
},
"status": "Ready",
"subscription": "354d5e5b-ad8d-4e29-a2b4-e8e7038d7207",
"targetWorkerCount": 0,
"targetWorkerSizeId": 0,
"type": "Microsoft.Web/serverfarms",
"zoneRedundant": false
}
PS /home/ramiro> az webapp create -g cli-webapp-rg -n webapp2-ramirobedoya -p aznewasp4566
{
"availabilityState": "Normal",
"clientAffinityEnabled": true,
"clientCertMode": "Required",
"containerSize": 0,
"customDomainVerificationId": "5FC64C983A71E6567210BF380AA68EB6A29C4974D6AF1A8555FF00374B610CFE",
"dailyMemoryTimeQuota": 0,
"defaultHostName": "webapp2-ramirobedoya.azurewebsites.net",
"enabled": true,
"enabledHostNames": [
"webapp2-ramirobedoya.azurewebsites.net",
"webapp2-ramirobedoya.scm.azurewebsites.net"
],
"ftpPublishingUrl": "ftp://waws-prod-blu-273.ftp.azurewebsites.windows.net/site/wwwroot",
"hostNameSslStates": [
{
"hostType": "Standard",
"ipBasedSslState": "NotConfigured",
"name": "webapp2-ramirobedoya.azurewebsites.net",
"sslState": "Disabled",
},
{
"hostType": "Repository",
"ipBasedSslState": "NotConfigured",
"name": "webapp2-ramirobedoya.scm.azurewebsites.net",
"sslState": "Disabled",
}
],
"hostNames": [
"webapp2-ramirobedoya.azurewebsites.net"
],
"id": "/subscriptions/354d5e5b-ad8d-4e29-a2b4-e8e7038d7207/resourceGroups/cli-webapp-rg/providers/Microsoft.Web/sites/webapp2-ramirobedoya",
"keyVaultReferenceIdentity": "SystemAssigned",
"kind": "app",
"lastModifiedTimeUtc": "2022-06-18T22:27:42.386666",
"location": "East US",
"name": "webapp2-ramirobedoya",
"redundancyMode": "None",
"repositorySiteName": "webapp2-ramirobedoya",
"resourceGroup": "cli-webapp-rg",
"serverFarmId": "/subscriptions/354d5e5b-ad8d-4e29-a2b4-e8e7038d7207/resourceGroups/cli-webapp-rg/providers/Microsoft.Web/serverfarms/aznewasp4566",
"siteConfig": {
"functionAppScaleLimit": 0,
"ipSecurityRestrictions": [
{
"action": "Allow",
"description": "Allow all access",
"ipAddress": "Any",
"name": "Allow all",
"priority": 1,
}
],
"linuxFxVersion": "",
"minimumElasticInstanceCount": 0,
"numberOfWorkers": 1,
"scmIpSecurityRestrictions": [
{
"action": "Allow",
"description": "Allow all access",
"ipAddress": "Any",
"name": "Allow all",
"priority": 1,
}
],
},
"state": "Running",
"type": "Microsoft.Web/sites",
"usageState": "Normal",
}
Deploy static website
PS /home/ramiro> az group create --name cli-webapp-rg --location eastus
PS /home/ramiro> az appservice plan create -g cli-webapp-rg -n aznewasp4566
PS /home/ramiro> mkdir newwebapp
PS /home/ramiro> git clone https://github.com/Azure-Samples/html-docs-hello-world
Cloning into 'html-docs-hello-world'...
remote: Enumerating objects: 50, done.
remote: Counting objects: 100% (4/4), done.
remote: Compressing objects: 100% (4/4), done.
remote: Total 50 (delta 0), reused 2 (delta 0), pack-reused 46
Unpacking objects: 100% (50/50), done.
PS /home/ramiro> cd ./html-docs-hello-world/
PS /home/ramiro/html-docs-hello-world> ls
css fonts img index.html js LICENSE README.md
PS /home/ramiro/html-docs-hello-world> az webapp up --location eastus --name simple-ramirobedoya-me2 -g cli-webapp-rg -p aznewasp4566 --html
The webapp 'simple-ramirobedoya-me2' doesn't exist
Creating AppServicePlan 'aznewasp4566' ...
Creating webapp 'simple-ramirobedoya-me2' ...
Configuring default logging for the app, if not already enabled
Creating zip with contents of dir /home/ramiro/html-docs-hello-world ...
Getting scm site credentials for zip deployment
Starting zip deployment. This operation can take a while to complete ...
Deployment endpoint responded with status code 202
You can launch the app at http://simple-ramirobedoya-me2.azurewebsites.net
Setting 'az webapp up' default arguments for current directory. Manage defaults with 'az configure --scope local'
--resource-group/-g default: cli-webapp-rg
--sku default: F1
--plan/-p default: aznewasp4566
--location/-l default: eastus
--name/-n default: simple-ramirobedoya-me2
{
"URL": "http://simple-ramirobedoya-me2.azurewebsites.net",
"appserviceplan": "aznewasp4566",
"location": "eastus",
"name": "simple-ramirobedoya-me2",
"os": "Windows",
"resourcegroup": "cli-webapp-rg",
"runtime_version": "-",
"runtime_version_detected": "-",
"sku": "FREE",
"src_path": "//home//ramiro//html-docs-hello-world"
}
if I don’t specify the resource group and App service plan, it will create by default
PS /home/ramiro/html-docs-hello-world> az webapp up --location eastus --name simple-ramirobedoya-me2 -g cli-webapp-rg -p aznewasp4566 --html
The webapp 'simple-ramirobedoya-me' doesn't exist
Creating Resource group 'whistler092_rg_6728' ...
Resource group creation complete
Creating AppServicePlan 'whistler092_asp_8600' ...
Creating webapp 'simple-ramirobedoya-me' ...
Configuring default logging for the app, if not already enabled
Creating zip with contents of dir /home/ramiro/html-docs-hello-world ...
Getting scm site credentials for zip deployment
Starting zip deployment. This operation can take a while to complete ...
Deployment endpoint responded with status code 202
You can launch the app at http://simple-ramirobedoya-me.azurewebsites.net
Setting 'az webapp up' default arguments for current directory. Manage defaults with 'az configure --scope local'
--resource-group/-g default: whistler092_rg_6728
--sku default: F1
--plan/-p default: whistler092_asp_8600
--location/-l default: eastus
--name/-n default: simple-ramirobedoya-me
{
"URL": "http://simple-ramirobedoya-me.azurewebsites.net",
"appserviceplan": "whistler092_asp_8600",
"location": "eastus",
"name": "simple-ramirobedoya-me",
"os": "Windows",
"resourcegroup": "whistler092_rg_6728",
"runtime_version": "-",
"runtime_version_detected": "-",
"sku": "FREE",
"src_path": "//home//ramiro//html-docs-hello-world"
}
Containers
> New-AzResourceGroup -Name myResourceGroup -Location EastUS
> New-AzContainerGroup -ResourceGroupName myResourceGroup -Name mycontainer -Image mcr.microsoft.com/windows/servercore/iis:nanoserver -OsType Windows -DnsNameLabel aci-demo-win
> Get-AzContainerGroup -ResourceGroupName myResourceGroup -Name mycontainer
FROM mcr.microsoft.com/dotnet/aspnet:3.1-buster-slim AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
FROM mcr.microsoft.com/dotnet/sdk:3.1-buster-slim AS build
WORKDIR /src
COPY ["WebApplication43/WebApplication43.csproj", "WebApplication43/"]
RUN dotnet restore "WebApplication43/WebApplication43.csproj"
COPY . .
WORKDIR "/src/WebApplication43"
RUN dotnet build "WebApplication43.csproj" -c Release -o /app/build
FROM build AS publish
RUN dotnet publish "WebApplication43.csproj" -c Release -o /app/publish
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "WebApplication43.dll"]
Storage Account
>az storage account create -n mystorageaccount -g MyResourceGroup -l westus --sku Standard_LRS
PS /home/ramiro> az storage account create --name imgstorageramirobedoya -g lab1-rg -l eastus --sku Standard_LRS
/ Running ..
{
"accessTier": "Hot",
"allowBlobPublicAccess": true,
"creationTime": "2022-07-10T03:30:53.728939+00:00",
"enableHttpsTrafficOnly": true,
"encryption": {
"keySource": "Microsoft.Storage",
"services": {
"blob": {
"enabled": true,
"keyType": "Account",
"lastEnabledTime": "2022-07-10T03:30:53.869559+00:00"
},
"file": {
"enabled": true,
"keyType": "Account",
"lastEnabledTime": "2022-07-10T03:30:53.869559+00:00"
},
}
},
"id": "/subscriptions/354d5e5b-ad8d-4e29-a2b4-e8e7038d7207/resourceGroups/lab1-rg/providers/Microsoft.Storage/storageAccounts/imgstorageramirobedoya",
"keyCreationTime": {
"key1": "2022-07-10T03:30:53.869559+00:00",
"key2": "2022-07-10T03:30:53.869559+00:00"
},
"kind": "StorageV2",
"location": "eastus",
"minimumTlsVersion": "TLS1_0",
"name": "imgstorageramirobedoya",
"networkRuleSet": {
"bypass": "AzureServices",
"defaultAction": "Allow",
"ipRules": [],
"virtualNetworkRules": []
},
"primaryEndpoints": {
"blob": "https://imgstorageramirobedoya.blob.core.windows.net/",
"dfs": "https://imgstorageramirobedoya.dfs.core.windows.net/",
"file": "https://imgstorageramirobedoya.file.core.windows.net/",
"queue": "https://imgstorageramirobedoya.queue.core.windows.net/",
"table": "https://imgstorageramirobedoya.table.core.windows.net/",
"web": "https://imgstorageramirobedoya.z13.web.core.windows.net/"
},
"primaryLocation": "eastus",
"privateEndpointConnections": [],
"provisioningState": "Succeeded",
"resourceGroup": "lab1-rg",
"sku": {
"name": "Standard_LRS",
"tier": "Standard"
},
"statusOfPrimary": "available",
"tags": {},
"type": "Microsoft.Storage/storageAccounts"
}
PS /home/ramiro> az storage container create --name images --public-access blob --account-name imgstorageramirobedoya
{
"created": true
}
Deploy Dotnet App - Lab1
> az login
> az webapp list -g lab1-rg
> az webapp list --resource-group lab1-rg --query "[?starts_with(name, 'imgapi')]"
> az webapp list --resource-group lab1-rg --query "[?starts_with(name, 'imgapi')].{Name:name}" --output tsv
imgapiramirobedoya
> az webapp deployment source config-zip --resource-group lab1-rg --src api.zip --name imgapiramirobedoya
> az appservice plan create -g cli-webapp-rg -n aznewasp4566 --sku S1 --location eastus
> az webapp create -g lab1-rg -n imgwebramirobedoya -p aznewasp4566
> az webapp list --resource-group lab1-rg --query "[?starts_with(name, 'imgweb')]"
> az webapp list --resource-group lab1-rg --query "[?starts_with(name, 'imgweb')].{Name:name}" --output tsv
imgwebramirobedoya
> az webapp deployment source config-zip --resource-group lab1-rg --src web.zip --name imgwebramirobedoya
http://imgapiramirobedoya.azurewebsites.net/
Commands - Lab2
> az login
> az storage account create -n imgstorramirobedoya -g lab2-rg -l eastus --sku Standard_LRS
Get Connection String
> az storage account show-connection-string \
--name $(az storage account list --resource-group lab2-rg --query "[?starts_with(name, 'imgsto')].{Name:name}" -o tsv) \
--resource-group lab2-rg \
--query "connectionString" -o tsv
DefaultEndpointsProtocol=https;EndpointSuffix=core.windows.net;AccountName=imgstorramirobedoya;AccountKey=asdasd;BlobEndpoint=https://imgstorramirobedoya.blob.core.windows.net/;FileEndpoint=https://imgstorramirobedoya.file.core.windows.net/;QueueEndpoint=https://imgstorramirobedoya.queue.core.windows.net/;TableEndpoint=https://imgstorramirobedoya.table.core.windows.net/
> az appservice plan create -g lab2-rg -n funcs-ramirobedoya --sku S1 --location eastus --is-linux
> az functionapp list-runtimes
> az functionapp create --name funclogicramirobedoya --resource-group lab2-rg --plan funcs-ramirobedoya --runtime dotnet --runtime-version 6 --functions-version 4 --storage-account imgstorramirobedoya
Create functions project
> func init --worker-runtime dotnet --force
> dotnet build
Microsoft (R) Build Engine version 17.2.0+41abc5629 for .NET
Copyright (C) Microsoft Corporation. All rights reserved.
Determining projects to restore...
All projects are up-to-date for restore.
func -> ~/AZ-204-DevelopingSolutionsforMicrosoftAzure/Allfiles/Labs/02/Starter/func/bin/Debug/net6.0/func.dll
Build succeeded.
0 Warning(s)
0 Error(s)
Time Elapsed 00:00:23.16
> func new --template "HTTP trigger" --name "Echo"
Select a number for template:Function name: Echo
The function "Echo" was created successfully from the "HTTP trigger" template.
> func start --build
Microsoft (R) Build Engine version 17.2.0+41abc5629 for .NET
Copyright (C) Microsoft Corporation. All rights reserved.
Determining projects to restore...
All projects are up-to-date for restore.
func -> ~/AZ-204-DevelopingSolutionsforMicrosoftAzure/Allfiles/Labs/02/Starter/func/bin/output/func.dll
Build succeeded.
0 Warning(s)
0 Error(s)
Time Elapsed 00:00:14.57
Azure Functions Core Tools
Core Tools Version: 4.0.4544 Commit hash: N/A (64-bit)
Function Runtime Version: 4.3.2.18186
[2022-07-12T20:55:13.120Z] Found ~/AZ-204-DevelopingSolutionsforMicrosoftAzure/Allfiles/Labs/02/Starter/func/func.csproj. Using for user secrets file configuration.
Functions:
Echo: [POST] http://localhost:7071/api/Echo
For detailed output, run func with --verbose flag.
[2022-07-12T20:55:32.745Z] Host lock lease acquired by instance ID '000000000000000000000000A4DAC17F'.
[2022-07-12T20:55:38.056Z] Executing 'Echo' (Reason='This function was programmatically called via the host APIs.', Id=05254f34-ab24-4646-a5ee-ad69630ea3a2)
[2022-07-12T20:55:38.068Z] C# HTTP trigger function processed a request.
[2022-07-12T20:55:38.097Z] Executed 'Echo' (Succeeded, Id=05254f34-ab24-4646-a5ee-ad69630ea3a2, Duration=63ms)
[2022-07-12T20:55:51.010Z] Executing 'Echo' (Reason='This function was programmatically called via the host APIs.', Id=46553eb7-3d9d-4924-81b9-8668c5b94b16)
[2022-07-12T20:55:51.010Z] C# HTTP trigger function processed a request.
[2022-07-12T20:55:51.010Z] Executed 'Echo' (Succeeded, Id=46553eb7-3d9d-4924-81b9-8668c5b94b16, Duration=6ms)
> func new --template "Timer trigger" --name "Recurring"
> func start --build
Microsoft (R) Build Engine version 17.2.0+41abc5629 for .NET
Copyright (C) Microsoft Corporation. All rights reserved.
Determining projects to restore...
All projects are up-to-date for restore.
func -> /Users/ramiroandres/workspace/AZ-204-DevelopingSolutionsforMicrosoftAzure/Allfiles/Labs/02/Starter/func/bin/output/func.dll
Build succeeded.
0 Warning(s)
0 Error(s)
Time Elapsed 00:00:11.68
Azure Functions Core Tools
Core Tools Version: 4.0.4544 Commit hash: N/A (64-bit)
Function Runtime Version: 4.3.2.18186
[2022-07-12T20:59:30.460Z] Found /Users/ramiroandres/workspace/AZ-204-DevelopingSolutionsforMicrosoftAzure/Allfiles/Labs/02/Starter/func/func.csproj. Using for user secrets file configuration.
Functions:
Echo: [POST] http://localhost:7071/api/Echo
Recurring: timerTrigger
For detailed output, run func with --verbose flag.
[2022-07-12T20:59:37.642Z] Host lock lease acquired by instance ID '000000000000000000000000A4DAC17F'.
[2022-07-12T21:00:30.063Z] Executing 'Recurring' (Reason='Timer fired at 2022-07-12T16:00:30.0205030-05:00', Id=5efaae60-4145-425e-8b7a-efa03ced230c)
[2022-07-12T21:00:30.122Z] C# Timer trigger function executed at: 7/12/2022 4:00:30 PM
[2022-07-12T21:00:30.146Z] Executed 'Recurring' (Succeeded, Id=5efaae60-4145-425e-8b7a-efa03ced230c, Duration=107ms)
Create a function that integrates with other services
Note: off means Private (no anonymous access).
> az storage container create
> az storage container create --name content --public-access off --account-name imgstorramirobedoya
> func new --template "HTTP trigger" --name "GetSettingInfo"
Select a number for template:Function name: GetSettingInfo
The function "GetSettingInfo" was created successfully from the "HTTP trigger" template.
>
> func extensions install --package Microsoft.Azure.WebJobs.Extensions.Storage --version 4.0.4
Update file with the following code
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
public static class GetSettingInfo
{
[FunctionName("GetSettingInfo")]
public static IActionResult Run(
[HttpTrigger("GET")] HttpRequest request,
[Blob("content/settings.json")] string json)
=> new OkObjectResult(json);
}
Deploy function
> func azure functionapp publish <function-app-name>
Lab 3
Create rg and storage account, then get some information about them
> az group create --name lab3-rg --location eastus
> az storage account create --name mediastorramirobedoya --location eastus --resource-group lab3-rg --sku Standard_LRS
Get Endpoints
> az storage account list --resource-group lab3-rg --query "[?starts_with(name, 'mediastor')].{primaryEndpoints:primaryEndpoints.blob}" -o tsv
https://mediastorramirobedoya.blob.core.windows.net/
> az storage account show-connection-string \
--name $(az storage account list --resource-group lab3-rg --query "[?starts_with(name, 'mediastor')].{Name:name}" -o tsv) \
--resource-group lab3-rg \
--query "connectionString" -o tsv
> az storage account keys list -g lab3-rg -n $(az storage account list --resource-group lab3-rg --query "[?starts_with(name, 'mediastor')].{Name:name}" -o tsv) --query "[0].value" -o tsv
asdf==
> az storage container create --name raster-graphics --public-access off --account-name $(az storage account list --resource-group lab3-rg --query "[?starts_with(name, 'mediastor')].{Name:name}" -o tsv)
> az storage container create --name compressed-audio --public-access off --account-name $(az storage account list --resource-group lab3-rg --query "[?starts_with(name, 'mediastor')].{Name:name}" -o tsv)
Create dotnet app
> dotnet new console --name BlobManager --output .
> dotnet add package Azure.Storage.Blobs --version 12.0.0
> dotnet build
Replace Program.cs with the following code
using Azure.Storage;
using Azure.Storage.Blobs;
using Azure.Storage.Blobs.Models;
public class Program
{
private const string blobServiceEndpoint = "https://mediastorramirobedoya.blob.core.windows.net/";
private const string storageAccountName = "mediastorramirobedoya";
private const string storageAccountKey = "k7EDU/wDfXEPjPPHPH95yMQZERZu4bNpcHYGPzGdvfW1+Zar4LSyLzkv+4kcB/9cKJ2z94wV5ISf+AStSVpfbw==";
public static async Task Main(string[] args)
{
var accountCredentials = new StorageSharedKeyCredential(storageAccountName, storageAccountKey);
var blobServiceClient = new BlobServiceClient(new Uri(blobServiceEndpoint), accountCredentials);
AccountInfo info = await blobServiceClient.GetAccountInfoAsync();
await Console.Out.WriteLineAsync($"Connected to Azure Storage Account");
await Console.Out.WriteLineAsync($"Account Name: \t{storageAccountName}");
await Console.Out.WriteLineAsync($"Account kind: \t{info?.AccountKind}");
await Console.Out.WriteLineAsync($"Account sku \t{info?.SkuName}");
await EnumerateContainersAsync(blobServiceClient);
}
private static async Task EnumerateContainersAsync(BlobServiceClient client)
{
await foreach (BlobContainerItem containerItem in client.GetBlobContainersAsync())
{
await Console.Out.WriteLineAsync($"Container: \t{containerItem.Name}");
}
}
}
Lab4
> az group create --name lab4-rg --location eastus
{
"id": "/subscriptions/354d5e5b-ad8d-4e29-a2b4-e8e7038d7207/resourceGroups/lab4-rg",
"location": "eastus",
"name": "lab4-rg",
"properties": {
"provisioningState": "Succeeded"
},
"type": "Microsoft.Resources/resourceGroups"
}
> az cosmosdb create \
--name polyglotdataramirobedoya \
--resource-group lab4-rg
> az cosmosdb keys list \
--name $(az cosmosdb list --resource-group lab4.1-rg --query "[?starts_with(name, 'polyglotdata')].{Name:name}" -o tsv) \
--resource-group lab4.1-rg \
--query "primaryMasterKey" -o tsv
> az storage account create --name polystorramirobedoya -g lab4.1-rg -l eastus --sku Standard_LRS
> az storage container create --name images --public-access blob --account-name $(az storage account list --resource-group lab4.1-rg --query "[?starts_with(name, 'polystor')].{Name:name}" -o tsv)
> az storage container list --account-name $(az storage account list --resource-group lab4.1-rg --query "[?starts_with(name, 'polystor')].{Name:name}" -o tsv)
Upload Json to Azure Cosmos DB
https://gist.github.com/Whistler092/483cee73529cb042836b27d7f4607f7a
Lab5
> az group create --name lab5-rg --location eastus
> az vm create --resource-group lab5-rg --name quickvm --image Debian --admin-username student --admin-password 6pD2ZSuf86pf7t1D --location eastus2 --size standard_ds1
> az vm show --resource-group lab5-rg --name quickvm
> az vm list-ip-addresses --resource-group lab5-rg --name quickvm
> az vm list-ip-addresses --resource-group lab5-rg --name quickvm --query '[].{ip:virtualMachine.network.publicIpAddresses[0].ipAddress}' --output tsv
20.69.246.133
> ipAddress=$(az vm list-ip-addresses --resource-group lab5-rg --name quickvm --query '[].{ip:virtualMachine.network.publicIpAddresses[0].ipAddress}' --output tsv)
> echo $ipAddress
> ssh student@$ipAddress
> student@quickvm:~$ uname -a
Linux quickvm 4.19.0-20-cloud-amd64 #1 SMP Debian 4.19.235-1 (2022-03-17) x86_64 GNU/Linux
> exit
Create dotnet projectg
Cloud Shell
PS /home/ramiro> cd ./clouddrive/
PS /home/ramiro/clouddrive> ls
PS /home/ramiro/clouddrive> mkdir ipcheck
PS /home/ramiro/clouddrive> cd ./ipcheck/
PS /home/ramiro/clouddrive/ipcheck> dotnet new console --output . --name ipcheck
https://github.com/Whistler092/ipcheck
Create a Container Registry resource
> az acr check-name --name conregistryramirobedoya
> az acr create --resource-group lab5-rg --name conregistryramirobedoya --sku Basic
{
"id": "/subscriptions/354d5e5b-ad8d-4e29-a2b4-e8e7038d7207/resourceGroups/lab5-rg/providers/Microsoft.ContainerRegistry/registries/conregistryramirobedoya",
"location": "eastus",
"loginServer": "conregistryramirobedoya.azurecr.io",
"name": "conregistryramirobedoya",
"networkRuleBypassOptions": "AzureServices",
"provisioningState": "Succeeded",
"publicNetworkAccess": "Enabled",
"resourceGroup": "lab5-rg",
"sku": {
"name": "Basic",
"tier": "Basic"
},
"type": "Microsoft.ContainerRegistry/registries",
"zoneRedundancy": "Disabled"
}
> az acr list --query "max_by([], &creationDate).name" --output tsv
conregistryramirobedoya
> acrName=$(az acr list --query "max_by([], &creationDate).name" --output tsv)
echo $acrName
> cd ~/clouddrive/ipcheck
> az acr build --registry $acrName --image ipcheck:latest .
> az acr repository list --name $acrName
In this exercise, you created a .NET console application to display a machine’s current IP address. You then added the Dockerfile file to the application so that it could be converted into a Docker container image. Finally, you deployed the container image to Container Registry.
Exercise 3: Deploy an Azure container instance
Open the Container registry/Overview/Update/ turn on Admin user.
> az container create --resource-group lab5-rg --name managedcompute1 --image conregistryramirobedoya.azurecr.io/ipcheck:latest
> az container logs --resource-group lab5-rg --name managedcompute
CorCurrent IP Address:
127.0.0.1
192.168.0.120
fe80::215:5dff:fe0c:6833%2
2022-07-14T17:32:59.9145453Z stderr F
Note: After the application finishes running, the container terminates because it has completed its work. For the manually created container instance, you indicated that a successful exit was acceptable, so the container ran once. The automatically created instance didn’t offer this option, and it assumes the container should always be running, so you’ll notice repeated restarts of the container.
Lab6 - Authenticate by using OpenID Connect, MSAL, and .NET SDKs
Cloud Shell
PS /home/ramiro> Connect-AzureAD
PS /home/ramiro> $aadDomainName = ((Get-AzureAdTenantDetail).VerifiedDomains)[0].Name
PS /home/ramiro> $aadDomainName
PS /home/ramiro> $passwordProfile = New-Object -TypeName Microsoft.Open.AzureAD.Model.PasswordProfile
PS /home/ramiro> $passwordProfile.Password = 'Pa55w.rd1234'
PS /home/ramiro> $passwordProfile.ForceChangePasswordNextLogin = $false
PS /home/ramiro> New-AzureADUser -AccountEnabled $true -DisplayName 'aad_lab_user1' -PasswordProfile $passwordProfile -MailNickName 'aad_lab_user1' -UserPrincipalName "aad_lab_user1@$aadDomainName"
PS /home/ramiro> (Get-AzureADUser -Filter "MailNickName eq 'aad_lab_user1'").UserPrincipalName
aad_lab_user1@whistler092outlook.onmicrosoft.com
Exercise 2: Create a single-tenant ASP.NET Core web app
cd “F:\Allfiles\Labs\06\Starter\OIDCClient”
> dotnet new mvc --auth SingleOrg --client-id <application_ID> --tenant-id <tenant_ID> --domain <domain_Name>
Update lauchSettings.json
Note: The port numbers must match the value you specified when creating the Azure AD app registration.
Lab7 - Access resource secrets more securely across services
Exercise 2: Configure secrets and identities
Exercise 1: Create Azure resources
> az group create --name lab7-rg --location eastus
> az storage account create -n securestorramirobedoya -g lab7-rg -l eastus --sku Standard_LRS
> az storage account show-connection-string \
--name $(az storage account list --resource-group lab7-rg --query "[?starts_with(name, 'securestor')].{Name:name}" -o tsv) \
--resource-group lab7-rg \
--query "connectionString" -o tsv
> az keyvault create --name securevaultramirobedoya --resource-group lab7-rg --location eastus
> az appservice plan create -g lab7-rg -n appservicefuncsramirobedoya --sku S1 --location eastus --is-linux
> az storage account create -n securestorramirobedoya -g lab7-rg -l eastus --sku Standard_LRS
> az functionapp create --name securefuncramirobedoya --resource-group lab7-rg --plan appservicefuncsramirobedoya --runtime dotnet --runtime-version 6 --functions-version 4 --storage-account securestorramirobedoya
Exercise 2: Configure secrets and identities
In Function App / Settings / Identity / System Assigned / Turn Status On
For the A system assigned managed identity is restricted to one per resource and is tied to the lifecycle of this resource. You can grant permissions to the managed identity by using Azure role-based access control (Azure RBAC). The managed identity is authenticated with Azure AD, so you don’t have to store any credentials in code. Learn more about Managed identities.
In Key vault / Settings / Secrets / + Generate/Import
Create the secret
For CLI
> az keyvault secret set --name securevaultramirobedoya --vault-name storagecredentials1 --value "DefaultEndpointsProtocol=https;EndpointSuffix=core.windows.net;AccountName=securestorramirobedoya;AccountKey=CF/jL5NUTilxe/vpD8PuWPx0pGyB01q41/JW8qFBHRX3E40SIgZL1TuPoEYG2mhYQTtAGKxMDv2w+AStdq6CXw==;BlobEndpoint=https://securestorramirobedoya.blob.core.windows.net/;FileEndpoint=https://securestorramirobedoya.file.core.windows.net/;QueueEndpoint=https://securestorramirobedoya.queue.core.windows.net/;TableEndpoint=https://securestorramirobedoya.table.core.windows.net/"
Inside the Key Valut, Go to Settings / Access Policies / Add Access Policy / Add access Policy
Select permission to get and set the principal app for securefuncramirobedoya
Save
Task 4: Create a Key Vault-derived application setting
In the Function App, go to Settings / Configuration / Application Settings and Add a new one,
Name: StorageConnectionString
Value: @Microsoft.KeyVault(SecretUri=Secret Identifier)
Note: You’ll need to build a reference to your Secret Identifier by using the above syntax. For example, if your secret identifier is
https://securevaultstudent.vault.azure.net/secrets/storagecredentials/17b41386df3e4191b92f089f5efb4cbf
,
your value would be @Microsoft.KeyVault(SecretUri=https://securevaultstudent.vault.azure.net/secrets/storagecredentials/17b41386df3e4191b92f089f5efb4cbf)
> cd F:\Allfiles\Labs\07\Starter\func
> func init --worker-runtime dotnet --force
> dotnet build
> func new --template "HTTP trigger" --name "FileParser"
Update the FileParser file
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.AspNetCore.Http;
using System;
using System.Threading.Tasks;
public static class FileParser
{
[FunctionName("FileParser")]
public static async Task<IActionResult> Run(
[HttpTrigger("GET")]HttpRequest request)
{
string connectionString = Environment.GetEnvironmentVariable("StorageConnectionString");
return new OkObjectResult(connectionString);
}
}
and local.settings.json
file with the StorageConnectionString field
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "UseDevelopmentStorage=true",
"FUNCTIONS_WORKER_RUNTIME": "dotnet",
"StorageConnectionString": "[TEST VALUE]"
}
}
Run func start --build
Execute FileParser: [GET] http://localhost:7071/api/FileParser
Should return [TEST VALUE]
Let’s deploy
> func azure functionapp publish <function-app-name>
Let’s go to the Azure Portal and test the function with the Code + Test
tool
> az storage container create --name drop --public-access blob --account-name $(az storage account list --resource-group lab7-rg --query "[?starts_with(name, 'securestor')].{Name:name}" -o tsv)
Lab 8 - Create a multi-tier solution by using Azure services
> az group create --name lab8-rg --location eastus
> az appservice plan create -g lab8-rg -n appserviceramirobedoya --sku S1 --location eastus --is-linux
> az webapp create --name httpapiramirobedoya --resource-group lab8-rg --plan appserviceramirobedoya --deployment-container-image-name kennethreitz/httpbin:latest
Lab 9 - Publish and subscribe to Event Grid events
> az provider list
> az provider list --query "[].namespace"
Notice that the Microsoft.EventGrid provider is currently included in the list of providers.
> az group create --name lab9-rg --location eastus
> az eventgrid topic create -g lab9-rg --name hrtopicramirobedoya -l eastus
> az appservice plan create -g lab9-rg -n appserviceeventsramirobedoya --sku S1 --location eastus --is-linux
> az webapp create --name eventviewerramirobedoya --resource-group lab9-rg --plan appserviceeventsramirobedoya --deployment-container-image-name microsoftlearning/azure-event-grid-viewer:latest
> az webapp list --resource-group lab9-rg --query "[?starts_with(name, 'eventviewe')].{defaultHostName:defaultHostName}" --output tsv
eventviewerramirobedoya.azurewebsites.net
> az eventgrid topic list --query "[].id" --output tsv
> az eventgrid event-subscription create --name basicsub2 --event-delivery-schema eventgridschema --endpoint-type webhook --endpoint https://eventviewerramirobedoya.azurewebsites.net/api/updates --source-resource-id /subscriptions/354d5e5b-ad8d-4e29-a2b4-e8e7038d7207/resourceGroups/lab9-rg/providers/Microsoft.EventGrid/topics/hrtopicramirobedoya
> az eventgrid topic key list --name hrtopicramirobedoya --resource-group lab9-rg --query "key1" --output tsv
tEGSPs81X348knhZNtdmXctNYrrlOW9tWIvNzzNu8vc=
> az eventgrid topic list --query "[].endpoint" --output tsv
https://hrtopicramirobedoya.eastus-1.eventgrid.azure.net/api/events
Exercise 3: Publish Event Grid events from .NET
> dotnet new console --name EventPublisher --output .
> dotnet add package Azure.Messaging.EventGrid --version 4.1.0
Update code
using Azure;
using Azure.Messaging.EventGrid;
public class Program
{
private const string topicEndpoint = "<topic-endpoint>";
private const string topicKey = "<topic-key>";
public static async Task Main(string[] args)
{
var endpoint = new Uri(topicEndpoint);
var credential = new AzureKeyCredential(topicKey);
var client = new EventGridPublisherClient(endpoint, credential);
var firstEvent = new EventGridEvent(
subject: $"New Employee: Ramiro Bedoya",
eventType: "Employees.Registration.New",
dataVersion: "1.0",
data: new
{
FullName = "Ramiro Andres Bedoya",
Address = "Calle falsa 123"
}
);
await client.SendEventAsync(firstEvent);
Console.WriteLine("First event published");
var secondEvent = new EventGridEvent(
subject: $"New Employee: Chino Moreno",
eventType: "Employees.Registration.New",
dataVersion: "1.0",
data: new
{
FullName = "Chino Moreno",
Address = "456 College Street, Bow, WA 98107"
}
);
await client.SendEventAsync(secondEvent);
Console.WriteLine("Second event published");
}
}
Lab 10: Asynchronously process messages by using Azure Service Bus Queues
> az group create --name lab10-rg --location eastus
> az servicebus namespace create --resource-group lab10-rg --name sbnamespaceramirobedoya --location eastus --sku Basic
> az servicebus namespace authorization-rule keys list \
--resource-group lab10-rg \
--name RootManageSharedAccessKey \
--query primaryConnectionString \
--output tsv \
--namespace-name sbnamespaceramirobedoya
Endpoint=sb://sbnamespaceramirobedoya.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=MkqKgzlnF0xpD/luFd+9lmG30eaOPPlZyRVXKClCFH4=
> az servicebus queue create --resource-group lab10-rg --namespace-name sbnamespaceramirobedoya --name messagequeue
Exercise 2: Create a .NET Core project to publish messages to a Service Bus queue
> dotnet new console --name MessagePublisher --output .
> dotnet add package Azure.Messaging.ServiceBus --version 7.2.1
using Azure.Messaging.ServiceBus;
public class Program
{
private const string storageConnectionString = "Endpoint=sb://<connection-string>";
private const string queueName = "messagequeue";
private const int numOfMessages = 3;
static ServiceBusClient client;
static ServiceBusSender sender;
public static async Task Main(string[] args)
{
client = new ServiceBusClient(storageConnectionString);
sender = client.CreateSender(queueName);
using ServiceBusMessageBatch messageBatch = await sender.CreateMessageBatchAsync();
for (int i = 0; i < numOfMessages; i++)
{
if (!messageBatch.TryAddMessage(new ServiceBusMessage($"Message {i}")))
{
throw new Exception($"The message {i} is too large to fit in the batch.");
}
}
try
{
await sender.SendMessagesAsync(messageBatch);
Console.WriteLine($"A batch of {numOfMessages} messages has been published to the queue.");
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
finally
{
await sender.DisposeAsync();
await client.DisposeAsync();
}
}
}
Exercise 3: Create a .NET Core project to read messages from a Service Bus queue
> dotnet new console --name MessageReader --output .
> dotnet add package Azure.Messaging.ServiceBus --version 7.2.1
using Azure.Messaging.ServiceBus;
public class Program
{
private const string storageConnectionString = "Endpoint=sb://<connection-string>";
private const string queueName = "messagequeue";
static ServiceBusClient client;
static ServiceBusProcessor processor;
public static async Task Main(string[] args)
{
client = new ServiceBusClient(storageConnectionString);
processor = client.CreateProcessor(queueName, new ServiceBusProcessorOptions());
try
{
processor.ProcessMessageAsync += MessageHandler;
processor.ProcessErrorAsync += ErrorHandler;
await processor.StartProcessingAsync();
Console.WriteLine("Wait for a minute and then press any key to end the process");
Console.ReadKey();
Console.WriteLine("\nStopping the receiver...");
await processor.StopProcessingAsync();
Console.WriteLine("Stop receiving messages");
}
finally
{
await processor.DisposeAsync();
await client.DisposeAsync();
}
}
static async Task MessageHandler(ProcessMessageEventArgs args)
{
string body = args.Message.Body.ToString();
Console.WriteLine($"Received: {body}");
await args.CompleteMessageAsync(args.Message);
}
static Task ErrorHandler(ProcessErrorEventArgs args)
{
Console.WriteLine(args.Exception.ToString());
return Task.CompletedTask;
}
}
Lab 11: Monitor services that are deployed to Azure
> az group create --name lab11-rg --location eastus
> az monitor app-insights component create --app instrmramirobedoya --location eastus --kind web --resource-group lab11-rg --application-type web
> az appservice plan create -g lab11-rg -n appservicemonitorramirobedoya --sku S1 --location eastus --is-linux
> az functionapp list-runtimes
> az webapp create --name smpapiramirobedoya --resource-group lab11-rg --plan appservicemonitorramirobedoya --runtime "DOTNETCORE:6.0"
> az monitor app-insights component connect-webapp -g lab11-rg -a instrmramirobedoya --web-app smpapiramirobedoya --enable-profiler --enable-snapshot-debugger
[
{
"name": "APPINSIGHTS_INSTRUMENTATIONKEY",
"slotSetting": false,
"value": "81bbd10b-03d4-401f-a3b3-2816427e01ad"
},
{
"name": "APPINSIGHTS_PROFILERFEATURE_VERSION",
"slotSetting": false,
"value": "1.0.0"
},
{
"name": "APPINSIGHTS_SNAPSHOTFEATURE_VERSION",
"slotSetting": false,
"value": "1.0.0"
}
]
> az webapp list --resource-group lab11-rg --query "[?starts_with(name, 'smpapi')].{defaultHostName:defaultHostName}" --output tsv
smpapiramirobedoya.azurewebsites.net
Exercise 2: Monitor a local web API by using Application Insights
> dotnet new webapi --output . --name SimpleApi
> dotnet add package Microsoft.ApplicationInsights --version 2.18.0
> dotnet add package Microsoft.ApplicationInsights.AspNetCore --version 2.18.0
> dotnet add package Microsoft.ApplicationInsights.PerfCounterCollector --version 2.18.0
> az webapp deployment source config-zip --resource-group lab11-rg --src api.zip --name smpapiramirobedoya
> dotnet add package Microsoft.Extensions.Logging.ApplicationInsights --version 2.18.0