I’ve made a PowerShell script you can use to connect to multiple Microsoft 365 services using the Secure Application Model. I’ve stored the Refresh Tokens and my Application Secrets in an Azure Key Vault (Secrets). This is the best and most secure way. Never hard-code these secrets in your PowerShell scripts.
Usage is very simple. Just start the script with the following arguments.
-tenantDomain azurescene.onmicrosoft.com
-vaultName theNameOfYourKeyVault
-AzureADCon $true (connect with AzureAD?)
-AzCon $true (connect with Az?)
-MSolCon $true (connect to MS Online?)
-ExchangeCon $true (connect to Exchange Online?)
[cmdletbinding()] param ( [Parameter( Mandatory = $true, HelpMessage="customer.onmicrosoft.com", Position=1 )][string] $TenantDomain, [Parameter( Mandatory = $true, HelpMessage="Name of the Azure Key Vault", Position=2 )][string] $vaultName, [Parameter( Mandatory = $false, HelpMessage="Connect to AzureAD?", Position=3 )][bool] $AzureADCon = $false, [Parameter( Mandatory = $false, HelpMessage="Connect to Az?", Position=4 )][bool] $AzCon = $false, [Parameter( Mandatory = $false, HelpMessage="Connect to MS online?", Position=5 )][bool] $MSolCon = $false, [Parameter( Mandatory = $false, HelpMessage="Connect to Exchange Online?", Position=6 )][bool] $ExchangeCon = $false ) if (!$AzCon -and !$AzureADCon -and !$MSolCon -and !$ExchangeCon) { Write-Host Write-Host "Nothing to connect." -ForegroundColor Magenta Break } #endregion #region Test Customer Tenant Try { $customerTenantID = (Invoke-WebRequest https://login.windows.net/$TenantDomain/.well-known/openid-configuration|ConvertFrom-Json).token_endpoint.Split('/')[3] } Catch { # Can't find customer tenant Break } #endregion #region PartnerCenter $PCModule = Get-Module -Name "PartnerCenter" -ListAvailable if ($PCModule -eq $null) { Write-Host "PartnerCenter PowerShell Module not installed." -ForegroundColor Red Write-Host "Install with 'Install-Module -Name PartnerCenter'" -ForegroundColor Red break } Write-Host Write-Host "PartnerCenter installed." -ForegroundColor Green #endregion #region AzureAD $AADModule = Get-Module -Name "AzureAD" -ListAvailable ## AzureADPreview Installed? if ($AADModule -eq $null) { $AADModule = Get-Module -Name "AzureADPreview" -ListAvailable } ## No AzureAD or AzureADPreview installed? If ($AADModule -eq $null) { Write-Host "AzureAD PowerShell Module not installed." -ForegroundColor Red Write-Host "Install with 'Install-Module -Name AzureAD'" -ForegroundColor Red break } Write-Host "AzureAD installed." -ForegroundColor Green #endregion #region Az $AZModule = Get-Module -Name "Az.Accounts" -ListAvailable if ($AZModule -eq $null) { Write-Host "Az PowerShell Module not installed." -ForegroundColor Red Write-Host "Install with 'Install-Module -Name Az'" -ForegroundColor Red break } Write-Host "Az Module installed." -ForegroundColor Green #endregion #region MSOnline $MSOnline = Get-Module -Name "MSOnline" -ListAvailable if ($MSOnline -eq $null) { Write-Host "MSOnline PowerShell Module not installed." -ForegroundColor Red Write-Host "Install with 'Install-Module -Name MSOnline'" -ForegroundColor Red break } Write-Host "MSOnline installed." -ForegroundColor Green #endregion #region Connect to services if ($AADModule -and $PCModule -and $MSOnline -and $AZModule) { Write-Host Write-Host "Log on with your CSP Admin" -ForegroundColor Yellow Write-Host "Be sure you have read permission on Key Vault" -ForegroundColor Yellow Try { Connect-AzAccount | Out-Null $AdminUser = (Get-AzContext).Account.Id } Catch { ## Connection went wrong break } #region Get Refresh Token from Azure Key Vault Try { $applicationID = (Get-AzKeyVaultSecret -vaultName $vaultName -name "applicationID").SecretValueText $applicationSecret = (Get-AzKeyVaultSecret -vaultName $vaultName -name "ApplicationSecret").SecretValueText $applicationSecret = ConvertTo-SecureString $applicationSecret -AsPlainText -Force $tenantID = (Get-AzKeyVaultSecret -vaultName $vaultName -name "tenantID").SecretValueText $refreshToken = (Get-AzKeyVaultSecret -vaultName $vaultName -name "RefreshToken").SecretValueText $ExchangerefreshToken = (Get-AzKeyVaultSecret -vaultName $vaultName -name "ExchangeRefreshToken").SecretValueText } Catch { Write-Host Write-Host "Something went wrong while fetching all information..." -ForegroundColor Red Break } #endregion #region Create Credentials with Tokens Try { $Credential = New-Object System.Management.Automation.PSCredential ($applicationID, $applicationSecret) } Catch { write-Host "Something went wrong while creating the credentials..." -ForegroundColor Red break } #endregion #region Connect to Azure AD if ($AzureADCon) { $aadGraphToken = New-PartnerAccessToken -ApplicationId $applicationID -Credential $credential -RefreshToken $refreshToken -Scopes 'https://graph.windows.net/.default' -ServicePrincipal -Tenant $customerTenantID $graphToken = New-PartnerAccessToken -ApplicationId $applicationID -Credential $credential -RefreshToken $refreshToken -Scopes 'https://graph.microsoft.com/.default' -ServicePrincipal -Tenant $customerTenantID Connect-AzureAD -AadAccessToken $aadGraphToken.AccessToken -AccountId $AdminUser -MsAccessToken $graphToken.AccessToken -TenantId $customerTenantID } #endregion #region Connect to Az if ($AzCon) { $azureToken = New-PartnerAccessToken -ApplicationId $applicationID -Credential $credential -RefreshToken $refreshToken -Scopes 'https://management.azure.com/user_impersonation' -ServicePrincipal -Tenant $customerTenantID $graphToken = New-PartnerAccessToken -ApplicationId $applicationID -Credential $credential -RefreshToken $refreshToken -Scopes 'https://graph.microsoft.com/.default' -ServicePrincipal -Tenant $customerTenantID Connect-AzAccount -AccessToken $azureToken.AccessToken -AccountId $AdminUser -GraphAccessToken $graphToken.AccessToken -TenantId $customerTenantID } #endregion #region Connect to MS Online if ($MSolCon) { $aadGraphToken = New-PartnerAccessToken -ApplicationId $applicationID -Credential $credential -RefreshToken $refreshToken -Scopes 'https://graph.windows.net/.default' -ServicePrincipal -Tenant $tenantID $graphToken = New-PartnerAccessToken -ApplicationId $applicationID -Credential $credential -RefreshToken $refreshToken -Scopes 'https://graph.microsoft.com/.default' -ServicePrincipal -Tenant $tenantID Connect-MsolService -AdGraphAccessToken $aadGraphToken.AccessToken -MsGraphAccessToken $graphToken.AccessToken Write-Host Write-Host "You should use " -NoNewline -ForegroundColor Yellow Write-Host "-TenantID 'CustomerTenantID' " -NoNewline -ForegroundColor Green Write-Host "when using MS Online commands" -ForegroundColor Yellow } #endregion #region Connect to Exchange Online if ($ExchangeCon) { $token = New-PartnerAccessToken -ApplicationId 'a0c73c16-a7e3-4564-9a95-2bdf47383716'-RefreshToken $ExchangeRefreshToken -Scopes 'https://outlook.office365.com/.default' -Tenant $customerTenantID $tokenValue = ConvertTo-SecureString "Bearer $($token.AccessToken)" -AsPlainText -Force $credential = New-Object System.Management.Automation.PSCredential($AdminUser, $tokenValue) $session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri "https://ps.outlook.com/powershell-liveid?DelegatedOrg=$($customerId)&BasicAuthToOAuthConversion=true" -Credential $credential -Authentication Basic -AllowRedirection Import-PSSession $session -DisableNameChecking | Out-Null } } #endregion
Hello and thanks for the script and article. I’m wondering what is required to be able to access your Azure Key Vault so easily. Are you needing to use Azure Cloud Shell for this to work?
Thanks,
Jeremy
Hi Jeremy! You can you ‘Connect-AzAccount’ to connect to your Azure tenant with a user that has access to your key vault. After connecting, you can use ‘Get-AzKeyVaultSecret’ to get all the secrets out of the key vault – no Azure Cloud Shell needed.
If you want to run this script without loggin in every time, you can use a certificate (https://docs.microsoft.com/en-us/powershell/module/az.accounts/connect-azaccount?view=azps-3.5.0).
Of course its possible to hardcode the tokens/passwords in your script, but you shouldn’t do that.
Thank you!
Is it possible to use MSAL to get a token and then use it with Connect-MsolService ? thanks
To my knowledge, that’s not possible.