Skip to content

Commit

Permalink
Merge pull request d365collaborative#860 from d365collaborative/test-…
Browse files Browse the repository at this point in the history
…import-d365aaduserv2

Import-D365AadUser: User principal name as email and removal of AzureAD dependency
  • Loading branch information
FH-Inway authored Nov 10, 2024
2 parents b93c83a + 04e9525 commit 3b2542b
Show file tree
Hide file tree
Showing 10 changed files with 209 additions and 61 deletions.
5 changes: 0 additions & 5 deletions .github/workflows/dependencies.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,6 @@ jobs:
uses: PowershellFrameworkCollective/psframework@32c18f13173be8cc6b6803c63c40b9d7ab5aec12 # version 1.0.12
- name: Azure.Storage
uses: Azure/[email protected] # 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
Expand Down
2 changes: 1 addition & 1 deletion build/vsts-prerequisites.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -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")

Write-Host "Installing Pester, maximum version 4.99.99" -ForegroundColor Cyan
Install-Module "Pester" -MaximumVersion 4.99.99 -Force -Confirm:$false -Scope CurrentUser -AllowClobber -SkipPublisherCheck
Expand Down
2 changes: 1 addition & 1 deletion build/vsts-validate-psscriptanalyzer.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion build/vsts-validate.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
20 changes: 18 additions & 2 deletions d365fo.tools/bin/d365fo.tools-index.json
Original file line number Diff line number Diff line change
Expand Up @@ -5404,15 +5404,31 @@
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": "",
"Author": "Rasmus Andersen (@ITRasmus)",
"Synopsis": "Used to import Aad users into D365FO",
"Name": "Import-D365AadUser",
"Links": null,
"Examples": "-------------------------- EXAMPLE 1 --------------------------\nPS C:\\\u003eImport-D365AadUser -Users \"[email protected]\",\"[email protected]\"\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 \"[email protected]\",\"[email protected]\" -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 \"[email protected]\",\"[email protected]\" -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 \"[email protected]\",\"[email protected]\"\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 \"[email protected]\",\"[email protected]\" -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 \"[email protected]\",\"[email protected]\" -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 \"[email protected]\",\"[email protected]\" -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",
Expand Down
1 change: 0 additions & 1 deletion d365fo.tools/d365fo.tools.psd1
Original file line number Diff line number Diff line change
Expand Up @@ -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' }
)
Expand Down
108 changes: 84 additions & 24 deletions d365fo.tools/functions/import-d365aaduser.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,17 @@
.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'
.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 "[email protected]","[email protected]"
Expand Down Expand Up @@ -99,13 +110,21 @@
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 "[email protected]","[email protected]" -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
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.
Expand Down Expand Up @@ -164,7 +183,14 @@ 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",

[Parameter(Mandatory = $false, Position = 16)]
[string] $TenantId = $Script:TenantId
)

$UseTrustedConnection = Test-TrustedConnection $PSBoundParameters
Expand All @@ -179,14 +205,14 @@ 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) {
$null = Connect-AzureAD -ErrorAction Stop -Credential $AzureAdCredential
Connect-AzAccount -Credential $AzureAdCredential -ErrorAction Stop -TenantId $TenantId
}
else {
if ($SkipAzureAd -eq $false) {
$null = Connect-AzureAD -ErrorAction Stop
Connect-AzAccount -ErrorAction Stop -TenantId $TenantId
}
}
}
Expand All @@ -202,16 +228,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
}
}
}

Expand All @@ -233,16 +274,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)
}
}
}
Expand All @@ -253,14 +300,19 @@ 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 {
$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"
Expand Down Expand Up @@ -305,7 +357,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 {
Expand All @@ -314,24 +366,32 @@ 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 <c='em'>'$oldId'</c> does not fit the <c='em'>20 character limit</c> on UserInfo table's ID field and will be truncated to <c='em'>'$id'</c>"
}

Write-PSFMessage -Level Verbose -Message "Id for user $($user.Mail) : $id"

$name = ""
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 "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"

Import-AadUserIntoD365FO $SqlCommand $email $name $id $sid $StartupCompany $identityProvider $networkDomain $user.ObjectId

if (Test-PSFFunctionInterrupt) { return }
}
Expand Down
Loading

0 comments on commit 3b2542b

Please sign in to comment.