Run application insights query from powershell module - powershell

With the AZ Cli I can run the following to query application insight instances:
az monitor app-insights query
There doesn't appear to be a direct equivalent in the azure powershell module. I've seen suggestions that you should use the REST API for application insights, but that requires an API key.
I do not have an API key for each of my (many) application insights' and do not want to have to create and store them so I can query application insights - the reason for not being able to use the Az Cli in my script is I want to run my script as a function app and the az cli isn't supported in function apps.
Is there an alternative way to query AI from powershell that I'm missing?

At the moment, Azure PowerShell just provides the module to manage Azure application insight resource. For more details, please refer to here. So if you want to query application insight with PowerShell, we need to use rest API. Besides, if you do not want to access it with API key, you can do that with AD token. For more details, please refer to here
For example
If you want to Azure AD auth to access Azure application insights API, please refer to the following steps
Register Azure AD application in your tenant
Configure API permissions
Create a client secret for the application
Configure assign contributor to the AD application in your subscription
Script
$appKey=""
$appId=""
$resource="https://api5.applicationinsights.io"
$secpasswd = ConvertTo-SecureString $appKey -AsPlainText -Force
$mycreds = New-Object System.Management.Automation.PSCredential ($appId, $secpasswd)
Connect-AzAccount -ServicePrincipal -Tenant "hanxia.onmicrosoft.com" -Credential $mycreds
$res=Get-AzAccessToken -ResourceUrl $resource
$headers=#{"Authorization"="Bearer "+$res.Token}
$body=#{"timespan"="P7D"; "query"="requests| summarize totalCount=sum(itemCount) by bin(timestamp, 30m)"}| ConvertTo-Json
Invoke-RestMethod 'https://api.applicationinsights.io/v1/apps/bd7cacd8-9607-4b53-b57b-995255292f36/query' -Method 'POST' -Headers $headers -Body $body -ContentType "application/json"

