Microsoft365DSC
Microsoft365DSC copied to clipboard
Issue leveraging CredentialsWithApplicationId Authentication Type
Details of the scenario you tried and the problem that is occurring
Performing an Export-M365DSCConfiguration
with a credential object and AppId combination, in an attempt to export data via the CredentialsWithApplicationId authentication type, fails with a "Could not determine authentication method"
error.
Verbose logs showing the problem
Import-Module Microsoft365DSC -Force -Verbose
VERBOSE: Removing the imported "Add-M365DSCEvent" function.
VERBOSE: Removing the imported "Add-M365DSCTelemetryEvent" function.
VERBOSE: Removing the imported "Assert-M365DSCBlueprint" function.
VERBOSE: Removing the imported "Confirm-ImportedCmdletIsAvailable" function.
VERBOSE: Removing the imported "Confirm-M365DSCDependencies" function.
VERBOSE: Removing the imported "Convert-M365DscHashtableToString" function.
VERBOSE: Removing the imported "ConvertTo-SPOUserProfilePropertyInstanceString" function.
VERBOSE: Removing the imported "Export-M365DSCConfiguration" function.
VERBOSE: Removing the imported "Export-M365DSCDiagnosticData" function.
VERBOSE: Removing the imported "Format-M365DSCString" function.
VERBOSE: Removing the imported "Format-M365DSCTelemetryParameters" function.
VERBOSE: Removing the imported "Get-AllSPOPackages" function.
VERBOSE: Removing the imported "Get-M365DSCAllResources" function.
VERBOSE: Removing the imported "Get-M365DSCAuthenticationMode" function.
VERBOSE: Removing the imported "Get-M365DSCCompiledPermissionList" function.
VERBOSE: Removing the imported "Get-M365DSCComponentsForAuthenticationType" function.
VERBOSE: Removing the imported "Get-M365DSCExportContentForResource" function.
VERBOSE: Removing the imported "Get-M365DSCOrganization" function.
VERBOSE: Removing the imported "Get-M365DSCTelemetryOption" function.
VERBOSE: Removing the imported "Get-M365DSCTenantDomain" function.
VERBOSE: Removing the imported "Get-M365DSCWorkloadsListFromResourceNames" function.
VERBOSE: Removing the imported "Get-M365TenantName" function.
VERBOSE: Removing the imported "Get-SPOAdministrationUrl" function.
VERBOSE: Removing the imported "Get-SPOUserProfilePropertyInstance" function.
VERBOSE: Removing the imported "Get-TeamByName" function.
VERBOSE: Removing the imported "Import-M365DSCDependencies" function.
VERBOSE: Removing the imported "Install-M365DSCDevBranch" function.
VERBOSE: Removing the imported "Invoke-M365DSCCommand" function.
VERBOSE: Removing the imported "New-EXOSafeAttachmentRule" function.
VERBOSE: Removing the imported "New-EXOSafeLinksRule" function.
VERBOSE: Removing the imported "New-M365DSCCmdletDocumentation" function.
VERBOSE: Removing the imported "New-M365DSCConnection" function.
VERBOSE: Removing the imported "New-M365DSCDeltaReport" function.
VERBOSE: Removing the imported "New-M365DSCLogEntry" function.
VERBOSE: Removing the imported "New-M365DSCReportFromConfiguration" function.
VERBOSE: Removing the imported "New-M365DSCStubFiles" function.
VERBOSE: Removing the imported "Remove-EmptyValue" function.
VERBOSE: Removing the imported "Remove-NullEntriesFromHashtable" function.
VERBOSE: Removing the imported "Save-M365DSCPartialExport" function.
VERBOSE: Removing the imported "Set-EXOSafeAttachmentRule" function.
VERBOSE: Removing the imported "Set-EXOSafeLinksRule" function.
VERBOSE: Removing the imported "Set-M365DSCAgentCertificateConfiguration" function.
VERBOSE: Removing the imported "Set-M365DSCTelemetryOption" function.
VERBOSE: Removing the imported "Split-ArrayByParts" function.
VERBOSE: Removing the imported "Start-M365DSCConfigurationExtract" function.
VERBOSE: Removing the imported "Test-M365DSCAgent" function.
VERBOSE: Removing the imported "Test-M365DSCDependenciesForNewVersions" function.
VERBOSE: Removing the imported "Test-M365DSCNewVersionAvailable" function.
VERBOSE: Removing the imported "Test-M365DSCParameterState" function.
VERBOSE: Removing the imported "Update-M365DSCAllowedGraphScopes" function.
VERBOSE: Removing the imported "Update-M365DSCDependencies" function.
VERBOSE: Removing the imported "Update-M365DSCExportAuthenticationResults" function.
VERBOSE: Removing the imported "Update-M365DSCResourcesSettingsJSON" function.
VERBOSE: Loading module from path 'C:\Users\adminuser\Documents\WindowsPowerShell\Modules\Microsoft365DSC\1.22.209.1\Microsoft365DSC.psd1'.
VERBOSE: Populating RepositorySourceLocation property for module Microsoft365DSC.
VERBOSE: Loading module from path 'C:\Users\adminuser\Documents\WindowsPowerShell\Modules\Microsoft365DSC\1.22.209.1\modules\M365DSCAgent.psm1'.
VERBOSE: Importing function 'Set-M365DSCAgentCertificateConfiguration'.
VERBOSE: Importing function 'Test-M365DSCAgent'.
VERBOSE: Loading module from path 'C:\Users\adminuser\Documents\WindowsPowerShell\Modules\Microsoft365DSC\1.22.209.1\modules\M365DSCErrorHandler.psm1'.
VERBOSE: Importing function 'Save-M365DSCPartialExport'.
VERBOSE: Loading module from path 'C:\Users\adminuser\Documents\WindowsPowerShell\Modules\Microsoft365DSC\1.22.209.1\modules\M365DSCLogEngine.psm1'.
VERBOSE: Importing function 'Add-M365DSCEvent'.
VERBOSE: Importing function 'Export-M365DSCDiagnosticData'.
VERBOSE: Importing function 'New-M365DSCLogEntry'.
VERBOSE: Loading module from path 'C:\Users\adminuser\Documents\WindowsPowerShell\Modules\Microsoft365DSC\1.22.209.1\modules\M365DSCPermissions.psm1'.
VERBOSE: Importing function 'Get-M365DSCCompiledPermissionList'.
VERBOSE: Importing function 'Update-M365DSCAllowedGraphScopes'.
VERBOSE: Importing function 'Update-M365DSCResourcesSettingsJSON'.
VERBOSE: Loading module from path 'C:\Users\adminuser\Documents\WindowsPowerShell\Modules\Microsoft365DSC\1.22.209.1\modules\M365DSCReport.psm1'.
VERBOSE: Importing function 'New-M365DSCDeltaReport'.
VERBOSE: Importing function 'New-M365DSCReportFromConfiguration'.
VERBOSE: Loading module from path 'C:\Users\adminuser\Documents\WindowsPowerShell\Modules\Microsoft365DSC\1.22.209.1\modules\M365DSCReverse.psm1'.
VERBOSE: Importing function 'Start-M365DSCConfigurationExtract'.
VERBOSE: Loading module from path 'C:\Users\adminuser\Documents\WindowsPowerShell\Modules\Microsoft365DSC\1.22.209.1\modules\M365DSCStubsUtility.psm1'.
VERBOSE: Importing function 'New-M365DSCStubFiles'.
VERBOSE: Loading module from path 'C:\Users\adminuser\Documents\WindowsPowerShell\Modules\Microsoft365DSC\1.22.209.1\modules\M365DSCTelemetryEngine.psm1'.
VERBOSE: Importing function 'Add-M365DSCTelemetryEvent'.
VERBOSE: Importing function 'Format-M365DSCTelemetryParameters'.
VERBOSE: Importing function 'Get-M365DSCTelemetryOption'.
VERBOSE: Importing function 'Set-M365DSCTelemetryOption'.
VERBOSE: Loading module from path 'C:\Users\adminuser\Documents\WindowsPowerShell\Modules\Microsoft365DSC\1.22.209.1\modules\M365DSCUtil.psm1'.
VERBOSE: Importing function 'Assert-M365DSCBlueprint'.
VERBOSE: Importing function 'Confirm-ImportedCmdletIsAvailable'.
VERBOSE: Importing function 'Confirm-M365DSCDependencies'.
VERBOSE: Importing function 'Convert-M365DscHashtableToString'.
VERBOSE: Importing function 'ConvertTo-SPOUserProfilePropertyInstanceString'.
VERBOSE: Importing function 'Export-M365DSCConfiguration'.
VERBOSE: Importing function 'Get-AllSPOPackages'.
VERBOSE: Importing function 'Get-M365DSCAllResources'.
VERBOSE: Importing function 'Get-M365DSCAuthenticationMode'.
VERBOSE: Importing function 'Get-M365DSCComponentsForAuthenticationType'.
VERBOSE: Importing function 'Get-M365DSCExportContentForResource'.
VERBOSE: Importing function 'Get-M365DSCOrganization'.
VERBOSE: Importing function 'Get-M365DSCTenantDomain'.
VERBOSE: Importing function 'Get-M365DSCWorkloadsListFromResourceNames'.
VERBOSE: Importing function 'Get-M365TenantName'.
VERBOSE: Importing function 'Get-SPOAdministrationUrl'.
VERBOSE: Importing function 'Get-SPOUserProfilePropertyInstance'.
VERBOSE: Importing function 'Get-TeamByName'.
VERBOSE: Importing function 'Import-M365DSCDependencies'.
VERBOSE: Importing function 'Install-M365DSCDevBranch'.
VERBOSE: Importing function 'Invoke-M365DSCCommand'.
VERBOSE: Importing function 'New-EXOSafeAttachmentRule'.
VERBOSE: Importing function 'New-EXOSafeLinksRule'.
VERBOSE: Importing function 'New-M365DSCCmdletDocumentation'.
VERBOSE: Importing function 'New-M365DSCConnection'.
VERBOSE: Importing function 'Remove-EmptyValue'.
VERBOSE: Importing function 'Remove-NullEntriesFromHashtable'.
VERBOSE: Importing function 'Set-EXOSafeAttachmentRule'.
VERBOSE: Importing function 'Set-EXOSafeLinksRule'.
VERBOSE: Importing function 'Split-ArrayByParts'.
VERBOSE: Importing function 'Test-M365DSCDependenciesForNewVersions'.
VERBOSE: Importing function 'Test-M365DSCNewVersionAvailable'.
VERBOSE: Importing function 'Test-M365DSCParameterState'.
VERBOSE: Importing function 'Update-M365DSCDependencies'.
VERBOSE: Importing function 'Update-M365DSCExportAuthenticationResults'.
VERBOSE: Loading module from path 'C:\Users\adminuser\Documents\WindowsPowerShell\Modules\Microsoft365DSC\1.22.209.1\modules\EncodingHelpers\M365DSCEmojis.psm1'.
VERBOSE: Loading module from path 'C:\Users\adminuser\Documents\WindowsPowerShell\Modules\Microsoft365DSC\1.22.209.1\modules\EncodingHelpers\M365DSCStringEncoding.psm1'.
VERBOSE: Importing function 'Format-M365DSCString'.
VERBOSE: Exporting function 'Set-M365DSCAgentCertificateConfiguration'.
VERBOSE: Exporting function 'Test-M365DSCAgent'.
VERBOSE: Exporting function 'Save-M365DSCPartialExport'.
VERBOSE: Exporting function 'Add-M365DSCEvent'.
VERBOSE: Exporting function 'Export-M365DSCDiagnosticData'.
VERBOSE: Exporting function 'New-M365DSCLogEntry'.
VERBOSE: Exporting function 'Get-M365DSCCompiledPermissionList'.
VERBOSE: Exporting function 'Update-M365DSCAllowedGraphScopes'.
VERBOSE: Exporting function 'Update-M365DSCResourcesSettingsJSON'.
VERBOSE: Exporting function 'New-M365DSCDeltaReport'.
VERBOSE: Exporting function 'New-M365DSCReportFromConfiguration'.
VERBOSE: Exporting function 'Start-M365DSCConfigurationExtract'.
VERBOSE: Exporting function 'New-M365DSCStubFiles'.
VERBOSE: Exporting function 'Add-M365DSCTelemetryEvent'.
VERBOSE: Exporting function 'Format-M365DSCTelemetryParameters'.
VERBOSE: Exporting function 'Get-M365DSCTelemetryOption'.
VERBOSE: Exporting function 'Set-M365DSCTelemetryOption'.
VERBOSE: Exporting function 'Assert-M365DSCBlueprint'.
VERBOSE: Exporting function 'Confirm-ImportedCmdletIsAvailable'.
VERBOSE: Exporting function 'Confirm-M365DSCDependencies'.
VERBOSE: Exporting function 'Convert-M365DscHashtableToString'.
VERBOSE: Exporting function 'ConvertTo-SPOUserProfilePropertyInstanceString'.
VERBOSE: Exporting function 'Export-M365DSCConfiguration'.
VERBOSE: Exporting function 'Get-AllSPOPackages'.
VERBOSE: Exporting function 'Get-M365DSCAllResources'.
VERBOSE: Exporting function 'Get-M365DSCAuthenticationMode'.
VERBOSE: Exporting function 'Get-M365DSCComponentsForAuthenticationType'.
VERBOSE: Exporting function 'Get-M365DSCExportContentForResource'.
VERBOSE: Exporting function 'Get-M365DSCOrganization'.
VERBOSE: Exporting function 'Get-M365DSCTenantDomain'.
VERBOSE: Exporting function 'Get-M365DSCWorkloadsListFromResourceNames'.
VERBOSE: Exporting function 'Get-M365TenantName'.
VERBOSE: Exporting function 'Get-SPOAdministrationUrl'.
VERBOSE: Exporting function 'Get-SPOUserProfilePropertyInstance'.
VERBOSE: Exporting function 'Get-TeamByName'.
VERBOSE: Exporting function 'Import-M365DSCDependencies'.
VERBOSE: Exporting function 'Install-M365DSCDevBranch'.
VERBOSE: Exporting function 'Invoke-M365DSCCommand'.
VERBOSE: Exporting function 'New-EXOSafeAttachmentRule'.
VERBOSE: Exporting function 'New-EXOSafeLinksRule'.
VERBOSE: Exporting function 'New-M365DSCCmdletDocumentation'.
VERBOSE: Exporting function 'New-M365DSCConnection'.
VERBOSE: Exporting function 'Remove-EmptyValue'.
VERBOSE: Exporting function 'Remove-NullEntriesFromHashtable'.
VERBOSE: Exporting function 'Set-EXOSafeAttachmentRule'.
VERBOSE: Exporting function 'Set-EXOSafeLinksRule'.
VERBOSE: Exporting function 'Split-ArrayByParts'.
VERBOSE: Exporting function 'Test-M365DSCDependenciesForNewVersions'.
VERBOSE: Exporting function 'Test-M365DSCNewVersionAvailable'.
VERBOSE: Exporting function 'Test-M365DSCParameterState'.
VERBOSE: Exporting function 'Update-M365DSCDependencies'.
VERBOSE: Exporting function 'Update-M365DSCExportAuthenticationResults'.
VERBOSE: Exporting function 'Format-M365DSCString'.
VERBOSE: Importing function 'Add-M365DSCEvent'.
VERBOSE: Importing function 'Add-M365DSCTelemetryEvent'.
VERBOSE: Importing function 'Assert-M365DSCBlueprint'.
VERBOSE: Importing function 'Confirm-ImportedCmdletIsAvailable'.
VERBOSE: Importing function 'Confirm-M365DSCDependencies'.
VERBOSE: Importing function 'Convert-M365DscHashtableToString'.
VERBOSE: Importing function 'ConvertTo-SPOUserProfilePropertyInstanceString'.
VERBOSE: Importing function 'Export-M365DSCConfiguration'.
VERBOSE: Importing function 'Export-M365DSCDiagnosticData'.
VERBOSE: Importing function 'Format-M365DSCString'.
VERBOSE: Importing function 'Format-M365DSCTelemetryParameters'.
VERBOSE: Importing function 'Get-AllSPOPackages'.
VERBOSE: Importing function 'Get-M365DSCAllResources'.
VERBOSE: Importing function 'Get-M365DSCAuthenticationMode'.
VERBOSE: Importing function 'Get-M365DSCCompiledPermissionList'.
VERBOSE: Importing function 'Get-M365DSCComponentsForAuthenticationType'.
VERBOSE: Importing function 'Get-M365DSCExportContentForResource'.
VERBOSE: Importing function 'Get-M365DSCOrganization'.
VERBOSE: Importing function 'Get-M365DSCTelemetryOption'.
VERBOSE: Importing function 'Get-M365DSCTenantDomain'.
VERBOSE: Importing function 'Get-M365DSCWorkloadsListFromResourceNames'.
VERBOSE: Importing function 'Get-M365TenantName'.
VERBOSE: Importing function 'Get-SPOAdministrationUrl'.
VERBOSE: Importing function 'Get-SPOUserProfilePropertyInstance'.
VERBOSE: Importing function 'Get-TeamByName'.
VERBOSE: Importing function 'Import-M365DSCDependencies'.
VERBOSE: Importing function 'Install-M365DSCDevBranch'.
VERBOSE: Importing function 'Invoke-M365DSCCommand'.
VERBOSE: Importing function 'New-EXOSafeAttachmentRule'.
VERBOSE: Importing function 'New-EXOSafeLinksRule'.
VERBOSE: Importing function 'New-M365DSCCmdletDocumentation'.
VERBOSE: Importing function 'New-M365DSCConnection'.
VERBOSE: Importing function 'New-M365DSCDeltaReport'.
VERBOSE: Importing function 'New-M365DSCLogEntry'.
VERBOSE: Importing function 'New-M365DSCReportFromConfiguration'.
VERBOSE: Importing function 'New-M365DSCStubFiles'.
VERBOSE: Importing function 'Remove-EmptyValue'.
VERBOSE: Importing function 'Remove-NullEntriesFromHashtable'.
VERBOSE: Importing function 'Save-M365DSCPartialExport'.
VERBOSE: Importing function 'Set-EXOSafeAttachmentRule'.
VERBOSE: Importing function 'Set-EXOSafeLinksRule'.
VERBOSE: Importing function 'Set-M365DSCAgentCertificateConfiguration'.
VERBOSE: Importing function 'Set-M365DSCTelemetryOption'.
VERBOSE: Importing function 'Split-ArrayByParts'.
VERBOSE: Importing function 'Start-M365DSCConfigurationExtract'.
VERBOSE: Importing function 'Test-M365DSCAgent'.
VERBOSE: Importing function 'Test-M365DSCDependenciesForNewVersions'.
VERBOSE: Importing function 'Test-M365DSCNewVersionAvailable'.
VERBOSE: Importing function 'Test-M365DSCParameterState'.
VERBOSE: Importing function 'Update-M365DSCAllowedGraphScopes'.
VERBOSE: Importing function 'Update-M365DSCDependencies'.
VERBOSE: Importing function 'Update-M365DSCExportAuthenticationResults'.
VERBOSE: Importing function 'Update-M365DSCResourcesSettingsJSON'.
PS C:\Windows\system32> $date = $(Get-Date -Format 'yyyy-M-dd')
$tenantId = 'REDACTED'
$appId = 'REDACTED'
$adminCredentials = $(Get-Credential)
#
$path = 'C:\temp\'
$fileName = "test.ps1"
$components = @("AADConditionalAccessPolicy")
########################################
PS C:\Windows\system32> Export-M365DSCConfiguration -Credential $adminCredentials -ApplicationId $appId -Components $components -Path $path -FileName $fileName
Updating dependency {MicrosoftTeams} to version {3.1.1}...✅
Connecting to {MicrosoftGraph}...✅
[1/1] Extracting [AADConditionalAccessPolicy]...Could not determine authentication method
Partial Export file was saved at: C:\Users\LOCAL_~4\Temp\756aecc1-3773-4eae-97ae-fa0471c1afa8.partial.ps1
Suggested solution to the issue
The Inbound parameters that get passed down to the underlying code in M365DSCUtil.psm1
contain both the Credential Object and AppId, but due to the nature of how the logic is setup, the code will error out before ever reaching the necessary return statement.
The upper-level elseif
statement checks to ensure there is a credential object, but expects the ApplicationId, TenantId, and CertificateThumbprint to be all null or empty. The nested if
statement (that we are looking to trigger) looks for an "ApplicationId" in the InboundParameters along with that ApplicationId not being empty-- a logic that will never trigger give its positioning within the upper-level elseif
statement stating the ApplicationId should be null or empty.
# Case only Credential is specified
elseif ($null -ne $InboundParameters.Credential -and `
[System.String]::IsNullOrEmpty($InboundParameters.ApplicationId) -and `
[System.String]::IsNullOrEmpty($InboundParameters.TenantId) -and `
[System.String]::IsNullOrEmpty($InboundParameters.CertificateThumbprint))
{
Write-Verbose -Message "Credential was specified. Connecting via User Principal"
if ([System.String]::IsNullOrEmpty($Url))
{...}
if ($InboundParameters.ContainsKey("Credential") -and
$null -ne $InboundParameters.Credential)
{...}
if ($InboundParameters.ContainsKey("ApplicationId") -and
-not [System.String]::IsNullOrEmpty($InboundParameters.ApplicationId))
{
Connect-M365Tenant -Workload $Workload `
-ApplicationId $InboundParameters.ApplicationId `
-Credential $InboundParameters.Credential `
-SkipModuleReload $Global:CurrentModeIsExport `
-ProfileName $ProfileName
$data.Add("ConnectionType", "CredentialsWithApplicationId")
try
{
$tenantId = $InboundParameters.Credential.Username.Split('@')[1]
$data.Add("Tenant", $tenantId)
}
catch
{
Write-Verbose $_
}
Add-M365DSCTelemetryEvent -Data $data -Type "Connection"
return 'CredentialsWithApplicationId'
}
...
...
}
By modifying the default M365DSCUtil.psm1
and moving the previously nested if
statement into a separate elseif
statement with modified logic above allows for the expected behavior.
elseif ($null -ne $InboundParameters.Credential -and -not [System.String]::IsNullOrEmpty($InboundParameters.ApplicationId) ) {
if ($InboundParameters.ContainsKey("ApplicationId") -and -not [System.String]::IsNullOrEmpty($InboundParameters.ApplicationId)) {
Connect-M365Tenant -Workload $Workload `
-ApplicationId $InboundParameters.ApplicationId `
-Credential $InboundParameters.Credential `
-SkipModuleReload $Global:CurrentModeIsExport `
-ProfileName $ProfileName
$data.Add("ConnectionType", "CredentialsWithApplicationId")
try {
$tenantId = $InboundParameters.Credential.Username.Split('@')[1]
$data.Add("Tenant", $tenantId)
}
catch {
Write-Verbose $_
}
Add-M365DSCTelemetryEvent -Data $data -Type "Connection"
return 'CredentialsWithApplicationId'
}
}
Example success after modifying M365DSCUtil.psm1
Connecting to {MicrosoftGraph}...✅
[1/1] Extracting [AADConditionalAccessPolicy]...
|---[1/2] Block Legacy AuthenticationTRIGGERED FIX SECTION
✅
|---[2/2] LockDownGlobalAdmin
✅
⌛ Export took {27 seconds}
As I am not intimately familiar with all of the various authentication types and the logic within the Microsoft365DSC module to accommodate for them, the "fix" provided here may be over simplified. For the case of testing and verifying this issue it does work however, someone more familiar with these layers might be able to propose a more elegant solution.
The operating system the target node is running
OsName : Microsoft Windows Server 2016 Standard OsOperatingSystemSKU : StandardServerEdition OsArchitecture : 64-bit WindowsBuildLabEx : 14393.4583.amd64fre.rs1_release.210730-1850 OsLanguage : en-US OsMuiLanguages : {en-US}
Version of the DSC module that was used ('dev' if using current dev branch)
1.22.119.1 1.22.202.1 1.22.209.1
What kind of authentication are you planning to use? Do you want to authenticate as an Application or a User?
- For Application Authentication you would need to specify the application secret to be used and do not specify the credential object.
- For User Authentication you do not need to specify the credential object and not add the ApplicationId parameter.
Both will not work.
For more details review these examples: https://microsoft365dsc.com/user-guide/cmdlets/Export-M365DSCConfiguration/#examples
The short answer to that question is, I've tried both without success. Each method I have attempted has resulted in a number of issues retrieving some (or all) data due to a combination of access and/or scope issues.
As for the long answer:
We have a large number of tenant environments that we would like to leverage Microsoft365DSC for in order to export their configuration data. Whatever the default Application utilized by Microsoft365DSC on an individual tenant does not have the necessary scopes configured in order to export all of the workflows we are interested in. If this were only one or two clients, then configuring an application within each tenant with the necessary scopes would normally not be a problem, but as we have upwards of 600+ tenant environments that we are looking to target, you can see how this would not really be practical. This lead me to looking into executing a similar workflow to how we are currently exporting tenant data via the GraphAPI, using a combination of the tenants' Global Admin credentials along with an AppId of an administrative application (created on the CSP side) to generate an accessToken/refreshToken pair for each individual tenant for authentication against the GraphAPI. This ideally is the same workflow that the CredentialsWithApplicationId authentication piece is performing (which is present in M365DSCUtil.psm1) but not currently utilized.
Example of Credential based authentication
PS C:\temp> $Credential
UserName Password
-------- --------
[email protected] System.Security.SecureString
Export-M365DSCConfiguration -Components @("AADApplication", "AADConditionalAccessPolicy", "AADGroupsSettings") -Credential $Credential -Path c:\temp -FileName test.ps1
Connecting to {MicrosoftGraph}...✅
[1/3] Extracting [AADApplication]...
❌
[2/3] Extracting [AADConditionalAccessPolicy]...Get-MgIdentityConditionalAccessPolicy : You cannot perform the requested operation, required scopes are missing in the token.
At C:\Users\sgalazzo\Documents\WindowsPowerShell\Modules\Microsoft365DSC\1.22.209.1\DSCResources\MSFT_AADConditionalAccessPolicy\MSFT_AADConditionalAccessPolicy.psm1:1965 char:9
+ [array] $Policies = Get-MgIdentityConditionalAccessPolicy
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: ({ Top = , Skip ...ndProperty = }:<>f__AnonymousType3`8) [Get-MgIdentityC...cessPolicy_List], RestException`1
+ FullyQualifiedErrorId : AccessDenied,Microsoft.Graph.PowerShell.Cmdlets.GetMgIdentityConditionalAccessPolicy_List
✅
[3/3] Extracting [AADGroupsSettings]...Get-MgDirectorySetting : Insufficient privileges to complete the operation.
At C:\Users\sgalazzo\Documents\WindowsPowerShell\Modules\Microsoft365DSC\1.22.209.1\DSCResources\MSFT_AADGroupsSettings\MSFT_AADGroupsSettings.psm1:89 char:9
+ $Policy = Get-MgDirectorySetting | Where-Object -FilterScript ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: ({ Top = , Skip ...ndProperty = }:<>f__AnonymousType25`8) [Get-MgDirectorySetting_List], RestException`1
+ FullyQualifiedErrorId : Authorization_RequestDenied,Microsoft.Graph.PowerShell.Cmdlets.GetMgDirectorySetting_List
✅
⌛ Export took {27 seconds}
Application based authentication Example
PS C:\temp> $AppId
e0202ff0-xxxx-xxxx-xxxx-xxxxxxxxxxxx # Partially Redacted
PS C:\temp> $Password
<REDACTED>
PS C:\temp> Export-M365DSCConfiguration -Mode 'Default' -ApplicationId $AppId -TenantId mechagalazzocapital.onmicrosoft.com -ApplicationSecret $Password -Path c:\temp -FileName test.ps1 -Components @("AADApplication", "AADConditionalAccessPolicy", "AADGroupsSettings")
Connecting to {MicrosoftGraph}...✅
[1/3] Extracting [AADApplication]...
❌
[2/3] Extracting [AADConditionalAccessPolicy]...Get-MgIdentityConditionalAccessPolicy : Applications without a signed-in user are not allowed access to this report or data.
At C:\Users\sgalazzo\Documents\WindowsPowerShell\Modules\Microsoft365DSC\1.22.209.1\DSCResources\MSFT_AADConditionalAccessPolicy\MSFT_AADConditionalAccessPolicy.psm1:1965 char:9
+ [array] $Policies = Get-MgIdentityConditionalAccessPolicy
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: ({ Top = , Skip ...ndProperty = }:<>f__AnonymousType3`8) [Get-MgIdentityC...cessPolicy_List], RestException`1
+ FullyQualifiedErrorId : AccessDenied,Microsoft.Graph.PowerShell.Cmdlets.GetMgIdentityConditionalAccessPolicy_List
✅
[3/3] Extracting [AADGroupsSettings]...Get-MgDirectorySetting : The identity of the calling application could not be established.
At C:\Users\sgalazzo\Documents\WindowsPowerShell\Modules\Microsoft365DSC\1.22.209.1\DSCResources\MSFT_AADGroupsSettings\MSFT_AADGroupsSettings.psm1:89 char:9
+ $Policy = Get-MgDirectorySetting | Where-Object -FilterScript ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: ({ Top = , Skip ...ndProperty = }:<>f__AnonymousType25`8) [Get-MgDirectorySetting_List], RestException`1
+ FullyQualifiedErrorId : Authorization_IdentityNotFound,Microsoft.Graph.PowerShell.Cmdlets.GetMgDirectorySetting_List
✅
⌛ Export took {24 seconds}
Thank you for the additional details on this topic.
CredentialsWithApplicationId is supported for MS Graph cmdLets. All other workloads that do not use Microsoft graph would fall back to using user authentication.
When registering your custom AAD Application you would need to request certain permissions for accessing the Microsoft Graph.
If you do not specify an application ID, the default MS Graph PowerShell Application ID would be used. You can request the necessary permission for the graph api by calling Update-M365DSCAllowedGraphScopes with the matching parameters. Basically you would need to do this or your custom application too.
Thanks for the follow up Andi. I appreciate the help here, but I apologize and hope you can bare with me as I am still a bit confused as to what workflows are actually supported and how these differ from what I am trying to do...
Based on what you said in your previous message, the CredentialsWithApplicationId authentication IS supported, but only workflows that utilize MS Graph cmdlets. Any other specified workflows that are included in the export command that do not use the MS Graph cmdlets should fallback to user authentication utilizing the credential object specified to complete the export of said workflow(s).
If these statements are accurate, then what I am attempting to do should work, as I am supplying a valid set of Global Admin credentials along with an AppId corresponding to a custom application which has the necessary permissions/scopes configured. Ideally, this should be no different than if the default MS Graph PowerShell App was used (assuming it was setup with the necessary scopes) except I am including the AppId in the command which seems to take the logic for a spin attempting to figure out what authentication method should be used, which ultimately fails and hence the error in my first post:
Export-M365DSCConfiguration -Credential $adminCredentials -ApplicationId $appId -Components $components -Path $path -FileName $fileName
Updating dependency {MicrosoftTeams} to version {3.1.1}...✅
Connecting to {MicrosoftGraph}...✅
[1/1] Extracting [AADConditionalAccessPolicy]...Could not determine authentication method
Based on what you have said, along with how the logic setup to handle this authentication method in M365DSCUtil.psm1, is this something that will only work currently when no AppId is provided? In other words, is this only "supported" when the default MS Graph PowerShell App is used and not a custom application...?
If this is indeed the case, then supporting the use of a custom application should be a simple add as the only real difference here are would be the logic specifying what information is passed off to the MSCloudLoginAssistant to generate the accessToken for MS Graph.
Hi @SGalazzo, so if I understand correctly: Right now the code only allows you to specify one authentication method, either Credentials or Service Principals. If you specify both, the code will throw an error.
Your suggestion is to allow both to be specified and the code first exporting the resources using the Service Principal, filtering out resources that don't support that option. And then continue with those resources, using the specified Credentials.
Am I correct?
@ykuijs, yes that is correct.
I believe many individuals will find themselves situations where they will be interested in exporting a combination of data and settings for various resources just to find themselves unable to do because of the provided authentication method(s). This would then require multiple differing commands to be executed in order to query all relevant information and then consolidation of the data would have to be done leading to more overhead and administrative burden. This would especially be true if you are looking to do this on a substantial number of tenant instances, so by supporting multiple authentications I believe this could save people a lot of headaches.
I am currently working on adding support for multiple authentication methods to the Export functionality. See https://github.com/microsoft/Microsoft365DSC/issues/1759#issuecomment-1175910359 for more information. Currently testing some last items before I can create the PR.
@SGalazzo, do you have the possibility to help test these updates using the following test version of Microsoft365DSC: Microsoft365DSC_v1.22.629.1_UpdatedExport.zip
If so:
- Download this file and extract it to C:\Program Files\WindowsPowerShell\Modules\Microsoft365DSC (make sure you also include the version folder that exists in the ZIP file)
- Run different exports using several different resource and authentication methods
- Check if the exports run successfully and without issues and if the created exports are using the correct authentication methods.
Let me know if you encounter any issues/bugs/errors/etc!
My apologies, I just recently had to recreate my lab environment as part of some other on-going projects so I am a little late getting back to this. Thank you @ykuijs that is great news! I'm very excited!
As for testing, I can definitely help assist. I have downloaded the test version provided and will look to perform some tests between this week & next to provide any feedback.
Just a bit of an update to keep the channel here open; I have done a bit of testing with the provided version and have noticed a few things... Unfortunately however, I will likely have to make a follow-up post here with the details, but for now I wanted to at least provide some sort of update.
In my on and off testing I noticed the logic seemingly working generally well for picking the best matched authentication method based on the resource and available methods, but it still seems like the logic contained within the New-M365DSCConnection function located in the M365DSCUtil.psm1 for determining the available methods based on the input parameters seems flawed (at least as far as some of the GraphAPI calls go).
At a high level, what I am is seeing is when you supply Credentials, TenantId, ApplicationId, and an ApplicationSecret, the logic taken once the code reaches the New-M365DSCConnection command will lose the Credentials from $InboundParameters and only contain TenantID, AppId, and Application secret thus resulting in the ServicePrincipalWithSecret method being selected.
While this is a problem, this also is separate from the initial issues I had where CredentialsWithApplicationId would never be selected as an authentication type due to the way the logic is written in the New-M365DSCConnection command as the upper level elseif statement it is encapsulated if Credentials are present and ApplicationId is missing where as it expects the ApplicationId to present.
I apologize again for the minimal detail here, but I will try and get a follow-up with some more code-snippets and screenshots soon to help provide some more insight.
The improved Export method has been merged in PR #2230 and is include in v1.22.831.1. With that change you can specify multiple authentication methods and the code picks the most secure one supported by each resource and uses that to export the resource. Please go ahead and test if this now works for you.
Closing this issue now