MSCloudLoginAssistant.psm1
<#
.SYNOPSIS The Test-MSCloudLogin function is used to assist with logging in to various Microsoft Cloud services, such as Azure, SharePoint Online, and SharePoint PnP. .EXAMPLE Test-MSCloudLogin -Platform AzureAD -UseMFA .EXAMPLE Test-MSCloudLogin -Platform PnP .PARAMETER Platform The Platform parameter specifies which cloud service for which we are testing the login state. Possible values are Azure, AzureAD, SharePointOnline, ExchangeOnline, MSOnline, and PnP. .PARAMETER UseMFA The UseMFA switch specifies that we already know the credentials we are logging in with require Multi-Factor Authentication so we won't even bother prompting for Windows-style credentials. .NOTES Created & maintained by Brian Lalancette (@brianlala), 2019. .LINK https://github.com/brianlala/Test-MSCloudLogin #> function Test-MSCloudLogin { [CmdletBinding()] param ( [Parameter(Mandatory=$true)] [ValidateSet("Azure","AzureAD","SharePointOnline","ExchangeOnline","MSOnline","PnP")] $Platform, [Parameter(Mandatory=$false)] [switch] $UseMFA ) switch ($Platform) { "Azure" {$testCmdlet = "Get-AzResource"; $exceptionStringMFA = "AADSTS50079"; $connectCmdlet = "Connect-AzAccount"; $variablePrefix = "az"} "AzureAD" {$testCmdlet = "Get-AzureADUser"; $exceptionStringMFA = "AADSTS"; $connectCmdlet = "Connect-AzureAD"; $connectCmdletArgs = "-Credential `$global:o365Credentials"; $variablePrefix = "aad"} "SharePointOnline" {Get-SPOAdminUrl; $testCmdlet = "Get-SPOSite"; $exceptionStringMFA = "sign-in name or password does not match one in the Microsoft account system"; $connectCmdlet = "Connect-SPOService"; $connectCmdletArgs = "-Url $global:AdminUrl -Credential `$global:o365Credentials"; $variablePrefix = "spo"} "ExchangeOnline" {$testCmdlet = "Get-Mailbox"; $exceptionStringMFA = "AADSTS"; $connectCmdlet = "Connect-AzureAD"; $connectCmdletArgs = "-Credential `$global:o365Credentials"; $variablePrefix = "exo"} "MSOnline" {$testCmdlet = "Get-MsolUser"; $exceptionStringMFA = "AADSTS"; $connectCmdlet = "Connect-MsolService"; $connectCmdletArgs = "-Credential `$global:o365Credentials"; $variablePrefix = "msol"} "PnP" {Get-SPOAdminUrl; $testCmdlet = "Get-PnPSite"; $exceptionStringMFA = "sign-in name or password does not match one in the Microsoft account system"; $connectCmdlet = "Connect-PnPOnline"; $connectCmdletArgs = "-Url $(($global:AdminUrl).Replace('-admin','')) -Credentials `$global:o365Credentials"; $variablePrefix = "pnp"} } New-Variable -Name $variablePrefix"LoginSucceeded" -Value $false -Scope Global -Option AllScope -Force Write-Debug -Message `$$variablePrefix"LoginSucceeded is $(Get-Variable -Name $($variablePrefix+"LoginSucceeded") -ValueOnly -Scope Global -ErrorAction SilentlyContinue)." try { Write-Verbose -Message " - Checking $Platform login..." # Run a simple command to check if we are logged in Invoke-Expression "$testCmdlet -ErrorAction Stop -WarningAction SilentlyContinue | Out-Null" if ($? -eq $false) { throw } else { Write-Verbose -Message " - You are already logged in to $Platform." } } catch { if ($_.Exception -like "*$connectCmdlet*") { try { # Only prompt for Windows-style credentials if we haven't explicitly specified multi-factor authentication if (($null -eq $global:o365Credentials) -and (!$UseMFA)) { $global:o365Credentials = Get-O365Credentials Write-Verbose -Message " - Will attempt to use credential for `"$($global:o365Credentials.UserName)`"..." } Write-Host -ForegroundColor Cyan " - Prompting for $Platform credentials..." Write-Verbose -Message " - Running '$connectCmdlet -ErrorAction Stop $connectCmdletArgs -ErrorVariable `$err'" Invoke-Expression "$connectCmdlet -ErrorAction Stop $connectCmdletArgs -ErrorVariable `$err" # | Out-Null" if ($? -eq $false -or $err) { throw } else { New-Variable -Name $variablePrefix"LoginSucceeded" -Value $true -Scope Global -Option AllScope -Force Write-Debug -Message `$$variablePrefix"LoginSucceeded is $(Get-Variable -Name $($variablePrefix+"LoginSucceeded") -ValueOnly -Scope Global -ErrorAction SilentlyContinue)." } } catch { if ($_.Exception -like "*User canceled authentication*") { throw "User canceled authentication" } elseif ($_.Exception -like "*The user name or password is incorrect*") { throw "Bad credentials were supplied" } elseif ($_.Exception -like "*$exceptionStringMFA*" -or $_.Exception -like "*Sequence contains no elements*") { Write-Verbose -Message " - Using existing credentials failed (possibly due to MFA or Live ID); prompting for fresh credentials..." try { # Remove the credential info from the arguments string and try again $connectCmdletArgs = $connectCmdletArgs.Replace('-Credential $global:o365Credentials','') Write-Debug -Message "`$connectCmdletArgs is $connectCmdletArgs" Invoke-Expression "$connectCmdlet -ErrorAction Stop $connectCmdletArgs | Out-Null" if ($? -eq $false) { throw } else { New-Variable -Name $variablePrefix"LoginSucceeded" -Value $true -Scope Global -Option AllScope -Force Write-Debug $variablePrefix"LoginSucceeded is $(Get-Variable -Name $($variablePrefix+"LoginSucceeded") -ValueOnly -Scope Global -ErrorAction SilentlyContinue)." } } catch { Write-Host -ForegroundColor Red $_.Exception throw "No/invalid credentials were provided, or another error occurred logging on to $Platform." } } else { Write-Host -ForegroundColor Red $_.Exception throw "No/invalid credentials were provided, or another error occurred logging on to $Platform." } } } elseif ($_.Exception -like "*Unable to acquire token for tenant*") { Write-Host -ForegroundColor Red $_.Exception } elseif ($_.Exception -like "*null array*") { # Do nothing } else { Write-Host -ForegroundColor Red $_.Exception } } finally { if (Get-Variable -Name $variablePrefix"LoginSucceeded" -ValueOnly -Scope "Global") { Write-Host -ForegroundColor Green " - Successfully logged in to $Platform." } } } function Test-AzureADLogin { [CmdletBinding()] param ( [Parameter(Mandatory=$false)] [switch] $UseMFA ) if ($UseMFA) { $UseMFASwitch = @{UseMFA = $true} } else { $UseMFASwitch = @{} } Write-Debug -Message "`$aadLoginSucceeded is $(Get-Variable -Name aadLoginSucceeded -ValueOnly -Scope Global -ErrorAction SilentlyContinue)." if (!$aadLoginSucceeded) { Test-MSCloudLogin -platform "AzureAD" @useMFASwitch } else { Write-Verbose -Message "Already logged into Azure AD." } } # Checks to see if we can run a simple Az command or if we get an exception about "Run Login-AzAccount to login" function Test-AzLogin { [CmdletBinding()] param ( [Parameter(Mandatory=$false)] [switch] $UseMFA ) if ($UseMFA) { $UseMFASwitch = @{UseMFA = $true} } else { $UseMFASwitch = @{} } Write-Debug -Message "`$azLoginSucceeded is $(Get-Variable -Name azLoginSucceeded -ValueOnly -Scope Global -ErrorAction SilentlyContinue)." $checkForMultiSubscriptions = $true if (!$azLoginSucceeded) { Test-MSCloudLogin -Platform "Azure" @useMFASwitch } else { Write-Verbose -Message " - Already logged into Azure." $checkForMultiSubscriptions = $false } if ($azLoginSucceeded -and $checkForMultiSubscriptions) { Write-Verbose -Message " - Successfully logged in to Azure." [array]$subscriptions = Get-AzSubscription -WarningAction Continue # Prompt for a subscription in case we have more than one if ($subscriptions.Count -gt 1) { Write-Host -ForegroundColor Cyan " - Prompting for subscription..." $global:subscriptionDetails = Get-AzSubscription -WarningAction SilentlyContinue | Sort-Object Name | Out-GridView -Title "Select ONE subscription..." -PassThru if ($null -eq $subscriptionDetails) { throw " - A subscription must be selected." } elseif ($subscriptionDetails.Count -gt 1) { throw " - Please select *only one* subscription." } Write-Host -ForegroundColor White " - Setting active subscription to '$($global:subscriptionDetails.Name)'..." Set-AzContext -Subscription $global:subscriptionDetails.Id } } } function Get-O365Credentials { [CmdletBinding()] param ( [Parameter(Mandatory=$false)] [String]$Username ) if (!([string]::IsNullOrEmpty($Username))) { $userNameParameter = @{Username = $Username} } Write-Host -ForegroundColor Cyan " - Prompting for O365 credentials..." $global:o365Credentials = Get-Credential -Message "Please enter your credentials for Office 365" @userNameParameter return $global:o365Credentials } function Get-SPOAdminUrl { [CmdletBinding()] param () Test-AzureADLogin Write-Verbose -Message "Getting SharePoint Online admin URL..." $defaultDomain = Get-AzureADDomain | Where-Object {$_.Name -like "*.onmicrosoft.com" -and $_.IsInitial -eq $true} # We don't use IsDefault here because the default could be a custom domain $global:tenantName = $defaultDomain[0].Name -replace ".onmicrosoft.com","" $global:AdminUrl = "https://$global:tenantName-admin.sharepoint.com" Write-Verbose -Message "SharePoint Online admin URL is $global:AdminUrl" } |