Ping/Get Status of Azure Classic Cloud Service with PowerShell script - azure

I'm trying to create a 'GET' method request to see if an old Azure Cloud Service (classic) is available or not - send a request and get the status code to see if its 200 OK or not.
I tried the following code:
function Get-AzCachedAccessToken() {
$AzureContext = Get-AzContext
$CurrentAzureProfile = [Microsoft.Azure.Commands.Common.Authentication.Abstractions.AzureRmProfileProvider]::Instance.Profile;
$CurrentAzureProfileClient = New-Object Microsoft.Azure.Commands.ResourceManager.Common.RMProfileClient($CurrentAzureProfile);
$AzureAccessToken = $CurrentAzureProfileClient.AcquireAccessToken($AzureContext.Tenant.Id).AccessToken;
$AzureAccessToken
}
function Get-AzBearerToken() {
$ErrorActionPreference = 'Stop'
('Bearer {0}' -f (Get-AzCachedAccessToken))
}
$CloudServiceURL = "http://test-myapp.cloudapp.net"
Invoke-RestMethod $CloudServiceURL `
-Headers #{Authorization = (Get-AzBearerToken) } `
-Method Get
The error I get is:
error msg
I'm also using an old Azure module in an automation workflow such as this: PowerShell Workflow Runbook so I could run it.
Is there anyway to restart an Azure classic cloud service role every interval?

Related

Azure Data factory pipeline and dependent triggers

