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

Added M365 connections to shared #2090

Open
wants to merge 22 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
159 changes: 159 additions & 0 deletions Shared/Connect-M365.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.

function Test-EXOConnection {
[CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'High')]
[OutputType([bool])]
param (
[Switch]$Force
iserrano76 marked this conversation as resolved.
Show resolved Hide resolved
)
#Validate EXO V2 is installed
if ((Get-Module -ListAvailable | Where-Object { $_.Name -like "ExchangeOnlineManagement" }).count -ge 1) {
iserrano76 marked this conversation as resolved.
Show resolved Hide resolved
Write-Host "ExchangeOnlineManagement Powershell Module installed"
iserrano76 marked this conversation as resolved.
Show resolved Hide resolved
} else {
if ($Force -or $PSCmdlet.ShouldContinue("Do you want to install the module?", "ExchangeOnlineManagement Powershell Module not installed")) {
Install-Module -Name ExchangeOnlineManagement -Force -ErrorAction SilentlyContinue -Scope CurrentUser
if ((Get-Module -ListAvailable | Where-Object { $_.Name -like "ExchangeOnlineManagement" }).count -ge 1) {
Write-Host "ExchangeOnlineManagement Powershell Module installed"
} else {
Write-Host "ExchangeOnlineManagement Powershell Module installation failed" -ForegroundColor Red
return $false
}
} else {
Write-Host "We cannot continue without ExchangeOnlineManagement Powershell module" -ForegroundColor Red
return $false
}
}

#Validate EXO V2 is loaded
if ((Get-Module | Where-Object { $_.Name -like "ExchangeOnlineManagement" }).count -ge 1) {
iserrano76 marked this conversation as resolved.
Show resolved Hide resolved
Write-Host "ExchangeOnlineManagement Powershell Module loaded"
} else {
Import-Module ExchangeOnlineManagement -ErrorAction SilentlyContinue -Force
if ((Get-Module | Where-Object { $_.Name -like "ExchangeOnlineManagement" }).count -ge 1) {
Write-Host "ExchangeOnlineManagement Powershell Module Imported"
} else {
Write-Host "ExchangeOnlineManagement Powershell Module Import failed" -ForegroundColor Red
return $false
}
}

#Validate EXO V2 is connected or try to connect
$connection = $null
$connection = Get-ConnectionInformation -ErrorAction SilentlyContinue
iserrano76 marked this conversation as resolved.
Show resolved Hide resolved
if ($null -eq $connection) {
Write-Host "Please use Global administrator credentials" -ForegroundColor Yellow
if ($Force -or $PSCmdlet.ShouldContinue("Do you want to connect?", "We need a ExchangeOnlineManagement connection")) {
iserrano76 marked this conversation as resolved.
Show resolved Hide resolved
Connect-ExchangeOnline -ErrorAction SilentlyContinue
$connection = Get-ConnectionInformation -ErrorAction SilentlyContinue
if ($null -eq $connection) {
Write-Host "Connection could not be established" -ForegroundColor Red
Write-Host "We cannot continue without ExchangeOnlineManagement Powershell session" -ForegroundColor Red
return $false
} else {
Write-Host "Connected to EXO V2"
Write-Host "Session details"
Write-Host "Tenant Id: $($connection.TenantId)"
Write-Host "User: $($connection.UserPrincipalName)"
return $true
}
} else {
Write-Host "We cannot continue without ExchangeOnlineManagement Powershell session" -ForegroundColor Red
return $false
}
} elseif ($connection.count -eq 1) {
Write-Host "Connected to EXO V2"
Write-Host "Session details"
Write-Host "Tenant Id: $($connection.TenantId)"
Write-Host "User: $($connection.UserPrincipalName)"
return $true
} else {
Write-Host "You have more than one EXO sessions please use just one session" -ForegroundColor Red
return $false
}
}

function Test-AADConnection {
[CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'High')]
[OutputType([bool])]
iserrano76 marked this conversation as resolved.
Show resolved Hide resolved
param (
[Switch]$Force
iserrano76 marked this conversation as resolved.
Show resolved Hide resolved
)

#Validate AzureAD is installed
if ((Get-Module -ListAvailable | Where-Object { $_.Name -like "AzureAD" }).count -ge 1) {
Write-Host "AzureAD Powershell Module installed"
} else {
if ($Force -or $PSCmdlet.ShouldContinue("Do you want to install the module?", "AzureAD Powershell Module not installed")) {
iserrano76 marked this conversation as resolved.
Show resolved Hide resolved
Install-Module -Name AzureAD -Repository PSGallery -AllowClobber -Force -ErrorAction SilentlyContinue -Scope CurrentUser
if ((Get-Module -ListAvailable | Where-Object { $_.Name -like "AzureAD" }).count -ge 1) {
Write-Host "AzureAD Powershell Module installed"
} else {
Write-Host "AzureAD Powershell Module installation failed" -ForegroundColor Red
return $false
}
} else {
Write-Host "We cannot continue without AzureAD Powershell module" -ForegroundColor Red
return $false
}
}

