The Remote Server returned an error : (415) Unsupported media type for PowerBI Data Refresh API Call - rest

I am trying to refresh power bi dataset using POST method with PowerShell script, but keep getting an error about media type so not sure what to do here. Just curious if somebody else having any solution for this. Thanks in advance for the help!!
Please see this source code for more details...
https://github.com/Azure-Samples/powerbi-powershell/blob/master/manageRefresh.ps1
# This sample script calls the Power BI API to progammtically trigger a refresh for the dataset
# It then calls the Power BI API to progammatically to get the refresh history for that dataset
# For full documentation on the REST APIs, see:
# https://msdn.microsoft.com/en-us/library/mt203551.aspx
# Instructions:
# 1. Install PowerShell (https://msdn.microsoft.com/en-us/powershell/scripting/setup/installing-windows-powershell) and the Azure PowerShell cmdlets (https://aka.ms/webpi-azps)
# 2. Set up a dataset for refresh in the Power BI service - make sure that the dataset can be
# updated successfully
# 3. Fill in the parameters below
# 4. Run the PowerShell script
# Parameters - fill these in before running the script!
# =====================================================
# An easy way to get group and dataset ID is to go to dataset settings and click on the dataset
# that you'd like to refresh. Once you do, the URL in the address bar will show the group ID and
# dataset ID, in the format:
# app.powerbi.com/groups/{groupID}/settings/datasets/{datasetID}
$groupID = " FILL ME IN " # the ID of the group that hosts the dataset. Use "me" if this is your My Workspace
$datasetID = " FILL ME IN " # the ID of the dataset that hosts the dataset
# AAD Client ID
# To get this, go to the following page and follow the steps to provision an app
# https://dev.powerbi.com/apps
# To get the sample to work, ensure that you have the following fields:
# App Type: Native app
# Redirect URL: urn:ietf:wg:oauth:2.0:oob
# Level of access: all dataset APIs
$clientId = " FILL ME IN "
# End Parameters =======================================
# Calls the Active Directory Authentication Library (ADAL) to authenticate against AAD
function GetAuthToken
{
$adal = "${env:ProgramFiles(x86)}\Microsoft SDKs\Azure\PowerShell\ServiceManagement\Azure\Services\Microsoft.IdentityModel.Clients.ActiveDirectory.dll"
$adalforms = "${env:ProgramFiles(x86)}\Microsoft SDKs\Azure\PowerShell\ServiceManagement\Azure\Services\Microsoft.IdentityModel.Clients.ActiveDirectory.WindowsForms.dll"
[System.Reflection.Assembly]::LoadFrom($adal) | Out-Null
[System.Reflection.Assembly]::LoadFrom($adalforms) | Out-Null
$redirectUri = "urn:ietf:wg:oauth:2.0:oob"
$resourceAppIdURI = "https://analysis.windows.net/powerbi/api"
$authority = "https://login.microsoftonline.com/common/oauth2/authorize";
$authContext = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext" -ArgumentList $authority
$authResult = $authContext.AcquireToken($resourceAppIdURI, $clientId, $redirectUri, "Auto")
return $authResult
}
# Get the auth token from AAD
$token = GetAuthToken
# Building Rest API header with authorization token
$authHeader = #{
'Content-Type'='application/json'
'Authorization'=$token.CreateAuthorizationHeader()
}
# properly format groups path
$groupsPath = ""
if ($groupID -eq "me") {
$groupsPath = "myorg"
} else {
$groupsPath = "myorg/groups/$groupID"
}
# Refresh the dataset
$uri = "https://api.powerbi.com/v1.0/$groupsPath/datasets/$datasetID/refreshes"
Invoke-RestMethod -Uri $uri -Headers $authHeader -Method POST -Verbose
# Check the refresh history
$uri = "https://api.powerbi.com/v1.0/$groupsPath/datasets/$datasetID/refreshes"
Invoke-RestMethod -Uri $uri -Headers $authHeader -Method GET -Verbose

I've came across this exact issue.
You are basically trying to return refresh info from a dataset that cannot be refreshed (Eg. A direct Query dataset or the builtin metrics datasets)
You need to either add -ErrorAction SilentlyContinue
or wrap the dataset refresh API call in a loop like this:
$datasets = Invoke-RestMethod -Uri $uri -Headers $authHeader -Method GET
foreach($dataset in $datasets.value)
{
if($dataset.isRefreshable -eq $true)
{
#Build API String
$uri2 = "https://api.powerbi.com/v1.0/$groupsPath/datasets/$($dataset.id)/refreshes"
#Return refresh info for each dataset
$refreshes = Invoke-RestMethod -Uri $uri2 -Headers $authHeader -Method GET
}
}

