Invoke-RestMethod in Azure Function not working - azure

I am facing an issue with my Azure function (Powershell, timer trigger on Linux) which extracts values from Power Bi Service and pass them to a DevOps Pipeline when triggering it.
The triggering is done through Invoke-RestMethod.
The function works fine until it gets values which contain special german characters (Ü, Ö, Ä,...) then the body of the request is somehow broken and the function fails.
I think the problem is related to the encoding but the only possible solution I found is to add charset=utf-8 to the header. Unfortunately, it did not solve the problem.
$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add("Content-Type", "application/json; charset=utf-8")
$headers.Add("Authorization", "Basic $secret")
$body = "{`"templateParameters`": {`"items`": `"$items`"}}"
$response = Invoke-RestMethod 'https://dev.azure.com/<repos>/<project>/_apis/pipelines/1/runs?api-version=7.0' -Method 'POST' -Headers $headers -Body $body
Items is a string of the form:
[['filename','userx','Workspace','givendateTime']]
when the Workspace has a Ö instead of 'o' an exception is raised:
Invoke-RestMethod : {"$id":"1","innerException":null,"message":"Value cannot be null.\r\nParameter name:
runParameters","typeName":"System.ArgumentNullException, mscorlib","typeKey":"ArgumentNullException","errorCode":0,"eventId":0}
+ ... $response = Invoke-RestMethod 'https://dev.azure.com/...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebException
+ FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand
Using Postman with the same parameters and values works fine.
Write-Host $body just before the Invoke-RestMethod is fine and the characters are correct.
Any help will be much appreciated :)

Related

Erorr exporting Azure sql database to blob storage with powershell

I'm trying to use Azure management API to export a SQL database to a bacpac file in a blob storage. The process seems fairly simple: obtain a token, and then:
$sqlAzureBackupHeaders = #{
Authorization = "Bearer $accessToken"
}
$sqlAzureBackupParams = #{
storageKey = "<key-goes-here>",
storageUri = "http://mystorageacct.blob.core.windows.net/my-blob-container/export-name.bacpac",
storageKeyType = "StorageAccessKey",
administratorLogin = "<sql-user>",
administratorLoginPassword = "<sql-password>",
authenticationType = "SQL"
}
$sqlAzureApiUri = "https://management.azure.com/subscriptions/<subscription-id>/resourceGroups/<resource-group>/providers/Microsoft.Sql/servers/<server-name>/databases/<database-name>/export?api-version=2014-04-01"
Invoke-RestMethod -Uri $sqlAzureApiUri -Method Post -Headers $sqlAzureBackupHeaders -Body $sqlAzureBackupParams
This results in an error:
Invoke-RestMethod : Receivera:InternalServiceFaultThe server was unable to process the request due to an internal error. For more
information about the error, either turn on IncludeExceptionDetailInFaults (either from ServiceBehaviorAttribute or from the
<serviceDebug> configuration behavior) on the server in order to send the exception information back to the client, or turn on tracing
as per the Microsoft .NET Framework SDK documentation and inspect the server trace logs.
At D:\Users\protec-admin\Desktop\run-backups.ps1:140 char:1
+ Invoke-RestMethod -uri $sqlAzureApiUri -Method Post -Headers $sqlAzur ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebException
+ FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand
I tried using Invoke-WebRequest and converting body to json string - with the same result.
When I try the same call using Postman, it works fine, so there's something with making the call from powershell that's not working correctly.
How can I get this working from powershell?
According to my test, the rest API just accept the json body. Please use ConvertTo-Json to convert the body to json.
For example
$headers=#{"Authorization" = "Bearer "+$token}
$body=#{
"storageKeyType"= "StorageAccessKey";
"storageKey"= "<your storage account access key>";
"storageUri"= "https://blobstorage0516.blob.core.windows.net/sample/testbacpac2.bacpac";
"administratorLogin"= "<SQL admin>";
"administratorLoginPassword"= "<SQL admin passsword>";
"authenticationType"= "SQL"
}|ConvertTo-Json
$sqlAzureApiUri = "https://management.azure.com/subscriptions/<subscription-id>/resourceGroups/<resource-group>/providers/Microsoft.Sql/servers/<server-name>/databases/<database-name>/export?api-version=2014-04-01"
Invoke-RestMethod -Method Post -Uri $uri -Headers $headers -Body $body -UseBasicParsing -ContentType "application/json"

