Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue leveraging CredentialsWithApplicationId Authentication Type #1761

Closed
SGalazzo opened this issue Feb 15, 2022 · 11 comments
Closed

Issue leveraging CredentialsWithApplicationId Authentication Type #1761

SGalazzo opened this issue Feb 15, 2022 · 11 comments
Assignees
Labels

Comments

@SGalazzo
Copy link

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

@andikrueger
Copy link
Collaborator

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.

@andikrueger
Copy link
Collaborator

For more details review these examples: https://microsoft365dsc.com/user-guide/cmdlets/Export-M365DSCConfiguration/#examples

@sgalazzo-aba
Copy link

sgalazzo-aba commented Mar 10, 2022

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}

@andikrueger
Copy link
Collaborator

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.

@SGalazzo
Copy link
Author

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.

@ykuijs
Copy link
Member

ykuijs commented Jun 3, 2022

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?

@SGalazzo
Copy link
Author

@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.

@andikrueger andikrueger added Enhancement New feature or request and removed Pending Information labels Jun 20, 2022
@ykuijs
Copy link
Member

ykuijs commented Jul 6, 2022

I am currently working on adding support for multiple authentication methods to the Export functionality. See #1759 (comment) 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!

@SGalazzo
Copy link
Author

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.

@sgalazzo-aba
Copy link

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.

image

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.

@ykuijs
Copy link
Member

ykuijs commented Sep 7, 2022

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

@ykuijs ykuijs closed this as completed Sep 7, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants