From f4c758c6e21a23773532334ea839b8be70d7996d Mon Sep 17 00:00:00 2001 From: Gert Van Der Heyden Date: Fri, 20 Sep 2024 15:15:22 +0200 Subject: [PATCH 01/13] added EmailValue option to use user principal name as email too --- d365fo.tools/functions/import-d365aaduser.ps1 | 37 ++++++++++++++----- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/d365fo.tools/functions/import-d365aaduser.ps1 b/d365fo.tools/functions/import-d365aaduser.ps1 index abf0ea94..5869e85d 100644 --- a/d365fo.tools/functions/import-d365aaduser.ps1 +++ b/d365fo.tools/functions/import-d365aaduser.ps1 @@ -63,6 +63,12 @@ .PARAMETER AadGroupId Azure Active directory user group ID containing users to be imported + .PARAMETER EmailValue + Specify which field to use as EMAIL value when importing the users. + Available options 'Mail' / 'UserPrincipalName' + + Default is 'Mail' + .EXAMPLE PS C:\> Import-D365AadUser -Users "Claire@contoso.com","Allen@contoso.com" @@ -164,7 +170,11 @@ function Import-D365AadUser { [switch] $ForceExactAadGroupName, [Parameter(Mandatory = $true, Position = 14, ParameterSetName = "GroupIdImport")] - [string] $AadGroupId + [string] $AadGroupId, + + [Parameter(Mandatory = $false, Position = 15)] + [ValidateSet('Mail', 'UserPrincipalName')] + [string] $EmailValue = "Mail" ) $UseTrustedConnection = Test-TrustedConnection $PSBoundParameters @@ -253,10 +263,11 @@ function Import-D365AadUser { if ($SkipAzureAd -eq $true) { $name = Get-LoginFromEmail $user $null = $azureAdUsers.Add([PSCustomObject]@{ - Mail = $user - GivenName = $name - DisplayName = $name - ObjectId = '' + Mail = $user + GivenName = $name + DisplayName = $name + ObjectId = '' + UserPrincipalName = $user }) } else { @@ -324,14 +335,22 @@ function Import-D365AadUser { if ($NameValue -eq 'DisplayName') { $name = $user.DisplayName + $NameSuffix } - else { $name = $user.GivenName + $NameSuffix } - Write-PSFMessage -Level Verbose -Message "Name for user $($user.Mail) : $name" - Write-PSFMessage -Level Verbose -Message "Importing $($user.Mail) - SID $sid - Provider $identityProvider" - Import-AadUserIntoD365FO $SqlCommand $user.Mail $name $id $sid $StartupCompany $identityProvider $networkDomain $user.ObjectId + $email = "" + if ($EmailValue -eq 'Mail') { + $email = $user.Mail + } + else { + $email = $user.UserPrincipalName + } + + Write-PSFMessage -Level Verbose -Message "Name for user $email : $name" + Write-PSFMessage -Level Verbose -Message "Importing $email - SID $sid - Provider $identityProvider" + + Import-AadUserIntoD365FO $SqlCommand $email $name $id $sid $StartupCompany $identityProvider $networkDomain $user.ObjectId if (Test-PSFFunctionInterrupt) { return } } From c8b621a6b6bc1fc0841ed4f981215509cb305b76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=B6tz=20Jensen?= Date: Mon, 23 Sep 2024 18:39:42 +0200 Subject: [PATCH 02/13] add Import-D365AadUser V2 version add in https://github.com/d365collaborative/d365fo.tools/issues/856#issuecomment-2368169697 --- d365fo.tools/functions/import-d365aaduser.ps1 | 63 +++++++++++++------ 1 file changed, 44 insertions(+), 19 deletions(-) diff --git a/d365fo.tools/functions/import-d365aaduser.ps1 b/d365fo.tools/functions/import-d365aaduser.ps1 index 5869e85d..d7d0946f 100644 --- a/d365fo.tools/functions/import-d365aaduser.ps1 +++ b/d365fo.tools/functions/import-d365aaduser.ps1 @@ -192,11 +192,11 @@ function Import-D365AadUser { Write-PSFMessage -Level Verbose -Message "Trying to connect to the Azure Active Directory" if ($PSBoundParameters.ContainsKey("AzureAdCredential") -eq $true) { - $null = Connect-AzureAD -ErrorAction Stop -Credential $AzureAdCredential + Login-AzAccount -Credential $AzureAdCredential -ErrorAction Stop } else { if ($SkipAzureAd -eq $false) { - $null = Connect-AzureAD -ErrorAction Stop + Login-AzAccount -ErrorAction Stop } } } @@ -212,16 +212,31 @@ function Import-D365AadUser { if ($PSCmdlet.ParameterSetName -eq 'GroupIdImport') { Write-PSFMessage -Level Verbose -Message "Search AadGroup by its ID : $AadGroupId" - $group = Get-AzureADGroup -ObjectId $AadGroupId + + $resObj = Invoke-AzRestMethod -Uri "https://graph.microsoft.com/v1.0/groups/$AadGroupId" + + if ($resObj.StatusCode -like "2**") { + $group = $resObj.Content | ConvertFrom-Json + } } else { if ($ForceExactAadGroupName) { Write-PSFMessage -Level Verbose -Message "Search AadGroup by its exactly name : $AadGroupName" - $group = Get-AzureADGroup -Filter "DisplayName eq '$AadGroupName'" + + $resObj = Invoke-AzRestMethod -Uri "https://graph.microsoft.com/v1.0/groups?`$filter=DisplayName eq '$AadGroupName'" + + if ($resObj.StatusCode -like "2**") { + $group = $resObj.Content | ConvertFrom-Json | Select-Object -ExpandProperty value + } } else { Write-PSFMessage -Level Verbose -Message "Search AadGroup by searching with its name : $AadGroupName" - $group = Get-AzureADGroup -SearchString $AadGroupName + + $resObj = Invoke-AzRestMethod -Uri "https://graph.microsoft.com/v1.0/groups?`$filter=startswith(DisplayName,'$AadGroupName')" + + if ($resObj.StatusCode -like "2**") { + $group = $resObj.Content | ConvertFrom-Json | Select-Object -ExpandProperty value + } } } @@ -243,16 +258,22 @@ function Import-D365AadUser { return } - $userlist = Get-AzureADGroupMember -ObjectId $group[0].ObjectId + $resMembersObj = Invoke-AzRestMethod -Uri "https://graph.microsoft.com/v1.0/groups/$($group.id)/members" + + if ($resMembersObj.StatusCode -like "2**") { + $userlist = $resMembersObj.Content | ConvertFrom-Json | Select-Object -ExpandProperty value + } foreach ($user in $userlist) { - if ($user.ObjectType -eq "User") { - $azureAdUser = Get-AzureADUser -ObjectId $user.ObjectId - if ($null -eq $azureAdUser.Mail) { + if ($user.'@odata.type' -eq "#microsoft.graph.user") { + + $azureAdUser = Invoke-AzRestMethod -Uri "https://graph.microsoft.com/v1.0/users/$($user.id)" + + if ($null -eq $azureAdUser.mail) { Write-PSFMessage -Level Critical "User $($user.ObjectId) did not have an Mail" } else { - $null = $azureAdUsers.Add((Get-AzureADUser -ObjectId $user.ObjectId)) + $null = $azureAdUsers.Add($azureAdUser) } } } @@ -263,15 +284,19 @@ function Import-D365AadUser { if ($SkipAzureAd -eq $true) { $name = Get-LoginFromEmail $user $null = $azureAdUsers.Add([PSCustomObject]@{ - Mail = $user - GivenName = $name - DisplayName = $name - ObjectId = '' - UserPrincipalName = $user + mail = $user + givenName = $name + displayName = $name + ObjectId = '' + userPrincipalName = $user }) } else { - $aadUser = Get-AzureADUser -SearchString $user + $resObj = Invoke-AzRestMethod -Uri "https://graph.microsoft.com/v1.0/users?`$filter=mail eq '$user' or userPrincipalName eq '$user'" + + if ($resObj.StatusCode -like "2**") { + $aadUser = $resObj.Content | ConvertFrom-Json | Select-Object -ExpandProperty value | Select-Object -First 1 + } if ($null -eq $aadUser) { Write-PSFMessage -Level Critical "Could not find user $user in AzureAAd" @@ -316,7 +341,7 @@ function Import-D365AadUser { if ($IdValue -eq 'Login') { $id = $IdPrefix + $(Get-LoginFromEmail $user.Mail) } - elseif($IdValue -eq 'UserPrincipalName') { + elseif ($IdValue -eq 'UserPrincipalName') { $id = $IdPrefix + $user.UserPrincipalName } else { @@ -325,11 +350,10 @@ function Import-D365AadUser { if ($id.Length -gt 20) { $oldId = $id - $id = $id -replace '^(.{0,20}).*','$1' + $id = $id -replace '^(.{0,20}).*', '$1' Write-PSFMessage -Level Host -Message "The id '$oldId' does not fit the 20 character limit on UserInfo table's ID field and will be truncated to '$id'" } - Write-PSFMessage -Level Verbose -Message "Id for user $($user.Mail) : $id" $name = "" if ($NameValue -eq 'DisplayName') { @@ -347,6 +371,7 @@ function Import-D365AadUser { $email = $user.UserPrincipalName } + Write-PSFMessage -Level Verbose -Message "Id for user $email : $id" Write-PSFMessage -Level Verbose -Message "Name for user $email : $name" Write-PSFMessage -Level Verbose -Message "Importing $email - SID $sid - Provider $identityProvider" From 5168329a5ab6c30fd57eec74b4a0ef58eab41f21 Mon Sep 17 00:00:00 2001 From: Florian Hopfner Date: Tue, 24 Sep 2024 18:15:40 +0200 Subject: [PATCH 03/13] add tenant id parameter --- d365fo.tools/functions/import-d365aaduser.ps1 | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/d365fo.tools/functions/import-d365aaduser.ps1 b/d365fo.tools/functions/import-d365aaduser.ps1 index d7d0946f..0211b5e0 100644 --- a/d365fo.tools/functions/import-d365aaduser.ps1 +++ b/d365fo.tools/functions/import-d365aaduser.ps1 @@ -174,7 +174,9 @@ function Import-D365AadUser { [Parameter(Mandatory = $false, Position = 15)] [ValidateSet('Mail', 'UserPrincipalName')] - [string] $EmailValue = "Mail" + [string] $EmailValue = "Mail", + + [string] $TenantId ) $UseTrustedConnection = Test-TrustedConnection $PSBoundParameters @@ -192,11 +194,11 @@ function Import-D365AadUser { Write-PSFMessage -Level Verbose -Message "Trying to connect to the Azure Active Directory" if ($PSBoundParameters.ContainsKey("AzureAdCredential") -eq $true) { - Login-AzAccount -Credential $AzureAdCredential -ErrorAction Stop + Login-AzAccount -Credential $AzureAdCredential -ErrorAction Stop -TenantId $TenantId } else { if ($SkipAzureAd -eq $false) { - Login-AzAccount -ErrorAction Stop + Login-AzAccount -ErrorAction Stop -TenantId $TenantId } } } From 26b2eac499d8c9d2a2f132bd0a90e15a8c9fc5ec Mon Sep 17 00:00:00 2001 From: Florian Hopfner Date: Thu, 3 Oct 2024 12:24:47 +0200 Subject: [PATCH 04/13] add TenantId variable --- d365fo.tools/internal/scripts/variables.ps1 | 1 + 1 file changed, 1 insertion(+) diff --git a/d365fo.tools/internal/scripts/variables.ps1 b/d365fo.tools/internal/scripts/variables.ps1 index 4bcd088f..7320cf52 100644 --- a/d365fo.tools/internal/scripts/variables.ps1 +++ b/d365fo.tools/internal/scripts/variables.ps1 @@ -39,6 +39,7 @@ Update-ModuleVariables $environment = Get-ApplicationEnvironment $Script:AOSPath = $environment.Aos.AppRoot +$Script:TenantId = $environment.Aad.TenantDomainGUID $dataAccess = $environment.DataAccess From 569fc0360f52345a69a3968be82a434798a59fd3 Mon Sep 17 00:00:00 2001 From: Florian Hopfner Date: Thu, 3 Oct 2024 12:25:13 +0200 Subject: [PATCH 05/13] improve environment variables structure --- d365fo.tools/internal/scripts/variables.ps1 | 45 ++++++++++++--------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/d365fo.tools/internal/scripts/variables.ps1 b/d365fo.tools/internal/scripts/variables.ps1 index 7320cf52..d11d21ab 100644 --- a/d365fo.tools/internal/scripts/variables.ps1 +++ b/d365fo.tools/internal/scripts/variables.ps1 @@ -36,56 +36,61 @@ $Script:MRConfigFile = 'C:\FinancialReporting\Server\ApplicationService\bin\MRSe #Update all module variables Update-ModuleVariables +# Environment variables $environment = Get-ApplicationEnvironment -$Script:AOSPath = $environment.Aos.AppRoot $Script:TenantId = $environment.Aad.TenantDomainGUID -$dataAccess = $environment.DataAccess +$aos = $environment.Aos +$Script:AOSPath = $aos.AppRoot +$Script:PackageDirectory = $aos.PackageDirectory +$Script:MetaDataDir = $aos.MetadataDirectory +$dataAccess = $environment.DataAccess $Script:DatabaseServer = $dataAccess.DbServer - $Script:DatabaseName = $dataAccess.Database +$Script:DatabaseUserName = $dataAccess.SqlUser +$Script:DatabaseUserPassword = $dataAccess.SqlPwd -$Script:BinDir = $environment.Common.BinDir - -$Script:PackageDirectory = $environment.Aos.PackageDirectory - -$Script:MetaDataDir = $environment.Aos.MetadataDirectory - -$Script:BinDirTools = $environment.Common.DevToolsBinDir +$common = $environment.Common +$Script:BinDir = $common.BinDir +$Script:BinDirTools = $common.DevToolsBinDir +$Script:IsOnebox = $common.IsOneboxEnvironment $Script:ServerRole = [ServerRole]::Unknown -$RoleVaule = $(If ($environment.Monitoring.MARole -eq "" -or $environment.Monitoring.MARole -eq "dev") { "Development" } Else { $environment.Monitoring.MARole }) - +$RoleVaule = $( + If ($environment.Monitoring.MARole -eq "" -or $environment.Monitoring.MARole -eq "dev") { + "Development" + } Else { + $environment.Monitoring.MARole + } +) if ($null -ne $RoleVaule) { $Script:ServerRole = [ServerRole][Enum]::Parse([type]"ServerRole", $RoleVaule, $true); } +$infrastructure = $environment.Infrastructure $Script:EnvironmentType = [EnvironmentType]::Unknown $Script:CanUseTrustedConnection = $false -if ($environment.Infrastructure.HostName -like "*cloud.onebox.dynamics.com*") { +if ($infrastructure.HostName -like "*cloud.onebox.dynamics.com*") { $Script:EnvironmentType = [EnvironmentType]::LocalHostedTier1 $Script:CanUseTrustedConnection = $true } -elseif ($environment.Infrastructure.HostName -match "(cloudax|axcloud).*dynamics.com") { +elseif ($infrastructure.HostName -match "(cloudax|axcloud).*dynamics.com") { $Script:EnvironmentType = [EnvironmentType]::AzureHostedTier1 $Script:CanUseTrustedConnection = $true } -elseif ($environment.Infrastructure.HostName -like "*sandbox.ax.dynamics.com*") { +elseif ($infrastructure.HostName -like "*sandbox.ax.dynamics.com*") { $Script:EnvironmentType = [EnvironmentType]::MSHostedTier1 $Script:CanUseTrustedConnection = $true } -elseif ($environment.Infrastructure.HostName -like "*sandbox.operations.*dynamics.com*") { +elseif ($infrastructure.HostName -like "*sandbox.operations.*dynamics.com*") { $Script:EnvironmentType = [EnvironmentType]::MSHostedTier2 } +$Script:Url = $infrastructure.HostUrl -$Script:Url = $environment.Infrastructure.HostUrl -$Script:DatabaseUserName = $dataAccess.SqlUser -$Script:DatabaseUserPassword = $dataAccess.SqlPwd $Script:Company = "DAT" -$Script:IsOnebox = $environment.Common.IsOneboxEnvironment $RegSplat = @{ Path = "HKLM:\SOFTWARE\Microsoft\Dynamics\Deployment\" From e542b1cf87bfb40c589f2fefca99c1ed244245c1 Mon Sep 17 00:00:00 2001 From: Florian Hopfner Date: Thu, 3 Oct 2024 12:29:29 +0200 Subject: [PATCH 06/13] provide default tenant id --- d365fo.tools/functions/import-d365aaduser.ps1 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/d365fo.tools/functions/import-d365aaduser.ps1 b/d365fo.tools/functions/import-d365aaduser.ps1 index 0211b5e0..b59fb2c0 100644 --- a/d365fo.tools/functions/import-d365aaduser.ps1 +++ b/d365fo.tools/functions/import-d365aaduser.ps1 @@ -176,7 +176,8 @@ function Import-D365AadUser { [ValidateSet('Mail', 'UserPrincipalName')] [string] $EmailValue = "Mail", - [string] $TenantId + [Parameter(Mandatory = $false, Position = 16)] + [string] $TenantId = $Script:TenantId ) $UseTrustedConnection = Test-TrustedConnection $PSBoundParameters From 218e9609e0ef8d398521cd39f2379375619bd902 Mon Sep 17 00:00:00 2001 From: Florian Hopfner Date: Thu, 3 Oct 2024 12:56:25 +0200 Subject: [PATCH 07/13] remove AzureAD dependency resolves #744 --- .github/workflows/dependencies.yml | 5 ----- build/vsts-prerequisites.ps1 | 2 +- build/vsts-validate-psscriptanalyzer.ps1 | 2 +- build/vsts-validate.ps1 | 2 +- d365fo.tools/d365fo.tools.psd1 | 1 - 5 files changed, 3 insertions(+), 9 deletions(-) diff --git a/.github/workflows/dependencies.yml b/.github/workflows/dependencies.yml index 1e6a0c66..ef06655b 100644 --- a/.github/workflows/dependencies.yml +++ b/.github/workflows/dependencies.yml @@ -14,11 +14,6 @@ jobs: uses: PowershellFrameworkCollective/psframework@32c18f13173be8cc6b6803c63c40b9d7ab5aec12 # version 1.0.12 - name: Azure.Storage uses: Azure/azure-powershell@v4.4.0-September2017 # unclear which commit/tag corresponds to https://www.powershellgallery.com/packages/Azure.Storage/4.4.0 - # AzureAd does not seem to have a public GitHub repository - # - name: AzureAd - # uses: - - name: PSNotification - uses: Splaxi/PSNotification@b344c3dfdb04db1a338f203d1a0c5ae72d67ae89 # version 0.5.3 - name: PSOAuthHelper uses: Splaxi/PSOAuthHelper@837a2da63bf76e86f339a4e43e38df5a3b82affe # version 0.3.0 - name: ImportExcel diff --git a/build/vsts-prerequisites.ps1 b/build/vsts-prerequisites.ps1 index 68dda50d..19149705 100644 --- a/build/vsts-prerequisites.ps1 +++ b/build/vsts-prerequisites.ps1 @@ -2,7 +2,7 @@ Write-Host "The user running is: $($env:UserName)" # $modules = @("PSFramework", "Az.Storage", "AzureAd", "PSNotification", "PSOAuthHelper", "PowerShellGet", "PackageManagement","ImportExcel","PSScriptAnalyzer") -$modules = @("PSFramework", "PSScriptAnalyzer", "Az.Storage", "AzureAd", "PSNotification", "PSOAuthHelper", "ImportExcel") +$modules = @("PSFramework", "PSScriptAnalyzer", "Az.Storage", "PSOAuthHelper", "ImportExcel") Install-Module "Pester" -MaximumVersion 4.99.99 -Force -Confirm:$false -Scope CurrentUser -AllowClobber -SkipPublisherCheck diff --git a/build/vsts-validate-psscriptanalyzer.ps1 b/build/vsts-validate-psscriptanalyzer.ps1 index 98892d91..d3ae8474 100644 --- a/build/vsts-validate-psscriptanalyzer.ps1 +++ b/build/vsts-validate-psscriptanalyzer.ps1 @@ -14,7 +14,7 @@ Write-Host "Working on the machine named: $($env:computername)" Write-Host "The user running is: $($env:UserName)" -$modules = @("PSFramework", "PSScriptAnalyzer", "Az.Storage", "AzureAd", "PSNotification", "PSOAuthHelper", "ImportExcel") +$modules = @("PSFramework", "PSScriptAnalyzer", "Az.Storage", "PSOAuthHelper", "ImportExcel") foreach ($item in $modules) { $module = Get-Module -Name $item -ErrorAction SilentlyContinue diff --git a/build/vsts-validate.ps1 b/build/vsts-validate.ps1 index e17d06b2..80a1f362 100644 --- a/build/vsts-validate.ps1 +++ b/build/vsts-validate.ps1 @@ -17,7 +17,7 @@ Write-Host "Working on the machine named: $($env:computername)" Write-Host "The user running is: $($env:UserName)" -$modules = @("PSFramework", "PSScriptAnalyzer", "Az.Storage", "AzureAd", "PSNotification", "PSOAuthHelper", "ImportExcel") +$modules = @("PSFramework", "PSScriptAnalyzer", "Az.Storage", "PSOAuthHelper", "ImportExcel") foreach ($item in $modules) { $module = Get-Module -Name $item -ErrorAction SilentlyContinue diff --git a/d365fo.tools/d365fo.tools.psd1 b/d365fo.tools/d365fo.tools.psd1 index 42054bbb..7acdeb3e 100644 --- a/d365fo.tools/d365fo.tools.psd1 +++ b/d365fo.tools/d365fo.tools.psd1 @@ -30,7 +30,6 @@ RequiredModules = @( @{ ModuleName = 'PSFramework'; ModuleVersion = '1.0.12' } , @{ ModuleName = 'Az.Storage'; ModuleVersion = '1.11.0' } - , @{ ModuleName = 'AzureAd'; ModuleVersion = '2.0.1.16' } , @{ ModuleName = 'PSOAuthHelper'; ModuleVersion = '0.3.0' } , @{ ModuleName = 'ImportExcel'; ModuleVersion = '7.1.0' } ) From 5a07a68396addc3cdc7a4615ad4998fe0c9e7244 Mon Sep 17 00:00:00 2001 From: Florian Hopfner Date: Thu, 3 Oct 2024 13:39:54 +0200 Subject: [PATCH 08/13] add cmdlet authors --- d365fo.tools/functions/import-d365aaduser.ps1 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/d365fo.tools/functions/import-d365aaduser.ps1 b/d365fo.tools/functions/import-d365aaduser.ps1 index b59fb2c0..1061b8c7 100644 --- a/d365fo.tools/functions/import-d365aaduser.ps1 +++ b/d365fo.tools/functions/import-d365aaduser.ps1 @@ -112,6 +112,8 @@ Author: Charles Colombel (@dropshind) Author: Mötz Jensen (@Splaxi) Author: Miklós Molnár (@scifimiki) + Author: Gert Van der Heyden (@gertvdh) + Author: Florian Hopfner (@FH-Inway) At no circumstances can this cmdlet be used to import users into a PROD environment. From 2d200f40f6b686dd9753a53137694d0ee84e9e6a Mon Sep 17 00:00:00 2001 From: Florian Hopfner Date: Thu, 3 Oct 2024 13:43:13 +0200 Subject: [PATCH 09/13] add -TenantId parameter documentation and example --- d365fo.tools/functions/import-d365aaduser.ps1 | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/d365fo.tools/functions/import-d365aaduser.ps1 b/d365fo.tools/functions/import-d365aaduser.ps1 index 1061b8c7..c1e74905 100644 --- a/d365fo.tools/functions/import-d365aaduser.ps1 +++ b/d365fo.tools/functions/import-d365aaduser.ps1 @@ -68,6 +68,11 @@ Available options 'Mail' / 'UserPrincipalName' Default is 'Mail' + + .PARAMETER TenantId + The TenantId to use when connecting to Azure Active Directory + + Uses the tenant id of the current environment if not specified. .EXAMPLE PS C:\> Import-D365AadUser -Users "Claire@contoso.com","Allen@contoso.com" @@ -104,6 +109,12 @@ Imports Claire and Allen as users. Will NOT make you connect to the Azure Active Directory(AAD). The needed details will be based on the e-mail address only, and the rest will be blanked. + + .EXAMPLE + PS C:\> Import-D365AadUser -Users "Claire@contoso.com","Allen@contoso.com" -TenantId "99999999-aaaa-bbbb-cccc-9999999999" + + Imports Claire and Allen as users. Uses tenant id "99999999-aaaa-bbbb-cccc-9999999999" + when connecting to Azure Active Directory(AAD). .NOTES Tags: User, Users, Security, Configuration, Permission, AAD, Azure Active Directory, Group, Groups From 2b59419f624c4c920bc26fdcb609df4374d1b740 Mon Sep 17 00:00:00 2001 From: Florian Hopfner Date: Thu, 3 Oct 2024 14:02:20 +0200 Subject: [PATCH 10/13] add tenant id debug information --- d365fo.tools/functions/import-d365aaduser.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/d365fo.tools/functions/import-d365aaduser.ps1 b/d365fo.tools/functions/import-d365aaduser.ps1 index c1e74905..417166c8 100644 --- a/d365fo.tools/functions/import-d365aaduser.ps1 +++ b/d365fo.tools/functions/import-d365aaduser.ps1 @@ -205,7 +205,7 @@ function Import-D365AadUser { $canonicalProvider = Get-CanonicalIdentityProvider try { - Write-PSFMessage -Level Verbose -Message "Trying to connect to the Azure Active Directory" + Write-PSFMessage -Level Verbose -Message "Trying to connect to the Azure Active Directory with tenant id '$TenantId'" if ($PSBoundParameters.ContainsKey("AzureAdCredential") -eq $true) { Login-AzAccount -Credential $AzureAdCredential -ErrorAction Stop -TenantId $TenantId From 3526b72877a1ba4d5d0271bfeefe4397dd26ba2c Mon Sep 17 00:00:00 2001 From: FH-Inway Date: Fri, 8 Nov 2024 17:41:08 +0000 Subject: [PATCH 11/13] =?UTF-8?q?=F0=9F=A4=96=20Fix=20best=20practice=20de?= =?UTF-8?q?viations?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This pull request was automatically created by the d365fo.tools-Generate-Text action' --- d365fo.tools/bin/d365fo.tools-index.json | 20 ++++++- d365fo.tools/functions/import-d365aaduser.ps1 | 8 +-- .../functions/Import-D365AadUser.Tests.ps1 | 32 ++++++++++-- docs/Import-D365AadUser.md | 52 +++++++++++++++++-- 4 files changed, 100 insertions(+), 12 deletions(-) diff --git a/d365fo.tools/bin/d365fo.tools-index.json b/d365fo.tools/bin/d365fo.tools-index.json index 5e1f0819..d89e5add 100644 --- a/d365fo.tools/bin/d365fo.tools-index.json +++ b/d365fo.tools/bin/d365fo.tools-index.json @@ -5404,6 +5404,22 @@ true, "false", "" + ], + [ + "EmailValue", + "Specify which field to use as EMAIL value when importing the users.\r\nAvailable options \u0027Mail\u0027 / \u0027UserPrincipalName\u0027\nDefault is \u0027Mail\u0027", + "", + false, + "false", + "Mail" + ], + [ + "TenantId", + "The TenantId to use when connecting to Azure Active Directory\nUses the tenant id of the current environment if not specified.", + "", + false, + "false", + "$Script:TenantId" ] ], "Alias": "", @@ -5411,8 +5427,8 @@ "Synopsis": "Used to import Aad users into D365FO", "Name": "Import-D365AadUser", "Links": null, - "Examples": "-------------------------- EXAMPLE 1 --------------------------\nPS C:\\\u003eImport-D365AadUser -Users \"Claire@contoso.com\",\"Allen@contoso.com\"\nImports Claire and Allen as users\n-------------------------- EXAMPLE 2 --------------------------\nPS C:\\\u003e$myPassword = ConvertTo-SecureString \"MyPasswordIsSecret\" -AsPlainText -Force\nPS C:\\\u003e $myCredentials = New-Object System.Management.Automation.PSCredential (\"MyEmailIsAlso\", $myPassword)\nPS C:\\\u003e Import-D365AadUser -Users \"Claire@contoso.com\",\"Allen@contoso.com\" -AzureAdCredential $myCredentials\nThis will import Claire and Allen as users.\n-------------------------- EXAMPLE 3 --------------------------\nPS C:\\\u003eImport-D365AadUser -AadGroupName \"CustomerTeam1\"\nif more than one group match the AadGroupName, you can use the ExactAadGroupName parameter\r\nImport-D365AadUser -AadGroupName \"CustomerTeam1\" -ForceExactAadGroupName\n-------------------------- EXAMPLE 4 --------------------------\nPS C:\\\u003eImport-D365AadUser -AadGroupName \"CustomerTeam1\" -ForceExactAadGroupName\nThis is used to force the cmdlet to find the exact named group in Azure Active Directory.\n-------------------------- EXAMPLE 5 --------------------------\nPS C:\\\u003eImport-D365AadUser -AadGroupId \"99999999-aaaa-bbbb-cccc-9999999999\"\nImports all the users that is present in the AAD Group called CustomerTeam1\n-------------------------- EXAMPLE 6 --------------------------\nPS C:\\\u003eImport-D365AadUser -Users \"Claire@contoso.com\",\"Allen@contoso.com\" -SkipAzureAd\nImports Claire and Allen as users.\r\nWill NOT make you connect to the Azure Active Directory(AAD).\r\nThe needed details will be based on the e-mail address only, and the rest will be blanked.", - "Syntax": "Import-D365AadUser [-Users] \u003cString[]\u003e [[-StartupCompany] \u003cString\u003e] [[-DatabaseServer] \u003cString\u003e] [[-DatabaseName] \u003cString\u003e] [[-SqlUser] \u003cString\u003e] [[-SqlPwd] \u003cString\u003e] [[-IdPrefix] \u003cString\u003e] [[-NameSuffix] \u003cString\u003e] [[-IdValue] \u003cString\u003e] [[-NameValue] \u003cString\u003e] [[-AzureAdCredential] \u003cPSCredential\u003e] [[-SkipAzureAd]] [\u003cCommonParameters\u003e]\nImport-D365AadUser [-AadGroupName] \u003cString\u003e [[-StartupCompany] \u003cString\u003e] [[-DatabaseServer] \u003cString\u003e] [[-DatabaseName] \u003cString\u003e] [[-SqlUser] \u003cString\u003e] [[-SqlPwd] \u003cString\u003e] [[-IdPrefix] \u003cString\u003e] [[-NameSuffix] \u003cString\u003e] [[-IdValue] \u003cString\u003e] [[-NameValue] \u003cString\u003e] [[-AzureAdCredential] \u003cPSCredential\u003e] [[-ForceExactAadGroupName]] [\u003cCommonParameters\u003e]\nImport-D365AadUser [[-StartupCompany] \u003cString\u003e] [[-DatabaseServer] \u003cString\u003e] [[-DatabaseName] \u003cString\u003e] [[-SqlUser] \u003cString\u003e] [[-SqlPwd] \u003cString\u003e] [[-IdPrefix] \u003cString\u003e] [[-NameSuffix] \u003cString\u003e] [[-IdValue] \u003cString\u003e] [[-NameValue] \u003cString\u003e] [[-AzureAdCredential] \u003cPSCredential\u003e] [-AadGroupId] \u003cString\u003e [\u003cCommonParameters\u003e]" + "Examples": "-------------------------- EXAMPLE 1 --------------------------\nPS C:\\\u003eImport-D365AadUser -Users \"Claire@contoso.com\",\"Allen@contoso.com\"\nImports Claire and Allen as users\n-------------------------- EXAMPLE 2 --------------------------\nPS C:\\\u003e$myPassword = ConvertTo-SecureString \"MyPasswordIsSecret\" -AsPlainText -Force\nPS C:\\\u003e $myCredentials = New-Object System.Management.Automation.PSCredential (\"MyEmailIsAlso\", $myPassword)\nPS C:\\\u003e Import-D365AadUser -Users \"Claire@contoso.com\",\"Allen@contoso.com\" -AzureAdCredential $myCredentials\nThis will import Claire and Allen as users.\n-------------------------- EXAMPLE 3 --------------------------\nPS C:\\\u003eImport-D365AadUser -AadGroupName \"CustomerTeam1\"\nif more than one group match the AadGroupName, you can use the ExactAadGroupName parameter\r\nImport-D365AadUser -AadGroupName \"CustomerTeam1\" -ForceExactAadGroupName\n-------------------------- EXAMPLE 4 --------------------------\nPS C:\\\u003eImport-D365AadUser -AadGroupName \"CustomerTeam1\" -ForceExactAadGroupName\nThis is used to force the cmdlet to find the exact named group in Azure Active Directory.\n-------------------------- EXAMPLE 5 --------------------------\nPS C:\\\u003eImport-D365AadUser -AadGroupId \"99999999-aaaa-bbbb-cccc-9999999999\"\nImports all the users that is present in the AAD Group called CustomerTeam1\n-------------------------- EXAMPLE 6 --------------------------\nPS C:\\\u003eImport-D365AadUser -Users \"Claire@contoso.com\",\"Allen@contoso.com\" -SkipAzureAd\nImports Claire and Allen as users.\r\nWill NOT make you connect to the Azure Active Directory(AAD).\r\nThe needed details will be based on the e-mail address only, and the rest will be blanked.\n-------------------------- EXAMPLE 7 --------------------------\nPS C:\\\u003eImport-D365AadUser -Users \"Claire@contoso.com\",\"Allen@contoso.com\" -TenantId \"99999999-aaaa-bbbb-cccc-9999999999\"\nImports Claire and Allen as users. Uses tenant id \"99999999-aaaa-bbbb-cccc-9999999999\"\r\nwhen connecting to Azure Active Directory(AAD).", + "Syntax": "Import-D365AadUser [-Users] \u003cString[]\u003e [[-StartupCompany] \u003cString\u003e] [[-DatabaseServer] \u003cString\u003e] [[-DatabaseName] \u003cString\u003e] [[-SqlUser] \u003cString\u003e] [[-SqlPwd] \u003cString\u003e] [[-IdPrefix] \u003cString\u003e] [[-NameSuffix] \u003cString\u003e] [[-IdValue] \u003cString\u003e] [[-NameValue] \u003cString\u003e] [[-AzureAdCredential] \u003cPSCredential\u003e] [[-SkipAzureAd]] [[-EmailValue] \u003cString\u003e] [[-TenantId] \u003cString\u003e] [\u003cCommonParameters\u003e]\nImport-D365AadUser [-AadGroupName] \u003cString\u003e [[-StartupCompany] \u003cString\u003e] [[-DatabaseServer] \u003cString\u003e] [[-DatabaseName] \u003cString\u003e] [[-SqlUser] \u003cString\u003e] [[-SqlPwd] \u003cString\u003e] [[-IdPrefix] \u003cString\u003e] [[-NameSuffix] \u003cString\u003e] [[-IdValue] \u003cString\u003e] [[-NameValue] \u003cString\u003e] [[-AzureAdCredential] \u003cPSCredential\u003e] [[-ForceExactAadGroupName]] [[-EmailValue] \u003cString\u003e] [[-TenantId] \u003cString\u003e] [\u003cCommonParameters\u003e]\nImport-D365AadUser [[-StartupCompany] \u003cString\u003e] [[-DatabaseServer] \u003cString\u003e] [[-DatabaseName] \u003cString\u003e] [[-SqlUser] \u003cString\u003e] [[-SqlPwd] \u003cString\u003e] [[-IdPrefix] \u003cString\u003e] [[-NameSuffix] \u003cString\u003e] [[-IdValue] \u003cString\u003e] [[-NameValue] \u003cString\u003e] [[-AzureAdCredential] \u003cPSCredential\u003e] [-AadGroupId] \u003cString\u003e [[-EmailValue] \u003cString\u003e] [[-TenantId] \u003cString\u003e] [\u003cCommonParameters\u003e]" }, { "CommandName": "Import-D365Bacpac", diff --git a/d365fo.tools/functions/import-d365aaduser.ps1 b/d365fo.tools/functions/import-d365aaduser.ps1 index 417166c8..9b989f72 100644 --- a/d365fo.tools/functions/import-d365aaduser.ps1 +++ b/d365fo.tools/functions/import-d365aaduser.ps1 @@ -68,10 +68,10 @@ Available options 'Mail' / 'UserPrincipalName' Default is 'Mail' - + .PARAMETER TenantId The TenantId to use when connecting to Azure Active Directory - + Uses the tenant id of the current environment if not specified. .EXAMPLE @@ -109,11 +109,11 @@ Imports Claire and Allen as users. Will NOT make you connect to the Azure Active Directory(AAD). The needed details will be based on the e-mail address only, and the rest will be blanked. - + .EXAMPLE PS C:\> Import-D365AadUser -Users "Claire@contoso.com","Allen@contoso.com" -TenantId "99999999-aaaa-bbbb-cccc-9999999999" - Imports Claire and Allen as users. Uses tenant id "99999999-aaaa-bbbb-cccc-9999999999" + Imports Claire and Allen as users. Uses tenant id "99999999-aaaa-bbbb-cccc-9999999999" when connecting to Azure Active Directory(AAD). .NOTES diff --git a/d365fo.tools/tests/functions/Import-D365AadUser.Tests.ps1 b/d365fo.tools/tests/functions/Import-D365AadUser.Tests.ps1 index 3a2020ad..2404cd04 100644 --- a/d365fo.tools/tests/functions/Import-D365AadUser.Tests.ps1 +++ b/d365fo.tools/tests/functions/Import-D365AadUser.Tests.ps1 @@ -206,24 +206,50 @@ $parameter.ParameterSets['GroupIdImport'].ValueFromPipelineByPropertyName | Should -Be $False $parameter.ParameterSets['GroupIdImport'].ValueFromRemainingArguments | Should -Be $False } + It 'Should have the expected parameter EmailValue' { + $parameter = (Get-Command Import-D365AadUser).Parameters['EmailValue'] + $parameter.Name | Should -Be 'EmailValue' + $parameter.ParameterType.ToString() | Should -Be System.String + $parameter.IsDynamic | Should -Be $False + $parameter.ParameterSets.Keys | Should -Be '__AllParameterSets' + $parameter.ParameterSets.Keys | Should -Contain '__AllParameterSets' + $parameter.ParameterSets['__AllParameterSets'].IsMandatory | Should -Be $False + $parameter.ParameterSets['__AllParameterSets'].Position | Should -Be 15 + $parameter.ParameterSets['__AllParameterSets'].ValueFromPipeline | Should -Be $False + $parameter.ParameterSets['__AllParameterSets'].ValueFromPipelineByPropertyName | Should -Be $False + $parameter.ParameterSets['__AllParameterSets'].ValueFromRemainingArguments | Should -Be $False + } + It 'Should have the expected parameter TenantId' { + $parameter = (Get-Command Import-D365AadUser).Parameters['TenantId'] + $parameter.Name | Should -Be 'TenantId' + $parameter.ParameterType.ToString() | Should -Be System.String + $parameter.IsDynamic | Should -Be $False + $parameter.ParameterSets.Keys | Should -Be '__AllParameterSets' + $parameter.ParameterSets.Keys | Should -Contain '__AllParameterSets' + $parameter.ParameterSets['__AllParameterSets'].IsMandatory | Should -Be $False + $parameter.ParameterSets['__AllParameterSets'].Position | Should -Be 16 + $parameter.ParameterSets['__AllParameterSets'].ValueFromPipeline | Should -Be $False + $parameter.ParameterSets['__AllParameterSets'].ValueFromPipelineByPropertyName | Should -Be $False + $parameter.ParameterSets['__AllParameterSets'].ValueFromRemainingArguments | Should -Be $False + } } Describe "Testing parameterset UserListImport" { <# UserListImport -Users - UserListImport -Users -StartupCompany -DatabaseServer -DatabaseName -SqlUser -SqlPwd -IdPrefix -NameSuffix -IdValue -NameValue -AzureAdCredential -SkipAzureAd + UserListImport -Users -StartupCompany -DatabaseServer -DatabaseName -SqlUser -SqlPwd -IdPrefix -NameSuffix -IdValue -NameValue -AzureAdCredential -SkipAzureAd -EmailValue -TenantId #> } Describe "Testing parameterset GroupNameImport" { <# GroupNameImport -AadGroupName - GroupNameImport -AadGroupName -StartupCompany -DatabaseServer -DatabaseName -SqlUser -SqlPwd -IdPrefix -NameSuffix -IdValue -NameValue -AzureAdCredential -ForceExactAadGroupName + GroupNameImport -AadGroupName -StartupCompany -DatabaseServer -DatabaseName -SqlUser -SqlPwd -IdPrefix -NameSuffix -IdValue -NameValue -AzureAdCredential -ForceExactAadGroupName -EmailValue -TenantId #> } Describe "Testing parameterset GroupIdImport" { <# GroupIdImport -AadGroupId - GroupIdImport -StartupCompany -DatabaseServer -DatabaseName -SqlUser -SqlPwd -IdPrefix -NameSuffix -IdValue -NameValue -AzureAdCredential -AadGroupId + GroupIdImport -StartupCompany -DatabaseServer -DatabaseName -SqlUser -SqlPwd -IdPrefix -NameSuffix -IdValue -NameValue -AzureAdCredential -AadGroupId -EmailValue -TenantId #> } diff --git a/docs/Import-D365AadUser.md b/docs/Import-D365AadUser.md index e39dd8bf..b7e0ea1a 100644 --- a/docs/Import-D365AadUser.md +++ b/docs/Import-D365AadUser.md @@ -17,7 +17,7 @@ Used to import Aad users into D365FO Import-D365AadUser [-Users] [[-StartupCompany] ] [[-DatabaseServer] ] [[-DatabaseName] ] [[-SqlUser] ] [[-SqlPwd] ] [[-IdPrefix] ] [[-NameSuffix] ] [[-IdValue] ] [[-NameValue] ] [[-AzureAdCredential] ] - [-SkipAzureAd] [] + [-SkipAzureAd] [[-EmailValue] ] [[-TenantId] ] [] ``` ### GroupNameImport @@ -25,7 +25,7 @@ Import-D365AadUser [-Users] [[-StartupCompany] ] [[-DatabaseS Import-D365AadUser [-AadGroupName] [[-StartupCompany] ] [[-DatabaseServer] ] [[-DatabaseName] ] [[-SqlUser] ] [[-SqlPwd] ] [[-IdPrefix] ] [[-NameSuffix] ] [[-IdValue] ] [[-NameValue] ] [[-AzureAdCredential] ] - [-ForceExactAadGroupName] [] + [-ForceExactAadGroupName] [[-EmailValue] ] [[-TenantId] ] [] ``` ### GroupIdImport @@ -33,7 +33,7 @@ Import-D365AadUser [-AadGroupName] [[-StartupCompany] ] [[-Data Import-D365AadUser [[-StartupCompany] ] [[-DatabaseServer] ] [[-DatabaseName] ] [[-SqlUser] ] [[-SqlPwd] ] [[-IdPrefix] ] [[-NameSuffix] ] [[-IdValue] ] [[-NameValue] ] [[-AzureAdCredential] ] [-AadGroupId] - [] + [[-EmailValue] ] [[-TenantId] ] [] ``` ## DESCRIPTION @@ -90,6 +90,15 @@ Imports Claire and Allen as users. Will NOT make you connect to the Azure Active Directory(AAD). The needed details will be based on the e-mail address only, and the rest will be blanked. +### EXAMPLE 7 +``` +Import-D365AadUser -Users "Claire@contoso.com","Allen@contoso.com" -TenantId "99999999-aaaa-bbbb-cccc-9999999999" +``` + +Imports Claire and Allen as users. +Uses tenant id "99999999-aaaa-bbbb-cccc-9999999999" +when connecting to Azure Active Directory(AAD). + ## PARAMETERS ### -AadGroupName @@ -334,6 +343,41 @@ Accept pipeline input: False Accept wildcard characters: False ``` +### -EmailValue +Specify which field to use as EMAIL value when importing the users. +Available options 'Mail' / 'UserPrincipalName' + +Default is 'Mail' + +```yaml +Type: String +Parameter Sets: (All) +Aliases: + +Required: False +Position: 16 +Default value: Mail +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -TenantId +The TenantId to use when connecting to Azure Active Directory + +Uses the tenant id of the current environment if not specified. + +```yaml +Type: String +Parameter Sets: (All) +Aliases: + +Required: False +Position: 17 +Default value: $Script:TenantId +Accept pipeline input: False +Accept wildcard characters: False +``` + ### CommonParameters This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). @@ -348,6 +392,8 @@ Author: Rasmus Andersen (@ITRasmus) Author: Charles Colombel (@dropshind) Author: Mötz Jensen (@Splaxi) Author: Miklós Molnár (@scifimiki) +Author: Gert Van der Heyden (@gertvdh) +Author: Florian Hopfner (@FH-Inway) At no circumstances can this cmdlet be used to import users into a PROD environment. From 4702af8c45af2e685440eae833d3e24421cf2d95 Mon Sep 17 00:00:00 2001 From: Florian Hopfner Date: Sun, 10 Nov 2024 11:13:42 +0100 Subject: [PATCH 12/13] remove trailing space --- d365fo.tools/functions/import-d365aaduser.ps1 | 2 +- d365fo.tools/internal/scripts/variables.ps1 | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/d365fo.tools/functions/import-d365aaduser.ps1 b/d365fo.tools/functions/import-d365aaduser.ps1 index 9b989f72..e8da6703 100644 --- a/d365fo.tools/functions/import-d365aaduser.ps1 +++ b/d365fo.tools/functions/import-d365aaduser.ps1 @@ -381,7 +381,7 @@ function Import-D365AadUser { $email = "" if ($EmailValue -eq 'Mail') { - $email = $user.Mail + $email = $user.Mail } else { $email = $user.UserPrincipalName diff --git a/d365fo.tools/internal/scripts/variables.ps1 b/d365fo.tools/internal/scripts/variables.ps1 index d11d21ab..e0b423d0 100644 --- a/d365fo.tools/internal/scripts/variables.ps1 +++ b/d365fo.tools/internal/scripts/variables.ps1 @@ -59,10 +59,10 @@ $Script:IsOnebox = $common.IsOneboxEnvironment $Script:ServerRole = [ServerRole]::Unknown $RoleVaule = $( - If ($environment.Monitoring.MARole -eq "" -or $environment.Monitoring.MARole -eq "dev") { - "Development" + If ($environment.Monitoring.MARole -eq "" -or $environment.Monitoring.MARole -eq "dev") { + "Development" } Else { - $environment.Monitoring.MARole + $environment.Monitoring.MARole } ) if ($null -ne $RoleVaule) { From 04e95250eb69cbad008adcb7ae9fafc25ea2b69c Mon Sep 17 00:00:00 2001 From: Florian Hopfner Date: Sun, 10 Nov 2024 11:14:41 +0100 Subject: [PATCH 13/13] replace alias --- d365fo.tools/functions/import-d365aaduser.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/d365fo.tools/functions/import-d365aaduser.ps1 b/d365fo.tools/functions/import-d365aaduser.ps1 index e8da6703..8f139be9 100644 --- a/d365fo.tools/functions/import-d365aaduser.ps1 +++ b/d365fo.tools/functions/import-d365aaduser.ps1 @@ -208,11 +208,11 @@ function Import-D365AadUser { Write-PSFMessage -Level Verbose -Message "Trying to connect to the Azure Active Directory with tenant id '$TenantId'" if ($PSBoundParameters.ContainsKey("AzureAdCredential") -eq $true) { - Login-AzAccount -Credential $AzureAdCredential -ErrorAction Stop -TenantId $TenantId + Connect-AzAccount -Credential $AzureAdCredential -ErrorAction Stop -TenantId $TenantId } else { if ($SkipAzureAd -eq $false) { - Login-AzAccount -ErrorAction Stop -TenantId $TenantId + Connect-AzAccount -ErrorAction Stop -TenantId $TenantId } } }