Cannot POST Cosmos DB Stored Procedures using PowerShell

I'm trying to deploy stored procedures to a collection within an Azure Cosmos DB account as part of my deployment pipeline in Azure DevOps. Due to security reasons, I have to use the REST API (cannot use or import PowerShell modules to do this).
The build agents that I'm using are on-premise agents. Again, security reasons.
In order to generate an authorization token to make requests, I have the following PowerShell function:
Add-Type -AssemblyName System.Web
# Generate Authorization Key for REST calls
Function Generate-MasterKeyAuthorizationSignature
{
[CmdletBinding()]
Param
(
[Parameter(Mandatory=$true)][String]$verb,
[Parameter(Mandatory=$true)][String]$resourceLink,
[Parameter(Mandatory=$true)][String]$resourceType,
[Parameter(Mandatory=$true)][String]$dateTime,
[Parameter(Mandatory=$true)][String]$key,
[Parameter(Mandatory=$true)][String]$keyType,
[Parameter(Mandatory=$true)][String]$tokenVersion
)
$hmacSha256 = New-Object System.Security.Cryptography.HMACSHA256
$hmacSha256.Key = [System.Convert]::FromBase64String($key)
$payLoad = "$($verb.ToLowerInvariant())`n$($resourceType.ToLowerInvariant())`n$resourceLink`n$($dateTime.ToLowerInvariant())`n`n"
$hashPayLoad = $hmacSha256.ComputeHash([System.Text.Encoding]::UTF8.GetBytes($payLoad))
$signature = [System.Convert]::ToBase64String($hashPayLoad);
[System.Web.HttpUtility]::UrlEncode("type=$keyType&ver=$tokenVersion&sig=$signature")
}
I then call this function within the POST function that I'm using to POST the stored procedure to Azure Cosmos DB:
Function Post-StoredProcToCosmosDb
{
[CmdletBinding()]
Param
(
[Parameter(Mandatory=$true)][String]$EndPoint,
[Parameter(Mandatory=$true)][String]$DataBaseId,
[Parameter(Mandatory=$true)][String]$CollectionId,
[Parameter(Mandatory=$true)][String]$MasterKey,
[Parameter(Mandatory=$true)][String]$JSON
)
$Verb = 'Post'
$ResourceType = "sprocs"
$ResourceLink = "dbs/$DataBaseId/colls/$CollectionId"
$dateTime = [DateTime]::UtcNow.ToString("r")
$authHeader = Generate-MasterKeyAuthorizationSignature -verb $Verb -resourceLink $ResourceLink -resourceType $ResourceType -key $MasterKey -keyType "master" -tokenVersion "1.0" -dateTime $dateTime
$header = #{authorization=$authHeader;"x-ms-version"="2017-02-22";"x-ms-date"=$dateTime;"xs-ms-session-token"="28"}
$contentType = "application/json"
$queryUri = "$EndPoint$ResourceLink/sprocs"
$result = Invoke-RestMethod -Headers $header -Method $Verb -ContentType $contentType -Uri $queryUri -Body $JSON
return $result.statuscode
}
I see from the documentation that I need to pass my stored procedure in the body as a string, so I set the path of my stored procedure to a variable like so:
$HelloWorld = Get-Content -Path '.\Databases\MyCosmosDB\MyCosmosCollection\Stored Procedures\HelloWorld.js' | Out-String
I then call my POST function like so:
Post-StoredProcToCosmosDb -EndPoint $env:COSMOSENDPOINT -DataBaseId $env:MYCOSMOSDB -CollectionId $MyCollection -MasterKey $env:MASTERKEY -JSON $HelloWorld
However, when I run the task, I get the following error:
Invoke-RestMethod : The remote server returned an error: (400) Bad Request
At D:_workAzure\r12\a_Cosmos\Deployment\scripts\postStoredProcedures.ps1:61 char:15
$result = Invoke-RestMethod -Headers $header -Method $Verb -Content ...
+ CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebException
+ FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand
I have followed the example request body as outlined in the documentation for my stored procedure.
Here is what it looks like for your info:
"function () {\r\n var context = getContext();\r\n var response = context.getResponse();\r\n\r\n response.setBody(\"Hello, World\");\r\n}"
I'm fairly new to PowerShell, so I'm wondering where I am going wrong. I've tried setting the contentType to both application/json and application/query+json but otherwise, I'm not sure where I am going wrong?
If anyone can provide any guidance on this, I'd be most grateful.
So turns out the request body was wrong. It should be like this:
{
"body":"function HelloWorld() {\r\n var context = getContext();\r\n var response = context.getResponse();\r\nresponse.setBody(\"Hello, World\");\r\n}",
"id": "HelloWorld"
}
That's the acceptable request body for Stored Procedures. So what I should have done is set my $HelloWorld variable to:
$HelloWorld = Get-Content -Path '.\Databases\MyCosmosDB\MyCosmosCollection\Stored Procedures\HelloWorld.json' | Out-String
Hope my stupidity helps someone someday :/

