BounShell.psm1
<#
.SYNOPSIS This is a tool to help users manage multiple office 365 tenants .DESCRIPTION Created by James Arber. www.UcMadScientist.com .NOTES Version : 0.6.1 Date : 04/05/2019 Lync Version : Tested against Skype4B 2015 Author : James Arber Header stolen from : Greig Sheridan who stole it from Pat Richard's amazing "Get-CsConnections.ps1" Special Thanks to : My Beta Testers. Greig Sheridan, Pat Richard and Justin O'Meara :v0.6: Beta Release Enabled Modern Auth Support Formating changes Broke up alot of my one-liners to make it easier for others to read/ understand the flow Updated error messages Better code comments Fixed an issue with the Compliance Portal code Added Module checker and installer based off Andrew Price's "Detect-MicrosoftTeams-Version" http://www.blogabout.cloud/2018/09/240/ Now Gluten Free Finally stopped feature creep :v0.5: Closed Beta Release Disclaimer: Whilst I take considerable effort to ensure this script is error free and wont harm your enviroment. I have no way to test every possible senario it may be used in. I provide these scripts free to the Lync and Skype4B community AS IS without any warranty on its appropriateness for use in your environment. I disclaim all implied warranties including, without limitation, any implied warranties of merchantability or of fitness for a particular purpose. The entire risk arising out of the use or performance of the sample scripts and documentation remains with you. In no event shall I be liable for any damages whatsoever (including, without limitation, damages for loss of business profits, business interruption, loss of business information, or other pecuniary loss) arising out of the use of or inability to use the script or documentation. Acknowledgements : Testing and Advice Greig Sheridan https://greiginsydney.com/about/ @greiginsydney : Auto Update Code Pat Richard https://ucunleashed.com @patrichard : Proxy Detection Michel de Rooij http://eightwone.com .LINK https://www.UcMadScientist.com/BounShell .KNOWN ISSUES Beta, Buggy as all get out. .EXAMPLE Loads the Module PS C:\> Start-BounShell.ps1 #> [CmdletBinding(DefaultParametersetName="Common")] param ( [Parameter(Mandatory=$false)] [switch]$SkipUpdateCheck, [Parameter(Mandatory=$false)] [String]$ConfigFilePath = $null, [Parameter(Mandatory=$false)] [String]$LogFileLocation = $null, [Parameter(Mandatory=$false)] [float]$Tenant = $null ) #region config [Net.ServicePointManager]::SecurityProtocol = 'tls12, tls11, tls' $StartTime = Get-Date $VerbosePreference = "SilentlyContinue" #TODO [float]$ScriptVersion = '0.6.1' [string]$GithubRepo = 'BounShell' ##todo [string]$GithubBranch = 'devel' #todo [string]$BlogPost = 'https://www.UcMadScientist.com/BounShell/' #todo #Check to see if paths were specified, Otherwise set defaults If (!$LogFileLocation) { $global:LogFileLocation = "$ENV:UserProfile\BounShell.log" } If (!$ConfigFilePath) { $global:ConfigFilePath = "$ENV:UserProfile\BounShell.xml" } #endregion config Function Write-Log { <# .SYNOPSIS Function to output messages to the console based on their severity and create log files .DESCRIPTION It's a logger. .PARAMETER Message The message to write .PARAMETER Path The location of the logfile. .PARAMETER Severity Sets the severity of the log message, Higher severities will call Write-Warning or Write-Error .PARAMETER Component Used to track the module or function that called "Write-Log" .PARAMETER LogOnly Forces Write-Log to not display anything to the user .EXAMPLE Write-Log -Message 'This is a log message' -Severity 3 -component 'Example Component' Writes a log file message and displays a warning to the user .NOTES N/A .LINK http://www.UcMadScientist.com .INPUTS This function does not accept pipelined input .OUTPUTS This function does not create pipelined output #> [CmdletBinding()] PARAM ( [String]$Message, [String]$Path = $global:LogFileLocation, [int]$Severity = 1, [string]$Component = 'Default', [switch]$LogOnly ) $Date = Get-Date -Format 'HH:mm:ss' $Date2 = Get-Date -Format 'MM-dd-yyyy' $MaxLogFileSizeMB = 10 If(Test-Path -Path $Path) { if(((Get-ChildItem -Path $Path).length/1MB) -gt $MaxLogFileSizeMB) # Check the size of the log file and archive if over the limit. { $ArchLogfile = $Path.replace('.log', "_$(Get-Date -Format dd-MM-yyy_hh-mm-ss).lo_") Rename-Item -Path ren -NewName $Path -Path $ArchLogfile } } "$env:ComputerName date=$([char]34)$Date2$([char]34) time=$([char]34)$Date$([char]34) component=$([char]34)$component$([char]34) type=$([char]34)$severity$([char]34) Message=$([char]34)$Message$([char]34)"| Out-File -FilePath $Path -Append -NoClobber -Encoding default If (!$LogOnly) { #If LogOnly is set, we dont want to write anything to the screen as we are capturing data that might look bad onscreen #If the log entry is just Verbose (1), output it to verbose if ($severity -eq 1) { "$Date $Message"| Write-Verbose } #If the log entry is just informational (2), output it to write-host if ($severity -eq 2) { "Info: $Date $Message"| Write-Host -ForegroundColor Green } #If the log entry has a severity of 3 assume its a warning and write it to write-warning if ($severity -eq 3) { "$Date $Message"| Write-Warning } #If the log entry has a severity of 4 or higher, assume its an error and display an error message (Note, critical errors are caught by throw statements so may not appear here) if ($severity -ge 4) { "$Date $Message"| Write-Error } } } Function Get-IEProxy { Write-Host "Info: Checking for proxy settings" -ForegroundColor Green If ( (Get-ItemProperty -Path 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings').ProxyEnable -ne 0) { $proxies = (Get-ItemProperty -Path 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings').proxyServer if ($proxies) { if ($proxies -ilike "*=*") { return $proxies -replace "=", "://" -split (';') | Select-Object -First 1 } Else { return ('http://{0}' -f $proxies) } } Else { return $null } } Else { return $null } } Function Get-ScriptUpdate { $Function = 'Get-ScriptUpdate' Write-Log -component $function -Message "Checking for Script Update" -severity 1 Write-Log -component $function -Message "Checking for Proxy" -severity 1 $ProxyURL = Get-IEProxy If ($ProxyURL) { Write-Log -component $function -Message "Using proxy address $ProxyURL" -severity 1 } Else { Write-Log -component $function -Message "No proxy setting detected, using direct connection" -severity 1 } Write-Log -component $function -Message "Polling https://raw.githubusercontent.com/atreidae/$GithubRepo/$GithubBranch/version" -severity 1 $GitHubScriptVersion = Invoke-WebRequest "https://raw.githubusercontent.com/atreidae/$GithubRepo/$GithubBranch/version" -TimeoutSec 10 -Proxy $ProxyURL #todo change back to master! If ($GitHubScriptVersion.Content.length -eq 0) { #Empty data, throw an error Write-Log -component $function -Message "Error checking for new version. You can check manualy here" -severity 3 Write-Log -component $function -Message $BlogPost -severity 1 #Todo Update URL Write-Log -component $function -Message "Pausing for 5 seconds" -severity 1 start-sleep 5 } else { #Process the returned data if ([single]$GitHubScriptVersion.Content -gt [single]$ScriptVersion) { #New Version available, #Prompt user to download Write-Log -component $function -Message "New Version Available" -severity 3 $title = "Update Available" $message = "an update to this script is available, did you want to download it?" $yes = New-Object System.Management.Automation.Host.ChoiceDescription "&Yes", ` "Launches a browser window with the update" $no = New-Object System.Management.Automation.Host.ChoiceDescription "&No", ` "No thanks." $options = [System.Management.Automation.Host.ChoiceDescription[]]($yes, $no) $result = $host.ui.PromptForChoice($title, $message, $options, 0) switch ($result) { 0 { #User said yes Write-Log -component $function -Message "User opted to download update" -severity 1 Start $BlogPost Write-Log -component $function -Message "Exiting Script" -severity 3 Exit } #User said no 1 {Write-Log -component $function -Message "User opted to skip update" -severity 1 } } } #We alreday have the lastest version Else { Write-Log -component $function -Message "Script is upto date" -severity 1 } } } Function Upgrade-BsConfigFile { <# .SYNOPSIS Function to upgrade BounShell Config files .LINK http://www.UcMadScientist.com .INPUTS This function does not accept pipelined input .OUTPUTS This function does not create pipelined output #> $Function= 'Upgrade-BsConfigFile' Write-Log -component $function Write-Log -component $function -Message "Found Config File Version $($global:Config.ConfigFileVersion)" -severity 2 #Backup the current config Try { $ShrtDate = Get-Date -Format 'dd-MM-yy' $global:Config| Export-CliXml -Path "$ENV:UserProfile\BounShell-backup-$ShrtDate.xml" Write-Log -component $function -Message "Backup File Saved" -severity 2 } Catch { Write-Log -component $function -Message "Error writing Config Backup file" -severity 4 Write-Log -component $function -Message "Sorry, something went wrong here and I couldnt backup your BounShell config. Please check permissions to create $ENV:UserProfile\BounShell-backup-$ShrtDate.xml" -severity 3 Throw "Bad File Operation, Abort Script" } If ($global:Config.ConfigFileVersion -lt "0.2") { Write-Log -component $function -Message "Adding Version 0.2 changes" -severity 2 #Config File Version 0.2 additions $global:Config.AutoUpdatesEnabled = $true $global:Config.ModernAuthClipboardEnabled = $true $global:Config.ModernAuthWarningAccepted = $false $global:Config.Tenant1.ConnectToAzureAD = $false $global:Config.Tenant1.ConnectToCompliance = $false $global:Config.Tenant2.ConnectToAzureAD = $false $global:Config.Tenant2.ConnectToCompliance = $false $global:Config.Tenant3.ConnectToAzureAD = $false $global:Config.Tenant3.ConnectToCompliance = $false $global:Config.Tenant4.ConnectToAzureAD = $false $global:Config.Tenant4.ConnectToCompliance = $false $global:Config.Tenant5.ConnectToAzureAD = $false $global:Config.Tenant5.ConnectToCompliance = $false $global:Config.Tenant6.ConnectToAzureAD = $false $global:Config.Tenant6.ConnectToCompliance = $false $global:Config.Tenant7.ConnectToAzureAD = $false $global:Config.Tenant7.ConnectToCompliance = $false $global:Config.Tenant8.ConnectToAzureAD = $false $global:Config.Tenant8.ConnectToCompliance = $false $global:Config.Tenant9.ConnectToAzureAD = $false $global:Config.Tenant9.ConnectToCompliance = $false $global:Config.Tenant10.ConnectToAzureAD = $false $global:Config.Tenant10.ConnectToCompliance = $false [Float]$global:Config.ConfigFileVersion = "0.2" } #Write the XML File Try { $global:Config| Export-CliXml -Path "$ENV:UserProfile\BounShell.xml" Write-Log -component $function -Message "Config File Updated to Version $($global:Config.ConfigFileVersion)" -severity 2 } Catch { Write-Log -component $function -Message "Error writing Config file" -severity 3 } } Function Read-BsConfigFile { $Function= 'Read-BsConfigFile' Write-Log -component $function Write-Log -component $function -Message "Reading Config file $($global:ConfigFilePath)" -severity 2 If(!(Test-Path $global:ConfigFilePath)) { #Cant locate test file, Throw error Write-Log -component $function -Message "Could not locate config file!" -severity 3 Write-Log -component $function -Message "Error reading Config, Loading Defaults" -severity 3 Import-BsDefaultConfig } Else { #Found the config file Write-Log -component $function -Message "Found Config file in the specified folder" -severity 1 } Write-Log -component $function -Message "Pulling XML data" -severity 1 [Void](Remove-Variable -Name Config -Scope Script -ErrorAction SilentlyContinue ) Try { #Load the Config $global:Config=@{} $global:Config = (Import-CliXml -Path $global:ConfigFilePath) Write-Log -component $function -Message "Config File Read OK" -severity 2 #Check the config file version If ($global:Config.ConfigFileVersion -lt 0.2) { Write-Log -component $function -Message "Old Config File Detected. Upgrading config file" -severity 3 Upgrade-BsConfigFile } #Config file is good. #Update the Gui options if we are loaded in the ISE If($PSISE) { #Update the PS ISE Addon Menu Update-BsAddonMenu } #Populate with Values [void] $Global:grid_Tenants.Rows.Clear() [void] $Global:grid_Tenants.Rows.Add("1",$global:Config.Tenant1.DisplayName,$global:Config.Tenant1.SignInAddress,"****",$global:Config.Tenant1.ModernAuth,$global:Config.Tenant1.ConnectToTeams,$global:Config.Tenant1.ConnectToSkype,$global:Config.Tenant1.ConnectToExchange,$global:Config.Tenant1.ConnectToAzureAD,$global:Config.Tenant1.ConnectToCompliance) [void] $Global:grid_Tenants.Rows.Add("2",$global:Config.Tenant2.DisplayName,$global:Config.Tenant2.SignInAddress,"****",$global:Config.Tenant2.ModernAuth,$global:Config.Tenant2.ConnectToTeams,$global:Config.Tenant2.ConnectToSkype,$global:Config.Tenant2.ConnectToExchange,$global:Config.Tenant2.ConnectToAzureAD,$global:Config.Tenant2.ConnectToCompliance) [void] $Global:grid_Tenants.Rows.Add("3",$global:Config.Tenant3.DisplayName,$global:Config.Tenant3.SignInAddress,"****",$global:Config.Tenant3.ModernAuth,$global:Config.Tenant3.ConnectToTeams,$global:Config.Tenant3.ConnectToSkype,$global:Config.Tenant3.ConnectToExchange,$global:Config.Tenant3.ConnectToAzureAD,$global:Config.Tenant3.ConnectToCompliance) [void] $Global:grid_Tenants.Rows.Add("4",$global:Config.Tenant4.DisplayName,$global:Config.Tenant4.SignInAddress,"****",$global:Config.Tenant4.ModernAuth,$global:Config.Tenant4.ConnectToTeams,$global:Config.Tenant4.ConnectToSkype,$global:Config.Tenant4.ConnectToExchange,$global:Config.Tenant4.ConnectToAzureAD,$global:Config.Tenant4.ConnectToCompliance) [void] $Global:grid_Tenants.Rows.Add("5",$global:Config.Tenant5.DisplayName,$global:Config.Tenant5.SignInAddress,"****",$global:Config.Tenant5.ModernAuth,$global:Config.Tenant5.ConnectToTeams,$global:Config.Tenant5.ConnectToSkype,$global:Config.Tenant5.ConnectToExchange,$global:Config.Tenant5.ConnectToAzureAD,$global:Config.Tenant5.ConnectToCompliance) [void] $Global:grid_Tenants.Rows.Add("6",$global:Config.Tenant6.DisplayName,$global:Config.Tenant6.SignInAddress,"****",$global:Config.Tenant6.ModernAuth,$global:Config.Tenant6.ConnectToTeams,$global:Config.Tenant6.ConnectToSkype,$global:Config.Tenant6.ConnectToExchange,$global:Config.Tenant6.ConnectToAzureAD,$global:Config.Tenant6.ConnectToCompliance) [void] $Global:grid_Tenants.Rows.Add("7",$global:Config.Tenant7.DisplayName,$global:Config.Tenant7.SignInAddress,"****",$global:Config.Tenant7.ModernAuth,$global:Config.Tenant7.ConnectToTeams,$global:Config.Tenant7.ConnectToSkype,$global:Config.Tenant7.ConnectToExchange,$global:Config.Tenant7.ConnectToAzureAD,$global:Config.Tenant7.ConnectToCompliance) [void] $Global:grid_Tenants.Rows.Add("8",$global:Config.Tenant8.DisplayName,$global:Config.Tenant8.SignInAddress,"****",$global:Config.Tenant8.ModernAuth,$global:Config.Tenant8.ConnectToTeams,$global:Config.Tenant8.ConnectToSkype,$global:Config.Tenant8.ConnectToExchange,$global:Config.Tenant8.ConnectToAzureAD,$global:Config.Tenant8.ConnectToCompliance) [void] $Global:grid_Tenants.Rows.Add("9",$global:Config.Tenant9.DisplayName,$global:Config.Tenant9.SignInAddress,"****",$global:Config.Tenant9.ModernAuth,$global:Config.Tenant9.ConnectToTeams,$global:Config.Tenant9.ConnectToSkype,$global:Config.Tenant9.ConnectToExchange,$global:Config.Tenant9.ConnectToAzureAD,$global:Config.Tenant9.ConnectToCompliance) [void] $Global:grid_Tenants.Rows.Add("10",$global:Config.Tenant10.DisplayName,$global:Config.Tenant10.SignInAddress,"****",$global:Config.Tenant10.ModernAuth,$global:Config.Tenant10.ConnectToTeams,$global:Config.Tenant10.ConnectToSkype,$global:Config.Tenant10.ConnectToExchange,$global:Config.Tenant10.ConnectToAzureAD,$global:Config.Tenant10.ConnectToCompliance) } Catch { #For some reason we ran into an issue updating variables, throw and error and revert to defaults Write-Log -component $function -Message "Error reading Config or updating GUI, Loading Defaults" -severity 3 Import-BsDefaultConfig } } Function Write-BsConfigFile { $function = 'Write-BsConfigFile' Write-Log -component $function -Message "Writing Config file" -severity 2 #Grab items from the GUI and stuff them into something useful $global:Config.Tenant1.DisplayName = $Global:grid_Tenants.Rows[0].Cells[1].Value $global:Config.Tenant1.SignInAddress = $Global:grid_Tenants.Rows[0].Cells[2].Value $global:Config.Tenant1.ModernAuth = $Global:grid_Tenants.Rows[0].Cells[4].Value $global:Config.Tenant1.ConnectToTeams = $Global:grid_Tenants.Rows[0].Cells[5].Value $global:Config.Tenant1.ConnectToSkype = $Global:grid_Tenants.Rows[0].Cells[6].Value $global:Config.Tenant1.ConnectToExchange = $Global:grid_Tenants.Rows[0].Cells[7].Value $global:Config.Tenant1.ConnectToAzureAD = $Global:grid_Tenants.Rows[0].Cells[8].Value $global:Config.Tenant1.ConnectToCompliance = $Global:grid_Tenants.Rows[0].Cells[9].Value $global:Config.Tenant2.DisplayName = $Global:grid_Tenants.Rows[1].Cells[1].Value $global:Config.Tenant2.SignInAddress = $Global:grid_Tenants.Rows[1].Cells[2].Value $global:Config.Tenant2.ModernAuth = $Global:grid_Tenants.Rows[1].Cells[4].Value $global:Config.Tenant2.ConnectToTeams = $Global:grid_Tenants.Rows[1].Cells[5].Value $global:Config.Tenant2.ConnectToSkype = $Global:grid_Tenants.Rows[1].Cells[6].Value $global:Config.Tenant2.ConnectToExchange = $Global:grid_Tenants.Rows[1].Cells[7].Value $global:Config.Tenant2.ConnectToAzureAD = $Global:grid_Tenants.Rows[1].Cells[8].Value $global:Config.Tenant2.ConnectToCompliance = $Global:grid_Tenants.Rows[1].Cells[9].Value $global:Config.Tenant3.DisplayName = $Global:grid_Tenants.Rows[2].Cells[1].Value $global:Config.Tenant3.SignInAddress = $Global:grid_Tenants.Rows[2].Cells[2].Value $global:Config.Tenant3.ModernAuth = $Global:grid_Tenants.Rows[2].Cells[4].Value $global:Config.Tenant3.ConnectToTeams = $Global:grid_Tenants.Rows[2].Cells[5].Value $global:Config.Tenant3.ConnectToSkype = $Global:grid_Tenants.Rows[2].Cells[6].Value $global:Config.Tenant3.ConnectToExchange = $Global:grid_Tenants.Rows[2].Cells[7].Value $global:Config.Tenant3.ConnectToAzureAD = $Global:grid_Tenants.Rows[2].Cells[8].Value $global:Config.Tenant3.ConnectToCompliance = $Global:grid_Tenants.Rows[2].Cells[9].Value $global:Config.Tenant4.DisplayName = $Global:grid_Tenants.Rows[3].Cells[1].Value $global:Config.Tenant4.SignInAddress = $Global:grid_Tenants.Rows[3].Cells[2].Value $global:Config.Tenant4.ModernAuth = $Global:grid_Tenants.Rows[3].Cells[4].Value $global:Config.Tenant4.ConnectToTeams = $Global:grid_Tenants.Rows[3].Cells[5].Value $global:Config.Tenant4.ConnectToSkype = $Global:grid_Tenants.Rows[3].Cells[6].Value $global:Config.Tenant4.ConnectToExchange = $Global:grid_Tenants.Rows[3].Cells[7].Value $global:Config.Tenant4.ConnectToAzureAD = $Global:grid_Tenants.Rows[3].Cells[8].Value $global:Config.Tenant4.ConnectToCompliance = $Global:grid_Tenants.Rows[3].Cells[9].Value $global:Config.Tenant5.DisplayName = $Global:grid_Tenants.Rows[4].Cells[1].Value $global:Config.Tenant5.SignInAddress = $Global:grid_Tenants.Rows[4].Cells[2].Value $global:Config.Tenant5.ModernAuth = $Global:grid_Tenants.Rows[4].Cells[4].Value $global:Config.Tenant5.ConnectToTeams = $Global:grid_Tenants.Rows[4].Cells[5].Value $global:Config.Tenant5.ConnectToSkype = $Global:grid_Tenants.Rows[4].Cells[6].Value $global:Config.Tenant5.ConnectToExchange = $Global:grid_Tenants.Rows[4].Cells[7].Value $global:Config.Tenant5.ConnectToAzureAD = $Global:grid_Tenants.Rows[4].Cells[8].Value $global:Config.Tenant5.ConnectToCompliance = $Global:grid_Tenants.Rows[4].Cells[9].Value $global:Config.Tenant6.DisplayName = $Global:grid_Tenants.Rows[5].Cells[1].Value $global:Config.Tenant6.SignInAddress = $Global:grid_Tenants.Rows[5].Cells[2].Value $global:Config.Tenant6.ModernAuth = $Global:grid_Tenants.Rows[5].Cells[4].Value $global:Config.Tenant6.ConnectToTeams = $Global:grid_Tenants.Rows[5].Cells[5].Value $global:Config.Tenant6.ConnectToSkype = $Global:grid_Tenants.Rows[5].Cells[6].Value $global:Config.Tenant6.ConnectToExchange = $Global:grid_Tenants.Rows[5].Cells[7].Value $global:Config.Tenant6.ConnectToAzureAD = $Global:grid_Tenants.Rows[5].Cells[8].Value $global:Config.Tenant6.ConnectToCompliance = $Global:grid_Tenants.Rows[5].Cells[9].Value $global:Config.Tenant7.DisplayName = $Global:grid_Tenants.Rows[6].Cells[1].Value $global:Config.Tenant7.SignInAddress = $Global:grid_Tenants.Rows[6].Cells[2].Value $global:Config.Tenant7.ModernAuth = $Global:grid_Tenants.Rows[6].Cells[4].Value $global:Config.Tenant7.ConnectToTeams = $Global:grid_Tenants.Rows[6].Cells[5].Value $global:Config.Tenant7.ConnectToSkype = $Global:grid_Tenants.Rows[6].Cells[6].Value $global:Config.Tenant7.ConnectToExchange = $Global:grid_Tenants.Rows[6].Cells[7].Value $global:Config.Tenant7.ConnectToAzureAD = $Global:grid_Tenants.Rows[6].Cells[8].Value $global:Config.Tenant7.ConnectToCompliance = $Global:grid_Tenants.Rows[6].Cells[9].Value $global:Config.Tenant8.DisplayName = $Global:grid_Tenants.Rows[7].Cells[1].Value $global:Config.Tenant8.SignInAddress = $Global:grid_Tenants.Rows[7].Cells[2].Value $global:Config.Tenant8.ModernAuth = $Global:grid_Tenants.Rows[7].Cells[4].Value $global:Config.Tenant8.ConnectToTeams = $Global:grid_Tenants.Rows[7].Cells[5].Value $global:Config.Tenant8.ConnectToSkype = $Global:grid_Tenants.Rows[7].Cells[6].Value $global:Config.Tenant8.ConnectToExchange = $Global:grid_Tenants.Rows[7].Cells[7].Value $global:Config.Tenant8.ConnectToAzureAD = $Global:grid_Tenants.Rows[7].Cells[8].Value $global:Config.Tenant8.ConnectToCompliance = $Global:grid_Tenants.Rows[7].Cells[9].Value $global:Config.Tenant9.DisplayName = $Global:grid_Tenants.Rows[8].Cells[1].Value $global:Config.Tenant9.SignInAddress = $Global:grid_Tenants.Rows[8].Cells[2].Value $global:Config.Tenant9.ModernAuth = $Global:grid_Tenants.Rows[8].Cells[4].Value $global:Config.Tenant9.ConnectToTeams = $Global:grid_Tenants.Rows[8].Cells[5].Value $global:Config.Tenant9.ConnectToSkype = $Global:grid_Tenants.Rows[8].Cells[6].Value $global:Config.Tenant9.ConnectToExchange = $Global:grid_Tenants.Rows[8].Cells[7].Value $global:Config.Tenant9.ConnectToAzureAD = $Global:grid_Tenants.Rows[8].Cells[8].Value $global:Config.Tenant9.ConnectToCompliance = $Global:grid_Tenants.Rows[8].Cells[9].Value $global:Config.Tenant10.DisplayName = $Global:grid_Tenants.Rows[9].Cells[1].Value $global:Config.Tenant10.SignInAddress = $Global:grid_Tenants.Rows[9].Cells[2].Value $global:Config.Tenant10.ModernAuth = $Global:grid_Tenants.Rows[9].Cells[4].Value $global:Config.Tenant10.ConnectToTeams = $Global:grid_Tenants.Rows[9].Cells[5].Value $global:Config.Tenant10.ConnectToSkype = $Global:grid_Tenants.Rows[9].Cells[6].Value $global:Config.Tenant10.ConnectToExchange = $Global:grid_Tenants.Rows[9].Cells[7].Value $global:Config.Tenant10.ConnectToAzureAD = $Global:grid_Tenants.Rows[9].Cells[8].Value $global:Config.Tenant10.ConnectToCompliance = $Global:grid_Tenants.Rows[9].Cells[9].Value #Encrypt passwords If ($Global:grid_Tenants.Rows[0].Cells[3].Value -ne "****") {$global:Config.Tenant1.Credential = ($Global:grid_Tenants.Rows[0].Cells[3].Value | ConvertTo-SecureString -AsPlainText -Force)} If ($Global:grid_Tenants.Rows[1].Cells[3].Value -ne "****") {$global:Config.Tenant2.Credential = ($Global:grid_Tenants.Rows[1].Cells[3].Value | ConvertTo-SecureString -AsPlainText -Force)} If ($Global:grid_Tenants.Rows[2].Cells[3].Value -ne "****") {$global:Config.Tenant3.Credential = ($Global:grid_Tenants.Rows[2].Cells[3].Value | ConvertTo-SecureString -AsPlainText -Force)} If ($Global:grid_Tenants.Rows[3].Cells[3].Value -ne "****") {$global:Config.Tenant4.Credential = ($Global:grid_Tenants.Rows[3].Cells[3].Value | ConvertTo-SecureString -AsPlainText -Force)} If ($Global:grid_Tenants.Rows[4].Cells[3].Value -ne "****") {$global:Config.Tenant5.Credential = ($Global:grid_Tenants.Rows[4].Cells[3].Value | ConvertTo-SecureString -AsPlainText -Force)} If ($Global:grid_Tenants.Rows[5].Cells[3].Value -ne "****") {$global:Config.Tenant6.Credential = ($Global:grid_Tenants.Rows[5].Cells[3].Value | ConvertTo-SecureString -AsPlainText -Force)} If ($Global:grid_Tenants.Rows[6].Cells[3].Value -ne "****") {$global:Config.Tenant7.Credential = ($Global:grid_Tenants.Rows[6].Cells[3].Value | ConvertTo-SecureString -AsPlainText -Force)} If ($Global:grid_Tenants.Rows[7].Cells[3].Value -ne "****") {$global:Config.Tenant8.Credential = ($Global:grid_Tenants.Rows[7].Cells[3].Value | ConvertTo-SecureString -AsPlainText -Force)} If ($Global:grid_Tenants.Rows[8].Cells[3].Value -ne "****") {$global:Config.Tenant9.Credential = ($Global:grid_Tenants.Rows[8].Cells[3].Value | ConvertTo-SecureString -AsPlainText -Force)} If ($Global:grid_Tenants.Rows[9].Cells[3].Value -ne "****") {$global:Config.Tenant10.Credential = ($Global:grid_Tenants.Rows[10].Cells[3].Value | ConvertTo-SecureString -AsPlainText -Force)} #Clear the password fields $Global:grid_Tenants.Rows[0].Cells[3].Value = "****" $Global:grid_Tenants.Rows[1].Cells[3].Value = "****" $Global:grid_Tenants.Rows[2].Cells[3].Value = "****" $Global:grid_Tenants.Rows[3].Cells[3].Value = "****" $Global:grid_Tenants.Rows[4].Cells[3].Value = "****" $Global:grid_Tenants.Rows[5].Cells[3].Value = "****" $Global:grid_Tenants.Rows[6].Cells[3].Value = "****" $Global:grid_Tenants.Rows[7].Cells[3].Value = "****" $Global:grid_Tenants.Rows[8].Cells[3].Value = "****" $Global:grid_Tenants.Rows[9].Cells[3].Value = "****" #Add the Global Settings #todo, delete these $global:Config.AllowUpdates $global:Config.AllowMFAClipboard #Todo map these to the gui elements $global:Config.AutoUpdatesEnabled = $true $global:Config.ModernAuthClipboardEnabled = $true #Write the XML File Try { $global:Config| Export-CliXml -Path "$ENV:UserProfile\BounShell.xml" Write-Log -component $function -Message "Config File Saved" -severity 2 } Catch { Write-Log -component $function -Message "Error writing Config file" -severity 3 } } Function Import-BsDefaultConfig { #Set Variables to Defaults #Remove and re-create the Config Array [Void](Remove-Variable -Name Config -Scope Script -ErrorAction SilentlyContinue) $global:Config=@{} #Populate with Defaults [void] $Global:grid_Tenants.Rows.Clear() $global:Config.Tenant1 =@{} $global:Config.Tenant1.DisplayName = "Undefined" $global:Config.Tenant1.SignInAddress = "user1@fabrikam.com" $global:Config.Tenant1.Credential = "****" $global:Config.Tenant1.ModernAuth = $false $global:Config.Tenant1.ConnectToTeams = $false $global:Config.Tenant1.ConnectToSkype = $false $global:Config.Tenant1.ConnectToExchange = $false $global:Config.Tenant1.ConnectToAzureAD = $false $global:Config.Tenant1.ConnectToCompliance = $false [void] $Global:grid_Tenants.Rows.Add("1",'Undefined','user1@fabrikam.com',"****",$False,$false,$false,$false,$false,$false) $global:Config.Tenant2 =@{} $global:Config.Tenant2.DisplayName = "Undefined" $global:Config.Tenant2.SignInAddress = "user2@fabrikam.com" $global:Config.Tenant2.Credential = "****" $global:Config.Tenant2.ModernAuth = $false $global:Config.Tenant2.ConnectToTeams = $false $global:Config.Tenant2.ConnectToSkype = $false $global:Config.Tenant2.ConnectToExchange = $false $global:Config.Tenant2.ConnectToAzureAD = $false $global:Config.Tenant2.ConnectToCompliance = $false [void] $Global:grid_Tenants.Rows.Add("2",'Undefined','user2@fabrikam.com',"****",$False,$false,$false,$false,$false,$false) $global:Config.Tenant3 =@{} $global:Config.Tenant3.DisplayName = "Undefined" $global:Config.Tenant3.SignInAddress = "user3@fabrikam.com" $global:Config.Tenant3.Credential = "****" $global:Config.Tenant3.ModernAuth = $false $global:Config.Tenant3.ConnectToTeams = $false $global:Config.Tenant3.ConnectToSkype = $false $global:Config.Tenant3.ConnectToExchange = $false $global:Config.Tenant3.ConnectToAzureAD = $false $global:Config.Tenant3.ConnectToCompliance = $false [void] $Global:grid_Tenants.Rows.Add("3",'Undefined','user3@fabrikam.com',"****",$False,$false,$false,$false,$false,$false) $global:Config.Tenant4 =@{} $global:Config.Tenant4.DisplayName = "Undefined" $global:Config.Tenant4.SignInAddress = "user4@fabrikam.com" $global:Config.Tenant4.Credential = "****" $global:Config.Tenant4.ModernAuth = $false $global:Config.Tenant4.ConnectToTeams = $false $global:Config.Tenant4.ConnectToSkype = $false $global:Config.Tenant4.ConnectToExchange = $false $global:Config.Tenant4.ConnectToAzureAD = $false $global:Config.Tenant4.ConnectToCompliance = $false [void] $Global:grid_Tenants.Rows.Add("4",'Undefined','user4@fabrikam.com',"****",$False,$false,$false,$false,$false,$false) $global:Config.Tenant5 =@{} $global:Config.Tenant5.DisplayName = "Undefined" $global:Config.Tenant5.SignInAddress = "user5@fabrikam.com" $global:Config.Tenant5.Credential = "****" $global:Config.Tenant5.ModernAuth = $false $global:Config.Tenant5.ConnectToTeams = $false $global:Config.Tenant5.ConnectToSkype = $false $global:Config.Tenant5.ConnectToExchange = $false $global:Config.Tenant5.ConnectToAzureAD = $false $global:Config.Tenant5.ConnectToCompliance = $false [void] $Global:grid_Tenants.Rows.Add("5",'Undefined','user5@fabrikam.com',"****",$False,$false,$false,$false,$false,$false) $global:Config.Tenant6 =@{} $global:Config.Tenant6.DisplayName = "Undefined" $global:Config.Tenant6.SignInAddress = "user6@fabrikam.com" $global:Config.Tenant6.Credential = "****" $global:Config.Tenant6.ModernAuth = $false $global:Config.Tenant6.ConnectToTeams = $false $global:Config.Tenant6.ConnectToSkype = $false $global:Config.Tenant6.ConnectToExchange = $false $global:Config.Tenant6.ConnectToAzureAD = $false $global:Config.Tenant6.ConnectToCompliance = $false [void] $Global:grid_Tenants.Rows.Add("6",'Undefined','user6@fabrikam.com',"****",$False,$false,$false,$false,$false,$false) $global:Config.Tenant7 =@{} $global:Config.Tenant7.DisplayName = "Undefined" $global:Config.Tenant7.SignInAddress = "user@fabrikam.com" $global:Config.Tenant7.Credential = "****" $global:Config.Tenant7.ModernAuth = $false $global:Config.Tenant7.ConnectToTeams = $false $global:Config.Tenant7.ConnectToSkype = $false $global:Config.Tenant7.ConnectToExchange = $false $global:Config.Tenant7.ConnectToAzureAD = $false $global:Config.Tenant7.ConnectToCompliance = $false [void] $Global:grid_Tenants.Rows.Add("7",'Undefined','user7@fabrikam.com',"****",$False,$false,$false,$false,$false,$false) $global:Config.Tenant8 =@{} $global:Config.Tenant8.DisplayName = "Undefined" $global:Config.Tenant8.SignInAddress = "user8@fabrikam.com" $global:Config.Tenant8.Credential = "****" $global:Config.Tenant8.ModernAuth = $false $global:Config.Tenant8.ConnectToTeams = $false $global:Config.Tenant8.ConnectToSkype = $false $global:Config.Tenant8.ConnectToExchange = $false $global:Config.Tenant8.ConnectToAzureAD = $false $global:Config.Tenant8.ConnectToCompliance = $false [void] $Global:grid_Tenants.Rows.Add("8",'Undefined','user8@fabrikam.com',"****",$False,$false,$false,$false,$false,$false) $global:Config.Tenant9 =@{} $global:Config.Tenant9.DisplayName = "Undefined" $global:Config.Tenant9.SignInAddress = "user@fabrikam.com" $global:Config.Tenant9.Credential = "****" $global:Config.Tenant9.ModernAuth = $false $global:Config.Tenant9.ConnectToTeams = $false $global:Config.Tenant9.ConnectToSkype = $false $global:Config.Tenant9.ConnectToExchange = $false $global:Config.Tenant9.ConnectToAzureAD = $false $global:Config.Tenant9.ConnectToCompliance = $false [void] $Global:grid_Tenants.Rows.Add("9",'Undefined','user9@fabrikam.com',"****",$False,$false,$false,$false,$false,$false) $global:Config.Tenant10 =@{} $global:Config.Tenant10.DisplayName = "Undefined" $global:Config.Tenant10.SignInAddress = "user@fabrikam.com" $global:Config.Tenant10.Credential = "****" $global:Config.Tenant10.ModernAuth = $false $global:Config.Tenant10.ConnectToTeams = $false $global:Config.Tenant10.ConnectToSkype = $false $global:Config.Tenant10.ConnectToExchange = $false $global:Config.Tenant10.ConnectToAzureAD = $false $global:Config.Tenant10.ConnectToCompliance = $false [void] $Global:grid_Tenants.Rows.Add("10",'Undefined','user10@fabrikam.com',"****",$False,$false,$false,$false,$false,$false) [Float]$global:Config.ConfigFileVersion = "0.2" [string]$global:Config.Description = "BounShell Configuration file. See Skype4BAdmin.com for more information" #Config File Version 0.2 additions $global:Config.AutoUpdatesEnabled = $true $global:Config.ModernAuthClipboardEnabled = $true $global:Config.ModernAuthWarningAccepted = $false $global:Config.Tenant1.ConnectToAzureAD = $false $global:Config.Tenant1.ConnectToCompliance = $false $global:Config.Tenant2.ConnectToAzureAD = $false $global:Config.Tenant2.ConnectToCompliance = $false $global:Config.Tenant3.ConnectToAzureAD = $false $global:Config.Tenant3.ConnectToCompliance = $false $global:Config.Tenant4.ConnectToAzureAD = $false $global:Config.Tenant4.ConnectToCompliance = $false $global:Config.Tenant5.ConnectToAzureAD = $false $global:Config.Tenant5.ConnectToCompliance = $false $global:Config.Tenant6.ConnectToAzureAD = $false $global:Config.Tenant6.ConnectToCompliance = $false $global:Config.Tenant7.ConnectToAzureAD = $false $global:Config.Tenant7.ConnectToCompliance = $false $global:Config.Tenant8.ConnectToAzureAD = $false $global:Config.Tenant8.ConnectToCompliance = $false $global:Config.Tenant9.ConnectToAzureAD = $false $global:Config.Tenant9.ConnectToCompliance = $false $global:Config.Tenant10.ConnectToAzureAD = $false $global:Config.Tenant10.ConnectToCompliance = $false } Function Invoke-BsNewTenantTab { <# .SYNOPSIS Function to Open new tab in ISE and call Connect-BsO365Tenant to connect to relevant services .DESCRIPTION .PARAMETER Tenant The tenant number to pass to Connect-BsO365Tenant .PARAMETER Tabname The name for the new tab .EXAMPLE Invoke-BsNewTenantTab -Tenant 1 -Tabname "Skype4badmin" Opens a new tab and connects to the Tenant stored in slot 1 .NOTES N/A .LINK http://www.UcMadScientist.com .INPUTS This function does not accept pipelined input .OUTPUTS This function does not create pipelined output #> param ( [Parameter(Mandatory=$true)] [string]$Tabname, [Parameter(Mandatory=$true)] [float]$Tenant ) $Function= 'Invoke-BsNewTenantTab' Write-Log -component $function -Message "Called Invoke-BsNewTenantTab to connect to Tenant $tenant with a Tabname of $tabname" -severity 1 if($tabname -ne 'Undefined') { Try { #kick off a new tab and call it tabname Write-Log -component $function -Message "Opening new ISE tab..." -severity 1 $TabNameTab=$psISE.PowerShellTabs.Add() $TabNameTab.DisplayName = $Tabname #Wait for the tab to wake up Write-Log -component $function -Message "Waiting for tab to become invokable" -severity 1 Do {sleep -m 100} While (!$TabNameTab.CanInvoke) #Kick off the connection Write-Log -component $function -Message "Invoking Command: Connect-BsO365Tenant -Tenant $Tenant" -severity 1 $TabNameTab.Invoke("Connect-BsO365Tenant -Tenant $Tenant") } Catch { #Something went wrong opening a new tab, probably already a tab with that name open Write-Log -component $function -Message "Failed to open new tab, Is there already a connection open to that tenant?" -severity 3 } } Else { #Tabname is "undefined", user clicked a tenant thats not confgured yey Write-Log -component $function -Message "Sorry, I cant find a config for Tenant $tenant" -severity 3 } } Function Connect-BsO365Tenant { <# .SYNOPSIS Connects to relevant Office365 services based on the configuration of the tenant we are passed .DESCRIPTION .PARAMETER Tenant The tenant number to connect to .EXAMPLE Connect-BsO365Tenant -Tenant 1 Connects to the Tenant stored in slot 1 based on the current context .NOTES N/A .LINK http://www.UcMadScientist.com .INPUTS This function does not accept pipelined input .OUTPUTS This function does not create pipelined output #> [CmdletBinding()] PARAM ( $Tenant ) [string]$Function = 'Connect-BsO365Tenant' [bool]$ModernAuth = $false [bool]$ConnectToTeams = $false [bool]$ConnectToSkype = $false [bool]$ConnectToExchange = $false [bool]$ConnectToSharepoint = $false [bool]$ConnectToAAD = $false [bool]$ConnectToCompliance = $false $ModernAuthPassword = ConvertTo-SecureString "Foo" -asplaintext -force [string]$ModernAuthUsername #Check to see if we are running in the ISE If ($PSISE) { #load the relevant stuff for the ISE enviroment Import-BsGuiElements #Clean up any stale sessions (we shouldnt have any, but whatever) Get-PSSession | Remove-PSSession } #Import the Config file so we have data Read-BsConfigFile #check to see if a tenant was specified If ($Tenant.length -eq 0) { Write-Log -Message 'Connect-BsO365Tenant calle without a tenant, displaying menu' -severity 1 #Menu code thanks to Greig. #Dodgy hack until I refactor the config code #TODO $Tenants = @() $Tenants += ($global:Config.Tenant1.DisplayName) $Tenants += ($global:Config.Tenant2.DisplayName) $Tenants += ($global:Config.Tenant3.DisplayName) $Tenants += ($global:Config.Tenant4.DisplayName) $Tenants += ($global:Config.Tenant5.DisplayName) $Tenants += ($global:Config.Tenant6.DisplayName) $Tenants += ($global:Config.Tenant7.DisplayName) $Tenants += ($global:Config.Tenant8.DisplayName) $Tenants += ($global:Config.Tenant9.DisplayName) $Tenants += ($global:Config.Tenant10.DisplayName) #First figure out the maximum width of the items name (for the tabular menu): $width = 0 foreach ($Tenant in ($Tenants)) { if ($Tenant.Length -gt $width) { $width = $Tenant.Length } } #Provide an on-screen menu of Front End Pools for the user to choose from: $index = 1 Write-Host "" Write-Host -Object ('ID '), ('Tenant Name'.Padright($width + 1), ' ') foreach ($Tenant in ($Tenants)) { Write-Host -Object ($index.ToString()).PadRight(2, ' '), " | ", ($Tenant.Padright($width + 1), ' ') $index++ } $index-- #Undo that last increment Write-Host Write-Host -Object 'Choose the tenant you wish to use' $chosen = Read-Host -Prompt 'Or any other value to quit' Write-Log -Message "User input $chosen" -severity 1 if ($chosen -notmatch '^\d$') { Exit } if ([int]$chosen -lt 0) { Exit } if ([int]$chosen -gt $index) { Exit } $Tenant = $chosen } Write-Log -component $Function -Message "Called to connect to Tenant $tenant" -severity 1 #change config based on tenant #region tenantswitch switch ($Tenant) { 1 #Tenant 1 { #Set Connection flags [bool]$ConnectToTeams = $global:Config.Tenant1.ConnectToTeams [bool]$ConnectToSkype = $global:Config.Tenant1.ConnectToSkype [bool]$ConnectToExchange = $global:Config.Tenant1.ConnectToExchange [bool]$ConnectToSharepoint = $false Write-Log -component $function -Message "Loading $($global:Config.Tenant1.DisplayName) Settings" -severity 2 #Check to see if the tenant is configured for modern auth If (!$global:Config.Tenant1.ModernAuth) { #Not using modern auth $global:pscred = New-Object System.Management.Automation.PSCredential($global:Config.Tenant1.SignInAddress,$global:Config.Tenant1.Credential) } Else { #Using modern auth $ModernAuth = $True #Convert the config into something we can work with later $ModernAuthPassword = $global:Config.Tenant1.Credential $ModernAuthUsername = $global:Config.Tenant1.SignInAddress } } 2 #Tenant 2 { #Set Connection flags [bool]$ConnectToTeams = $global:Config.Tenant2.ConnectToTeams [bool]$ConnectToSkype = $global:Config.Tenant2.ConnectToSkype [bool]$ConnectToExchange = $global:Config.Tenant2.ConnectToExchange [bool]$ConnectToSharepoint = $false Write-Log -component $function -Message "Loading $($global:Config.Tenant2.DisplayName) Settings" -severity 2 #Check to see if the tenant is configured for modern auth If (!$global:Config.Tenant2.ModernAuth) { #Not using modern auth $global:pscred = New-Object System.Management.Automation.PSCredential($global:Config.Tenant2.SignInAddress,$global:Config.Tenant2.Credential) } Else { #Using modern auth $ModernAuth = $True #Convert the config into something we can work with later $ModernAuthPassword = $global:Config.Tenant2.Credential $ModernAuthUsername = $global:Config.Tenant2.SignInAddress } } 3 #Tenant 3 { #Set Connection flags [bool]$ConnectToTeams = $global:Config.Tenant3.ConnectToTeams [bool]$ConnectToSkype = $global:Config.Tenant3.ConnectToSkype [bool]$ConnectToExchange = $global:Config.Tenant3.ConnectToExchange [bool]$ConnectToSharepoint = $false Write-Log -component $function -Message "Loading $($global:Config.Tenant3.DisplayName) Settings" -severity 2 #Check to see if the tenant is configured for modern auth If (!$global:Config.Tenant3.ModernAuth) { #Not using modern auth $global:pscred = New-Object System.Management.Automation.PSCredential($global:Config.Tenant3.SignInAddress,$global:Config.Tenant3.Credential) } Else { #Using modern auth $ModernAuth = $True #Convert the config into something we can work with later $ModernAuthPassword = $global:Config.Tenant3.Credential $ModernAuthUsername = $global:Config.Tenant3.SignInAddress } } 4 #Tenant 4 { #Set Connection flags [bool]$ConnectToTeams = $global:Config.Tenant4.ConnectToTeams [bool]$ConnectToSkype = $global:Config.Tenant4.ConnectToSkype [bool]$ConnectToExchange = $global:Config.Tenant4.ConnectToExchange [bool]$ConnectToSharepoint = $false Write-Log -component $function -Message "Loading $($global:Config.Tenant4.DisplayName) Settings" -severity 2 #Check to see if the tenant is configured for modern auth If (!$global:Config.Tenant4.ModernAuth) { #Not using modern auth $global:pscred = New-Object System.Management.Automation.PSCredential($global:Config.Tenant4.SignInAddress,$global:Config.Tenant4.Credential) } Else { #Using modern auth $ModernAuth = $True #Convert the config into something we can work with later $ModernAuthPassword = $global:Config.Tenant4.Credential $ModernAuthUsername = $global:Config.Tenant4.SignInAddress } } 5 #Tenant 5 { #Set Connection flags [bool]$ConnectToTeams = $global:Config.Tenant5.ConnectToTeams [bool]$ConnectToSkype = $global:Config.Tenant5.ConnectToSkype [bool]$ConnectToExchange = $global:Config.Tenant5.ConnectToExchange [bool]$ConnectToSharepoint = $false Write-Log -component $function -Message "Loading $($global:Config.Tenant5.DisplayName) Settings" -severity 2 #Check to see if the tenant is configured for modern auth If (!$global:Config.Tenant5.ModernAuth) { #Not using modern auth $global:pscred = New-Object System.Management.Automation.PSCredential($global:Config.Tenant5.SignInAddress,$global:Config.Tenant5.Credential) } Else { #Using modern auth $ModernAuth = $True #Convert the config into something we can work with later $ModernAuthPassword = $global:Config.Tenant5.Credential $ModernAuthUsername = $global:Config.Tenant5.SignInAddress } } 6 #Tenant 6 { #Set Connection flags [bool]$ConnectToTeams = $global:Config.Tenant6.ConnectToTeams [bool]$ConnectToSkype = $global:Config.Tenant6.ConnectToSkype [bool]$ConnectToExchange = $global:Config.Tenant6.ConnectToExchange [bool]$ConnectToSharepoint = $false Write-Log -component $function -Message "Loading $($global:Config.Tenant6.DisplayName) Settings" -severity 2 #Check to see if the tenant is configured for modern auth If (!$global:Config.Tenant6.ModernAuth) { #Not using modern auth $global:pscred = New-Object System.Management.Automation.PSCredential($global:Config.Tenant6.SignInAddress,$global:Config.Tenant6.Credential) } Else { #Using modern auth $ModernAuth = $True #Convert the config into something we can work with later $ModernAuthPassword = $global:Config.Tenant6.Credential $ModernAuthUsername = $global:Config.Tenant6.SignInAddress } } 7 #Tenant 7 { #Set Connection flags [bool]$ConnectToTeams = $global:Config.Tenant7.ConnectToTeams [bool]$ConnectToSkype = $global:Config.Tenant7.ConnectToSkype [bool]$ConnectToExchange = $global:Config.Tenant7.ConnectToExchange [bool]$ConnectToSharepoint = $false Write-Log -component $function -Message "Loading $($global:Config.Tenant7.DisplayName) Settings" -severity 2 #Check to see if the tenant is configured for modern auth If (!$global:Config.Tenant7.ModernAuth) { #Not using modern auth $global:pscred = New-Object System.Management.Automation.PSCredential($global:Config.Tenant7.SignInAddress,$global:Config.Tenant7.Credential) } Else { #Using modern auth $ModernAuth = $True #Convert the config into something we can work with later $ModernAuthPassword = $global:Config.Tenant7.Credential $ModernAuthUsername = $global:Config.Tenant7.SignInAddress } } 8 #Tenant 8 { #Set Connection flags [bool]$ConnectToTeams = $global:Config.Tenant8.ConnectToTeams [bool]$ConnectToSkype = $global:Config.Tenant8.ConnectToSkype [bool]$ConnectToExchange = $global:Config.Tenant8.ConnectToExchange [bool]$ConnectToSharepoint = $false Write-Log -component $function -Message "Loading $($global:Config.Tenant8.DisplayName) Settings" -severity 2 #Check to see if the tenant is configured for modern auth If (!$global:Config.Tenant8.ModernAuth) { #Not using modern auth $global:pscred = New-Object System.Management.Automation.PSCredential($global:Config.Tenant8.SignInAddress,$global:Config.Tenant8.Credential) } Else { #Using modern auth $ModernAuth = $True #Convert the config into something we can work with later $ModernAuthPassword = $global:Config.Tenant8.Credential $ModernAuthUsername = $global:Config.Tenant8.SignInAddress } } 9 #Tenant 9 { #Set Connection flags [bool]$ConnectToTeams = $global:Config.Tenant9.ConnectToTeams [bool]$ConnectToSkype = $global:Config.Tenant9.ConnectToSkype [bool]$ConnectToExchange = $global:Config.Tenant9.ConnectToExchange [bool]$ConnectToSharepoint = $false Write-Log -component $function -Message "Loading $($global:Config.Tenant9.DisplayName) Settings" -severity 2 #Check to see if the tenant is configured for modern auth If (!$global:Config.Tenant9.ModernAuth) { #Not using modern auth $global:pscred = New-Object System.Management.Automation.PSCredential($global:Config.Tenant9.SignInAddress,$global:Config.Tenant9.Credential) } Else { #Using modern auth $ModernAuth = $True #Convert the config into something we can work with later $ModernAuthPassword = $global:Config.Tenant9.Credential $ModernAuthUsername = $global:Config.Tenant9.SignInAddress } } 10 #Tenant 10 { #Set Connection flags [bool]$ConnectToTeams = $global:Config.Tenant10.ConnectToTeams [bool]$ConnectToSkype = $global:Config.Tenant10.ConnectToSkype [bool]$ConnectToExchange = $global:Config.Tenant10.ConnectToExchange [bool]$ConnectToSharepoint = $false Write-Log -component $function -Message "Loading $($global:Config.Tenant10.DisplayName) Settings" -severity 2 #Check to see if the tenant is configured for modern auth If (!$global:Config.Tenant10.ModernAuth) { #Not using modern auth $global:pscred = New-Object System.Management.Automation.PSCredential($global:Config.Tenant10.SignInAddress,$global:Config.Tenant10.Credential) } Else { #Using modern auth $ModernAuth = $True #Convert the config into something we can work with later $ModernAuthPassword = $global:Config.Tenant10.Credential $ModernAuthUsername = $global:Config.Tenant10.SignInAddress } } } #endregion tenantswitch #check to see if the Modern Auth flag has been set and use the appropriate connection method If ($ModernAuth) { # We are using Modern Auth, Check to see if the user accepted the warning. if not. Prompt them If ($global:Config.ModernAuthWarningAccepted -eq $false) { #We should only warn them if the feature is actually on. If ($global:Config.ModernAuthClipboardEnabled = $true) { Write-log -Message 'User hasnt accepted the Modern Auth disclaimer, prompt' -Severity 1 -Component $Function Write-host "Modern Auth Clipboard intergration is currently enabled" #Todo. Write-host "Your Username and password will be placed into the clipboard to facilitate login" Write-host "You can disable this feature in Add-ons > BounShell > Settings" Write-host "More information on this is available at https://UcMadScientist.com/BounShell-Auth/" Write-host "You will only be shown this warning once." Write-host "." Write-host "**************************************************************************************" Write-host "***** Whilst all care is taken, you are still responsible for your own security. *****" Write-host "** I cannot be held liable if your tenant is compromised, explodes or catches fire. **" Write-host "** To remove this warning and enable this feature, type 'I Accept' and press enter. **" Write-host "**************************************************************************************" Write-host "Press Ctrl+C to abort this connection or" $disclaimer = (Read-host -Prompt "Type 'I Accept' to continue") if ($disclaimer -eq "I Accept") { Write-log -Message 'User chose to accept' -Severity 3 -Component $Function $global:Config.ModernAuthWarningAccepted = $true Write-BsConfigFile } Else { Write-log -Message 'User did not accept' -Severity 3 -Component $Function $global:Config.ModernAuthWarningAccepted = $False Throw "User did not accept modern auth warning, aborting connection" } } } Write-host "Modern Auth is a Beta feature...." #Todo. Write-host "Your Username will be copied to the clipboard, Paste it into the Modern Auth Window" Write-host "Once Ctrl+V has been pressed BounShell will copy your password into the clipboard" Write-host "Upon pasting this, BounShell will clear the clipboard and overwrite the memory just incase." #As we are dealing with modern auth we need to convert the password back to an insecure string do that here $BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($ModernAuthPassword) $UnsecurePassword = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR) If ($ConnectToTeams) { Try { # So Now we need to kick off a new window that waits for the clipboard events Write-Log -Message "Connecting to Microsoft Teams" -Severity 2 -Component $Function #Create a script block with the expanded variables [String]$cmd = "Watch-BsCredentials -ModernAuthUsername $ModernAuthUsername -UnsecurePassword $UnsecurePassword" [ScriptBlock]$sb = [ScriptBlock]::Create($cmd) #and now call it Start-process powershell $sb #Sleep for a few seconds to let the powershell window pop and fill the clipboard. Start-Sleep -Seconds 3 #Now we can invoke the session #$TeamsSession = (Connect-MicrosoftTeams) Connect-MicrosoftTeams } Catch { $ErrorMessage = $_.Exception.Message Write-log -Message $ErrorMessage -Severity 3 -Component $Function Write-log -Message 'Error connecting to Microsoft Teams' -Severity 3 -Component $Function } } #Check for the Exchange connection flag If ($ConnectToExchange) { #Flag is set, connect to Exchange Try { #Exchange connection try block Write-Log -Message "Connecting to Exchange Online" -Severity 2 -Component $Function #So Now we need to kick off a new window that waits for the clipboard events #Create a script block with the expanded variables [String]$cmd = "Watch-BsCredentials -ModernAuthUsername $ModernAuthUsername -UnsecurePassword $UnsecurePassword" [ScriptBlock]$sb = [ScriptBlock]::Create($cmd) #and now call it Start-process powershell $sb #Sleep for a few seconds to let the powershell window pop and fill the clipboard. Start-Sleep -Seconds 3 #Now we invoke the session $O365Session = (New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://outlook.office365.com/powershell-liveid/ -AllowRedirection ) Write-Log -Message "Importing Session" -Severity 1 -Component $Function $VerbosePreference = "SilentlyContinue" #Todo. fix for import-psmodule ignoring the -Verbose:$false flag Import-Module (Import-PSSession -Session $O365Session -AllowClobber -DisableNameChecking) -Global -DisableNameChecking $VerbosePreference = "Continue" #Todo. fix for import-psmodule ignoring the -Verbose:$false flag } Catch { #We had an issue connecting to Exchange $ErrorMessage = $_.Exception.Message Write-log -Message $ErrorMessage -Severity 3 -Component $Function Write-log -Message 'Error connecting to Exchange Online' -Severity 3 -Component $Function } } #Check for the Skype4B connection flag If ($ConnectToSkype) { #Flag is set, connect to Skype4B Try { #Skype connection try block Write-Log -Message "Connecting to Skype4B Online" -Severity 2 -Component $Function #So Now we need to kick off a new window that waits for the clipboard events #Create a script block with the expanded variables [String]$cmd = "Watch-BsCredentials -ModernAuthUsername $ModernAuthUsername -UnsecurePassword $UnsecurePassword" [ScriptBlock]$sb = [ScriptBlock]::Create($cmd) #and now call it Start-process powershell $sb #Sleep for a few seconds to let the powershell window pop and fill the clipboard. Start-Sleep -Seconds 3 #Now we invoke the session $S4BOSession = (New-CsOnlineSession) $VerbosePreference = "SilentlyContinue" #Todo. fix for import-psmodule ignoring the -Verbose:$false flag Import-Module (Import-PSSession -Session $S4BOSession -AllowClobber -DisableNameChecking) -Global -DisableNameChecking $VerbosePreference = "Continue" #Todo. fix for import-psmodule ignoring the -Verbose:$false flag } Catch { #We had an issues connecting to Skype $ErrorMessage = $_.Exception.Messag Write-log -Message $ErrorMessage -Severity 3 -Component $Function Write-log -Message 'Error connecting to Skype4B Online' -Severity 3 -Component $Function } } #Check for the Sharepoint connection flag If ($ConnectToSharepoint) { #Flag is set, connect to Sharepoint Try { #Sharepoint connection try block Write-Log -Message "Connecting to Sharepoint Online" -Severity 2 -Component $Function #So Now we need to kick off a new window that waits for the clipboard events #Create a script block with the expanded variables [String]$cmd = "Watch-BsCredentials -ModernAuthUsername $ModernAuthUsername -UnsecurePassword $UnsecurePassword" [ScriptBlock]$sb = [ScriptBlock]::Create($cmd) #and now call it Start-process powershell $sb #Sleep for a few seconds to let the powershell window pop and fill the clipboard. Start-Sleep -Seconds 3 #Now we invoke the session $SharepointSession = (Connect-SPOService) $VerbosePreference = "SilentlyContinue" #Todo. fix for import-psmodule ignoring the -Verbose:$false flag Import-Module (Import-PSSession -Session $SharepointSession -AllowClobber -DisableNameChecking) -Global -DisableNameChecking $VerbosePreference = "Continue" #Todo. fix for import-psmodule ignoring the -Verbose:$false flag } Catch { #We had an issue connecting to Sharepoint $ErrorMessage = $_.Exception.Message Write-log -Message $ErrorMessage -Severity 3 -Component $Function Write-log -Message 'Error connecting to Sharepoint Online' -Severity 3 -Component $Function } } #Check for the AzureAD connection flag If ($ConnectToAAD) { #Flag is set, connect to AzureAD Try { #Azure AD try block Write-Log -Message "Connecting to Azure AD" -Severity 2 -Component $Function #So Now we need to kick off a new window that waits for the clipboard events #Create a script block with the expanded variables [String]$cmd = "Watch-BsCredentials -ModernAuthUsername $ModernAuthUsername -UnsecurePassword $UnsecurePassword" [ScriptBlock]$sb = [ScriptBlock]::Create($cmd) #and now call it Start-process powershell $sb #Sleep for a few seconds to let the powershell window pop and fill the clipboard. Start-Sleep -Seconds 3 #Now we invoke the session $AADSession = (Connect-AzureAD) $VerbosePreference = "SilentlyContinue" #Todo. fix for import-psmodule ignoring the -Verbose:$false flag Import-Module (Import-PSSession -Session $AADSession -AllowClobber -DisableNameChecking) -Global -DisableNameChecking $VerbosePreference = "Continue" #Todo. fix for import-psmodule ignoring the -Verbose:$false flag } Catch { #We had an issue connecting to AzureAD $ErrorMessage = $_.Exception.Message Write-log -Message $ErrorMessage -Severity 3 -Component $Function Write-log -Message 'Error connecting to Azure AD' -Severity 3 -Component $Function } } #Check for the 365 Compliance Centre flag If ($ConnectToCompliance) { #Flag is set, connect to Compiance Centre Try { Write-Log -Message "Connecting to Office 365 Compliance Centre" -Severity 2 -Component $Function #So Now we need to kick off a new window that waits for the clipboard events #Create a script block with the expanded variables [String]$cmd = "Watch-BsCredentials -ModernAuthUsername $ModernAuthUsername -UnsecurePassword $UnsecurePassword" [ScriptBlock]$sb = [ScriptBlock]::Create($cmd) #and now call it Start-process powershell $sb #Sleep for a few seconds to let the powershell window pop and fill the clipboard. Start-Sleep -Seconds 3 #Now we invoke the session $ComplianceSession = (New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://ps.compliance.protection.outlook.com/powershell-liveid/ -AllowRedirection) $VerbosePreference = "SilentlyContinue" #Todo. fix for import-psmodule ignoring the -Verbose:$false flag Import-Module (Import-PSSession -Session $ComplianceSession -AllowClobber -DisableNameChecking) -Global -DisableNameChecking $VerbosePreference = "Continue" #Todo. fix for import-psmodule ignoring the -Verbose:$false flag } Catch { #We had an issue connecting to the Compliance Centre $ErrorMessage = $_.Exception.Message Write-log -Message $ErrorMessage -Severity 3 -Component $Function Write-log -Message 'Error connecting to Office 365 Compliance Centre' -Severity 3 -Component $Function } } } #region NoModern #If the modern auth flag hasnt been set, we can simply connect to the services using secure credentials If (!$ModernAuth) { #See if we got passed creds Write-Log -Message 'Checking for Office365 Credentials' -Severity 1 -Component $Function If ($pscred -eq $null) { #No credentials, prompt user for some Write-Log -Message 'No Office365 credentials Found, Prompting user for creds' -Severity 3 -Component $Function $psCred = Get-Credential } Else { #Found creds, continue Write-Log -Message "Found Office365 Creds for Username: $($pscred.username)" -Severity 1 -Component $Function } #Check for the Exchange connection flag If ($ConnectToExchange) { #Flag is set, connect to Exchange Try { #Exchange connection try block Write-Log -Message "Connecting to Exchange Online" -Severity 2 -Component $Function $O365Session = (New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://outlook.office365.com/powershell-liveid/ -Credential $pscred -Authentication Basic -AllowRedirection ) Write-Log -Message "Importing Session" -Severity 1 -Component $Function $VerbosePreference = "SilentlyContinue" #Todo. fix for import-psmodule ignoring the -Verbose:$false flag Import-Module (Import-PSSession -Session $O365Session -AllowClobber -DisableNameChecking) -Global -DisableNameChecking $VerbosePreference = "Continue" #Todo. fix for import-psmodule ignoring the -Verbose:$false flag } Catch { #We had an issue connecting to Exchange $ErrorMessage = $_.Exception.Message Write-log -Message $ErrorMessage -Severity 3 -Component $Function Write-log -Message 'Error connecting to Exchange Online' -Severity 3 -Component $Function } } #Check for the Skype4B connection flag If ($ConnectToSkype) { #Flag is set, connect to Skype4B Try { #Skype connection try block Write-Log -Message "Connecting to Skype4B Online" -Severity 2 -Component $Function $S4BOSession = (New-CsOnlineSession -Credential $pscred) $VerbosePreference = "SilentlyContinue" #Todo. fix for import-psmodule ignoring the -Verbose:$false flag Import-Module (Import-PSSession -Session $S4BOSession -AllowClobber -DisableNameChecking) -Global -DisableNameChecking $VerbosePreference = "Continue" #Todo. fix for import-psmodule ignoring the -Verbose:$false flag } Catch { #We had an issues connecting to Skype $ErrorMessage = $_.Exception.Messag Write-log -Message $ErrorMessage -Severity 3 -Component $Function Write-log -Message 'Error connecting to Skype4B Online' -Severity 3 -Component $Function } } #Check for the Teams connection flag If ($ConnectToTeams) { #Flag is set, connect to Teams Try { #Teams connection try block Write-Log -Message "Connecting to Microsoft Teams" -Severity 2 -Component $Function $TeamsSession = (Connect-MicrosoftTeams -Credential $pscred) $VerbosePreference = "SilentlyContinue" #Todo. fix for import-psmodule ignoring the -Verbose:$false flag #No need to import the session. Import-Module (Import-PSSession -Session $TeamsSession -AllowClobber -DisableNameChecking) -Global -DisableNameChecking $VerbosePreference = "Continue" #Todo. fix for import-psmodule ignoring the -Verbose:$false flag } Catch { #We had an issue connecting to Teams $ErrorMessage = $_.Exception.Message Write-log -Message $ErrorMessage -Severity 3 -Component $Function Write-log -Message 'Error connecting to Microsoft Teams' -Severity 3 -Component $Function } } #Check for the Sharepoint connection flag If ($ConnectToSharepoint) { #Flag is set, connect to Sharepoint Try { #Sharepoint connection try block Write-Log -Message "Connecting to Sharepoint Online" -Severity 2 -Component $Function $SharepointSession = (Connect-SPOService -Credential $pscred) $VerbosePreference = "SilentlyContinue" #Todo. fix for import-psmodule ignoring the -Verbose:$false flag Import-Module (Import-PSSession -Session $SharepointSession -AllowClobber -DisableNameChecking) -Global -DisableNameChecking $VerbosePreference = "Continue" #Todo. fix for import-psmodule ignoring the -Verbose:$false flag } Catch { #We had an issue connecting to Sharepoint $ErrorMessage = $_.Exception.Message Write-log -Message $ErrorMessage -Severity 3 -Component $Function Write-log -Message 'Error connecting to Sharepoint Online' -Severity 3 -Component $Function } } #Check for the AzureAD connection flag If ($ConnectToAAD) { #Flag is set, connect to AzureAD Try { #Azure AD try block Write-Log -Message "Connecting to Azure AD" -Severity 2 -Component $Function $AADSession = (Connect-AzureAD -Credential $pscred) $VerbosePreference = "SilentlyContinue" #Todo. fix for import-psmodule ignoring the -Verbose:$false flag Import-Module (Import-PSSession -Session $AADSession -AllowClobber -DisableNameChecking) -Global -DisableNameChecking $VerbosePreference = "Continue" #Todo. fix for import-psmodule ignoring the -Verbose:$false flag } Catch { #We had an issue connecting to AzureAD $ErrorMessage = $_.Exception.Message Write-log -Message $ErrorMessage -Severity 3 -Component $Function Write-log -Message 'Error connecting to Azure AD' -Severity 3 -Component $Function } } #Check for the 365 Compliance Centre flag If ($ConnectToCompliance) { #Flag is set, connect to Compiance Centre Try { Write-Log -Message "Connecting to Office 365 Compliance Centre" -Severity 2 -Component $Function $ComplianceSession = (New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://ps.compliance.protection.outlook.com/powershell-liveid/ -Credential $Credential -Authentication Basic -AllowRedirection) $VerbosePreference = "SilentlyContinue" #Todo. fix for import-psmodule ignoring the -Verbose:$false flag Import-Module (Import-PSSession -Session $ComplianceSession -AllowClobber -DisableNameChecking) -Global -DisableNameChecking $VerbosePreference = "Continue" #Todo. fix for import-psmodule ignoring the -Verbose:$false flag } Catch { #We had an issue connecting to the Compliance Centre $ErrorMessage = $_.Exception.Message Write-log -Message $ErrorMessage -Severity 3 -Component $Function Write-log -Message 'Error connecting to Office 365 Compliance Centre' -Severity 3 -Component $Function } } } #endregion NoModern } Function Update-BsAddonMenu { #Check to see if we are loaded, if we are cleanup after ourselves if (($psISE.CurrentPowerShellTab.AddOnsMenu.Submenus).displayname -eq "_BounShell") { [void]$psISE.CurrentPowerShellTab.AddOnsMenu.Submenus.remove($Global:isemenuitem) } #Create Initial Menu Object [void]($Global:IseMenuItem = ($psISE.CurrentPowerShellTab.AddOnsMenu.Submenus.Add('_BounShell',$null ,$null))) #Add the Settings Button [void]($Global:IseMenuItem.Submenus.add('_Settings...', {Show-BsGuiElements}, $null) ) #Now add each Tenant #Need to put a for each code in here that adds Tenant 1 through 10 [void]($Global:IseMenuItem.Submenus.add("$($global:Config.Tenant1.DisplayName)",{Invoke-BsNewTenantTab -tabname $global:Config.Tenant1.DisplayName -Tenant 1}, 'Ctrl+Alt+1')) [void]($Global:IseMenuItem.Submenus.add("$($global:Config.Tenant2.DisplayName)",{Invoke-BsNewTenantTab -tabname $global:Config.Tenant2.DisplayName -Tenant 2}, 'Ctrl+Alt+2')) [void]($Global:IseMenuItem.Submenus.add("$($global:Config.Tenant3.DisplayName)",{Invoke-BsNewTenantTab -tabname $global:Config.Tenant3.DisplayName -Tenant 3}, 'Ctrl+Alt+3')) [void]($Global:IseMenuItem.Submenus.add("$($global:Config.Tenant4.DisplayName)",{Invoke-BsNewTenantTab -tabname $global:Config.Tenant4.DisplayName -Tenant 4}, 'Ctrl+Alt+4')) [void]($Global:IseMenuItem.Submenus.add("$($global:Config.Tenant5.DisplayName)",{Invoke-BsNewTenantTab -tabname $global:Config.Tenant5.DisplayName -Tenant 5}, 'Ctrl+Alt+5')) [void]($Global:IseMenuItem.Submenus.add("$($global:Config.Tenant6.DisplayName)",{Invoke-BsNewTenantTab -tabname $global:Config.Tenant6.DisplayName -Tenant 6}, 'Ctrl+Alt+6')) [void]($Global:IseMenuItem.Submenus.add("$($global:Config.Tenant7.DisplayName)",{Invoke-BsNewTenantTab -tabname $global:Config.Tenant7.DisplayName -Tenant 7}, 'Ctrl+Alt+7')) [void]($Global:IseMenuItem.Submenus.add("$($global:Config.Tenant8.DisplayName)",{Invoke-BsNewTenantTab -tabname $global:Config.Tenant8.DisplayName -Tenant 8}, 'Ctrl+Alt+8')) [void]($Global:IseMenuItem.Submenus.add("$($global:Config.Tenant9.DisplayName)",{Invoke-BsNewTenantTab -tabname $global:Config.Tenant9.DisplayName -Tenant 9}, 'Ctrl+Alt+9')) [void]($Global:IseMenuItem.Submenus.add("$($global:Config.Tenant10.DisplayName)",{Invoke-BsNewTenantTab -tabname $global:Config.Tenant10.DisplayName -Tenant 10}, 'Ctrl+Alt+0')) } Function Import-BsGuiElements { #First we need to import the Functions so they exist for the GUI items Import-BsGuiFunctions #region Gui [void][System.Reflection.Assembly]::Load('System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a') [void][System.Reflection.Assembly]::Load('System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089') $Global:SettingsForm = New-Object -TypeName System.Windows.Forms.Form [System.Windows.Forms.DataGridView]$Global:grid_Tenants = $null [System.Windows.Forms.Button]$Global:btn_CancelConfig = $null [System.Windows.Forms.Button]$Global:Btn_ReloadConfig = $null [System.Windows.Forms.Button]$Global:Btn_SaveConfig = $null [System.Windows.Forms.Button]$Global:Btn_Default = $null [System.Windows.Forms.DataGridViewTextBoxColumn]$Global:Tenant_ID = $null [System.Windows.Forms.DataGridViewTextBoxColumn]$Global:Tenant_DisplayName = $null [System.Windows.Forms.DataGridViewTextBoxColumn]$Global:Tenant_Email = $null [System.Windows.Forms.DataGridViewTextBoxColumn]$Global:Tenant_Credentials = $null [System.Windows.Forms.DataGridViewCheckBoxColumn]$Global:Tenant_ModernAuth = $null [System.Windows.Forms.DataGridViewCheckBoxColumn]$Global:Tenant_Teams = $null [System.Windows.Forms.DataGridViewCheckBoxColumn]$Global:Tenant_Skype = $null [System.Windows.Forms.DataGridViewCheckBoxColumn]$Global:Tenant_Exchange = $null [System.Windows.Forms.CheckBox]$Global:cbx_AutoUpdates = $null [System.Windows.Forms.DataGridViewCellStyle]$Global:dataGridViewCellStyle1 = (New-Object -TypeName System.Windows.Forms.DataGridViewCellStyle) [System.Windows.Forms.DataGridViewCellStyle]$Global:dataGridViewCellStyle2 = (New-Object -TypeName System.Windows.Forms.DataGridViewCellStyle) [System.Windows.Forms.DataGridViewCellStyle]$Global:dataGridViewCellStyle3 = (New-Object -TypeName System.Windows.Forms.DataGridViewCellStyle) $Global:btn_CancelConfig = (New-Object -TypeName System.Windows.Forms.Button) $Global:Btn_ReloadConfig = (New-Object -TypeName System.Windows.Forms.Button) $Global:Btn_SaveConfig = (New-Object -TypeName System.Windows.Forms.Button) $Global:cbx_AutoUpdates = (New-Object -TypeName System.Windows.Forms.CheckBox) $Global:grid_Tenants = (New-Object -TypeName System.Windows.Forms.DataGridView) $Global:Btn_Default = (New-Object -TypeName System.Windows.Forms.Button) $Global:Tenant_ID = (New-Object -TypeName System.Windows.Forms.DataGridViewTextBoxColumn) $Global:Tenant_DisplayName = (New-Object -TypeName System.Windows.Forms.DataGridViewTextBoxColumn) $Global:Tenant_Email = (New-Object -TypeName System.Windows.Forms.DataGridViewTextBoxColumn) $Global:Tenant_Credentials = (New-Object -TypeName System.Windows.Forms.DataGridViewTextBoxColumn) $Global:Tenant_ModernAuth = (New-Object -TypeName System.Windows.Forms.DataGridViewCheckBoxColumn) $Global:Tenant_Teams = (New-Object -TypeName System.Windows.Forms.DataGridViewCheckBoxColumn) $Global:Tenant_Skype = (New-Object -TypeName System.Windows.Forms.DataGridViewCheckBoxColumn) $Global:Tenant_Exchange = (New-Object -TypeName System.Windows.Forms.DataGridViewCheckBoxColumn) $Global:Tenant_AzureAD = (New-Object -TypeName System.Windows.Forms.DataGridViewCheckBoxColumn) $Global:Tenant_Compliance = (New-Object -TypeName System.Windows.Forms.DataGridViewCheckBoxColumn) $Global:cbx_ClipboardAuth = (New-Object -TypeName System.Windows.Forms.CheckBox) $Global:cliplabel = (New-Object -TypeName System.Windows.Forms.LinkLabel) ([System.ComponentModel.ISupportInitialize]$Global:grid_Tenants).BeginInit() $Global:SettingsForm.SuspendLayout() # #btn_CancelConfig # $Global:btn_CancelConfig.BackColor = [System.Drawing.Color]::White $Global:btn_CancelConfig.FlatStyle = [System.Windows.Forms.FlatStyle]::Flat $Global:btn_CancelConfig.Font = (New-Object -TypeName System.Drawing.Font -ArgumentList @([System.String]'Microsoft Sans Serif',[System.Single]8.25,[System.Drawing.FontStyle]::Bold,[System.Drawing.GraphicsUnit]::Pixel,([System.Byte][System.Byte]0))) $Global:btn_CancelConfig.ForeColor = [System.Drawing.Color]::FromArgb(([System.Int32]([System.Byte][System.Byte]8)),([System.Int32]([System.Byte][System.Byte]116)),([System.Int32]([System.Byte][System.Byte]170))) $Global:btn_CancelConfig.Location = (New-Object -TypeName System.Drawing.Point -ArgumentList @([System.Int32]936,[System.Int32]368)) $Global:btn_CancelConfig.Name = [System.String]'btn_CancelConfig' $Global:btn_CancelConfig.Size = (New-Object -TypeName System.Drawing.Size -ArgumentList @([System.Int32]94,[System.Int32]23)) $Global:btn_CancelConfig.TabIndex = [System.Int32]59 $Global:btn_CancelConfig.Text = [System.String]'Cancel' $Global:btn_CancelConfig.UseVisualStyleBackColor = $false $Global:btn_CancelConfig.add_Click($Global:btn_CancelConfig_Click) # #Btn_ReloadConfig # $Global:Btn_ReloadConfig.BackColor = [System.Drawing.Color]::White $Global:Btn_ReloadConfig.FlatStyle = [System.Windows.Forms.FlatStyle]::Flat $Global:Btn_ReloadConfig.Font = (New-Object -TypeName System.Drawing.Font -ArgumentList @([System.String]'Microsoft Sans Serif',[System.Single]8.25,[System.Drawing.FontStyle]::Bold,[System.Drawing.GraphicsUnit]::Pixel,([System.Byte][System.Byte]0))) $Global:Btn_ReloadConfig.ForeColor = [System.Drawing.Color]::FromArgb(([System.Int32]([System.Byte][System.Byte]8)),([System.Int32]([System.Byte][System.Byte]116)),([System.Int32]([System.Byte][System.Byte]170))) $Global:Btn_ReloadConfig.Location = (New-Object -TypeName System.Drawing.Point -ArgumentList @([System.Int32]704,[System.Int32]368)) $Global:Btn_ReloadConfig.Name = [System.String]'Btn_ReloadConfig' $Global:Btn_ReloadConfig.Size = (New-Object -TypeName System.Drawing.Size -ArgumentList @([System.Int32]110,[System.Int32]23)) $Global:Btn_ReloadConfig.TabIndex = [System.Int32]58 $Global:Btn_ReloadConfig.Text = [System.String]'Reload Config' $Global:Btn_ReloadConfig.UseVisualStyleBackColor = $true $Global:Btn_ReloadConfig.add_Click($Global:Btn_ConfigReload_Click) # #Btn_SaveConfig # $Global:Btn_SaveConfig.BackColor = [System.Drawing.Color]::White $Global:Btn_SaveConfig.FlatStyle = [System.Windows.Forms.FlatStyle]::Flat $Global:Btn_SaveConfig.Font = (New-Object -TypeName System.Drawing.Font -ArgumentList @([System.String]'Microsoft Sans Serif',[System.Single]8.25,[System.Drawing.FontStyle]::Bold,[System.Drawing.GraphicsUnit]::Pixel,([System.Byte][System.Byte]0))) $Global:Btn_SaveConfig.ForeColor = [System.Drawing.Color]::FromArgb(([System.Int32]([System.Byte][System.Byte]8)),([System.Int32]([System.Byte][System.Byte]116)),([System.Int32]([System.Byte][System.Byte]170))) $Global:Btn_SaveConfig.Location = (New-Object -TypeName System.Drawing.Point -ArgumentList @([System.Int32]820,[System.Int32]368)) $Global:Btn_SaveConfig.Name = [System.String]'Btn_SaveConfig' $Global:Btn_SaveConfig.Size = (New-Object -TypeName System.Drawing.Size -ArgumentList @([System.Int32]110,[System.Int32]23)) $Global:Btn_SaveConfig.TabIndex = [System.Int32]57 $Global:Btn_SaveConfig.Text = [System.String]'Save Config' $Global:Btn_SaveConfig.UseVisualStyleBackColor = $false $Global:Btn_SaveConfig.add_Click($Global:Btn_SaveConfig_Click) # #cbx_AutoUpdates # $Global:cbx_AutoUpdates.AutoSize = $true $Global:cbx_AutoUpdates.Checked = $true $Global:cbx_AutoUpdates.CheckState = [System.Windows.Forms.CheckState]::Checked $Global:cbx_AutoUpdates.ForeColor = [System.Drawing.Color]::FromArgb(([System.Int32]([System.Byte][System.Byte]8)),([System.Int32]([System.Byte][System.Byte]116)),([System.Int32]([System.Byte][System.Byte]170))) $Global:cbx_AutoUpdates.Location = (New-Object -TypeName System.Drawing.Point -ArgumentList @([System.Int32]27,[System.Int32]370)) $Global:cbx_AutoUpdates.Name = [System.String]'cbx_AutoUpdates' $Global:cbx_AutoUpdates.Size = (New-Object -TypeName System.Drawing.Size -ArgumentList @([System.Int32]183,[System.Int32]17)) $Global:cbx_AutoUpdates.TabIndex = [System.Int32]75 $Global:cbx_AutoUpdates.Text = [System.String]'Automatically Check For Updates' $Global:cbx_AutoUpdates.UseVisualStyleBackColor = $true $Global:cbx_AutoUpdates.add_CheckedChanged($Global:cbx_NoIntLCD_CheckedChanged_1) # #grid_Tenants # $Global:grid_Tenants.AllowUserToAddRows = $false $Global:grid_Tenants.AllowUserToDeleteRows = $false $Global:dataGridViewCellStyle1.Alignment = [System.Windows.Forms.DataGridViewContentAlignment]::MiddleLeft $Global:dataGridViewCellStyle1.BackColor = [System.Drawing.SystemColors]::Control $Global:dataGridViewCellStyle1.Font = (New-Object -TypeName System.Drawing.Font -ArgumentList @([System.String]'Microsoft Sans Serif',[System.Single]8.25,[System.Drawing.FontStyle]::Regular,[System.Drawing.GraphicsUnit]::Pixel,([System.Byte][System.Byte]0))) $Global:dataGridViewCellStyle1.ForeColor = [System.Drawing.SystemColors]::WindowText $Global:dataGridViewCellStyle1.SelectionBackColor = [System.Drawing.SystemColors]::Highlight $Global:dataGridViewCellStyle1.SelectionForeColor = [System.Drawing.SystemColors]::HighlightText $Global:dataGridViewCellStyle1.WrapMode = [System.Windows.Forms.DataGridViewTriState]::True $Global:grid_Tenants.ColumnHeadersDefaultCellStyle = $Global:dataGridViewCellStyle1 $Global:grid_Tenants.ColumnHeadersHeightSizeMode = [System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode]::AutoSize $Global:grid_Tenants.Columns.AddRange($Global:Tenant_ID,$Global:Tenant_DisplayName,$Global:Tenant_Email,$Global:Tenant_Credentials,$Global:Tenant_ModernAuth,$Global:Tenant_Teams,$Global:Tenant_Skype,$Global:Tenant_Exchange,$Tenant_AzureAD,$Tenant_Compliance) $Global:dataGridViewCellStyle2.Alignment = [System.Windows.Forms.DataGridViewContentAlignment]::MiddleLeft $Global:dataGridViewCellStyle2.BackColor = [System.Drawing.SystemColors]::Window $Global:dataGridViewCellStyle2.Font = (New-Object -TypeName System.Drawing.Font -ArgumentList @([System.String]'Microsoft Sans Serif',[System.Single]8.25,[System.Drawing.FontStyle]::Regular,[System.Drawing.GraphicsUnit]::Pixel,([System.Byte][System.Byte]0))) $Global:dataGridViewCellStyle2.ForeColor = [System.Drawing.Color]::FromArgb(([System.Int32]([System.Byte][System.Byte]8)),([System.Int32]([System.Byte][System.Byte]116)),([System.Int32]([System.Byte][System.Byte]170))) $Global:dataGridViewCellStyle2.SelectionBackColor = [System.Drawing.SystemColors]::Highlight $Global:dataGridViewCellStyle2.SelectionForeColor = [System.Drawing.SystemColors]::HighlightText $Global:dataGridViewCellStyle2.WrapMode = [System.Windows.Forms.DataGridViewTriState]::False $Global:grid_Tenants.DefaultCellStyle = $Global:dataGridViewCellStyle2 $Global:grid_Tenants.Location = (New-Object -TypeName System.Drawing.Point -ArgumentList @([System.Int32]12,[System.Int32]12)) $Global:grid_Tenants.Name = [System.String]'grid_Tenants' $Global:dataGridViewCellStyle3.Alignment = [System.Windows.Forms.DataGridViewContentAlignment]::MiddleLeft $Global:dataGridViewCellStyle3.BackColor = [System.Drawing.SystemColors]::Control $Global:dataGridViewCellStyle3.Font = (New-Object -TypeName System.Drawing.Font -ArgumentList @([System.String]'Microsoft Sans Serif',[System.Single]8.25,[System.Drawing.FontStyle]::Regular,[System.Drawing.GraphicsUnit]::Pixel,([System.Byte][System.Byte]0))) $Global:dataGridViewCellStyle3.ForeColor = [System.Drawing.SystemColors]::WindowText $Global:dataGridViewCellStyle3.SelectionBackColor = [System.Drawing.SystemColors]::Highlight $Global:dataGridViewCellStyle3.SelectionForeColor = [System.Drawing.SystemColors]::HighlightText $Global:dataGridViewCellStyle3.WrapMode = [System.Windows.Forms.DataGridViewTriState]::True $Global:grid_Tenants.RowHeadersDefaultCellStyle = $Global:dataGridViewCellStyle3 $Global:grid_Tenants.Size = (New-Object -TypeName System.Drawing.Size -ArgumentList @([System.Int32]1020,[System.Int32]336)) $Global:grid_Tenants.TabIndex = [System.Int32]76 $Global:grid_Tenants.add_CellContentClick($Global:grid_Tenants_CellContentClick) # #Btn_Default # $Global:Btn_Default.BackColor = [System.Drawing.Color]::White $Global:Btn_Default.FlatStyle = [System.Windows.Forms.FlatStyle]::Flat $Global:Btn_Default.Font = (New-Object -TypeName System.Drawing.Font -ArgumentList @([System.String]'Microsoft Sans Serif',[System.Single]8.25,[System.Drawing.FontStyle]::Bold,[System.Drawing.GraphicsUnit]::Pixel,([System.Byte][System.Byte]0))) $Global:Btn_Default.ForeColor = [System.Drawing.Color]::FromArgb(([System.Int32]([System.Byte][System.Byte]8)),([System.Int32]([System.Byte][System.Byte]116)),([System.Int32]([System.Byte][System.Byte]170))) $Global:Btn_Default.Location = (New-Object -TypeName System.Drawing.Point -ArgumentList @([System.Int32]588,[System.Int32]368)) $Global:Btn_Default.Name = [System.String]'Btn_Default' $Global:Btn_Default.Size = (New-Object -TypeName System.Drawing.Size -ArgumentList @([System.Int32]110,[System.Int32]23)) $Global:Btn_Default.TabIndex = [System.Int32]77 $Global:Btn_Default.Text = [System.String]'Reset to Default' $Global:Btn_Default.UseVisualStyleBackColor = $true $Global:Btn_Default.add_Click($Global:Btn_Default_Click) # #Tenant_ID # $Global:Tenant_ID.AutoSizeMode = [System.Windows.Forms.DataGridViewAutoSizeColumnMode]::AllCells $Global:Tenant_ID.Frozen = $true $Global:Tenant_ID.HeaderText = [System.String]'ID' $Global:Tenant_ID.Name = [System.String]'Tenant_ID' $Global:Tenant_ID.ReadOnly = $true $Global:Tenant_ID.Width = [System.Int32]43 # #Tenant_DisplayName # $Global:Tenant_DisplayName.AutoSizeMode = [System.Windows.Forms.DataGridViewAutoSizeColumnMode]::AllCells $Global:Tenant_DisplayName.Frozen = $true $Global:Tenant_DisplayName.HeaderText = [System.String]'Display Name' $Global:Tenant_DisplayName.Name = [System.String]'Tenant_DisplayName' $Global:Tenant_DisplayName.SortMode = [System.Windows.Forms.DataGridViewColumnSortMode]::NotSortable $Global:Tenant_DisplayName.Width = [System.Int32]78 # #Tenant_Email # $Global:Tenant_Email.AutoSizeMode = [System.Windows.Forms.DataGridViewAutoSizeColumnMode]::AllCells $Global:Tenant_Email.Frozen = $true $Global:Tenant_Email.HeaderText = [System.String]'Sign In Address' $Global:Tenant_Email.Name = [System.String]'Tenant_Email' $Global:Tenant_Email.SortMode = [System.Windows.Forms.DataGridViewColumnSortMode]::NotSortable $Global:Tenant_Email.Width = [System.Int32]78 # #Tenant_Credentials # $Global:Tenant_Credentials.Frozen = $true $Global:Tenant_Credentials.HeaderText = [System.String]'Credentials' $Global:Tenant_Credentials.Name = [System.String]'Tenant_Credentials' # #Tenant_ModernAuth # $Global:Tenant_ModernAuth.HeaderText = [System.String]'Uses Modern Auth?' $Global:Tenant_ModernAuth.Name = [System.String]'Tenant_ModernAuth' # #Tenant_Teams # $Global:Tenant_Teams.HeaderText = [System.String]'Connect to Teams?' $Global:Tenant_Teams.Name = [System.String]'Tenant_Teams' # #Tenant_Skype # $Global:Tenant_Skype.HeaderText = [System.String]'Connect to Skype?' $Global:Tenant_Skype.Name = [System.String]'Tenant_Skype' # #Tenant_Exchange # $Global:Tenant_Exchange.HeaderText = [System.String]'Connect to Exchange?' $Global:Tenant_Exchange.Name = [System.String]'Tenant_Exchange' # #Tenant_AzureAD # $Global:Tenant_AzureAD.HeaderText = [System.String]'Connect to Azure AD' $Global:Tenant_AzureAD.Name = [System.String]'Tenant_AzureAD' $Global:Tenant_AzureAD.Resizable = [System.Windows.Forms.DataGridViewTriState]::True $Global:Tenant_AzureAD.SortMode = [System.Windows.Forms.DataGridViewColumnSortMode]::Automatic # #Tenant_Compliance # $Global:Tenant_Compliance.HeaderText = [System.String]'Connect to Compliance Centre' $Global:Tenant_Compliance.Name = [System.String]'Tenant_Compliance' # #cbx_ClipboardAuth # $Global:cbx_ClipboardAuth.AutoSize = $true $Global:cbx_ClipboardAuth.ForeColor = [System.Drawing.Color]::FromArgb(([System.Int32]([System.Byte][System.Byte]8)),([System.Int32]([System.Byte][System.Byte]116)),([System.Int32]([System.Byte][System.Byte]170))) $Global:cbx_ClipboardAuth.Location = (New-Object -TypeName System.Drawing.Point -ArgumentList @([System.Int32]230,[System.Int32]370)) $Global:cbx_ClipboardAuth.Name = [System.String]'cbx_ClipboardAuth' $Global:cbx_ClipboardAuth.Size = (New-Object -TypeName System.Drawing.Size -ArgumentList @([System.Int32]228,[System.Int32]17)) $Global:cbx_ClipboardAuth.TabIndex = [System.Int32]78 $Global:cbx_ClipboardAuth.Text = [System.String]'Disable Modern Auth Clipboard Intergration' $Global:cbx_ClipboardAuth.UseVisualStyleBackColor = $true # #cliplabel # $Global:cliplabel.AutoSize = $true $Global:cliplabel.Location = (New-Object -TypeName System.Drawing.Point -ArgumentList @([System.Int32]460,[System.Int32]370)) $Global:cliplabel.Name = [System.String]'cliplabel' $Global:cliplabel.Size = (New-Object -TypeName System.Drawing.Size -ArgumentList @([System.Int32]53,[System.Int32]13)) $Global:cliplabel.TabIndex = [System.Int32]79 $Global:cliplabel.TabStop = $true $Global:cliplabel.Text = [System.String]'more info.' $Global:cliplabel.add_Click($Global:cliplabel_click) # #Global:SettingsForm # $Global:SettingsForm.BackColor = [System.Drawing.Color]::White $global:SettingsForm.ClientSize = (New-Object -TypeName System.Drawing.Size -ArgumentList @([System.Int32]1044,[System.Int32]404)) $Global:SettingsForm.Controls.Add($Global:Btn_Default) $Global:SettingsForm.Controls.Add($Global:grid_Tenants) $Global:SettingsForm.Controls.Add($Global:cbx_AutoUpdates) $Global:SettingsForm.Controls.Add($Global:btn_CancelConfig) $Global:SettingsForm.Controls.Add($Global:Btn_ReloadConfig) $Global:SettingsForm.Controls.Add($Global:Btn_SaveConfig) $Global:SettingsForm.Controls.Add($Global:cliplabel) $Global:SettingsForm.Controls.Add($global:cbx_ClipboardAuth) $Global:SettingsForm.Name = [System.String]'Global:SettingsForm' $Global:SettingsForm.add_Load($Global:SettingsForm_Load) ([System.ComponentModel.ISupportInitialize]$Global:grid_Tenants).EndInit() $Global:SettingsForm.ResumeLayout($false) $Global:SettingsForm.PerformLayout() Add-Member -InputObject $Global:SettingsForm -Name base -Value $base -MemberType NoteProperty Add-Member -InputObject $Global:SettingsForm -Name grid_Tenants -Value $Global:grid_Tenants -MemberType NoteProperty Add-Member -InputObject $Global:SettingsForm -Name btn_CancelConfig -Value $Global:btn_CancelConfig -MemberType NoteProperty Add-Member -InputObject $Global:SettingsForm -Name Btn_ReloadConfig -Value $Global:Btn_ReloadConfig -MemberType NoteProperty Add-Member -InputObject $Global:SettingsForm -Name Btn_SaveConfig -Value $Global:Btn_SaveConfig -MemberType NoteProperty Add-Member -InputObject $Global:SettingsForm -Name Btn_Default -Value $Global:Btn_Default -MemberType NoteProperty Add-Member -InputObject $Global:SettingsForm -Name Tenant_ID -Value $Global:Tenant_ID -MemberType NoteProperty Add-Member -InputObject $Global:SettingsForm -Name Tenant_DisplayName -Value $Global:Tenant_DisplayName -MemberType NoteProperty Add-Member -InputObject $Global:SettingsForm -Name Tenant_Email -Value $Global:Tenant_Email -MemberType NoteProperty Add-Member -InputObject $Global:SettingsForm -Name Tenant_Credentials -Value $Global:Tenant_Credentials -MemberType NoteProperty Add-Member -InputObject $Global:SettingsForm -Name Tenant_ModernAuth -Value $Global:Tenant_ModernAuth -MemberType NoteProperty Add-Member -InputObject $Global:SettingsForm -Name Tenant_Teams -Value $Global:Tenant_Teams -MemberType NoteProperty Add-Member -InputObject $Global:SettingsForm -Name Tenant_Skype -Value $Global:Tenant_Skype -MemberType NoteProperty Add-Member -InputObject $Global:SettingsForm -Name Tenant_Exchange -Value $Tenant_Exchange -MemberType NoteProperty Add-Member -InputObject $Global:SettingsForm -Name Tenant_AzureAD -Value $Global:Tenant_AzureAD -MemberType NoteProperty Add-Member -InputObject $Global:SettingsForm -Name Tenant_Compliance -Value $Global:Tenant_Compliance -MemberType NoteProperty Add-Member -InputObject $Global:SettingsForm -Name cbx_ClipboardAuth -Value $Global:cbx_ClipboardAuth -MemberType NoteProperty Add-Member -InputObject $Global:SettingsForm -Name cliplabel -Value $Global:cliplabel -MemberType NoteProperty Add-Member -InputObject $Global:SettingsForm -Name cbx_AutoUpdates -Value $Global:cbx_AutoUpdates -MemberType NoteProperty #endregion Gui } Function Import-BsGuiFunctions { #Gui Cancel button $Global:btn_CancelConfig_Click = { Read-BsConfigFile [void]$Global:SettingsForm.Hide() } #Gui Save Config Button $Global:Btn_SaveConfig_Click = { $Global:btn_CancelConfig.Text = [System.String]'Close' Write-BsConfigFile If ($PSISE) { Update-BsAddonMenu } } #Gui Set Defaults Button $Global:Btn_Default_Click = { Import-BsDefaultConfig If ($PSISE) { Update-BsAddonMenu } } #Gui Button to Reload Config $Global:Btn_ConfigReload_Click = { Read-BsConfigFile If ($PSISE) { Update-BsAddonMenu } } #Gui link object to open a browser for more info on the modern auth clipboard $Global:cliplabel_click = { Start "https://UcMadScientist.com/BounShell-Auth/" } } Function Import-BsIseFunctions { } Function Show-BsGuiElements { #Reset the cancel button $Global:btn_CancelConfig.Text = [System.String]'Cancel' [void]$Global:SettingsForm.ShowDialog() } Function Hide-BsGuiElements { [void]$Global:SettingsForm.Hide() } Function Start-BounShell { $function = 'Start-BounShell' #Allows us to seperate all the "onetime" run objects incase we get dot sourced. Write-Log -component $function -Message "Script executed from $PSScriptRoot" -severity 1 Write-Log -component $function -Message "Loading BounShell..." -severity 2 #Load the Gui Elements Import-BsGuiElements #check for config file then load the default #Check for and load the config file if present If(Test-Path $global:ConfigFilePath) { Write-Log -component $function -Message "Found $ConfigFilePath, loading..." -severity 1 Read-BsConfigFile } Else { Write-Log -component $function -Message "Could not locate config file, Using Defaults" -severity 3 #If there is no config file. Load a default Import-BsDefaultConfig Write-Log -component $function -Message "As we didnt find a config file we will assume this is a first run." -severity 3 Write-Log -component $function -Message "Thus we will remind you that while all care is taken to store your credentials in a safe manner, we cannot be held responsible for any data breaches" -severity 3 Write-Log -component $function -Message "If someone was to get a hold of your BounShell.xml AND your user profile private encryption key its possible to reverse engineer stored credentials" -severity 3 Write-Log -component $function -Message "Seriously, Whilst the password store is encrypted, its not perfect!" -severity 3 Pause } #check for script update if ($SkipUpdateCheck -eq $false) { Get-ScriptUpdate } #todo enable update checking #Check for Modules #Test-ManagementTools #todo fix #Now Create the Objects in the ISE If($PSISE) { Update-BsAddonMenu } Write-Log -component $function -Message "BounShell Loaded" -severity 2 #Check we are actually in the ISE If(!$PSISE) { Write-Log -component $function -Message 'Could not locate $PSISE Variable' -severity 1 Write-Log -component $function -Message 'Launched BounShell without ISE Support, Keyboard Shotcuts will be unavailable' -severity 2 Write-Host "" Write-Log -component $function -Message 'To configure BounShell tenants run Show-BsGuiElements' -severity 2 Write-Log -component $function -Message 'To connect to a tenant run Connect-BsO365Tenant' -severity 2 Return #Yes I know Return sucks, but I think its better than Throw. } } Function Watch-BsCredentials { [CmdletBinding()] PARAM ( $ModernAuthUsername, $UnsecurePassword ) [string]$Function = 'Watch-BsCredentials' If (!$ModernAuthUsername) { Write-Log -component $Function -Message "This Cmdlet is for BoundShell's internal use only. Please use 'Start-Bounshell' to launch the tool" -severity 3 pause return } Write-Log -component $Function -Message "Called to connect to $ModernAuthUsername" -severity 3 # Load the API we need for Keypresses $signature = @' [DllImport("user32.dll", CharSet=CharSet.Auto, ExactSpelling=true)] public static extern short GetAsyncKeyState(int virtualKeyCode); '@ # load signatures and make members available $API = Add-Type -MemberDefinition $signature -Name 'Keypress' -Namespace API -PassThru # define that we are waiting for 'v' keypress $waitFor = 'v' $ascii = [byte][char]$waitFor.ToUpper() Set-Clipboard -Value $ModernAuthUsername Write-Log -component $Function -Message "$ModernAuthUsername placed into Clipboard" -severity 1 Write-Log -component $Function -Message "Press 'Ctrl+v' to paste the username $ModernAuthUsername in the modern auth window" -severity 3 do { Start-Sleep -Milliseconds 40 } until ($API::GetAsyncKeyState($ascii) -eq -32767) Set-Clipboard -Value $UnsecurePassword Write-Log -component $Function -Message "Password placed into Clipboard" -severity 1 Write-Log -component $Function -Message "Press 'Ctrl+v' to paste the password in the modern auth window" -severity 3 do { Start-Sleep -Milliseconds 40 } until ($API::GetAsyncKeyState($ascii) -eq -32767) Set-Clipboard -Value "Thanks for using BounShell" } Function Test-BsInstalledModules { param ( [Parameter(Mandatory=$true)] [string]$ModuleName, [Parameter(Mandatory=$true)] [float]$ModuleVersion ) [string]$Function = 'Test-BsInstalledModules' Write-Log -component $Function -Message "Called to check $ModuleName" -severity 1 $NeedsInstall = $false $NeedsUpdate = $false $NeedsCleaup = $false $LatestModuleVersion = $null #Pull the module from the local machine $Module = Get-Module -Name $ModuleName -ListAvailable #If we have more than one version we need to clean up if($Module.count -gt 1) { Write-Log -component $Function -Message "Found multiple copies of $ModuleName" -severity 3 $needscleanup = $true # Identify modules with multiple versions installed $MultiModules = $Module | Group-Object -Property name -NoElement | Where-Object count -gt 1 } #If we have one module, check its up to date if($Module.count -eq 1) { Write-Log -component $Function -Message "Found one copy of $ModuleName" -severity 1 } #Module not installed if($Module.count -eq 0) { Write-Log -component $Function -Message "$ModuleName Not Installed on Local Computer" -severity 3 $NeedsInstall = $true } #Okay, we have checked if everything is installed, now lets check and report on the version Write-Log -component $Function -Message "Checking for the latest version of $ModuleName in the PSGallery" -severity 2 $gallery = $module.where({$_.repositorysourcelocation}) foreach ($module in $gallery) { #find the current version in the gallery Try { $online = Find-Module -Name $module.name -Repository PSGallery -ErrorAction Stop } Catch { #Todo What the fuck? Write-Warning -Message ('Module {0} was not found in the PSGallery' -f $module.name) } #compare versions if ($online.version -gt $module.version) { $NeedsUpdate = $true Write-Log -component $Function -Message "An updated version of the $ModuleName module is available in the PSGallery" -severity 2 } else { Write-Log -component $Function -Message "Your version of the $ModuleName module is up to date" -severity 2 } #write a custom object to the pipeline [pscustomobject]@{ Name = $module.name MultipleVersions = ($g.name -contains $module.name) InstalledVersion = $module.version OnlineVersion = $online.version Update = $NeedsUpdate Path = $module.modulebase } } } Function Repair-BsInstalledModules { param ( [Parameter(Mandatory=$true)] [string]$ModuleName, [Parameter(Mandatory=$true)] [string]$Operation #Install, Cleaup, Update ) [string]$Function = 'Repair-BsInstalledModules' Write-Log -component $Function -Message "Called to $Operation $ModuleName" -severity 1 Write-Log -component $Function -Message "Checking for elevated session" -severity 1 #Check we are running as admin, we dont want to install modules in the users context if (!(([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] 'Administrator'))){ # throw 'Please Note: You are trying to run this script without evalated Administator Priviliges. In order to run this script you will required Powershell running in Administrator Mode' Write-Log -component $Function -Message "Not Running as administrator, invoking new session" -severity 2 #Todo, kick off a new window with admin privs } else { Write-Log -component $Function -Message "Running as administrator, performing $Operation" -severity 2 } Switch ($Operation) { "Install" { Install-Module -name $ModuleName } "Cleanup" { #Pull the currently installed modules $Module = Get-Module -Name $ModuleName -ListAvailable # Identify modules with multiple versions installed $g = $module | Group-Object -Property name -NoElement | Where-Object count -gt 1} #Remove all but the latest one <#foreach ($module in $g) { Write-Log -component $Function -Message "Removing $($Module.version)" -severity 2 Uninstall-Module -Name $MicrosoftTeams -RequiredVersion $module.version } #> default { 'anything else'} } } #now we export the relevant stuff Export-ModuleMember Read-BsConfigFile Export-ModuleMember Write-BsConfigFile Export-ModuleMember Import-BsDefaultConfig Export-ModuleMember Invoke-BsNewTenantTab Export-ModuleMember Connect-BsO365Tenant Export-ModuleMember Update-BsAddonMenu Export-ModuleMember Import-BsGuiElements Export-ModuleMember Import-BsGuiFunctions Export-ModuleMember Show-BsGuiElements Export-ModuleMember Hide-BsGuiElements Export-ModuleMember Start-BounShell Export-ModuleMember Watch-BsCredentials Export-ModuleMember Test-BsInstalledModules Export-ModuleMember Repair-BsInstalledModules |