PowerShell - Concatenate Two HTML Tables

46 Views Asked by At

I have to stop the app services and start them with 3 mins delay in between. This status has to be captured in mail. Below is the code.

#Connect to Azure Account
Connect-AzAccount -Identity -AccountID '1234'

#Get subscription ID
$subscriptionID = (Get-AzSubscription).Id

#Get resource group
$resourceGroup = (Get-AzResourceGroup).ResourceGroupName

#Get env from resource group
$env = $resourceGroup -split '-'
$env = $env[-1].ToUpper()

#Get current time in EST
$currentTime = Get-Date
$currentTimeEST = [System.TimeZoneInfo]::ConvertTimeBySystemTimeZoneId((Get-Date -Date $currentTime), 'Eastern Standard Time')

#Mail parameters
$destEmailAddress = "ABC"
$fromEmailAddress = "XYZ"
$subjectLine = "Restart Status [Env: $env]"
$ccEmailAddress1 = ""
$ccEmailAddress2 = ""
$ccEmailAddress3 = ""
$bccEmailAddress = ""

# Initialize an empty string to store the email body as HTML
$emailBody = "<html><head><style>table { border-collapse: collapse; } th, td { border: 1px solid black; padding: 8px; }</style></head><body>"
$emailBody += "<p><b>Dear Team,</b><br><br><b>Below is the status of function and web app(s) restart as of $currentTimeEST (EST).</b></p>"
$emailBody += "<table><tr><th>App Name</th><th>Stop Time</th><th>Stop Status</th><th>Start Time</th><th>Start Status</th></tr>"


# Get all function and web apps in the resource group
$appNames = Get-AzWebApp -ResourceGroupName $resourceGroup | where-object {$_.State -eq "Running"}

# Restart each Function/Web App
foreach ($appName in $appNames) {
    try{
        $appName = $appName.Name
        Write-Output "Stopping App: $appName."
        $stopTime = Get-Date
        $stopTime = [System.TimeZoneInfo]::ConvertTimeBySystemTimeZoneId((Get-Date -Date $stopTime), 'Eastern Standard Time')
        Stop-AzWebApp -Name $appName -ResourceGroupName $resourceGroup
        Write-Output "$appName is stopped."
        $stopStatus = (Get-AzWebApp -ResourceGroupName $resourceGroup -Name $appName).State

        Write-Output "Starting App: $appName."
        $startTime = Get-Date
        $startTime = [System.TimeZoneInfo]::ConvertTimeBySystemTimeZoneId((Get-Date -Date $startTime), 'Eastern Standard Time')
        Start-AzWebApp -Name $appName -ResourceGroupName $resourceGroup 
        Write-Output "$appName is started."
        $startStatus = (Get-AzWebApp -ResourceGroupName $resourceGroup -Name $appName).State

        # Append information to email body
        $emailBody += "<tr><td>$appName</td><td>$stopTime</td><td>$stopStatus</td><td>$startTime</td><td>$startStatus</td></tr>"
    }catch{
        Write-Host "An error occurred: $_.Exception.Message"
    }
    
}

# Final email body
$emailBody += "</table><p><b>Thanks,<br/>ABC</b></p></body></html>"

# Pass parameters to another runbook
$runbookParams = @{
    destEmailAddress = $destEmailAddress
    fromEmailAddress = $fromEmailAddress
    ccEmailAddress1 = $ccEmailAddress1
    ccEmailAddress2 = $ccEmailAddress2
    ccEmailAddress3 = $ccEmailAddress3
    bccEmailAddress = $bccEmailAddress
    subject = $subjectLine
    content = $emailBody
}


Start-AzAutomationRunbook -AutomationAccountName "automationacc" -Name "send-sendgrid-email-parameter" -ResourceGroupName $resourceGroup -Parameters $runbookParams

Requirement: I have to stop all the function apps at once, wait for 3 minutes and then start all the function apps. I believe the for loop should be split into 2 loops (one for stop and one for start) and in between we use a Start-sleep. But for the email content, how do I capture all this status in one table. It should be like below.

enter image description here

1

There are 1 best solutions below

0
Theo On

If you really want to split the restart loop in two, you could try this (untested)

# Connect to Azure Account
Connect-AzAccount -Identity -AccountID '1234'

