TeamsFunctions.psm1

using module .\Class\TeamsFunctions.Classes.psm1
using module .\Class\TeamsFunctions.Enums.psm1
using module .\Class\TeamsFunctions.ArgumentCompleter.psm1
# Above needs to remain the first line to import Classes
# remove the comment when using classes

# Requirements
#Requires -Version 5.1
#Requires -Modules @{ ModuleName="MicrosoftTeams"; ModuleVersion="4.2.0" }, AzureAd

<#
  TeamsFunctions
  Module for Management of Teams Voice Configuration for Tenant and Users
  User Configuration for Voice, Creation and connection of Resource Accounts,
  Licensing of Objects for Calling Plans & Direct Routing,
  Creation and Management of Call Queues and Auto Attendants
 
  by David Eberhardt
  david@davideberhardt.at
  @MightyOrmus
  www.davideberhardt.at
  https://github.com/DEberhardt
  https://davideberhardt.wordpress.com/
 
  This Module is a Fork of the Module SkypeFunctions and built on the work of Jeff Brown.
  Jeff@JeffBrown.tech / @JeffWBrown / www.jeffbrown.tech / https://github.com/JeffBrownTech
  Individual Scripts incorporated into this Module are taken with the express permission of the original Author
 
  Any and all technical advice, scripts, and documentation are provided as is with no guarantee.
  Always review any code and steps before applying to a production system to understand their full impact.
 
  # Versioning
  This Module follows the Versioning Convention to show the Release Date in the Version number
  Major v20 is the the first one published in 2020, followed by Minor version for the Month.
  Subsequent Minor versions include the Day and are released as PreReleases
  Revisions are planned quarterly, but are currently on a monthly schedule until mature. PreReleases as required.
 
  # Version History
  Please see VERSION.md
 
.LINK
  https://github.com/DEberhardt/TeamsFunctions/tree/master/docs
 
#>


#region Functions
#Get public and private function definition files.
$Public = @( Get-ChildItem -Path $PSScriptRoot\Public\*.ps1 -Recurse -ErrorAction SilentlyContinue )
$Private = @( Get-ChildItem -Path $PSScriptRoot\Private\*.ps1 -Recurse -ErrorAction SilentlyContinue )

#Dot source the files
Foreach ($Function in @($Public + $Private)) {
  Try {
    . $Function.Fullname
  }
  Catch {
    Write-Error -Message "Failed to import function $($Function.Fullname): $_"
  }
}

# Exporting Module Members (Functions)
Export-ModuleMember -Function $Public.Basename
#endregion

#region Aliases
# Query Aliases
$Aliases = $null
#$Aliases = Foreach ($Function in @($Public + $Private)) {
$Aliases = Foreach ($Function in @($Public)) {
  if ( $($Function.Fullname) -match '.tests.ps1' ) { continue }
  $Content = $AliasBlocks = $null

  $Content = $Function | Get-Content

  $AliasBlocks = $Content -split "`n" | Select-String 'Alias\(' -Context 1, 1
  $AliasBlocks | ForEach-Object {
    $Lines = $($_ -split "`n")
    if ( $Lines[0] -match 'CmdletBinding' -or $Lines[0] -match 'OutputType' -or $Lines[2] -match 'CmdletBinding' -or $Lines[2] -match 'OutputType' ) {
      if ( $($_ -split "`n")[1] -match "Alias\('(?<content>.*)'\)" ) {
        $($matches.content -split ',' -replace "'" -replace ' ') | ForEach-Object { if ( $_ -ne '' ) { $_ } }
      }
    }
    else {
      continue
    }
  }
}
Write-Verbose -Message "Queried Aliases to Export - List: $($Aliases -join ',')"
Write-Verbose -Message "Queried Aliases to Export - Count: $($Aliases.Count)"

# Manual definitions
# Adding manual Aliases (not recorded in Functions)
Set-Alias -Name Remove-TeamsAutoAttendantSchedule -Value Remove-CsOnlineSchedule
Set-Alias -Name Remove-TeamsAASchedule -Value Remove-CsOnlineSchedule
Set-Alias -Name cmt -Value Connect-MicrosoftTeams