I am trying to list all of my ADF pipelines and their dependent triggers.
As per this article https://learn.microsoft.com/en-us/rest/api/datafactory/triggers/get there is a simple GET method which will list all the triggers with their associated pipelines.
This is working fine when I use a web activity with GET method in ADF pipeline.
I am trying to do the same using powershell. The pipeline name which is visible in ADF output is no longer visible when running via powershell.
Can someone please help me with the code below to identify what needs to be added to fetch the dependent pipeline name for a trigger when this GET method is executed. Any other approach will also be highly appreciated.
Connect-AzAccount -Identity
$azContext = Get-AzContext
$azProfile = [Microsoft.Azure.Commands.Common.Authentication.Abstractions.AzureRmProfileProvider]::Instance.Profile
$profileClient = New-Object -TypeName Microsoft.Azure.Commands.ResourceManager.Common.RMProfileClient -ArgumentList ($azProfile)
$token = $profileClient.AcquireAccessToken($azContext.Subscription.TenantId)
$authHeader = #{
'Content-Type'='application/json'
'Authorization'='Bearer ' + $token.AccessToken
}
$restUri = 'https://management.azure.com/subscriptions/1111111-1111-1111-11111-1111111/resourceGroups/resourceGroupName/providers/Microsoft.DataFactory/factories/DataFactoryName/triggers?api-version=2018-06-01'
$response = Invoke-RestMethod -Method GET -Header $authHeader -URI $restUri
$response | ConvertTo-Json
Powershell Output - Using powershell 5.1 via Azure runbook
"value": [
{
"id": "/subscriptions/1234-1234-1234-1234/resourceGroups/ResourceGroupName/providers/Microsoft.DataFactory/factories/DataFactoryName/triggers/eventbasedtrigger",
"name": "eventbasedtrigger",
"type": "Microsoft.DataFactory/factories/triggers",
"properties": "#{description=Tets Trigger; annotations=System.Object[]; runtimeState=Stopped; pipelines=System.Object[]; type=BlobEventsTrigger; typeProperties=}",
"etag": "000000-0000-0d00-0000-0000000"
},
Cheers
Powershell command Get-AzDataFactoryV2Trigger will provide you the list of triggers for an ADF pipeline / data factory
To get information about all the triggers in ADF:
Get-AzDataFactoryV2Trigger -ResourceGroupName "<RG_NAME>"
-DataFactoryName "<ADF_NAME>"
Get information about a specific trigger
Get-AzDataFactoryV2Trigger -ResourceGroupName "<RG_NAME>" -DataFactoryName "<ADF_NAME>" -TriggerName "<TRIGGER_NAME>"

Azure Data Factory webhook execution times out instead of relaying errors

I've attempted to set up a simple webhook execution in Azure Data Factory (v2), calling a simple (parameter-less) webhook for an Azure Automation Runbook I set up.
From the Azure Portal, I can see that the webhook is being executed and my runbook is being run, so far so good. The runbook is (currently) returning an error within 1 minute of execution - but that's fine, I also want to test failure scenarios.
Problem:
Data Factory doesn't seem to be 'seeing' the error result and spins until the timeout (10 minutes) elapses. When I kick off a debug run of the pipeline, I get the same - a timeout and no error result.
Update: I've fixed the runbook and it's now completing successfully, but Data Factory is still timing out and is not seeing the success response either.
Here is a screenshot of the setup:
And here is the portal confirming that the webhook is being run by azure data factory, and is completing in under a minute:
WEBHOOKDATA JSON is:
{"WebhookName":"Start CAMS VM","RequestBody":"{\r\n \"callBackUri\": \"https://dpeastus.svc.datafactory.azure.com/dataplane/workflow/callback/f7c...df2?callbackUrl=AAEAFF...0927&shouldReportToMonitoring=True&activityType=WebHook\"\r\n}","RequestHeader":{"Connection":"Keep-Alive","Expect":"100-continue","Host":"eab...ddc.webhook.eus2.azure-automation.net","x-ms-request-id":"7b4...2eb"}}
So as far as I can tell, things should be in place to pick up on the result (success of failure). Hopefully someone who's done this before knows what I'm missing.
Thanks!
I had assumed that Azure would automatically notify the ADF "callBackUri" with the result once the runbook completed or errored out (since they take care of 99% of the scaffolding without requiring a line of code).
It turns out that is not the case, and anyone wishing to execute a runbook from ADF will have to manually extract the callBackUri from the Webhookdata input parameter, and POST the result to it when done.
I haven't nailed this down yet, since the Microsoft tutorial sites I've found have a bad habit of taking screenshots of the code that does this rather than providing the code itself:
I guess I'll come back and edit this once I have it figured out.
EDIT I ended up implementing this by leaving my original Webhook untouched, and creating a "wrapper"/helper/utility Runbook that will execute an arbitrary webhook, and relay its status to ADF once it's complete.
Here's the full code I ended up with, in case it helps someone else. It's meant to be generic:
Setup / Helper Functions
param
(
[Parameter (Mandatory = $false)]
[object] $WebhookData
)
Import-Module -Name AzureRM.resources
Import-Module -Name AzureRM.automation
# Helper function for getting the current running Automation Account Job
# Inspired heavily by: https://github.com/azureautomation/runbooks/blob/master/Utility/ARM/Find-WhoAmI
<#
Queries the automation accounts in the subscription to find the automation account, runbook and resource group that the job is running in.
AUTHOR: Azure/OMS Automation Team
#>
Function Find-WhoAmI {
[CmdletBinding()]
Param()
Begin { Write-Verbose ("Entering {0}." -f $MyInvocation.MyCommand) }
Process {
# Authenticate
$ServicePrincipalConnection = Get-AutomationConnection -Name "AzureRunAsConnection"
Add-AzureRmAccount `
-ServicePrincipal `
-TenantId $ServicePrincipalConnection.TenantId `
-ApplicationId $ServicePrincipalConnection.ApplicationId `
-CertificateThumbprint $ServicePrincipalConnection.CertificateThumbprint | Write-Verbose
Select-AzureRmSubscription -SubscriptionId $ServicePrincipalConnection.SubscriptionID | Write-Verbose
# Search all accessible automation accounts for the current job
$AutomationResource = Get-AzureRmResource -ResourceType Microsoft.Automation/AutomationAccounts
$SelfId = $PSPrivateMetadata.JobId.Guid
foreach ($Automation in $AutomationResource) {
$Job = Get-AzureRmAutomationJob -ResourceGroupName $Automation.ResourceGroupName -AutomationAccountName $Automation.Name -Id $SelfId -ErrorAction SilentlyContinue
if (!([string]::IsNullOrEmpty($Job))) {
return $Job
}
Write-Error "Could not find the current running job with id $SelfId"
}
}
End { Write-Verbose ("Exiting {0}." -f $MyInvocation.MyCommand) }
}
Function Get-TimeStamp {
return "[{0:yyyy-MM-dd} {0:HH:mm:ss}]" -f (Get-Date)
}
My Code
### EXPECTED USAGE ###
# 1. Set up a webhook invocation in Azure data factory with a link to this Runbook's webhook
# 2. In ADF - ensure the body contains { "WrappedWebhook": "<your url here>" }
# This should be the URL for another webhook.
# LIMITATIONS:
# - Currently, relaying parameters and authentication credentials is not supported,
# so the wrapped webhook should require no additional authentication or parameters.
# - Currently, the callback to Azure data factory does not support authentication,
# so ensure ADF is configured to require no authentication for its callback URL (the default behaviour)
# If ADF executed this runbook via Webhook, it should have provided a WebhookData with a request body.
if (-Not $WebhookData) {
Write-Error "Runbook was not invoked with WebhookData. Args were: $args"
exit 0
}
if (-Not $WebhookData.RequestBody) {
Write-Error "WebhookData did not contain a ""RequestBody"" property. Data was: $WebhookData"
exit 0
}
$parameters = (ConvertFrom-Json -InputObject $WebhookData.RequestBody)
# And this data should contain a JSON body containing a 'callBackUri' property.
if (-Not $parameters.callBackUri) {
Write-Error 'WebhookData was missing the expected "callBackUri" property (which Azure Data Factory should provide automatically)'
exit 0
}
$callbackuri = $parameters.callBackUri
# Check for the "WRAPPEDWEBHOOK" parameter (which should be set up by the user in ADF)
$WrappedWebhook = $parameters.WRAPPEDWEBHOOK
if (-Not $WrappedWebhook) {
$ErrorMessage = 'WebhookData was missing the expected "WRAPPEDWEBHOOK" peoperty (which the user should have added to the body via ADF)'
Write-Error $ErrorMessage
}
else
{
# Now invoke the actual runbook desired
Write-Output "$(Get-TimeStamp) Invoking Webhook Request at: $WrappedWebhook"
try {
$OutputMessage = Invoke-WebRequest -Uri $WrappedWebhook -UseBasicParsing -Method POST
} catch {
$ErrorMessage = ("An error occurred while executing the wrapped webhook $WrappedWebhook - " + $_.Exception.Message)
Write-Error -Exception $_.Exception
}
# Output should be something like: {"JobIds":["<JobId>"]}
Write-Output "$(Get-TimeStamp) Response: $OutputMessage"
$JobList = (ConvertFrom-Json -InputObject $OutputMessage).JobIds
$JobId = $JobList[0]
$OutputMessage = "JobId: $JobId"
# Get details about the currently running job, and assume the webhook job is being run in the same resourcegroup/account
$Self = Find-WhoAmI
Write-Output "Current Job '$($Self.JobId)' is running in Group '$($Self.ResourceGroupName)' and Automation Account '$($Self.AutomationAccountName)'"
Write-Output "Checking for Job '$($JobId)' in same Group and Automation Account..."
# Monitor the job status, wait for completion.
# Check against a list of statuses that likely indicate an in-progress job
$InProgressStatuses = ('New', 'Queued', 'Activating', 'Starting', 'Running', 'Stopping')
# (from https://learn.microsoft.com/en-us/powershell/module/az.automation/get-azautomationjob?view=azps-4.1.0&viewFallbackFrom=azps-3.7.0)
do {
# 1 second between polling attempts so we don't get throttled
Start-Sleep -Seconds 1
try {
$Job = Get-AzureRmAutomationJob -Id $JobId -ResourceGroupName $Self.ResourceGroupName -AutomationAccountName $Self.AutomationAccountName
} catch {
$ErrorMessage = ("An error occurred polling the job $JobId for completion - " + $_.Exception.Message)
Write-Error -Exception $_.Exception
}
Write-Output "$(Get-TimeStamp) Polled job $JobId - current status: $($Job.Status)"
} while ($InProgressStatuses.Contains($Job.Status))
# Get the job outputs to relay to Azure Data Factory
$Outputs = Get-AzureRmAutomationJobOutput -Id $JobId -Stream "Any" -ResourceGroupName $Self.ResourceGroupName -AutomationAccountName $Self.AutomationAccountName
Write-Output "$(Get-TimeStamp) Outputs from job: $($Outputs | ConvertTo-Json -Compress)"
$OutputMessage = $Outputs.Summary
Write-Output "Summary ouput message: $($OutputMessage)"
}
# Now for the entire purpose of this runbook - relay the response to the callback uri.
# Prepare the success or error response as per specifications at https://learn.microsoft.com/en-us/azure/data-factory/control-flow-webhook-activity#additional-notes
if ($ErrorMessage) {
$OutputJson = #"
{
"output": { "message": "$ErrorMessage" },
"statusCode": 500,
"error": {
"ErrorCode": "Error",
"Message": "$ErrorMessage"
}
}
"#
} else {
$OutputJson = #"
{
"output": { "message": "$OutputMessage" },
"statusCode": 200
}
"#
}
Write-Output "Prepared ADF callback body: $OutputJson"
# Post the response to the callback URL provided
$callbackResponse = Invoke-WebRequest -Uri $callbackuri -UseBasicParsing -Method POST -ContentType "application/json" -Body $OutputJson
Write-Output "Response was relayed to $callbackuri"
Write-Output ("ADF replied with the response: " + ($callbackResponse | ConvertTo-Json -Compress))
At a high-level, steps I've taken are to:
Execute the "main" Webhook - get back a "Job Id"
Get the current running job's "context" (resource group and automation account info) so that I can poll the remote job.
Poll the job until it is complete
Put together either a "success" or "error" response message in the format that Azure Data Factory expects.
Invoke the ADF callback.
For those looking, I created a secondary approach to the above solution - one that executes a Runbook (with parameters) from a Webhook, rather than a invoking a nested Webhook. This has a couple of benefits:
Parameters can be passed through to the Runbook (rather than requiring parameters to be baked-into a new Webhook.
A Runbook from another Azure Automation Account / Resource Group can be invoked.
There's no need to poll the status of the job, since the Start-AzureRmAutomationRunbook commandlet has a -Wait parameter.
Here's the code:
param
(
# Note: While "WebhookData" is the only root-level parameter (set by Azure Data Factory when it invokes this webhook)
# The user should ensure they provide (via the ADF request body) these additional properties required to invoke the runbook:
# - RunbookName
# - ResourceGroupName (TODO: Can fill this in by default if not provided)
# - AutomationAccountName (TODO: Can fill this in by default if not provided)
# - Parameters (A nested dict containing parameters to forward along)
[Parameter (Mandatory = $false)]
[object] $WebhookData
)
Import-Module -Name AzureRM.resources
Import-Module -Name AzureRM.automation
Function Get-TimeStamp {
return "[{0:yyyy-MM-dd} {0:HH:mm:ss}]" -f (Get-Date)
}
# If ADF executed this runbook via Webhook, it should have provided a WebhookData with a request body.
if (-Not $WebhookData) {
Write-Error "Runbook was not invoked with WebhookData. Args were: $args"
exit 0
}
if (-Not $WebhookData.RequestBody) {
Write-Error "WebhookData did not contain a ""RequestBody"" property. Data was: $WebhookData"
exit 0
}
$parameters = (ConvertFrom-Json -InputObject $WebhookData.RequestBody)
# And this data should contain a JSON body containing a 'callBackUri' property.
if (-Not $parameters.callBackUri) {
Write-Error 'WebhookData was missing the expected "callBackUri" property (which Azure Data Factory should provide automatically)'
exit 0
}
$callbackuri = $parameters.callBackUri
# Check for required parameters, and output any errors.
$ErrorMessage = ''
$RunbookName = $parameters.RunbookName
$ResourceGroupName = $parameters.ResourceGroupName
$AutomationAccountName = $parameters.AutomationAccountName
if (-Not $RunbookName) {
$ErrorMessage += 'WebhookData was missing the expected "RunbookName" property (which the user should have added to the body via ADF)`n'
} if (-Not $ResourceGroupName) {
$ErrorMessage += 'WebhookData was missing the expected "ResourceGroupName" property (which the user should have added to the body via ADF)`n'
} if (-Not $AutomationAccountName) {
$ErrorMessage += 'WebhookData was missing the expected "AutomationAccountName" property (which the user should have added to the body via ADF)`n'
} if ($ErrorMessage) {
Write-Error $ErrorMessage
} else {
# Set the current automation connection's authenticated account to use for future Azure Resource Manager cmdlet requests.
# TODO: Provide the user with a way to override this if the target runbook doesn't support the AzureRunAsConnection
$ServicePrincipalConnection = Get-AutomationConnection -Name "AzureRunAsConnection"
Add-AzureRmAccount -ServicePrincipal `
-TenantId $ServicePrincipalConnection.TenantId `
-ApplicationId $ServicePrincipalConnection.ApplicationId `
-CertificateThumbprint $ServicePrincipalConnection.CertificateThumbprint | Write-Verbose
Select-AzureRmSubscription -SubscriptionId $ServicePrincipalConnection.SubscriptionID | Write-Verbose
# Prepare the properties to pass on to the next runbook - all provided properties exept the ones specific to the ADF passthrough invocation
$RunbookParams = #{ }
if($parameters.parameters) {
$parameters.parameters.PSObject.Properties | Foreach { $RunbookParams[$_.Name] = $_.Value }
Write-Output "The following parameters will be forwarded to the runbook: $($RunbookParams | ConvertTo-Json -Compress)"
}
# Now invoke the actual runbook desired, and wait for it to complete
Write-Output "$(Get-TimeStamp) Invoking Runbook '$($RunbookName)' from Group '$($ResourceGroupName)' and Automation Account '$($AutomationAccountName)'"
try {
# Runbooks have this nice flag that let you wait on their completion (unlike webhook-invoked)
$Result = Start-AzureRmAutomationRunbook -Wait -Name $RunbookName -AutomationAccountName $AutomationAccountName -ResourceGroupName $ResourceGroupName –Parameters $RunbookParams
} catch {
$ErrorMessage = ("An error occurred while invoking Start-AzAutomationRunbook - " + $_.Exception.Message)
Write-Error -Exception $_.Exception
}
# Digest the result to be relayed to ADF
if($Result) {
Write-Output "$(Get-TimeStamp) Response: $($Result | ConvertTo-Json -Compress)"
$OutputMessage = $Result.ToString()
} elseif(-Not $ErrorMessage) {
$OutputMessage = "The runbook completed without errors, but the result was null."
}
}
# Now for the entire purpose of this runbook - relay the response to the callback uri.
# Prepare the success or error response as per specifications at https://learn.microsoft.com/en-us/azure/data-factory/control-flow-webhook-activity#additional-notes
if ($ErrorMessage) {
$OutputJson = #{
output = #{ message = $ErrorMessage }
statusCode = 500
error = #{
ErrorCode = "Error"
Message = $ErrorMessage
}
} | ConvertTo-Json -depth 2
} else {
$OutputJson = #{
output = #{ message = $OutputMessage }
statusCode = 200
} | ConvertTo-Json -depth 2
}
Write-Output "Prepared ADF callback body: $OutputJson"
# Post the response to the callback URL provided
$callbackResponse = Invoke-WebRequest -Uri $callbackuri -UseBasicParsing -Method POST -ContentType "application/json" -Body $OutputJson
Write-Output "Response was relayed to $callbackuri"
Write-Output ("ADF replied with the response: " + ($callbackResponse | ConvertTo-Json -Compress))

Is it possible to update URL is availability test in application insights through powershell on a schedule task/frequency

I have a number of environments in azure which utilize on-premise Restful services for one of our customers. We currently have application insights configured within a resource group, and an availability test configured to ping a URL at a specified frequency, configured with an insights alert (email when goes down)
An access token is embedded into the URL which needs to be updated frequently. Is it possible to update the URL highlighted programmatically to replace the token (Scheduled/automated basis )
Just wondering what technologies could be used to update an availability URL on a scheduled basis (every two weeks)
Azure functions?
Some sort of PowerShell script as a scheduled task?
ARM templates using the example here https://learn.microsoft.com/en-us/azure/azure-monitor/app/powershell#add-an-availability-test
Any advice on how to proceed with this task efficiently and using the most appropriate technologies would be appreciated.
I have to say seems there is no PowerShell module provided to modify the url of App Insight webtest , but we can do it via REST API . Try the PowerShell below :
$clientId = "<your Azure AD application ID>"
$clientSec="<your Azure AD application secret>"
$appInsightName ="<your app insight name>"
$webtestName="<your webtest name>"
$subscriptionId = "<your subscription ID>"
$resourceGroupName = "<your resource group name that your app insight in>"
$tenant = "<your tenant name/ID>"
$newUrl = "<the new URL>"
#get access token to fetch details of webtest
$body=#{
    "grant_type"="client_credentials";
    "resource"="https://management.azure.com/";
    "client_id"= $clientId;
    "client_secret" = $clientSec
}
$accessToken=(Invoke-RestMethod -Uri "https://login.windows.net/$tenant/oauth2/token" -Method POST -Body $body ).access_token
$uri = "https://management.azure.com/subscriptions/{0}/resourcegroups/{1}/providers/microsoft.insights/webtests/{2}-{3}?api-version=2015-05-01"
$uri = $uri.Replace("{0}",$subscriptionId).Replace("{1}",$resourceGroupName).Replace("{2}",$webtestName).Replace("{3}",$appInsightName)
$webtestResult = Invoke-RestMethod -Uri $uri -Method GET -Headers #{"Authorization"="Bearer $accessToken"}
#modify the url of webtest
$webTestConf = [xml]#($webtestResult.properties.Configuration.WebTest)
$webTestConf.WebTest.Items.Request.Url = $newUrl
#structure request json to update webtest
$locations = $webtestResult.properties.Locations | ConvertTo-Json
$Configuration = $webTestConf.WebTest.OuterXml | ConvertTo-Json
$Configuration = $Configuration.Replace("\u003c","<").replace("\u003e",">")
$location = $webtestResult.location
$tags = $webtestResult.tags| ConvertTo-Json
$name = $webtestResult.properties.Name
$kind = $webtestResult.properties.Kind
$json = #"
{
"location":"$location",
"tags":$tags,
"properties":{
"Name":"$name",
"Enabled": true,
"Frequency": 300,
"Timeout": 120,
"Locations":$locations,
"Configuration":{"webtest":$Configuration},
"Kind":"$kind"
}
}
"#
Invoke-RestMethod -Uri $uri -Method PUT -Body $json -Headers #{"Authorization"="Bearer $accessToken";"Content-Type"="application/json"}
Except for Azure function, you can use Azure automation powershell Runbook with scheduled task to meet your requirement .
Btw, this powershell demo uses service principle to connect to your Azure subscription, make sure your Azure ad application has permission to modify your app insight. If you have anything unclear , pls feel free to let me know . This issue shall not be passed !

Azure Activity Log

I want to monitor who made a change in rbac assignment, I created powershell script for collection data from Azure Activity Log. I used below piece of code. Using this solution I am able to get items like:
caller - user who made a role assignment change,
timestamp,
Resource name - on this resource assignment change has been provided,
action type - write or delete
In Activity Log panel in Azure portal, in Summary portal (Message: shared with "user info"), I can see name of a user who has been granted permissions/assignment to the resource, but using my powershell script I am not able to catch this information, is there any method to get this info?
Get-AzureRmLog -StartTime (Get-Date).AddDays(-7) |
Where-Object {$_.Authorization.Action -like
'Microsoft.Authorization/roleAssignments/*'} |
Select-Object #{N="Caller";E={$_.Caller}},
#{N="Resource";E={$_.Authorization.Scope}},
#{N="Action";E={Split-Path $_.Authorization.action -leaf}},
EventTimestamp
script output:
Caller : username#xxx.com
Resource :/subscriptions/xxxx/resourceGroups/Powershell/providers/Microsoft.Compute/virtualMachines/xx/providers/Microsoft.Authorization/roleAssignments/xxxx
Action : write
EventTimestamp : 8/29/2019 10:12:31 AM
Your requirement of fetching the user name to whom the RBAC role is assigned is currently not supported using Az PowerShell cmdlet Get-AzLog or Get-AzureRmLog.
However, we can accomplish your requirement by leveraging Azure REST API for Activity Logs - List and Az PowerShell cmdlet Get-AzureADUser.
In this way as we are depending on Azure REST API for Activity Logs - List (but looks like you want PowerShell way of accomplishing the requirement) so call the REST API in PowerShell as something shown below.
$request = "https://management.azure.com/subscriptions/{subscriptionId}/providers/microsoft.insights/eventtypes/management/values?api-version=2015-04-01&`$filter={$filter}"
$auth = "eyxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
$authHeader = #{
'Content-Type'='application/json'
'Accept'='application/json'
'Authorization'= "Bearer $auth"
}
$Output = Invoke-RestMethod -Uri $request -Headers $authHeader -Method GET -Body $Body
$ActivityLogsFinalOutput = $Output.Value
Develop your PowerShell code to get "PrincipalId" (which is under "properties") from the output of your Azure REST API for Activity Logs - List call. The fetched "PrincipalId" is the ObjectID of the user whom you want to get ultimately.
Now leverage Az PowerShell cmdlet Get-AzureADUser and have your command something like shown below.
(Get-AzureADUser -ObjectID "<PrincipalID>").DisplayName
Hope this helps!! Cheers!!
UPDATE:
Please find PowerShell way of fetching auth token (i.e., $auth) that needs to be used in above REST API call.
$ClientID = "<ClientID>" #ApplicationID
$ClientSecret = "<ClientSecret>" #key from Application
$tennantid = "<TennantID>"
$TokenEndpoint = {https://login.windows.net/{0}/oauth2/token} -f $tennantid
$ARMResource = "https://management.core.windows.net/";
$Body1 = #{
'resource'= $ARMResource
'client_id' = $ClientID
'grant_type' = 'client_credentials'
'client_secret' = $ClientSecret
}
$params = #{
ContentType = 'application/x-www-form-urlencoded'
Headers = #{'accept'='application/json'}
Body = $Body1
Method = 'Post'
URI = $TokenEndpoint
}
$token = Invoke-RestMethod #params
$token | select access_token, #{L='Expires';E={[timezone]::CurrentTimeZone.ToLocalTime(([datetime]'1/1/1970').AddSeconds($_.expires_on))}} | fl *
I see this new way as well but I didn't get chance to test this out. If interested, you may alternatively try this or go with above approach.
UPDATE2:
$ActivityLogsFinalOutput| %{
if(($_.properties.responseBody) -like "*principalId*"){
$SplittedPrincipalID = $_.properties.responseBody -split "PrincipalID"
$SplittedComma = $SplittedPrincipalID[1] -split ","
$SplittedDoubleQuote = $SplittedComma[0] -split "`""
$PrincipalID = $SplittedDoubleQuote[2]
#Continue code for getting Azure AD User using above fetched $PrincipalID
#...
#...
}
}
Does this work for you?
Get-AzureRmLog -StartTime (Get-Date).AddDays(-7) |
Where-Object {$_.Authorization.Action -like 'Microsoft.Authorization/roleAssignments/*'} |
Select-Object #{N="Caller";E={$_.Caller}},
#{N="Resource";E={$_.Authorization.Scope}},
#{N="Action";E={Split-Path $_.Authorization.action -leaf}},
#{N="Name";E={$_.Claims.Content.name}},
EventTimestamp
My output:
Caller : username#domain.com
Resource : /subscriptions/xxxx/resourceGroups/xxxx/providers/Microsoft.Authorization/roleAssignments/xxxx
Action : write
Name : John Doe
EventTimestamp : 30.08.2019 12.05.52
NB: I used Get-AzLog. Not sure if there is any difference between Get-AzLog and Get-AzureRmLog.
Fairly certain this wouldn't be exposed with this cmdlet. I dont even see this information in the Role Assignments. So not sure what do you mean exactly.

In Azure, how can you configure an alert or notification when a SQL Server failover happened?

In Azure, how can you configure an alert or notification when a SQL Server failover happened if you setup a SQL server with Failover groups and failover policy is set to automatic? If it can't be setup in Monitor can it be scripted elsewhere?
Found a way to script this in Azure using Automation Accounts > Runbook > using Powershell. A simple script like this should do it. Just need to figure out the run as account and trigger it by schedule or alert.
function sendEmailAlert
{
# Send email
}
function checkFailover
{
$list = Get-AzSqlDatabaseFailoverGroup -ResourceGroupName "my-resourceGroup" -server "my-sql-server"
if ( $list.ReplicationRole -ne 'Primary')
{
sendEmailAlert
}
}
checkFailover
Azure SQL database only support these alert metrics:
We could not using the alert when SQL Server failure happened. You can get this from this document: Create alerts for Azure SQL Database and Data Warehouse using Azure portal.
Hope this helps.
Thanks CKelly - gave me a good kick start to something that should be standard in Azure. I created an Azure Automation Account, added the Az.Account, Az.Automation and Az.Sql modules then added a bit more to your code. In Azure I created a SendGrid account.
#use the Azure Account Automation details to login to Azure
$Conn = Get-AutomationConnection -Name AzureRunAsConnection
Connect-AzAccount -ServicePrincipal -Tenant $Conn.TenantID -ApplicationId $Conn.ApplicationID -CertificateThumbprint $Conn.CertificateThumbprint
#create email alert
function sendEmailAlert
{
# Send email
$From = "<email from>"
$To = "<email of stakeholders to receive this message>"
$SMTPServer = "smtp.sendgrid.net"
$SMTPPort = "587"
$Username = "<sendgrid username>"
$Password = "<sendgridpassword>"
$subject = "<email subject>"
$body = "<text to go in email body>"
$smtp = New-Object System.Net.Mail.SmtpClient($SMTPServer, $SMTPPort)
$smtp.EnableSSL = $true
$smtp.Credentials = New-Object System.Net.NetworkCredential($Username, $Password)
$smtp.Send($From, $To, $subject, $body)
}
#create failover check and send if the primary server has changed
function checkFailover
{
$list = Get-AzSqlDatabaseFailoverGroup -ResourceGroupName "<the resourcegroup>" -server "<SQl Databse server>"
if ( $list.ReplicationRole -ne 'Primary')
{
sendEmailAlert
}
}
checkFailover
This process may help others.

Resources