Related

Get SPO sites using MS Graph API powershell not working

I'm trying to get all SharePoint Online sites' name and url via PowerShell using MS Graph API, but it's not seem to be working. That's all I get from the request:
#{#odata.context=https://graph.microsoft.com/v1.0/$metadata#sites; value=System.Object[]}
The application I use have all the needed Application type API permissions (Sites.Read, Sites.ReadWrite.All) with admin consent.
Do you have any idea why my script not working?
The code:
$TenantID = 'xxxxxxxxx.ONMICROSOFT.COM'
$ApplicationId = "xxxxx-xxxxxx-xxxx-xxxx"
$ApplicationSecret = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
$body = #{
'resource' = 'https://graph.microsoft.com'
'client_id' = $ApplicationId
'client_secret' = $ApplicationSecret
'grant_type' = "client_credentials"
'scope' = "openid"
}
$ClientToken = Invoke-RestMethod -Method post -Uri "https://login.microsoftonline.com/$($tenantid)/oauth2/token" -Body $body -ErrorAction Stop
$headers = #{ "Authorization" = "Bearer $($ClientToken.access_token)" }
$AllSites = Invoke-RestMethod -Uri "https://graph.microsoft.com/v1.0/sites?search=*" -Headers $headers -Method Get
Write-Host $AllSites
I've also tried these URIs:
https://graph.microsoft.com/v1.0/sites?search=*
https://graph.microsoft.com/v1.0/sites
https://graph.microsoft.com/v1.0/sites$select=siteCollection,webUrl&$filter=siteCollection/root%20ne%20null
The Write-Host cmdlet's primary purpose is to produce
for-(host)-display-only output, such as printing colored text like
when prompting the user for input in conjunction with Read-Host.
Write-Host uses the ToString() method to write the output. By
contrast, to output data to the pipeline, use Write-Output or implicit
output.
reference
This mean that your output is transformed for display purposes. Where you see System.Object[], there is actually data in there just waiting for you.
Based on your current results, your query look good.
Just do not use Write-Host and dig into the object as needed.
To get the site names, just use $AllSites.Value.Name
$AllSites = Invoke-RestMethod -Uri "https://graph.microsoft.com/v1.0/sites?search=*" -Headers $headers -Method Get
# Return site names
$AllSites.Value.Name
If you need to get additional information from each return you can loop into them, like this to do whatever you need. Here is a custom display of the site name along with an arbitrary index and the associated URL
$index = 0
# Will display results like
# 0: SiteName - www.contoso.sharepoint.com/SiteUrl
foreach ($Site in $AllSites.Value) {
Write-Host "$($index.ToString().PadRight(3,' ')): $($Site.Name) - " -NoNewline
Write-Host $site.webUrl -ForegroundColor Cyan
$index += 1
}
Also, here is an additional reference when working with Azure Graph API that will confirm your requests are working as expected: https://developer.microsoft.com/en-us/graph/graph-explorer

SCOM REST API to get Windows/Linux machine's availability (whether the server is running & reachable)?

I want to know whether SCOM exposes an API from which I can get the server status (whether the server is running & reachable) given a particular object id.
Yes in SCOM 2019 UR1+ you can access the rest API programmatically and get the state.
POST http://<Servername>/OperationsManager/data/state
Retrieve SCOM State Data
Quick Start – SCOM REST API
Here is an example in PowerShell using the SCOM REST API
$SCOMHeaders = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$SCOMHeaders.Add('Content-Type', 'application/json; charset=utf-8')
$BodyRaw = "Windows"
$Bytes = [System.Text.Encoding]::UTF8.GetBytes($BodyRaw)
$EncodedText = [Convert]::ToBase64String($Bytes)
$JSONBody = $EncodedText | ConvertTo-Json
# The SCOM REST API authentication URL
$URIBase = 'http://<Servername>/OperationsManager/authenticate'
# Initiate the Cross-Site Request Forgery (CSRF) token, this is to prevent CSRF attacks
$CSRFtoken = $WebSession.Cookies.GetCookies($UriBase) | ? { $_.Name -eq 'SCOM-CSRF-TOKEN' }
$SCOMHeaders.Add('SCOM-CSRF-TOKEN', [System.Web.HttpUtility]::UrlDecode($CSRFtoken.Value))
# Authentication
$Authentication = Invoke-RestMethod -Method Post -Uri $URIBase -Headers $SCOMHeaders -body $JSONBody -UseDefaultCredentials -SessionVariable WebSession
# The query which contains the criteria for our states
$Query = #(#{ "classId" = ""
# Criteria: Enter the name of the monitored computer (do not use the FQDN)
"criteria" = "Id = 'f20f6a00-0c86-fab5-ac6b-14e30097ff4a'"
"displayColumns" = "displayname", "healthstate", "name", "path"
})
# Convert our query to JSON format
$JSONQuery = $Query | ConvertTo-Json
$Response = Invoke-RestMethod -Uri 'http://<Servername>/OperationsManager/data/state' -Method Post -Body $JSONQuery -ContentType "application/json" -WebSession $WebSession
# Print out the state results
$State = $Response.rows
$State
Output of health state

