- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe to Topic
- Printer Friendly Page
- Mark as New
- Bookmark
- Subscribe
- Mute
- Permalink
- Report Inappropriate Content
Secure Application Model after June 30th 2022 Azure AD Graph deprecation
Azure AD Graph is due to be deprecated on June 30th 2022.
Currently I use code similar to the below to connect to partner tenants using the secure application model.
(Application registered separately obviously)
$aadGraphToken = New-PartnerAccessToken -ApplicationId $ApplicationId -Credential $credential -RefreshToken $refreshToken -Scopes ‘https://graph.windows.net/.default’ -ServicePrincipal -Tenant $tenantID
$graphToken = New-PartnerAccessToken -ApplicationId $ApplicationId -Credential $credential -RefreshToken $refreshToken -Scopes ‘https://graph.microsoft.com/.default’ -ServicePrincipal -Tenant $tenantID
Connect-AzureAD -AadAccessToken $aadGraphToken.AccessToken -AccountId 'VALIDEMAILADDRESS' -MsAccessToken $graphToken.AccessToken -TenantId $tenantID
and similarly for Connect-Msolservice
This works great but what happens after the deprecation of the Azure AD Graph endpoint
‘https://graph.windows.net/.default’
Connect-AzureAD and Connect-MSolservice will no longer work with the secure application model. They don't accept a response from the Microsoft Graph endpoint only Azure AD Graph.
Is there a way around this or an alternative in the works?
- Labels:
-
Development Platform & Tools
- Mark as New
- Bookmark
- Subscribe
- Mute
- Permalink
- Report Inappropriate Content
I'm not sure I follow all this 100%:
- PowerShell 7 aka PowerShell Core 7 is definitely based on .NET Core - it's the portable version of .NET / PowerShell, runs on Windows, Linux, macOS, starts with version 6.0 and goes up from there. Windows PowerShell 5.1 (and below) rely on Windows .NET Framework (.NET Framework 4.x and below, depending on the version) - runs on Windows OS only.
- The Azure AD Graph is being retired, but the Microsoft Graph has nearly the same functionality. The modules that rely on the AAD Graph are the AzureAD V2 and Msol/MicrosoftOnline/MSOnline V1, and Azure Az modules (of the ones we care about for PartnerCenter module access, as far as I know). The new MsGraph module is likely to include much of that functionality. Exchange Online doesn't need it.
- The Azure Az module is being updated - the intent being that the module will remain the same but the back-end APIs called will be different. So while V7 will have some front-end changes they will be minimized. The Az module also has some User/Group functionality, but not nearly as much as the AzureAD module of course.
- Some aspects of the AzureAD and MSOnline modules will stop working. Namely the License assignment bits.
- I wouldn't be surprised if the MSOnline V1 module stops working entirely since it is already old/deprecated and replaced by the AzureAD V2 module. I know some features are not migrated (yet!!) such as the MFA stuff, but hopefully that is resolved before June.
- The AzureAD V2 module currently needs the AAD Graph but the module isn't dead, as far as I know, so will likely see a new version before June, dropping the features it can no longer perform (License management) and using only the MS Graph on the back-end. Which may mean the front-end interface of the module may change slightly. But it won't work on PowerShell 7, use the MsGraph module for that.
- You can use the MsGraph module with the PartnerCenter module Tokens, as you note. Basically: Connect-MgGraph -AccessToken $graphTok.AccessToken
- You can also use the Invoke-GraphRequest cmdlet (which is in the Microsoft.Graph.Authentication module, so really that's all you need) to connect to any MS Graph API endpoint yourself: Invoke-GraphRequest -Method GET -Uri 'https://graph.microsoft.com/v1.0/Groups/' (remember Disconnect-MgGraph after)
- Or you can use POPS - Plain Ol' PowerShell: Invoke-RestMethod -Headers @{Authorization = "Bearer $($graphTok.AccessToken)"} -Uri 'https://graph.microsoft.com/v1.0/Groups/' -Method GET | select -expand value
- You won't need 2 tokens after, just the 1 MS Graph Token. (or the office365.com for Exch Online or the azure.com one for Azure Az module)
You can also connect using anything that can handle HTTPS requests, such as JavaScript which you could convert to PowerShell if you wanted to raw API access using Invoke-RestMethod. Here's basically how I do it in JavaScript/Node:
const request = require("request-promise")
// This is BASED on our actual code, using a custom api wrapper module. But this code is not going to work as-is.
var apiDefaultsPartnerCenter // Microsoft CSP Partner Portal
function connectPartnerCenter() {
const tenantID = "our-csp-partner-domain.ca"
const authRequest = {
resource: "https://api.partnercenter.microsoft.com",
grant_type: 'refresh_token',
refresh_token: 'super long refresh token, or grab from wherever you store it'
scope: "openid",
client_id: "f7282f04-blah-blah-blah-4798946", // the AzureAD App ID
client_secret: "iTA7-foo-bar-foo-bar-k2iWC" // the AzureAD App Shared Secret
}
const authResponse = api.post({ // api is a custom wrapper for Request, but basically an API POST call
url: "https://login.microsoftonline.com/" + tenantID + "/oauth2/token",
form: authRequest
})
if (authResponse.token_type != "Bearer" && authResponse.scope != "user_impersonation") {
console.log("ERROR Obtaining access_token! The refresh_token may have expired or need to be reacquired. Or the client_secret may have expired.\nThe OAuth results are:\n")
console.log(authResponse)
throw "Token_Type not Bearer or Scope not User_Impersonation."
}
const partnerCenterHeaders = {
'Accept': "application/json; charset=utf-8",
'MS-Contract-Version': "v1",
'MS-PartnerCenter-Application': "Some-Name-For-Your-App",
'X-Locale': "en-US"
}
// Update global variable for future calls to our api module by setting defaults:
apiDefaultsPartnerCenter = request.defaults({
baseUrl: "https://api.partnercenter.microsoft.com/",
json: true,
encoding: 'utf8',
headers: partnerCenterHeaders,
auth: {
bearer: authResponse.access_token // AccessToken is only valid for 60 mins
}
});
}
var apiDefaultsGraphApi // Microsoft Graph API (not the older Azure AD Graph) - uses the SAME AzureAD NativeApp for Auth as PartnerCenter
function connectMsGraphApi() {
const tenantID = "our-csp-partner-domain.ca"
const authRequest = {
resource: "https://graph.microsoft.com",
grant_type: 'refresh_token',
refresh_token: 'super long refresh token, or grab from wherever you store it'
scope: "https://graph.microsoft.com/.default", // Also seems to work as "openid"
client_id: "f7282f04-blah-blah-blah-4798946", // the AzureAD App ID
client_secret: "iTA7-foo-bar-foo-bar-k2iWC" // the AzureAD App Shared Secret
}
const authResponse = api.post({ // api is a custom wrapper for Request, but basically an API POST call
url: "https://login.microsoftonline.com/" + tenantID + "/oauth2/token",
form: authRequest
)
if (authResponse.token_type != "Bearer") {
console.log("ERROR Obtaining Graph API access_token! The refresh_token may have expired or need to be reacquired. Or the client_secret may have expired.\nThe OAuth results are:\n")
console.log(authResponse)
throw "Token_Type not Bearer."
}
const graphHeaders = {
'Accept': "application/json;",
'Host' : "graph.microsoft.com"
}
// Update global variable with BearerToken for future connections, sets defaults for Request. You'd need to handle pagination and such
apiDefaultsGraphApi = request.defaults({
baseUrl: "https://graph.microsoft.com/v1.0/",
json: true,
headers: graphHeaders,
auth: {
bearer: authResponse.access_token // AccessToken is only valid for 60 mins
}
});
}
// Could then do raw API calls with an api.get({url: '/blah-blah/whatever'}) using the apiDefaults set in these connect functions.
I hope that helps somewhat.
--Saul
- Mark as New
- Bookmark
- Subscribe
- Mute
- Permalink
- Report Inappropriate Content
I'm not sure I follow all this 100%:
- PowerShell 7 aka PowerShell Core 7 is definitely based on .NET Core - it's the portable version of .NET / PowerShell, runs on Windows, Linux, macOS, starts with version 6.0 and goes up from there. Windows PowerShell 5.1 (and below) rely on Windows .NET Framework (.NET Framework 4.x and below, depending on the version) - runs on Windows OS only.
- The Azure AD Graph is being retired, but the Microsoft Graph has nearly the same functionality. The modules that rely on the AAD Graph are the AzureAD V2 and Msol/MicrosoftOnline/MSOnline V1, and Azure Az modules (of the ones we care about for PartnerCenter module access, as far as I know). The new MsGraph module is likely to include much of that functionality. Exchange Online doesn't need it.
- The Azure Az module is being updated - the intent being that the module will remain the same but the back-end APIs called will be different. So while V7 will have some front-end changes they will be minimized. The Az module also has some User/Group functionality, but not nearly as much as the AzureAD module of course.
- Some aspects of the AzureAD and MSOnline modules will stop working. Namely the License assignment bits.
- I wouldn't be surprised if the MSOnline V1 module stops working entirely since it is already old/deprecated and replaced by the AzureAD V2 module. I know some features are not migrated (yet!!) such as the MFA stuff, but hopefully that is resolved before June.
- The AzureAD V2 module currently needs the AAD Graph but the module isn't dead, as far as I know, so will likely see a new version before June, dropping the features it can no longer perform (License management) and using only the MS Graph on the back-end. Which may mean the front-end interface of the module may change slightly. But it won't work on PowerShell 7, use the MsGraph module for that.
- You can use the MsGraph module with the PartnerCenter module Tokens, as you note. Basically: Connect-MgGraph -AccessToken $graphTok.AccessToken
- You can also use the Invoke-GraphRequest cmdlet (which is in the Microsoft.Graph.Authentication module, so really that's all you need) to connect to any MS Graph API endpoint yourself: Invoke-GraphRequest -Method GET -Uri 'https://graph.microsoft.com/v1.0/Groups/' (remember Disconnect-MgGraph after)
- Or you can use POPS - Plain Ol' PowerShell: Invoke-RestMethod -Headers @{Authorization = "Bearer $($graphTok.AccessToken)"} -Uri 'https://graph.microsoft.com/v1.0/Groups/' -Method GET | select -expand value
- You won't need 2 tokens after, just the 1 MS Graph Token. (or the office365.com for Exch Online or the azure.com one for Azure Az module)
You can also connect using anything that can handle HTTPS requests, such as JavaScript which you could convert to PowerShell if you wanted to raw API access using Invoke-RestMethod. Here's basically how I do it in JavaScript/Node:
const request = require("request-promise")
// This is BASED on our actual code, using a custom api wrapper module. But this code is not going to work as-is.
var apiDefaultsPartnerCenter // Microsoft CSP Partner Portal
function connectPartnerCenter() {
const tenantID = "our-csp-partner-domain.ca"
const authRequest = {
resource: "https://api.partnercenter.microsoft.com",
grant_type: 'refresh_token',
refresh_token: 'super long refresh token, or grab from wherever you store it'
scope: "openid",
client_id: "f7282f04-blah-blah-blah-4798946", // the AzureAD App ID
client_secret: "iTA7-foo-bar-foo-bar-k2iWC" // the AzureAD App Shared Secret
}
const authResponse = api.post({ // api is a custom wrapper for Request, but basically an API POST call
url: "https://login.microsoftonline.com/" + tenantID + "/oauth2/token",
form: authRequest
})
if (authResponse.token_type != "Bearer" && authResponse.scope != "user_impersonation") {
console.log("ERROR Obtaining access_token! The refresh_token may have expired or need to be reacquired. Or the client_secret may have expired.\nThe OAuth results are:\n")
console.log(authResponse)
throw "Token_Type not Bearer or Scope not User_Impersonation."
}
const partnerCenterHeaders = {
'Accept': "application/json; charset=utf-8",
'MS-Contract-Version': "v1",
'MS-PartnerCenter-Application': "Some-Name-For-Your-App",
'X-Locale': "en-US"
}
// Update global variable for future calls to our api module by setting defaults:
apiDefaultsPartnerCenter = request.defaults({
baseUrl: "https://api.partnercenter.microsoft.com/",
json: true,
encoding: 'utf8',
headers: partnerCenterHeaders,
auth: {
bearer: authResponse.access_token // AccessToken is only valid for 60 mins
}
});
}
var apiDefaultsGraphApi // Microsoft Graph API (not the older Azure AD Graph) - uses the SAME AzureAD NativeApp for Auth as PartnerCenter
function connectMsGraphApi() {
const tenantID = "our-csp-partner-domain.ca"
const authRequest = {
resource: "https://graph.microsoft.com",
grant_type: 'refresh_token',
refresh_token: 'super long refresh token, or grab from wherever you store it'
scope: "https://graph.microsoft.com/.default", // Also seems to work as "openid"
client_id: "f7282f04-blah-blah-blah-4798946", // the AzureAD App ID
client_secret: "iTA7-foo-bar-foo-bar-k2iWC" // the AzureAD App Shared Secret
}
const authResponse = api.post({ // api is a custom wrapper for Request, but basically an API POST call
url: "https://login.microsoftonline.com/" + tenantID + "/oauth2/token",
form: authRequest
)
if (authResponse.token_type != "Bearer") {
console.log("ERROR Obtaining Graph API access_token! The refresh_token may have expired or need to be reacquired. Or the client_secret may have expired.\nThe OAuth results are:\n")
console.log(authResponse)
throw "Token_Type not Bearer."
}
const graphHeaders = {
'Accept': "application/json;",
'Host' : "graph.microsoft.com"
}
// Update global variable with BearerToken for future connections, sets defaults for Request. You'd need to handle pagination and such
apiDefaultsGraphApi = request.defaults({
baseUrl: "https://graph.microsoft.com/v1.0/",
json: true,
headers: graphHeaders,
auth: {
bearer: authResponse.access_token // AccessToken is only valid for 60 mins
}
});
}
// Could then do raw API calls with an api.get({url: '/blah-blah/whatever'}) using the apiDefaults set in these connect functions.
I hope that helps somewhat.
--Saul
- Mark as New
- Bookmark
- Subscribe
- Mute
- Permalink
- Report Inappropriate Content
You may be able to get the access token with a raw call to the microsoft graph API. I haven't looked into that, so not sure how awkward that would be, or if it is even possible.
However, are you using the latest PartnerCenter PowerShell module?
https://github.com/microsoft/Partner-Center-PowerShell
it lists compatibility as 'PowerShell Core 6.x and later on all platforms'
The above link may help. Using this module is the easiest way I found to do what I needed.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Permalink
- Report Inappropriate Content
I was trying to figure out how to do the API call but unfortunately the Microsoft Graph module doesn't seem to let you connect with the two different tokens so I'm not sure how you would connect if you manage to get the token.
I'm using the latest version of the PartnerCenter PowerShell module, unfortunately that has a dependency on .net core I believe which is not supported on PowerShell 7. Here is an issue that has been open for a very long time and doesn't like like it's going to be resolved anytime soon:
- Mark as New
- Bookmark
- Subscribe
- Mute
- Permalink
- Report Inappropriate Content
It looks like MSOnline and AzureAD modules will stop working with the secure application model after June 30th 2022 so MgGraph PowerShell is the only option. (or raw API requests)
After some experimentation I have managed to connect to Microsoft Graph Powershell SDK using Kelvin's script available on cyberdrain.com
The below allows connection to MgGraph using the secure application model.
Still testing but seems to work fine. (Might need to add some extra permissions for Microsoft Graph into the app registration possibly for some MgGraph commands? ($graphappaccess))
$ApplicationID = ‘ApplicationID’
$ApplicationSecret = ‘ApplicationSecret’
$TenantID = ‘YourTenantID’
$refreshtoken = ‘LongRefreshToken’
$ApplicationSecretSecure = ConvertTo-SecureString -String $ApplicationSecret -AsPlainText -Force
$credential = New-Object System.Management.Automation.PSCredential($ApplicationId, $ApplicationSecretSecure)
$graphToken = New-PartnerAccessToken -ApplicationId $applicationId -Scopes ‘https://graph.microsoft.com/.default’ -RefreshToken $refreshtoken -Credential $credential -Tenant $tenantID
Connect-MgGraph -AccessToken $graphToken.AccessToken
- Mark as New
- Bookmark
- Subscribe
- Mute
- Permalink
- Report Inappropriate Content
hi Glenndsq,
We are using this solution as well but currently we're having problems with the PartnerCenter Powershell module not working in Powershell 7. Do you know of a way to get the access token without using this module?
