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

https://docs.microsoft.com/en-us/learn/modules/execute-azure-function-with-triggers/4-create-timer-trigger?pivots=csharp

For Console

https://docs.microsoft.com/en-us/learn/modules/develop-test-deploy-azure-functions-with-core-tools/3-exercise-create-function-core-tools

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

https://docs.microsoft.com/en-us/visualstudio/containers/container-build?WT.mc_id=visualstudio_containers_aka_containerfastmode&view=vs-2022

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

https://microsoftlearning.github.io/AZ-204-DevelopingSolutionsforMicrosoftAzure/Instructions/Labs/AZ-204_lab_06.html

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