PowerShell Azure Functions $TriggerMetadata Methode is GET but shoud be POST - azure

I'm new to Azure Functions, so it might be something obvious.
Here's what it is:
I have a Powershell Azure Functions HTTP Trigger Function with Pode, which has a GET and a POST route. Now when I send a POST request via Postman, Invoke-WebRequest or any other tool except Azure Test Tool, I end up in the GET route.
My debugging revealed that $TriggerMetadata contains '"Method": "GET"' in these cases. '"Method": "POST"' only when the request comes from Azure Test Tool itself.
I am faced with a riddle. I hope someone can help me.
My Code:
param($Request, $TriggerMetadata)
$endpoint = '/api/Object'
Write-Host "$endpoint - PowerShell HTTP trigger function processed a request."
Start-PodeServer -Request $TriggerMetadata -ServerlessType AzureFunctions {
# get route that can return data
Add-PodeRoute -Method Get -Path $endpoint -ScriptBlock {
Write-Host "$endpoint - Get"
#doing stuff
}
# post route to create some data
Add-PodeRoute -Method Post -Path $endpoint -ScriptBlock {
Write-Host "$endpoint - Post"
#doing stuff
}
}
My function.json:
{
"bindings": [
{
"authLevel": "function",
"type": "httpTrigger",
"direction": "in",
"name": "Request",
"methods": [
"get",
"post"
]
},
{
"type": "http",
"direction": "out",
"name": "Response"
}
]
}

I am very sorry, especially since this is very unsatisfactory, but the problem no longer exists.
I strongly suspect that it was a bug in Azure, since I did not change anything and everything is working again.
Time to check the Azure Functions SLA I guesse.

Related

How to update 'Default agent pool for YAML' for a pipeline in Azure Devops using Rest API?

I have tried to use the definition update api to try to update the 'Default agent pool for YAML' but no success. I kept receiving '200' response status code but the setting stay the same.
I have also tried to capture the actual request content when perform the update manually via UI, then pretty much copied the same content into the Body of the request but the result stayed the same.
Below is a sample of the request that I'm using:
Invoke-WebRequest -URI "https://dev.azure.com/***/***/_apis/build/definitions/***?api-version=6.1-preview.7" -Method PUT -ContentType "application/json" -Headers #{ Authorization = "Basic ***" } -Body '{***}'
The body is in the JSON format of:
{
...
"queue": {
"id": 882,
"name": "Azure Pipelines",
"pool": {
"id": 17,
"name": "Azure Pipelines",
"isHosted": true
}
},
...
}
Update
As suggested by the Microsoft team, the feature is not supported. I have logged a suggestion for the feature here.
This looks to be enabled now, but through a different set of properties. You can set the default pool through the following property:
process.phases.target.agentSpecification.identifier
The relevant snippet looks like this:
"process": {
"phases": [
{
"name": "NameGoesHere",
"target": {
"agentSpecification": {
"identifier": "windows-latest"
}
}
}
]
}
As fair warning: I found that if I had the wrong revision number in my payload, the API will respond with a 200, but the pool won't change. This was especially noteworthy when I was trying to reset the pool through the UI to prove that the API call worked. Essentially, it's probably a good idea to do a GET, modify that payload, and send that to the PUT without any other actions in between.

how to create an azure function key in ARM template?