InvalidOperation while doing a post method in PS

I'm trying to create a comment in a Azure Devops Pull Request thread:
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
# Variables
$organization = "movieseat"
$project = "pokedex"
$repositoryId = "Pokedex"
$pullRequestId = "97"
$threadId = "283"
$pat = "Bearer $env:System_AccessToken"
$body = #"
{
"content"="Finished building feature branch"
"commentType"="text";
}
"#
$postURL = "https://dev.azure.com/$organization/$project/_apis/git/repositories/$repositoryId/pullRequests/$pullRequestId/threads/$threadId/comments?api-version=5.0"
$prComment = Invoke-RestMethod -Uri $postURL -Headers #{Authorization = $pat} -Body $body -Method Post -ContentType 'application/json'
Write-Output $prComment
But during the release step I get:
Invoke-RestMethod : {"$id":"1","innerException":null,"message":"Value cannot be null.\r\nParameter name:
comment","typeName":"System.ArgumentNullException,
mscorlib","typeKey":"ArgumentNullException","errorCode":0,"eventId":0}
At D:\a\r1\a\_Pokedex master\PokeDexArtifact\release\commentURL.ps1:49 char:14
+ ... prComment = Invoke-RestMethod -Uri $postURL -Headers #{Authorization ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebException
+ FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand
##[error]PowerShell exited with code '1'.
##[section]Finishing: PowerShell Script
I can't find any info relating to this error.
I'm not 100% sure, but I think this was the actual error:
message":"Value cannot be null.\r\nParameter name: comment",
$body = #"
{
"content": "http://google.com",
"commentType": "text";
}
"#
Running the code like this works. Notice the , after the content value. Although I removed the commentType value since it works without it as well.
// edit. I've updated the code block, replaced a = with a : in the content line.
{
"content"="Finished building feature branch"
"commentType"="text";
}
That is not valid JSON. The best way to handle creating JSON strings in PowerShell is to use ConvertTo-Json on an associative array:
$body = #{
content = 'Finished building feature branch'
commentType = 'text'
} | ConvertTo-Json -Depth 10

Unable to access admin URL of Azure Functions

I am using powershell and trying to access Azure functions Administration using api.
I am trying to get list of all functions created under $appName
Certainly i am changing $appName with actual Azure Function name before call
I also got valid $authToken before this call.
Below URL:
$Functions = Invoke-RestMethod -Method GET -Headers #{Authorization = ("Bearer {0}" -f $authToken)} -Uri "https://$appName.azurewebsites.net/admin/functions"
and the error in my powershell execution is :
Invoke-RestMethod :
The underlying connection was closed: An unexpected error occurred on a send.
At KeyFA.ps1:36 char:18
+ ... Functions = Invoke-RestMethod -Method GET -Headers #{Authorization = ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebException
+ FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand
I tried make it POST instead of GET but same error.
I tried access this url in broswer and the error in my broswer is :
http 401 means unauthorized.
Then i also tried access this URL from postman with Bearer auth correctly set but get below errors:
Could not get any response
There was an error connecting to
https://appname_comes_here.azurewebsites.net/admin/functions/
What am i not doing correctly?
Not able to fix this error. Is the url discontinued by Azure function site now?
Due to you just post the partial PowerShell code and the error information seems to be a network issue, I don't know what real issue you got is and how to fix it.
So I just post my work PowerShell script at here, you can refer to my code to fix your issue.
$appName = "<your app name>"
$userName='<your app credential user name>'
$userPWD='<your app credential user password>'
$apiBaseUrl = "https://$($appName).scm.azurewebsites.net/api"
$appBaseUrl = "https://$($appName).azurewebsites.net"
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $userName,$userPWD)))
$jwt = Invoke-RestMethod -Uri "$apiBaseUrl/functions/admin/token" -Headers #{Authorization=("Basic {0}" -f $base64AuthInfo)} -Method GET
$Functions = Invoke-RestMethod -Method GET -Headers #{Authorization = ("Bearer {0}" -f $jwt)} -Uri "$appBaseUrl/admin/functions"
Note: you can follow the figures below to get the $userName and $userPWD values.
Fig 1. On Azure portal, open the Platform features tab of your Function App and click the Deployment Center link
Fig 2. Select the FTP option in the first step of SOURCE CONTROL and click the Dashboard button to copy the values of Username and Password, but just use the part of Username with $ prefix as $userName in my script