# Get subscription ID
$subscriptionID = (Get-AzSubscription).Id
# Get resource group
$resourceGroup = (Get-AzResourceGroup).ResourceGroupName
# Get env from resource group
# changed '$env' into '$rgEnv' to not confuse with PowerShell $env: variables
$rgEnv = ($resourceGroup -split '-')[-1].ToUpper()
# Get current time in EST
$currentTimeEST = [System.TimeZoneInfo]::ConvertTimeBySystemTimeZoneId((Get-Date), 'Eastern Standard Time')

# Mail parameters
$destEmailAddress = "ABC"
$fromEmailAddress = "XYZ"
$subjectLine      = "Restart Status [Env: $rgEnv]"
$ccEmailAddress1  = ""
$ccEmailAddress2  = ""
$ccEmailAddress3  = ""
$bccEmailAddress  = ""


# Initialize a template here-string to store the email body as HTML
$emailBody = @"
<html><head>
<style>
    table { border-collapse: collapse; } 
    th, td { border: 1px solid black; padding: 8px; }
</style>
</head><body>
<p><b>Dear Team,</b><br><br><b>Below is the status of function and web app(s) restart as of $currentTimeEST (EST).</b></p>
<table><tr><th>App Name</th><th>Stop Time</th><th>Stop Status</th><th>Start Time</th><th>Start Status</th></tr>
{0}
</table><p><b>Thanks,<br/>ABC</b></p></body></html>
"@



# Get all function and web apps in the resource group
$appNames = Get-AzWebApp -ResourceGroupName $resourceGroup | Where-Object {$_.State -eq "Running"}

# capture the current ErrorActionPreference value and set it to Stop for the next two loops
$oldErrorPref = $ErrorActionPreference
$ErrorActionPreference = 'Stop'

# 1st loop to stop each Function/Web App
$appsData = foreach ($appName in $appNames.Name) {
    try{
        Write-Host "Stopping App: $appName."
        $stopTime = [System.TimeZoneInfo]::ConvertTimeBySystemTimeZoneId((Get-Date), 'Eastern Standard Time')
        Stop-AzWebApp -Name $appName -ResourceGroupName $resourceGroup
        Write-Host "$appName is stopped."
        $stopStatus = (Get-AzWebApp -ResourceGroupName $resourceGroup -Name $appName).State
        # output an object with properties you want to use in the email body
        [PsCustomObject]@{
            AppName     = $appName
            StopTime    = $stopTime
            StopStatus  = $stopStatus
        }
    }
    catch{
        Write-Host "An error occurred: $_.Exception.Message"
    }
}

# do your other stuff here and after the 3 minute wait enter this next loop
Start-Sleep -Seconds 180  # demo 3 minute wait


# this 2nd loop starts the apps and outputs HTML formatted rows
$tblRows = $appsData | ForEach-Object {
    # for convenience
    $appName = $_.AppName
    Write-Host "Starting App: $appName."
    $startTime = Get-Date
    $startTime = [System.TimeZoneInfo]::ConvertTimeBySystemTimeZoneId((Get-Date -Date $startTime), 'Eastern Standard Time')
    Start-AzWebApp -Name $appName -ResourceGroupName $resourceGroup 
    Write-Host "$appName is started."
    $startStatus = (Get-AzWebApp -ResourceGroupName $resourceGroup -Name $appName).State
    # next, output a <tr>..</tr> data row to be collected in variable $tblRows
    '<tr><td>{0}</td><td>{1}</td><td>{2}</td><td>{3}</td><td>{4}</td></tr>' -f $appName, 
                                                                               $_.StopTime, 
                                                                               $_.StopStatus, 
                                                                               $startTime, 
                                                                               $startStatus
}

# restore the ErrorActionPreference
$ErrorActionPreference = $oldErrorPref

# Pass parameters to another runbook
$runbookParams = @{
    destEmailAddress = $destEmailAddress
    fromEmailAddress = $fromEmailAddress
    ccEmailAddress1  = $ccEmailAddress1
    ccEmailAddress2  = $ccEmailAddress2
    ccEmailAddress3  = $ccEmailAddress3
    bccEmailAddress  = $bccEmailAddress
    subject          = $subjectLine
    content          = $emailBody -f ($tblRows -join "`r`n")
}

Start-AzAutomationRunbook -AutomationAccountName "automationacc" -Name "send-sendgrid-email-parameter" -ResourceGroupName $resourceGroup -Parameters $runbookParams