#Validate AzureAD is loaded
if ((Get-Module | Where-Object { $_.Name -like "AzureAD" }).count -ge 1) {
iserrano76 marked this conversation as resolved.
Show resolved Hide resolved
Write-Host "AzureAD Powershell Module loaded"
} else {
Import-Module AzureAD -ErrorAction SilentlyContinue -Force
if ((Get-Module | Where-Object { $_.Name -like "AzureAD" }).count -ge 1) {
Write-Host "AzureAD Powershell Module Imported"
} else {
Write-Host "AzureAD Powershell Module Import failed" -ForegroundColor Red
return $false
}
}

#Validate AzureAD is connected or try to connect
try {
$connection = $null
$connection = Get-AzureADTenantDetail -ErrorAction SilentlyContinue
if ($null -eq $connection) {
Write-Host "Not connected to AzureAD" -ForegroundColor Red
Write-Host "We cannot continue without AzureAD Powershell session" -ForegroundColor Red
return $false
} else {
if ($connection.count -eq 1) {
Write-Host "Connected to AzureAD"
Write-Host "Session details"
Write-Host "Tenant: $($connection.DisplayName)"
return $true
} else {
Write-Host "You have more than one AzureAD sessions please use just one session" -ForegroundColor Red
return $false
}
}
} catch [Microsoft.Open.Azure.AD.CommonLibrary.AadNeedAuthenticationException] {
iserrano76 marked this conversation as resolved.
Show resolved Hide resolved
Write-Host "Please use Global administrator credentials" -ForegroundColor Yellow
if ($Force -or $PSCmdlet.ShouldContinue("Do you want to connect?", "We need a AzureAD connection")) {
Connect-AzureAD -ErrorAction SilentlyContinue
try {
$connection = Get-AzureADTenantDetail -ErrorAction SilentlyContinue
if ($null -eq $connection) {
Write-Host "Connection could not be established" -ForegroundColor Red
Write-Host "We cannot continue without AzureAD Powershell session" -ForegroundColor Red
return $false
} else {
Write-Host "Connected to AzureAD"
Write-Host "Session details"
Write-Host "Tenant: $($connection.DisplayName)"
return $true
}
} catch [Microsoft.Open.Azure.AD.CommonLibrary.AadNeedAuthenticationException] {
Write-Host "Connection could not be established" -ForegroundColor Red
Write-Host "We cannot continue without AzureAD Powershell session" -ForegroundColor Red
return $false
iserrano76 marked this conversation as resolved.
Show resolved Hide resolved
}
} else {
Write-Host "We cannot continue without AzureAD Powershell session" -ForegroundColor Red
return $false
}
}
}
104 changes: 104 additions & 0 deletions Shared/M365/GraphConnection.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.

. $PSScriptRoot\..\ModuleHandle.ps1

iserrano76 marked this conversation as resolved.
Show resolved Hide resolved
function Connect-GraphAdvanced {
param (
[Parameter(Mandatory = $true)]
[string[]]$Scopes,
[Parameter(Mandatory = $true)]
[string[]]$Modules,
[Parameter(Mandatory = $false)]
[switch]$DoNotShowConnectionDetails
)

#Validate Graph is installed and loaded
$requestModule = $false
$requestModule = Request-Module -Modules $Modules
iserrano76 marked this conversation as resolved.
Show resolved Hide resolved
if (-not $requestModule) {
Write-Host "We cannot continue without $Modules Powershell module" -ForegroundColor Red
return $null
}

#Validate Graph is connected or try to connect
$connection = $null
$connection = Get-MgContext -ErrorAction SilentlyContinue
if ($null -eq $connection) {
Write-Host "Not connected to Graph" -ForegroundColor Yellow
$connection = Add-GraphConnection -Scopes $Scopes
} else {
Write-Verbose "You have a Graph sessions"
Write-Verbose "Checking scopes"
if (-not (Test-GraphContext -Scopes $connection.Scopes -ExpectedScopes $Scopes)) {
Write-Host "Not connected to Graph with expected scopes" -ForegroundColor Yellow
$connection = Add-GraphConnection -Scopes $Scopes
}
}
if ($null -ne $connection -and -not $DoNotShowConnectionDetails) {
$connection.PSObject.Properties | ForEach-Object { Write-Verbose "$($_.Name): $($_.Value)" }
Show-GraphContext -Context $connection
}
return $connection
}