I have been struggling with this one all day, I am trying to create a Function App function key from an ARM template.
So far I have been able to create my function key on the Host level using the following template:
{
"type": "Microsoft.Web/sites/host/functionKeys",
"apiVersion": "2018-11-01",
"name": "[concat(parameters('appServiceName'), '/default/PortalFunctionKey')]",
"properties": {
"name": "PortalFunctionKey"
}
then I found a couple of articles and link showing it is possible via API:
https://github.com/Azure/azure-functions-host/wiki/Key-management-API
And I was able to generate it via this API posting to:
https://{myfunctionapp}.azurewebsites.net/admin/functions/{MyFunctionName}/keys/{NewKeyName}?code={_masterKey}
But I can't for the sake of me figure out how to do that in my ARM template!
I have tried various combinations of type and name, for example:
{
"type": "Microsoft.Web/sites/host/functionKeys",
"apiVersion": "2018-11-01",
"name": "[concat(parameters('appServiceName'), '/{myfunctionName}/PortalFunctionKey')]",
"properties": {
"name": "PortalFunctionKey"
}
or /functions/{myfunctionName}/PortalFunctionKey
as suggested in some articles, and i just can't get any to work, can't find much documentation on ARM Microsoft.Web/sites/host/functionKeys either.
Did anyone succeed to create a FUNCTION key (not host) in ARM template? I would gladly hear how you got there :)!
Basically:
Many thanks in advance,
Emmanuel
This might solve the problem now: https://learn.microsoft.com/en-us/azure/templates/microsoft.web/2020-06-01/sites/functions/keys
I was able to create a function key by passing an ARM template resource that looked like this:
{
"type": "Microsoft.Web/sites/functions/keys",
"apiVersion": "2020-06-01",
"name": "{Site Name}/{Function App Name}/{Key Name}",
"properties": {
"value": "(optional)-key-value-can-be-passed-here"
}
}
It seems that even if you don't have 'value' in the properties, then you have to at least pass an empty properties object.
To solve this problem , you could refer to this github issue. First issue and second issue, these issues all have the problem about how to get the function key in the ARM template.
For now the sample to get the key value as the below shows:
"properties": {
"contentType": "text/plain",
"value": "[listkeys(concat(variables('functionAppId'), '/host/default/'),'2016-08-01').functionKeys.default]"
}
or with below to get the key object.
"functionkeys": {
"type": "object",
"value": "[listkeys(concat(variables('functionAppId'), '/host/default'), '2018-11-01')]" }
}
You could have a try, hope this could help you.
So it is not possible to create a Function level Function key in ARM template at the moment.
I therefore created a feature request you can vote on if you are interested in it:
https://feedback.azure.com/forums/169385-web-apps/suggestions/39789043-create-function-level-keys-for-azure-functions-in
For now though, we are creating function level function keys via a powershell deployment task step. here is how.
add output parameter to your ARM template:
"outputs": {
"masterKey": {
"type": "string",
"value": "[listkeys(concat(resourceId(resourceGroup().name, 'Microsoft.Web/sites', parameters('appServiceName')), '/host/default'), '2018-11-01').masterKey]"
},
"appServiceName": {
"type": "string",
"value": "[parameters('appServiceName')]"
},
"functionKeys": {
"type": "array",
"value": [
{
"functionName": "myFunctionName",
"keys": [ "FunctionKeyName1", "FunctionKeyName2" ]
}
]
}
}
Add the following PS script file to your deploy project:
param (
[Parameter(Mandatory=$true)]
[string]
$armOutputString
)
Write-Host $armOutputString
$armOutputObj = $armOutputString | convertfrom-json
Write-Host $armOutputObj
$masterKey = $armOutputObj.masterKey.value
$appServiceName = $armOutputObj.appServiceName.value
$httpHeaders = #{
"x-functions-key" = $masterKey
}
$contentType = "application/json; charset=utf-8"
foreach($function in $armOutputObj.functionKeys.value){
$retryCount = 5;
while ($true) {
try {
$uriBase = "https://$($appServiceName).azurewebsites.net/admin/functions/$($function.functionName)/keys"
$existingKeys = Invoke-RestMethod -Method Get -Uri $uriBase -Headers $httpHeaders -ContentType $contentType
break;
}
catch {
if ($_.Exception.Response.StatusCode.value__ -eq 502) {
if ($retryCount-- -eq 0) {
throw;
}
else {
Write-Output ("Retry" + ": " + $_.Exception.Response.StatusCode + "; attempts=$retryCount")
[System.Threading.Thread]::Sleep(1000);
continue;
}
}
else {
throw;
}
}
}
foreach ($keyname in $function.keys){
$keyExists = 0
foreach($exstingKey in $existingKeys.keys){
if($exstingKey.name -eq $keyname){
$keyExists = 1
Write-Host "key $($keyname) already exists"
}
}
if($keyExists -eq 0){
$uri = "$($uriBase)/$($keyname)?code=$($masterKey)";
Write-Host "Adding $($keyname) key"
Invoke-RestMethod -Method Post -Uri "$($uriBase)/$($keyname)" -Headers $httpHeaders -ContentType $contentType;
}
}
}
The script ensures that the key will not be overwritten if it already exists, and will retry if it fails (the function MUST exist and be running for the API to work).
In your "Azure resource group deployment" task, under "Advanced" set "Deployment outputs" to "armDeployOutput".
Add a Powershell task, your script path to the powershell file in your deploy project, and set "Arguments" as "-armOutputString '$(armDeployOutput)'".
And that's it.