Save-AzureWebSiteLog Invoke-WebRequest error

I was really close to finish my job but it started to cause this error.
when I execute this
Save-AzureWebSiteLog -Name $WebSiteName -Output "C:\logs\error.zip"
Save-AzureWebSiteLog : The maximum message size quota for incoming
messages (65536) has been exceeded. To increase the quota, use the
MaxReceivedMessageSize property on the appropriate binding element.
so, I searched for the solution, it seems like that many people have exact same problem.
https://azure.microsoft.com/en-us/blog/windows-azure-websites-online-tools-you-should-know-about/
Thanks to #Parth Sehgal, I have tried to solve the problem by using powershell
$username = "maiemai"
$password = "Password"
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $username,$password)))
$apiUrl = "https://wngphase2it.scm.azurewebsites.net/api/zip/LogFiles/"
$response = Invoke-WebRequest -Uri $apiUrl -Headers #{Authorization=("Basic {0}" -f $base64AuthInfo)} -Method GET
try
{
$filename = [System.IO.Path]::GetFileName($response.BaseResponse.ResponseUri.OriginalString)
$filepath = [System.IO.Path]::Combine("c:\asdf\", "http1.zip")
$filestream = [System.IO.File]::Create($filepath)
$response.RawContentStream.WriteTo($filestream)
}
finally
{
$filestream.Close()
}
but I am stuck with this error
Invoke-WebRequest : Server Error
401 - Unauthorized: Access is denied due to invalid credentials.
You do not have permission to view this directory or page using the credentials that you supplied.
At line:5 char:13
+ $response = Invoke-WebRequest -Uri $apiUrl -Headers #{Authorization=("Basic {0}" ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-WebRequest],
WebException
+ FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeWebRequestCommand
You cannot call a method on a null-valued expression.
At line:11 char:1
+ $response.RawContentStream.WriteTo($filestream)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
Username and Password is definitely correct, but it is still causing this error.
How should I change this line?
$response = Invoke-WebRequest -Uri $apiUrl -Headers #{Authorization=("Basic {0}" -f $base64AuthInfo)} -Method GET
First of all, your username is incorrect in this case.
In order to use the Azure Kudu REST API to retrieve the zipped log files for your Azure web app, you will need to use your web app's MSDeploy credential in the publish profile file.
The correct form of Azure web app's MSDeploy username should be ${yoursitename}.
You can get your web app's publish profile from the new Azure portal or via Azure PowerShell command: Get-AzureRMWebAppPublishingProfile
I have also fixed the issue in your PowerShell script which I tested with my own web app.
$username = "`$wngphase2it"
$password = "yourMSDeployUserPwd"
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $username,$password)))
$apiUrl = "https://wngphase2it.scm.azurewebsites.net/api/zip/LogFiles/"
$response = Invoke-WebRequest -Uri $apiUrl -Headers #{Authorization=("Basic {0}" -f $base64AuthInfo)} -Method GET
try
{
$filename = [System.IO.Path]::GetFileName($response.BaseResponse.ResponseUri.OriginalString)
$filepath = [System.IO.Path]::Combine("c:\asdf\", "http1.zip")
$filestream = [System.IO.File]::Create($filepath)
$response.RawContentStream.WriteTo($filestream)
}
finally
{
$filestream.Close()
}
Reference: Sample of using Kudu REST API with PowerShell
Let me know whether it helps to resolve your issue.

Resources