Error when trying to use Power BI REST API - Invoke-RestMethod : A positional parameter cannot be found that accepts argument

Lately I've been trying to use Power BI REST API to make the refresh of a certain dataset automatically, by calling a .ps1 program. By following this tutorial, I was able to get this code, which is addapted as you can see below:
$groupID = "me" # the ID of the group that hosts the dataset. Use "me" if this is your My Workspace
$datasetID = "MYDATASETID" # the ID of the dataset that hosts the dataset
$clientId = "MYCLIENTID"
# Calls the Active Directory Authentication Library (ADAL) to authenticate against AAD
function GetAuthToken
{
if(-not (Get-Module AzureRm.Profile)) {
Import-Module AzureRm.Profile
}
$redirectUri = "urn:ietf:wg:oauth:2.0:oob"
$resourceAppIdURI = "https://analysis.windows.net/powerbi/api"
$authority = "https://login.microsoftonline.com/common/oauth2/authorize";
$authContext = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext" -ArgumentList $authority
$authResult = $authContext.AcquireToken($resourceAppIdURI, $clientId, $redirectUri, "Auto")
return $authResult
}
$token = GetAuthToken
$authHeader = #{
'Content-Type'='application/json'
'Authorization'=$token.CreateAuthorizationHeader()
}
$groupsPath = ""
if ($groupID -eq "me") {
$groupsPath = "myorg"
} else {
$groupsPath = "myorg/groups/$groupID"
}
$uri = "https://api.powerbi.com/v1.0/$groupsPath/datasets/$datasetID/refreshes"
Invoke-RestMethod -Uri $uri –Headers $authHeader –Method POST –Verbose
$uri = "https://api.powerbi.com/v1.0/$groupsPath/datasets/$datasetID/refreshes"
Invoke-RestMethod -Uri $uri –Headers $authHeader –Method GET –Verbose
I made sure to collect the parameters (groupID, clientID and datasetID) exactly as specified in the links above. However, when I try to execute this code, I get back the error:
Invoke-RestMethod : A positional parameter cannot be found that accepts argument 'â€Headers System.Collections.Hashtable â€Method'.
At C:\Users\me\Desktop:41 char:1
I can't quite tell what's going on, and I even found some similar cases, but none of the solutions worked for me. So, some help would be deeply appreciated.
It looks like this solution is copy/pasted from somewhere and the dashes are screwed up:
Delete the last 3 dashes in Invoke-RestMethod, which looks like dashes, but are other looks like dash unicode symbols, and replace them with normal "typed by the keyboard" ones.
Hope this helps!

Accessing Microsoft Graph With PowerShell

