Closed BastiGit closed 1 year ago
Hello @BastiGit,
Have you tried using the -ModernAuth parameter? For a list of all parameters, see https://github.com/grahamr975/EWS-Office365-Contact-Sync/blob/master/EWSContactSync.ps1
Follow the Get Started guide in the README file. This shows how to set up the script with modern authentication.
I'd recommend you test this on an account with basic authentication disabled to verify the script will function properly in your environment using only modern authentication. The guide below shows you how to set up a security group with no basic authentication using PowerShell. It's working well in mine.
Hello @grahamr975,
thanks for your quick reply.
Yes, I have used the -ModernAuth parameter as described in the README. However, then the following error appears:
[outlook.office365.com] Connecting to remote server outlook.office365.com failed with the following error message : Access is denied.
Is there anything else to do for modern authentication?
I have saved the credentials by Export-Clixml, but they are only relevant for BasicAuth, right?
Did you unblock all of the DLL files referenced in step 4 of the README?
You do still need credentials for Modern Auth since we use those to generate the OAuth access token. This account should have permissions as specified in the README.
Yes, I have unblocked all DLL files from step 4.
At Export-Clixml I enter my Office 365 account data. This account is an administrator and also has the Application Impersonation permissions.
Unfortunately, the access denied error message comes up again.
This issue is from the ExchangeOnline Powershell Module and occurs for one of the following reasons:
Note that the ExchangeOnline Powershell Module in this script still uses basic authentication. It's on my to-do list to migrate this over to OAuth just as I have done for the EWS portions.
We only use ExchangeOnline to retrieve the contacts, so if you're up to the challenge you could follow a guide like the one here to set up an AzureAD App. After that, you'd need to modify the function here: https://github.com/grahamr975/EWS-Office365-Contact-Sync/blob/master/EWSContacts/Module/functions/contacts/Get-GALContacts.ps1
$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri $ConnectionUri -Credential $Credentials -Authentication Basic -AllowRedirection
Thank you very much for your tips and time.
I have created an Azure-AD app using the tutorial and have customized the function in the Get-GALContacts.ps1 script. Now everything works perfectly and the contacts are being synced.
The script now uses the following function:
Connect-ExchangeOnline -CertificateThumbPrint “<CertThumbprint>” -AppID “<MyAppId>” -Organization “<MyTenant.OnMicrosoft.com>”
and instead of Remove-PSSession $Session
there is now Disconnect-ExchangeOnline -Confirm:$false
at the end of the GALContact script.
We disabled BasicAuth on our tenant for all services, so I'm glad we don't have to enable it again.
Thanks @grahamr975!
@BastiGit Thanks for this information. I'll work on incorporating this piece into the script as time allows since basic authentication will be fully depreciated next year, as you point out.
Thank you very much for your tips and time.
I have created an Azure-AD app using the tutorial and have customized the function in the Get-GALContacts.ps1 script. Now everything works perfectly and the contacts are being synced.
The script now uses the following function:
Connect-ExchangeOnline -CertificateThumbPrint “<CertThumbprint>” -AppID “<MyAppId>” -Organization “<MyTenant.OnMicrosoft.com>”
and instead of
Remove-PSSession $Session
there is nowDisconnect-ExchangeOnline -Confirm:$false
at the end of the GALContact script.We disabled BasicAuth on our tenant for all services, so I'm glad we don't have to enable it again.
Thanks @grahamr975! Can you send me the PS1 you have use or using ?
We have activate mfa for admin accounts. My exchange admin account have already all permistions but getting error :: ERROR Failed to Sync-ContactList for icttest@domainname.nl A constructor was not found. Cannot find an appropriate constructor for type Microsoft.Exchange.WebServices.Data.OAuthCredentials.
Hello @nldenic,
I'm sorry, but I can't send you the original .ps1 file, because it contains confidential data.
I have replaced the "PSSession" sections with "ExchangeOnline" in both the Get-Mailboxes.ps1 and Get-GALContacts.ps1 files, as described above.
Have you created an Azure AD app for the script (as described here)?
Thank you for your reply. Than i will create first the Application in azure and follow this steps. Than will change the ps1 files and see if that works.
The commands to will not change still same am i right so :
cd "%~dp0EWS-Office365-Contact-Sync"
PowerShell.exe -ExecutionPolicy Bypass ^ -File "%CD%\EWSContactSync.ps1" ^ -CredentialPath "C:\Encrypted Credentials\SecureCredential.cred" ^ -FolderName "Directory Contacts" ^ -LogPath "%~dp0Logs" ^ -MailboxList john.doe@mycompany.com ^ -ModernAuth pause
I have write this in an bat file. This is no issue am i right?
@BastiGit @grahamr975
Can you maybe just send the ps1 without your credentials and appid.
i have follow every step but still getting an error. in this case its now : New-PSSession : A parameter cannot be found that matches parameter name 'AppID'
My Galcontacts.ps1 is now like :
process {
try {
# Connect to Office 365 Exchange Server using a Remote Session
$Session = New-PSSession Connect-ExchangeOnline -CertificateThumbPrint “Thumbprint" -AppID "appid" -Organization “organisation.onmicrosoft.com”
Import-PSSession $Session -DisableNameChecking -AllowClobber
# Import Global Address List into Powershell from Office 365 Exchange as an array
$ContactList = Get-User -ResultSize unlimited
# If the ExcludeSharedMailboxContacts switch is enabled, exclude contacts that are a shared mailbox or mailbox with no liscense
if ($ExcludeSharedMailboxContacts) {
$DirectoryList = $(Get-Mailbox -ResultSize unlimited | Where-Object {$_.HiddenFromAddressListsEnabled -Match "False"})
$EmailAddressList = $DirectoryList.PrimarySMTPAddress
$ContactList = $ContactList | Select-Object DisplayName,FirstName,LastName,Title,Company,Department,WindowsEmailAddress,Phone,MobilePhone | Where-Object {$EmailAddressList.Contains($_.WindowsEmailAddress)}
} else {
$ContactList = $ContactList | Select-Object DisplayName,FirstName,LastName,Title,Company,Department,WindowsEmailAddress,Phone,MobilePhone
}
# If the IncludeNonUserContacts switch is enabled, also include contacts that aren't actual users in the directory
if ($IncludeNonUserContacts) {
$ContactList += Get-Contact -ResultSize unlimited | Select-Object DisplayName,FirstName,LastName,Title,Company,Department,WindowsEmailAddress,Phone,MobilePhone
}
# If the ExcludeContactsWithoutPhoneNumber switch is enabled, exclude contacts that don't have a phone or mobile number
if ($ExcludeContactsWithoutPhoneNumber) {
$ContactList = $ContactList | Where-Object {$_.Phone -or $_.MobilePhone}
}
# Only return contacts with email addresses
return $ContactList | Where-Object {$null -ne $_.WindowsEmailAddress -and "" -ne $_.WindowsEmailAddress}
} catch {
Write-Log -Level "FATAL" -Message "Failed to fetch Global Address List Contacts from Office 365 Directory" -exception $_.Exception.Message
}
}
}Disconnect-ExchangeOnline -Confirm:$false
Can you please check this and confirm its set good ?
Its in this case changed for both Get-Mailboxes.ps1 and Get-GALContacts.ps1 but still same error message.
When i run empty powershell with. $Session = New-PSSession Connect-ExchangeOnline -CertificateThumbPrint “Thumbprint" -AppID "appid" -Organization “organisation.onmicrosoft.com”
Its working and exchange shell starts. So I don't get it how to write this correct in the ps1 files.
dear all, I've changed Get-GALContacts.ps1's lines starting here:
...
process {
try {
# Connect to Office 365 Exchange Server using a Remote Session
# $Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri $ConnectionUri -Credential $Credentials -Authentication Basic -AllowRedirection
# Import-PSSession $Session -DisableNameChecking -AllowClobber
$cert = Get-ChildItem Cert:\CurrentUser\My\<self-signed-cert-thumbprint>
$appId = 'my-azure-app-id'
$exchangeOrgId = 'myOrgID.onmicrosoft.com'
$paramConnectExchangeOnline = @{
CertificateThumbprint = $cert.ThumbPrint
AppId = $appId
Organization = $exchangeOrgId
}
Connect-ExchangeOnline @paramConnectExchangeOnline
# Import Global Address List into Powershell from Office 365 Exchange as an array
$ContactList = Get-User -ResultSize unlimited -RecipientTypeDetails 'Usermailbox'
... end of change
... and it works like a charm.
I hope you find it useful!
Cheers, Csarly
@Csarly
I have try you Galsync changes. But still same error message :(
Which file do you select here : $cert = Get-ChildItem Cert:\CurrentUser\My\
is it the Cer or pfx file ?
i have also already click allow public client flows in the application settings in azure :
Are you able to share me your ps1 ? Is there Basicauth active for your account which you use ?
@nldenic ,
what is the error message the script throws?
Sorry, there's a missing back-slash, this line is correct:
$cert = Get-ChildItem Cert:\CurrentUser\My\
Have you created a self-signed certificate?
Take it's thumbprint and replace "
I'm new to GitHub, so please forgive me, I just don't find the button to add a file... :(
@Csarly No problem we can share here the script together.
Please see my error message :
My script is now as following:
Is this correct or do i need to fill this different ?
Get-GALContacts.txt Hi, I'm sorry, I was trying to create a branch, but it doesn't finish uploading... I finaly found the obvious thing: drag&drop the script here... facepalm You need to modify the parameters commented in capital letters! That should do it.. You have to provide your cert thumbprint, otherwise it won't work. Your version is a mixture of certificate store and desktop. That will probably cause the error...
I hope it helps! KR, Csarly
Hello Csarly,
have you updated the Sync-ContactList or the Connect-EXCExchange Modules in your environment?
Hi benj288, no, sadly I was pulled away from this and had no time to invest further. :( best, Csarly
Hi Csarly, thank you for your reply! You don't use it anymore or has the problem resolved itself? Kind regards
Hi ben, both, due to other topics and lacking time, I could not finish the adjustments. If the need arises again, and the 3rd party forces me again, I will post my version here. Sorry for not being that helpful at the moment... Cheers, Csarly
Hello,
Does anyone have this script working without ANY basic authentication? So without the $creds based on a (Global Admin) useraccount?
In several functions we see that the $creds variable is used. When leaving the $creds empty the script does not work, also not with the -ModernAuth parameter.
On this moment we have the script working with the -Modernauth parameter, but the script still requires credentials as described above. As we use Azure Privileged Identity Management, we cannot automate the script on this moment.
Does anyone else had this problem and managed to solve it?
Kind regards, Sebastiaan
@JBW-Imthorn , hi Sebastiaan, nope, EWS doesn't provide cert based auth, e.g., but I managed to run the script - kind of automated - with user & pw stored in an encrypted xml in my tests a few months ago. I think there is a Azure Key Vault you maybe can leverage for storing your credentials. (I'm not familiar with it)
In my case OAuth2 was successfully commited after I changed line 99 in Connect-EXCExchange.ps1
from:
$service.Credentials = New-Object Microsoft.Exchange.WebServices.Data.OAuthCredentials($token.AccessToken)
to:
$service.Credentials = [Microsoft.Exchange.WebServices.Data.OAuthCredentials]$token.AccessToken
I actually don't know why exactly... might be because I have installed the EWS Package ( -Name 'Exchange.WebServices.Managed.Api')....
I replaced line 55 against:
$EWSDLL = (Get-ChildItem -Path "$(split-path $((Get-Package -Name 'Exchange.WebServices.Managed.Api').Source) -Parent)\Microsoft.Exchange.WebServices.dll" -Recurse).FullName
I hope this helps a little bit though.. kr, Csarly
Hi @Csarly,
Thank you for your reply, I came across this item in the Microsoft docs. So that was triggering me with the question if anyone already tried.
Yes the encrypted XML is what we use too to run the script, and as you described we also changed the content of Connect-EXCExchange.ps1 and this is fully working.
The problem is more that we use Azure Privileged Identity Management. This means we need to activate a role in the Azure environment to gain access rights on the useraccount, it's more secure but also preventing us to automate the contactsync script as a privileged user account is needed.
We will lookin further for what the possibilities are, when we found a solution I will definitely post it here so others can use it also.
Kind regards, Sebastiaan
All,
The latest version of the app moves to Azure-app-based certificate authentication which removes the need for basic auth & fixes MFA issues. See commit 9fcfe1f06192848882564615dd9aa05e71d69970.
Hello,
can someone explain, how to correctly use ModernAuth with this script? We would like to keep BasicAuth disabled for our O365-Tenant, because Microsoft will disable it in 2022.
Any suggestion will be appreciated. Thank you very much in advance.