Given you have $appInsResourceGroupName and $appInsName pointing to your Application Insights instance.
$component = Get-AzApplicationInsights -ResourceGroupName $appInsResourceGroupName -Name $appInsName
$apiKey = New-AzApplicationInsightsApiKey -ApplicationInsightsComponent $component -Permissions ReadTelemetry -Description "Collector"
$query = "requests | limit 5"
(Invoke-WebRequest -Method POST -Uri https://api.applicationinsights.io/v1/apps/$($component.AppId)/query -ContentType application/json -Body $('{"query":"' + $query + '"}') -Headers #{"X-Api-Key"=$apiKey.ApiKey}).Content
to clean up / remove unused API keys
Get-AzApplicationInsightsApiKey -ApplicationInsightsComponent $component | ?{$_.Description -eq "Collector"} | %{Remove-AzApplicationInsightsApiKey -ApplicationInsightsComponent $component -ApiKeyId $_.Id}
if you're using any domestic clouds you need to account for that; e.g. for China you need to change the URL to api.applicationinsights.azure.cn

Related

Using Managed Identity in a Azure Function to access Graph API

Short version
I want to avoid username/passwords/secrets/key valults/etc. by using Managed Identity, in a PowerShell script, running on Azure Functions.
It seems to fail on:
Import-Module Microsoft.Graph.Authentication
Connect-MgGraph -Scopes 'Reports.Read.All', 'Group.ReadWrite.All'
Background
I have followed Access Microsoft Graph from a secured app as the app, and the setup seems to be fine.
I enable System Identity on the Azure Function and give permission to Microsoft Graph, when I check Enterprise App, permissions seems fine. And I find the managed identity in GraphAggregatorService (00000003-0000-0000-c000-000000000000).
When I debug from VScode, with my identity, the script works perfectly.
When Azure Functions runs the code, the following happens:
WARNING: Interactive authentication is not supported in this session,
falling back to DeviceCode. Future versions will not automatically fallback to DeviceCode.
Then
ERROR: Could not find file 'C:\home\site\wwwroot\.graph'.
Exception : Type : System.IO.FileNotFoundException
Message : Could not find file 'C:\home\site\wwwroot\.graph'.
FileName : C:\home\site\wwwroot\.graph TargetSite :
Name : MoveNext DeclaringType : Microsoft.Graph.PowerShell.Authentication.Cmdlets.ConnectMgGraph+<ProcessRecordAsync>d__52, Microsoft.Graph.Authentication, Version=1.6.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
...<cut>
Line : Connect-MgGraph -Scopes 'Reports.Read.All', 'Group.ReadWrite.All' PositionMessage : At C:\home\site\wwwroot\TestPowerShellTimer\run.ps1:15 char:1 + Connect-MgGraph -Scopes 'Reports.Read.All', 'Group.ReadWrite.All'
...<cut>
Code
# Input bindings are passed in via param block.
param($Timer)
Import-Module Microsoft.Graph.Authentication
Connect-MgGraph -Scopes 'Reports.Read.All', 'Group.ReadWrite.All'
$reportJson = Invoke-GraphRequest -Uri 'https://graph.microsoft.com/beta/reports/credentialUserRegistrationDetails?$top=5000' -Method GET
Why
I could have used Connect-MsOnline (doing the same with msonline), but the code uses uses significantly longer time to complete.
What
I am looping through our users to see if they have set up MFA, and add them to a security group. No, there is no way to do this with azure ad dynamic groups afaik. But if someone has suggestions to other ways of achieving this, feel free to mention it...
My thoughts
Obviously, I am missing something or totally misunderstood something.
The part of the errormsg "C:\home\site\wwwroot.graph", I cannot figure out. Google is not my friend at this point.
I guess I have to, somehow, instruct AzF to use the managed identity:
Import-Module Microsoft.Graph.Authentication
Connect-MgGraph -Scopes -TenantId -ClientId
but I cannot figure out how. I realize that I have ended up with guessing, and then it is time to ask for help.
How to use managed identity in Azure Functions with the Microsoft.Graph.Authentication module?
Since you are using a system identity, which is already connected to Azure, you can generate an access token and pass it down to Connect-MGGraph -AccessToken
Here's a function I made about a year or two ago that serve that exact purpose.
(I needed any authenticated users to be able to gain a token to any azure endpoints based on their currently connected identity without having any other form of credential validation)
function Get-AzToken {
[CmdletBinding()]
param (
[Parameter(Mandatory = $true)]
[String]
$ResourceUri,
[Switch]$AsHeader
)
$Context = [Microsoft.Azure.Commands.Common.Authentication.Abstractions.AzureRmProfileProvider]::Instance.Profile.DefaultContext
$Token = [Microsoft.Azure.Commands.Common.Authentication.AzureSession]::Instance.AuthenticationFactory.Authenticate($context.Account, $context.Environment, $context.Tenant.Id.ToString(), $null, [Microsoft.Azure.Commands.Common.Authentication.ShowDialog]::Never, $null, $ResourceUri).AccessToken
if ($AsHeader) {
return #{Headers = #{Authorization = "Bearer $Token" } }
}
return $Token
}
$Token = Get-AzToken -ResourceUri 'https://graph.microsoft.com/'
Connect-MgGraph -AccessToken $Token
Note that for this to work, in your Azure function profile.ps1, you should have the Connect-AzAccount -Identity line uncommented.
Profile.ps1 snippet
if ($env:MSI_SECRET) {
Disable-AzContextAutosave -Scope Process | Out-Null
Connect-AzAccount -Identity
}
This method will work to obtain token for any of the Azure endpoints, including your own functions, should you enable the Azure AD authentication.
Bonus
Here is how you would use it to call your Azure function if the Azure function is protected by Azure AD authentication.
# This work assuming you connecteded through Connect-AzAccount at some point.
# ResourceUri is the ClientID of your application.
$Headers = Get-AzToken -ResourceUri '3953d051-c61f-43c5-8848-487a921aae31' -AsHeader
$base = 'https://YourFunctionUrl.azurewebsites.net/api'
Invoke-RestMethod -Method Get -Uri "$base/MyApiEndpoint" #Headers
Here is a quicker way to get MS Graph token and Azure AD Graph token. It's 4 lines from below. I provide more to cover all use cases.
# use this line for system managed identity
Connect-AzAccount -Identity
# use this line for user managed identity, specify its AppID as AccountId
Connect-AzAccount -Identity -AccountId <ClientID>
$context = [Microsoft.Azure.Commands.Common.Authentication.Abstractions.AzureRmProfileProvider]::Instance.Profile.DefaultContext
$graphToken = [Microsoft.Azure.Commands.Common.Authentication.AzureSession]::Instance.AuthenticationFactory.Authenticate($context.Account, $context.Environment, $context.Tenant.Id.ToString(), $null, [Microsoft.Azure.Commands.Common.Authentication.ShowDialog]::Never, $null, "https://graph.microsoft.com").AccessToken
$aadToken = [Microsoft.Azure.Commands.Common.Authentication.AzureSession]::Instance.AuthenticationFactory.Authenticate($context.Account, $context.Environment, $context.Tenant.Id.ToString(), $null, [Microsoft.Azure.Commands.Common.Authentication.ShowDialog]::Never, $null, "https://graph.windows.net").AccessToken
Write-Output "Hi I'm $($context.Account.Id)"
# Connect to AAD to use Azure AD Graph
Connect-AzureAD -AadAccessToken $aadToken -AccountId $context.Account.Id -TenantId $context.tenant.id
# To use MS Graph use the below line
Connect-MgGraph -AccessToken $graphToken
Note that Azure AD Graph is retiring on 30 June 2022 and is not recommended anymore. Accordingly you should not use AzureAD commandlets which are based on this SDK.

Check Groupmembership or jobtitle of Logged On User withouth calling azuread (Get-AzureADUserMembership)

I am building a script with a colleague. This script will show a popup.
We want this popup only to be shown to a certain group of users (teachers and not students). So we want to check group membership of a user. Since this script will be installed on the computer locally and we would not like to install azuread cmdlets on all our computers and also not pass azure ad credentials to the script.
So we where wondering if their is azure-ad info about group membership stored on the computers locally. And also if we can acces it via powershell? (if we could get jobtitle of user that would also be helpfull)
Other ideas are also welcome.
The information related user that you are looking for less likely to be stored locally.
So to meet your requirement, you will have to have some means to communicate with the Azure AD. Your requirement was not to make use of any additional libraries and by using PowerShell.
Graph API can come handy.
To prevent user intervention, you can use App only Graph permission for the App.
You can refer this article to know more App registration, client secret & Application permission :
https://learn.microsoft.com/en-us/azure/active-directory/develop/quickstart-register-app
https://learn.microsoft.com/en-us/graph/notifications-integration-app-registration
You consume the graph endpoint from PowerShell and acquire the necessary details of the logged user from the Azure AD without a necessity of external libraries.
#Acquiring the graph token
$web="https://login.microsoftonline.com/<TENANT ID>/oauth2/v2.0/token"
$body = "client_id=<CLIENT ID>&scope=https://graph.microsoft.com/.default&client_secret=<CLIENTSECRET>&grant_type=client_credentials"
$response = Invoke-WebRequest $web -Body $body -Method Post
$token = ($response | ConvertFrom-Json).access_token
#Getting the logged username that will be used in the graph api
$upn = $env:USERNAME + "#" + $env:USERDNSDOMAIN
#building the authorization header
$header = #{"Authorization" = " Bearer $token"}
#gettting the user details
$content = Invoke-WebRequest "https://graph.microsoft.com/v1.0/users/$upn" -Headers $header -Method Get
$details = $content.Content | ConvertFrom-Json
#getting the group membership
$content = Invoke-WebRequest "https://graph.microsoft.com/v1.0/users/$upn/memberof" -Headers $header -Method Get
$groupdetails = ($content.Content | ConvertFrom-Json).value

Authenticate Azure Pipelines Powershell task against Azure DevOps Rest API

Requirements
My requirement is that for my Azure devops release pipeline I want to tag a specific commit with an annotated tag which contains the build number and the date (which is auto-set on an annotated tag).
Proposed solution
My solution to this is to use a the Azure Powershell pipeline task, the one shown here:
The task (ignore what's in the script box right now) will use the Azure Subscription that I have set in order to authenticate towards the Azure DevOps REST API. I have successfully been able to perform the task I want using a personal access token (PAT) but this is not stable long-term for a whole team and I want to use our Azure Subscription.
The problem
My problem is that I'm not sure how to use the authentication of the Azure Subscription correctly. I seem to get some data using Get-AzureRmContext (see current code below) and then I found a GitHub issue which seems to do sort of the same thing. The code gets some kind of OAuth token but using the code below, Azure still returns to me that I need to sign in, so I assume it's not the correct token. I don't understand how things hatch into each other.
Note that my subscription should have all the permissions it needs to do what I want.
Code so far:
Function Get-AccessToken($tenantId) {
$cache = [Microsoft.IdentityModel.Clients.ActiveDirectory.TokenCache]::DefaultShared
$cacheItem = $cache.ReadItems() | Where-Object { $_.TenantId -eq $tenantId } | Select-Object -First 1
return $cacheItem.AccessToken
}
$context = Get-AzureRmContext
$uri = "https://dev.azure.com/<my_org>/<my_area>/_apis/git/repositories/<project_sha>/annotatedtags?api-version=5.0-preview.1"
$token = Get-AccessToken $context.tenantID
$body = #"
{
"taggedObject": {
"objectId": "$(BUILD.SOURCEVERSION)"
},
"name": "D-$(Build.BuildNumber)",
"message": "dummy"
}
"#
$header = #{"Authorization" = "Bearer" + $token}
Invoke-RestMethod -Uri $uri -Method Post -ContentType "application/json" -Body $body -Headers $header
Any help is greatly appreciated!
There is the example for the build tasks: Use a PowerShell script to customize your build pipeline
You have to enable access to token (option Allow Scripts to Access OAuth Token)
Then use it in your script. Script from the example:
$url = "$($env:SYSTEM_TEAMFOUNDATIONCOLLECTIONURI)$env:SYSTEM_TEAMPROJECTID/_apis/build/definitions/$($env:SYSTEM_DEFINITIONID)?api-version=5.0"
Write-Host "URL: $url"
$pipeline = Invoke-RestMethod -Uri $url -Headers #{
Authorization = "Bearer $env:SYSTEM_ACCESSTOKEN"
}
Write-Host "Pipeline = $($pipeline | ConvertTo-Json -Depth 100)"

POSTing data to ServiceNow via Powershell using Invoke-WebRequest

I am trying to POST information into a table in ServiceNow via a Powershell script. When I run it I get an error
Invoke-WebRequest : The remote server returned an error: (500) Internal Server Error.
Can someone help me figure out how to solve this? Thank you all in advance.
$userName = 'helpMe'
$password = 'iAmStuck' | ConvertTo-SecureString -asPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential($userName, $password)
$uri = 'stuff'
$postParams = "test"
#[System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true}
Invoke-WebRequest -Uri $uri -Method Post -Body $postParams -Credential $cred
ServiceNow has a REST API explorer with various code examples to start working with.
Below is an example that I threw together that posts to the incident table with an admin account. Two important factors here, the user must have roles (here for info https://docs.servicenow.com/bundle/istanbul-servicenow-platform/page/integrate/inbound-rest/reference/r_RESTAPIRoles.html) to use the API and must have access to the table you are trying to post to. Also, note that the body of the post needs to be RAW JSON and all the correct header data is supplied in the URL. If successful ServiceNow will return JSON data about the post.
# Eg. User name="admin", Password="admin" for this code sample.
$user = "admin"
$pass = "noPassword"
# Build auth header
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $user, $pass)))
# Set proper headers
$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add('Authorization',('Basic {0}' -f $base64AuthInfo))
$headers.Add('Accept','application/json')
$headers.Add('Content-Type','application/json')
# Specify endpoint uri
$uri = "https://xxxxx.service-now.com/api/now/table/incident"
# Specify HTTP method
$method = "post"
# Specify request body
{request.body ? "$body = \"" :""}}{\"active\":\"true\",\"number\":\"123\",\"short_description\":\"test\"}"
# Send HTTP request
$response = Invoke-WebRequest -Headers $headers -Method $method -Uri $uri -Body $body
# Print response
$response.RawContent
Even though you posted code, you posted nothing relevant to the problem. Whatever ServiceNow is might have an API for reference on what it's expecting. Often when interacting with web-based APIs, there is a structure that is required for the API to be able to understand the data you're supplying in $postParams. Sometimes it can just be key->value pairs in the case of a flat HTTP POST but often times for RESTful APIs you'll need to structure a JSON header as defined by the API documentation.
If you do a search for "servicenow powershell interaction" it looks like there's a GitHub project for interacting with ServiceNow via PowerShell and also a PDF that specifcally covers this topic.

Calling Graph API with powershell or batch

In trying to design a simplified script for use with the office 365 graph API I can't seem to find any way to call it from a simplified outset.
For the use that I have intended for it I really don't want to take the time to build and compile an actual program when everything else can be done from powershell or a batch script.
In specific, I really only want to be able to call the graph API for a list of groups and store the result (in an array or text file). Is it possible to call the graph API from powershell or command line and if so, how?
In specific, I really only want to be able to call the graph API for a list of groups and store the result (in an array or text file).
If you just need to export a list of groups. I suggest you using the Azure Active Directory PowerShell.
$msolcred = get-credential
connect-msolservice -credential $msolcred
Get-MsolGroup | Out-File C:\Workbench\temp\tests\export.txt
Is it possible to call the graph API from powershell or command line and if so, how?
Yes, it is possible, to call the REST API:
First, you need to Obtaining an Access Token
Then, use the Invoke-RestMethod to call Graph API.
Invoke-RestMethod -Uri $uri -Headers #{Authorization = "Bearer {your_access_token}"}
You can use the PSMSGRAPH module for this. Can be download from the gallery
You must register an application in Azure to authenticate and delegate the necessary right to your app. You can do it at the appreg portal
Once this is done you just need to auth and run your request.
When running the code you will have to provide a credential to authorize.
$username = 'entertheappidhere'
$password = 'entertheapppaswordhere' | ConvertTo-SecureString -AsPlainText -Force
$ClientCredential = New-Object -TypeName
System.Management.Automation.PSCredential($username,$password)
$GraphAppParams = #{}
$GraphAppParams.Add('Name','Office365TenantMigration')
$GraphAppParams.Add('ClientCredential',$ClientCredential)
$GraphAppParams.Add('RedirectUri','https://localhost/')
$GraphAppParams.Add('Tenant','yourtenant.onmicrosoft.com')
$GraphApp = New-GraphApplication #GraphAppParams
# This will prompt you to log in with your O365/Azure credentials.
$AuthCode = $GraphApp | Get-GraphOauthAuthorizationCode
$GraphAccessToken = $AuthCode | Get-GraphOauthAccessToken -Resource 'https://graph.microsoft.com/'
$GraphAccessToken | Export-GraphOAuthAccessToken -Path 'f:\O365Report\AccessToken.XML'
$GraphAccessToken = Import-GraphOAuthAccessToken -Path 'f:\O365Report\AccessToken.XML'
$GraphAccessToken | Update-GraphOAuthAccessToken -Force
### Run the query
Invoke-GraphRequest -Uri "https://graph.microsoft.com/v1.0/groups"-Method GET -AccessToken $GraphAccessToken