I've been having a hell of a time trying to access the Microsoft Graph using PowerShell.
First I tried using the authorization flow and Invoke-WebRequest and Invoke-RestMethod neither of which I could get to work.
Then I found this blog that showed how to do it using PowerShell and a couple of the Azure modules. Below is the code I'm using (ripped right from that blog) but every time I get to the Invoke-RestMethod (in the do-while loop) instead of getting the result of the query I get a 403 Forbidden error:
Invoke-RestMethod : The remote server returned an error: (403) Forbidden.
Function GetAuthToken {
Param (
[Parameter()]
$TenantName
)
Import-Module Azure
$clientId = "1950a258-227b-4e31-a9cf-717495945fc2"
$resourceAppIdURI = "https://graph.microsoft.com"
$authority = "https://login.microsoftonline.com/$TenantName"
$authContext = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext" -ArgumentList $authority
$Credential = Get-Credential
$AADCredentialUser = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.UserCredential" -ArgumentList $credential.UserName, $credential.Password
$authResult = $authContext.AcquireToken($resourceAppIdURI, $clientId, $AADCredentialUser)
Write-Output $authResult
}
Function GetAllObjectOfType {
param
(
[Parameter(Mandatory = $true)]
$Tenant,
[Parameter(Mandatory = $true)]
$Type,
[Parameter(Mandatory = $false)]
$BatchSize = 100,
[Parameter(Mandatory = $false)]
$Version = 'Beta'
)
#------Get the authorization token------#
$token = GetAuthToken -TenantName $tenant
#------Building Rest Api header with authorization token------#
$authHeader = #{
'Content-Type' = 'application/json'
'Authorization' = $token.CreateAuthorizationHeader()
}
#------Initial URI Construction------#
#$uritest = "https://graph.microsoft.com/v1.0/users/user#contoso.com/mailFolders/Inbox/childFolders"
$uritest = "https://graph.microsoft.com/v1.0/me/mailFolders/Inbox"
#Join-Path -Path ''
$ObjCapture = #()
do {
$users = Invoke-RestMethod -Uri $uritest -Headers $authHeader -Method Get
$FoundUsers = ($Users.value).count
write-host "URI" $uri " | Found:" $FoundUsers
#------Batched URI Construction------#
$uri = $users.'#odata.nextlink'
$ObjCapture = $ObjCapture + $users.value
}until ($uri -eq $null)
$ObjCapture
}
I can run this same query (/v1.0/me/mailFolders/Inbox) from the Graph Explorer and it runs perfectly fine with no errors.
The GetAuthToken seems to be working as I do get a token back with an expiry, refresh token, etc and the $token.CreateAuthorizationHeader() also returns the correct Authorization = Bearer token
I've never done anything with the Microsoft Graph before so I'm sure there is something I'm doing wrong but I cannot for the life of me figure out what.
You cannot reuse the clientid from that blog post. You need to obtain your own clientid by registering your application. See Register your app with the Azure AD v2.0 endpoint for details on how to register your app.
This seems like it was answered in a follow-up blog post from the same source.
When an App is created, by default it has rights to access only the data of
the user that had signed in with the account though the “Sign in and read user
profile” delegated permissions. If you try to execute a script that uses this
AppID/ClientID to query Azure AD to get a list of all users in the directory,
you would receive an error stating (403) Forbidden because it didn’t have
adequate permissions to do that activity.
Putting this here in case any other wandering devs come across the post like I did. Here's the powershell function I'm using to get the access token from our tenant. ClientId and Secret are created in the Azure App Registrations, like others have mentioned.
$clientId = $args[0]
$secret = $args[1]
$redeemURI = "https://login.microsoftonline.com/{tenantGuid}/oauth2/v2.0/token"
$body = "client_id=$clientId&scope=https%3A%2F%2Fgraph.microsoft.com%2F.default&client_secret=$secret&grant_type=client_credentials"
$response = Invoke-RestMethod -Method Post -Uri $redeemURI -Body $body -ContentType "application/x-www-form-urlencoded"
return $response.access_token
Usage:
$token = ./GetAccessToken.ps1 "{clientId}" "{secret}"
I think it needs AD Azure Premium 2 licences
enter link description here

Azure CDN - Custom Domain SSL via Resource Management API