# Manual definitions
$ManualAliases = @(
  'Remove-TeamsAutoAttendantSchedule', 'Remove-TeamsAASchedule', 'cmt'
)

# Exporting Module Members (Aliases)
$AliasesToExport = @($Aliases + $ManualAliases)
if ( $AliasesToExport ) {
  Export-ModuleMember -Alias $AliasesToExport
}
Write-Verbose -Message "Aliases to Export - List: $($Aliases -join ',')"
Write-Verbose -Message "Aliases to Export - Count: $($Aliases.Count)"
#endregion

#region Variables

# Defining Help URL Base string:
[string]$script:TeamsFunctionsHelpURLBase = 'https://github.com/DEberhardt/TeamsFunctions/blob/master/docs/'

# Time Zones
$script:TFUniqueTimeZones = @('UTC-12:00', 'UTC-11:00', 'UTC-10:00', 'UTC-09:00', 'UTC-08:00', 'UTC-07:00', 'UTC-06:00', 'UTC-05:00', 'UTC-04:00', 'UTC-03:30', 'UTC-03:00', 'UTC-02:00', 'UTC-01:00', 'UTC', 'UTC+00:00', 'UTC+01:00', 'UTC+02:00', 'UTC+03:00', 'UTC+03:30', 'UTC+04:00', 'UTC+04:30', 'UTC+05:00', 'UTC+05:30', 'UTC+05:45', 'UTC+06:00', 'UTC+06:30', 'UTC+07:00', 'UTC+08:00', 'UTC+09:00', 'UTC+09:30', 'UTC+10:00', 'UTC+11:00', 'UTC+12:00', 'UTC+13:00', 'UTC+14:00')

# Match Strings
[string]$script:TFMatchNumber = '^(tel:\+|\+)?([0-9]?[-\s]?(\(?[0-9]{3}\)?)[-\s]?([0-9]{3}[-\s]?[0-9][-\s]?[0-9]{3})|([0-9][-\s]?){4,20})((x|;ext=)([0-9]{3,8}))?$'
[string]$script:TFMatchCommonEmergencyNumber = '^(000|1(\d{2})|9(\d{2})|\d{1}11)$'
[string]$script:TFMatchGuid = '^[0-9a-f]{8}-([0-9a-f]{4}\-){3}[0-9a-f]{12}$'
[string]$script:TFMatchChannelGuid = '^(19:)[0-9a-f]{32}(@thread.)(skype|tacv2|([0-9a-z]{5}))$'
[string]$script:TFMatchAudioFileExtension = '.(wav|wma|mp3)$'
[string]$script:TFMatchIUTMisconfigured = 'Disabled|OnPrem|NotLicensedForService|WithNoService|WithMCOValidationError|NotInPDL|Failed|PendingDeletionFromAD'
# for other variables, please see Enums and ArgumentCompleter
#endregion

#region Custom Module Functions
# Addressing Limitations
# Strict Mode
function Get-StrictMode {
  # returns the currently set StrictMode version 1, 2, 3 or 0 if StrictMode is off.
  #NOTE Higher versions may be available but not able to test against them yet. Functionally v3 is the higheest
  try { $xyz = @(1); $null = ($null -eq $xyz[2]) }
  catch { return 3 }

  try { 'Not-a-Date'.Year }
  catch { return 2 }

  try { $null = ($undefined -gt 1) }
  catch { return 1 }

  return 0
}

if ((Get-StrictMode) -gt 0) {
  Write-Verbose 'TeamsFunctions: Strict Mode interferes with Script execution. Switching Strict Mode off - Please refer to https://github.com/DEberhardt/TeamsFunctions/issues/64 for details'
  Set-StrictMode -Off
}