Azure Create Alert via API

Creating Alert via API in Azure.
Alert does get created but the Event Category field is showing as all instead of Administrative.
Alert i want to create is for Administrative Event Category but it is getting created for all Event Category.
I had used the same code earlier and it was working.
Azure Alert ScreenShot
If i try to update anything via GUI it gives an error: Failed to update alert 'Testing'.The category field is missing in the condition..
Error ScreenShot
PowerShell
Body to create Alert
$Remediate = #" {
"id": "/subscriptions/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/resourceGroups/xxxxxxxxxxxxxxx/providers/microsoft.insights/activityLogAlerts/Testing",
"type": "Microsoft.Insights/ActivityLogAlerts",
"name": "Testing",
"location": "Global",
"kind": null,
"tags": {},
"properties": {
"scopes": ["/subscriptions/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"],
"condition": {
"allOf": [{
"field": "Category",
"equals": "Administrative",
"containsAny": null
}, {
"field": "operationName",
"equals": "Microsoft.Authorization/policyAssignments/write",
"containsAny": null
}]
},
"actions": {
"actionGroups": [{
"actionGroupId": "/subscriptions/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/resourcegroups/xxxxxxxxxxxxxxx/providers/microsoft.insights/actiongroups/TestingAlertGRP",
"webhookProperties": ""
}]
},
"enabled": true,
"description": "Alert created for Testing"
},
"identity": null
}
"#
API
$API = "https://management.azure.com/subscriptions/$SubscriptionID/resourceGroups/$ResourceGroupName/providers/microsoft.insights/activityLogAlerts/$Name`?api-version=2017-04-01"
Invoke-RestMethod -Method Put -Uri $API -Headers #{Authorization = "Bearer $Token"} -Body $Remediate -ContentType 'application/json' | Out-Null
Note: You must specify at least one (Administrative, Security, Service Health, Recommendation, Policy, Autoscale) of the preceding criteria in your alert. You may not create an alert that activates every time an event is created in the activity logs.
For more details, refer “Create activity log alerts (Classic)”.
Alert does get created but the Event Category field is showing as all instead of Administrative.
Not to reproduce this issue, I check the request body, it should be fine.
If i try to update anything via GUI it gives an error: Failed to update alert 'Testing'.The category field is missing in the condition
I have reproduced this issue when the Event category is all(I modify the category to all via the API mentioned below).
If you want to fix the issue, I recommend you to use this API. Just click the Try It in the page and login your account. You could refer to the screenshot and my sample request body.
My sample request body:
{"location":"global","properties":{"scopes":["/subscriptions/xxxxxxx"],"description":"test","condition":{"allOf":[{"field":"category","equals":"Administrative"},{"field":"resourceType","equals":"Microsoft.Web/serverFarms"}]},"actions":{"actionGroups":[{"actionGroupId":"/subscriptions/xxxxxxx/resourcegroups/joywebapp/providers/microsoft.insights/actiongroups/joyactiongroup","webhookProperties":{}}]},"enabled":true}}
Request:
Check in the portal:

TFS Code Search/Work Rest API return 404

we are using TFS on-premise.
TFS version:
Microsoft Visual Studio Team Foundation Server
Version 16.122.27409.2 (2018).
We need to perform TFS source control (Code Search)
According to MS API documentation this the way to use TFS REST API.
Build and Release API are working, but search API return 404.
Search Code extension installed and working fine from TFS portal.
API Url:
POST: http://{DNS}:8080/tfs/{Collection}/{Project}/_apis/search/codesearchresults?api-version=4.1-preview.1
the result:
Please help, what I'm, doing wrong?
You can't just open it in a browser. You have to provide a request body, as expressed clearly in the API examples:
{
"searchText": "CodeSearchController",
"$skip": 0,
"$top": 1,
"filters": {
"Project": [
"MyFirstProject"
],
"Repository": [
"MyFirstProject"
],
"Path": [
"/"
],
"Branch": [
"master"
],
"CodeElement": [
"def",
"class"
]
},
"$orderBy": [
{
"field": "filename",
"sortOrder": "ASC"
}
],
"includeFacets": true
}
Just as Daniel said "You can't just open it in a browser. You have to provide a request body"
So you can use tools such as Postman to send the request with request body, or you can use PowerShell to call the REST API with request body.
Besides, based on my test it seems the REST API you mentioned (Code Search Results) is not apply to on-premise TFS. I tested on TFS 2018 Update2 (Version 16.131.27701.1), it always return "count": 0,.
However you can use below REST API to search code:
POST http://server:8080/tfs/DefaultCollection/{Project}/_api/_search/postCodeQuery?api-version=4.1-preview.1
Request Body:
{"searchText":"<test1>",
"scope":"Team Foundation Server",
"filters":"{\"ProjectFilters\":[\"0511ScrumTFVC\"]}",
"skipResults":0,
"takeResults":50,
"sortOptions":""
}
Below PowerShell sample for your reference:
Param(
[string]$baseurl = "http://server:8080/tfs/DefaultCollection",
[string]$projectName = "ProjectName",
[string]$user = "username",
[string]$token = "password"
)
# Base64-encodes the Personal Access Token (PAT) appropriately
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $user,$token)))
function CreateJsonBody
{
$value = #"
{"searchText":"<test1>",
"scope":"Team Foundation Server",
"filters":"{\"ProjectFilters\":[\"ProjectName\"]}",
"skipResults":0,
"takeResults":50,
"sortOptions":""
}
"#
return $value
}
$json = CreateJsonBody
$uri = "$baseurl/$($projectName)/_api/_search/postCodeQuery?api-version=4.1-preview.1"
Write-Host $uri
$result = Invoke-RestMethod -Uri $uri -Method POST -Body $json -ContentType "application/json" -Headers #{Authorization=("Basic {0}" -f $base64AuthInfo)}
$result = $result | convertto-json
Write-host $result

Azure Function with PowerShell, Storage Queue trigger, and OneDrive for Business