Using the latest Azure Powershell SDK, but still can't seem to create Custom SSL Domains for CDNs in Azure via API Management. We have 100s of subdomains to create and need to be able to script the creation of this task for future extensibility.
Does anyone know how to toggle this flag via the REST API since the SDK has no support? We are using the New-AzureRmCdnCustomDomain commandlet.
Update: The AzureRM 6.13.0-module and the new Az-modules (including Az.Cdn) now supports this using a cmdlet. See Enable-AzureCdnCustomDomain (AzureRM.Cdn) or Enable-AzCdnCustomDomain (Az.Cdn)
The REST API for enabling Custom Domain HTTPS is documented at learn.microsoft.com
Enable Custom Https
Enable https delivery of the custom domain.
POST /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Cdn/profiles/{profileName}/endpoints/{endpointName}/customDomains/{customDomainName}/enableCustomHttps?api-version=2017-10-12
Before you can use the Azure REST API you need to get an access token:
Generating access token using PowerShell:
$Token = Invoke-RestMethod -Uri https://login.microsoftonline.com/<TenantID>/oauth2/token?api-version=1.0 -Method Post -Body #{
"grant_type" = "client_credentials"
"resource" = "https://management.core.windows.net/"
"client_id" = "<application id>"
"client_secret" = "<password you selected for authentication>"
}
The response contains an access token, information about how long that
token is valid, and information about what resource you can use that
token for. The access token you received in the previous HTTP call
must be passed in for all request to the Resource Manager API. You
pass it as a header value named "Authorization" with the value "Bearer
YOUR_ACCESS_TOKEN". Notice the space between "Bearer" and your access
token.
Client ID is retrived by creating an app registration in Azure AD and the clientkey is generated in the Keys-section of the created app registration. This can be combined into a solution like this:
$subscriptionId = "..."
$resourceGroupName = "..."
$profileName = "..."
$endpointName = "..."
$customDomainName = ".."
$Token = Invoke-RestMethod -Uri https://login.microsoftonline.com/<TenantID>/oauth2/token?api-version=1.0 -Method Post -Body #{
"grant_type" = "client_credentials"
"resource" = "https://management.core.windows.net/"
"client_id" = "<application id>"
"client_secret" = "<password you selected for authentication>"
}
$header = #{
"Authorization"= "Bearer $($Token.access_token)"
}
Invoke-RestMethod -Method Post -Headers $header -Uri "https://management.azure.com/subscriptions/$subscriptionId/resourceGroups/$resourceGroupName/providers/Microsoft.Cdn/profiles/$profileName/endpoints/$endpointName/customDomains/$customDomainName/enableCustomHttps?api-version=2016-10-02"
If you don't need to automate the script, you can login manually using GUI (no need for app-registration) using this modified sample (based on Source). It requires AzureRM-module, which can be installed using Install-Module AzureRM:
Function Login-AzureRESTApi {
Import-Module AzureRM.Profile
# Load ADAL Azure AD Authentication Library Assemblies
$modulepath = Split-Path (Get-Module -Name AzureRM.Profile).Path
$adal = "$modulepath\Microsoft.IdentityModel.Clients.ActiveDirectory.dll"
$adalforms = "$modulepath\Microsoft.IdentityModel.Clients.ActiveDirectory.WindowsForms.dll"
$null = [System.Reflection.Assembly]::LoadFrom($adal)
$null = [System.Reflection.Assembly]::LoadFrom($adalforms)
# Login to Azure
$Env = Login-AzureRmAccount
# Select Subscription
$Subscription = (Get-AzureRmSubscription | Out-GridView -Title "Choose a subscription ..." -PassThru)
$adTenant = $Subscription.TenantId
$global:SubscriptionID = $Subscription.SubscriptionId
# Client ID for Azure PowerShell
$clientId = "1950a258-227b-4e31-a9cf-717495945fc2"
# Set redirect URI for Azure PowerShell
$redirectUri = "urn:ietf:wg:oauth:2.0:oob"
# Set Resource URI to Azure Service Management API | #marckean
$resourceAppIdURIASM = "https://management.core.windows.net/"
$resourceAppIdURIARM = "https://management.azure.com/"
# Set Authority to Azure AD Tenant
$authority = "https://login.windows.net/$adTenant"
# Create Authentication Context tied to Azure AD Tenant
$authContext = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext" -ArgumentList $authority
# Acquire token
$global:authResultASM = $authContext.AcquireToken($resourceAppIdURIASM, $clientId, $redirectUri, "Auto")
$global:authResultARM = $authContext.AcquireToken($resourceAppIdURIARM, $clientId, $redirectUri, "Auto")
}
$resourceGroupName = "..."
$profileName = "..."
$endpointName = "..."
$customDomainName = ".."
Login-AzureRESTApi
#Reuse selected subscription from login
$Subscription = $global:subscriptionId
$header = #{
"Authorization"= $global:authResultARM.CreateAuthorizationHeader()
}
Invoke-RestMethod -Method Post -Headers $header -Uri "https://management.azure.com/subscriptions/$subscriptionId/resourceGroups/$resourceGroupName/providers/Microsoft.Cdn/profiles/$profileName/endpoints/$endpointName/customDomains/$customDomainName/enableCustomHttps?api-version=2017-10-12"