# Allows use of [ArgumentCompletions] block native to PowerShell 6 and later!
if ($PSVersionTable.PSEdition -ne 'Core') {
  # add the attribute [ArgumentCompletions()]:
  $code = @'
using System;
using System.Collections.Generic;
using System.Management.Automation;
 
    public class ArgumentCompletionsAttribute : ArgumentCompleterAttribute
    {
 
        private static ScriptBlock _createScriptBlock(params string[] completions)
        {
            string text = "\"" + string.Join("\",\"", completions) + "\"";
            string code = "param($Command, $Parameter, $WordToComplete, $CommandAst, $FakeBoundParams);@(" + text + ") -like \"*$WordToComplete*\" | Foreach-Object { [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_) }";
            return ScriptBlock.Create(code);
        }
 
        public ArgumentCompletionsAttribute(params string[] completions) : base(_createScriptBlock(completions))
        {
        }
    }
'@


  $null = Add-Type -TypeDefinition $code *>&1
}
#endregion


# SIG # Begin signature block
# MIIECAYJKoZIhvcNAQcCoIID+TCCA/UCAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB
# gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR
# AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUZEuyK+UmDhdKB8XOLorGviMa
# FXmgggIZMIICFTCCAX6gAwIBAgIQa3i9Sh/NdbhOjG+ewKFPfjANBgkqhkiG9w0B
# AQUFADAlMSMwIQYDVQQDDBpEYXZpZCBFYmVyaGFyZHQgLSBDb2RlU2lnbjAeFw0y
# MDA2MTMxMTA4NTNaFw0yNDA2MTMwMDAwMDBaMCUxIzAhBgNVBAMMGkRhdmlkIEVi
# ZXJoYXJkdCAtIENvZGVTaWduMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC3
# m6z32wDOJ/ZnUYR5tJaujtCN2MVrOYs/ZwSVJvralxDUKHSLAGdmKmO1H5hH4Nmv
# NBe1/L95AVDugTaoH9UK/snN9pcYJ7E7UqLH4ySqJuqE10VmpD2sRi3I2RDL1/eh
# weUut8B3G4bwrA3o2Iy4Y6Kd7IMUAZzUVWwl01jsPQIDAQABo0YwRDATBgNVHSUE
# DDAKBggrBgEFBQcDAzAdBgNVHQ4EFgQUO8DeqyD0FHkF6JO8JT7syAeXJXAwDgYD
# VR0PAQH/BAQDAgeAMA0GCSqGSIb3DQEBBQUAA4GBAFCN2PtWoAvowM+pcxIV/gp2
# RB2rFyPfjLWjfAeKPfXmcfsMAPIoevTrKj3VAzzoF32wZRvdHk7jLssrhT0nmF7L
# 20n7K7RxJ3lccZ0MEdIHsmiklqbV+f9moVtXmgwwJzYkWekjIfrDUSdJeu0BYzR0
# H+8/FVd9YHgogHQN9t3hMYIBWTCCAVUCAQEwOTAlMSMwIQYDVQQDDBpEYXZpZCBF
# YmVyaGFyZHQgLSBDb2RlU2lnbgIQa3i9Sh/NdbhOjG+ewKFPfjAJBgUrDgMCGgUA
# oHgwGAYKKwYBBAGCNwIBDDEKMAigAoAAoQKAADAZBgkqhkiG9w0BCQMxDAYKKwYB
# BAGCNwIBBDAcBgorBgEEAYI3AgELMQ4wDAYKKwYBBAGCNwIBFTAjBgkqhkiG9w0B
# CQQxFgQUwfnELt36kZqDYZP4/6QZd2/MlGIwDQYJKoZIhvcNAQEBBQAEgYCPh2dg
# xza0FE8KuuQqsdCEuRMT0jRsL1jJuVVRmWFWEUjixD4DBpCLnpjx9aN9dwvgtCXM
# CSGGuIQkNa0tZgRwA5BioRb5y/cDtvnvupcIi+ZWwL44VPXg1f+ubML3qXQdJ9pi
# hdCmI+/1XSiTVx3xdwOzVlYtkHrc2Fg7A91CtA==
# SIG # End signature block