function Add-GraphConnection {
[CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = "High")]
param (
[Parameter(Mandatory = $true)]
[string[]]$Scopes
)

if ($PSCmdlet.ShouldProcess("Do you want to connect?", "We need a Graph connection with scopes $Scopes")) {
Write-Verbose "Connecting to Microsoft Graph API using scopes $Scopes"
Connect-MgGraph -Scopes $Scopes -NoWelcome -ErrorAction SilentlyContinue
$connection = $null
$connection = Get-MgContext -ErrorAction SilentlyContinue
Write-Verbose "Checking scopes"
if (-not $connection) {
Write-Host "We cannot continue without Graph Powershell session" -ForegroundColor Red
return $null
}
if (-not (Test-GraphContext -Scopes $connection.Scopes -ExpectedScopes $Scopes)) {
Write-Host "We cannot continue without Graph Powershell session without Expected Scopes" -ForegroundColor Red
return $null
}
return $connection
}
}

function Test-GraphContext {
iserrano76 marked this conversation as resolved.
Show resolved Hide resolved
[OutputType([bool])]
param (
[Parameter(Mandatory = $true)]
[string[]]$ExpectedScopes,
[Parameter(Mandatory = $true)]
[string[]]$Scopes
)

$foundError = $false
foreach ($expectedScope in $ExpectedScopes) {
if ($Scopes -notcontains $expectedScope) {
Write-Host "The following scope is missing: $expectedScope" -ForegroundColor Red
$foundError = $true
}
}

if ($foundError) {
return $false
} else {
Write-Verbose "All expected scopes are present."
return $true
}
iserrano76 marked this conversation as resolved.
Show resolved Hide resolved
}

function Show-GraphContext {
param (
[Parameter(Mandatory = $true)]
[Microsoft.Graph.PowerShell.Authentication.AuthContext]$Context
)
Write-Host "`nConnected to Graph"
Write-Host "Session details"
Write-Host "Tenant Id: $($Context.TenantId)"
Write-Host "Account: $($Context.Account)"
}
51 changes: 51 additions & 0 deletions Shared/ModuleHandle.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.

iserrano76 marked this conversation as resolved.
Show resolved Hide resolved
function Request-Module {
[OutputType([bool])]
param (
[Parameter(Mandatory = $true)]
[string[]]$Modules,
[Parameter(Mandatory = $false)]
[System.Version]$MinModuleVersion = $null
Comment on lines +33 to +34
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should add a parameter validation here for if multiple $Modules are provided, that we should not be trying to find a $MinModuleVersion available.

image

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting I did not see that documented.
Maybe could be better to check one by one.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's also address this prior to merging.

)
dpaulson45 marked this conversation as resolved.
Show resolved Hide resolved

$installed = $null
iserrano76 marked this conversation as resolved.
Show resolved Hide resolved
Write-Verbose "Checking $Modules PowerShell Module"
if ($MinModuleVersion) {
Write-Verbose "with minimum version $minModuleVersion"
$installed = Get-InstalledModule -Name $Modules -MinimumVersion $MinModuleVersion -ErrorAction SilentlyContinue
} else {
Write-Verbose "without minimum version"
$installed = Get-InstalledModule -Name $Modules -ErrorAction SilentlyContinue
}

$foundError = $false
foreach ($module in $Modules) {
if ($null-eq $installed -or $installed.Name -notcontains $module) {
Write-Host "The following module is missing: $module" -ForegroundColor Yellow
$confirmed = $null
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't required if we are setting $confirmed prior to testing it in an if statement.

if ($MinModuleVersion) {
Write-Verbose "Installing $module with minimum version $minModuleVersion"
Install-Module -Name $module -Scope CurrentUser -MinimumVersion $MinModuleVersion
$confirmed = Get-InstalledModule -Name $module -MinimumVersion $MinModuleVersion -ErrorAction SilentlyContinue
if (-not $confirmed) {
Write-Host "We could not install module: $module with minimum version $minModuleVersion" -ForegroundColor Red
$foundError = $true
}
} else {
Write-Verbose "Installing $module"
Install-Module -Name $module -Scope CurrentUser
$confirmed = Get-InstalledModule -Name $module -ErrorAction SilentlyContinue
if (-not $confirmed) {
Write-Host "We could not install module: $module" -ForegroundColor Red
$confirmed = $true
}
}
}
}
if ($foundError) {
return $false
}
return $true
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could change to

return (-not $foundError) 

image

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, I think we should exit if we find an error. If we are using this function, we should just straight up exit if we run into an issue as the request of the script shouldn't work. Thoughts?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

About the first comment, agree, it is easier. I will simplify it.

About second one, similar to previous one, if works I return true if fails I return false and leave the decision on the one that use the function.
I think maybe you can try to request another version and it is more flexible.
What do you think?

}