I'm trying to create an Azure Function that executes PowerShell with a Storage Queue trigger. For testing purposes, I want this function to manipulate a file in my OneDrive for Business account. To copy the file at aapdftoimage/ThreePages.pdf to aapdftoimage/output_ThreePages.pdf.
When OneDrive for Business is integrated as an Input, I get errors any time the function is triggered by a new message in the queue. If I disconnect OneDrive as input I don't get any errors and $triggerInput contains the message.
The errors are:
2017-05-25T22:24:38.484 Function started (Id=a0c37fdf-ed3c-473c-9c79-236d63531e7e)
2017-05-25T22:24:38.499 Function completed (Failure, Id=a0c37fdf-ed3c-473c-9c79-236d63531e7e, Duration=1ms)
2017-05-25T22:24:38.562 Exception while executing function: Functions.QueueTriggerPowerShell1. Microsoft.Azure.WebJobs.Host: No value for named parameter 'file'.
Here's my PowerShell:
$inData = Get-Content $triggerInput
$inFile = Get-Content $inputFile
Write-Output "PowerShell script processed queue message '$inData'"
Write-Output "inFile: $inFile"
Here's function.json:
{
"bindings": [
{
"name": "triggerInput",
"type": "queueTrigger",
"direction": "in",
"queueName": "samples-powershell-pdftoimage",
"connection": "<storageaccount>_STORAGE"
},
{
"type": "apiHubFile",
"name": "inputFile",
"path": "aapdftoimage/{file}",
"connection": "onedriveforbusiness1_ONEDRIVEFORBUSINESS",
"direction": "in"
}
],
"disabled": false
}
As I'm writing this, I think part of my confusion is over the Input and Output (not connected in my test) integrations of OneDrive for Business.
I know what $triggerInput is. It's the content of the message. But what is $inputFile? And where does {file} come from?
I thought maybe I would do the following but it too doesn't work (same errors):
$file = Get-Content $triggerInput
I thought this might define $inputFile as "aapdftoimage/$file" but it does nothing of the sort.
Needless to say, I'm at a standstill. Can anyone give me some guidance and straighten me out?
#Henry Hamid Safi is correct. Using C#, you can leverage the Binder object to dynamically name the file.
In your use-case, the only way to dynamically provide the name of the file is to pass it as a JSON object in your trigger payload. Here is a sample setup that worked for me.
function.json:
{
"bindings": [
{
"name": "triggerInput",
"type": "queueTrigger",
"direction": "in",
"queueName": "samples-powershell",
"connection": "AzureWebJobsStorage"
},
{
"type": "apiHubFile",
"name": "inputFile",
"path": "aapdftoimage/{file}",
"connection": "onedriveforbusiness_ONEDRIVEFORBUSINESS",
"direction": "in"
},
{
"type": "apiHubFile",
"name": "outputFile",
"path": "aapdftoimage/output_{file}",
"connection": "onedriveforbusiness_ONEDRIVEFORBUSINESS",
"direction": "out"
}
],
"disabled": false
}
run.ps1:
$in = Get-Content $triggerInput
Write-Output "PowerShell script processed queue message '$in'"
Copy-Item $inputFile $outputFile
Request body (if using Test pane in Portal) or Queue trigger payload:
{
"file":"ThreePages.pdf"
}
Log entries:
2017-05-26T22:27:53.984 Function started (Id=032c4469-8378-44ce-af9e-5a941afb0d82)
2017-05-26T22:27:54.875 PowerShell script processed queue message '{ "file":"ThreePages.pdf" }'
2017-05-26T22:27:54.891 Function completed (Success, Id=032c4469-8378-44ce-af9e-5a941afb0d82, Duration=899ms)
OneDrive folder screen shot:
Working example
Function.json:
{
"bindings": [
{
"name": "triggerInput",
"type": "queueTrigger",
"direction": "in",
"queueName": "test",
"connection": "AzureWebJobsDashboard"
},
{
"type": "apiHubFile",
"name": "inputFile",
"path": "aapdftoimage/ThreePages.pdf",
"connection": "onedrive_ONEDRIVE",
"direction": "in"
},
{
"type": "apiHubFile",
"name": "outputFile",
"path": "aapdftoimage/output_ThreePages.pdf",
"connection": "onedrive_ONEDRIVE",
"direction": "out"
}
],
"disabled": false
}
run.ps1:
$in = Get-Content $triggerInput
Write-Output "PowerShell script processed queue message '$in'"
Copy-Item $inputFile $outputFile

Resources