Public/AutoAttendant/New-TeamsAutoAttendantSchedule.ps1

# Module: TeamsFunctions
# Function: AutoAttendant
# Author: David Eberhardt
# Updated: 01-DEC-2020
# Status: Live




function New-TeamsAutoAttendantSchedule {
  <#
  .SYNOPSIS
    Creates a Schedule to be used in Auto Attendants
  .DESCRIPTION
    Wrapper for New-CsOnlineSchedule to simplify creation of Schedules with repeating patterns
    Incorporates New-CsOnlineTimeRange with examples
  .PARAMETER Name
    Provides a friendly Name to the Schedule (visible in the Auto Attendant Object)
  .PARAMETER WeeklyRecurrentSchedule
    Defines a schedule that is recurring weekly with Business Hours for every day of the week.
    This is suitable for an After Hours in an Auto Attendant. New-TeamsAutoAttendant will utilise a Default Schedule
    For simplicity, this command assumes the same hours of operation for each day that the business is open.
    For a more granular approach, aim for a "best match", then amend the schedule afterwards in the Admin Center
    If desired via PowerShell, please use BusinessHoursStart/BusinessHoursEnd or define manually with:
    New-CsOnlineTimeRange and New-CsOnlineSchedule respectively.
  .PARAMETER Fixed
    Defines a fixed schedule, suitable for Holiday Sets
  .PARAMETER BusinessDays
    Parameter for WeeklyReccurrentSchedule
    Days defined as Business days. Will be combined with BusinessHours to form a WeeklyReccurrentSchedule
  .PARAMETER BusinessHours
    Parameter for WeeklyReccurrentSchedule - Option 1: Choose from a predefined Time Frame
    Predefined business hours. Combined with BusinessDays, forms the WeeklyRecurrentSchedule
    Covering most of regular working hour patterns to choose from.
  .PARAMETER BusinessHoursStart
    Parameter for WeeklyReccurrentSchedule - Option 2: Select a specific Start and End Time
    Predefined business hours. Combined with BusinessDays, forms the WeeklyRecurrentSchedule
    Manual start and end time to be provided in 15 minute increments only, leading 0 can be omitted: "9:00 AM" or "08:45"
  .PARAMETER BusinessHoursEnd
    Parameter for WeeklyReccurrentSchedule - Option 2: Select a specific Start and End Time
    Predefined business hours. Combined with BusinessDays, forms the WeeklyRecurrentSchedule
    Manual start and end time to be provided in 15 minute increments only, leading 0 can be omitted: "5:15 PM" or "17:30"
  .PARAMETER TimeRanges
    Parameter for WeeklyReccurrentSchedule - Option 3: Provide a TimeRange Object
    One Object or Objects defined with New-CsOnlineTimeRange. Time Range will be applied to Business Days equally (or MonToFri)
    Allows for slightly more granular options then the provided BusinessHours examples.
  .PARAMETER DateTimeRanges
    Parameter for Fixed Schedule - Option 3: Provide a DateTimeRange Object
    Object or Objects defined with New-CsOnlineTimeRange
    Allows for more granular options then the provided BusinessHours examples or to provide Dates for Fixed
  .PARAMETER Complement
    The Complement parameter indicates how the schedule is used.
    When Complement is enabled, the schedule is used as the inverse of the provided configuration
    For example, if Complement is enabled and the schedule only contains time ranges of Monday to Friday from 9AM to 5PM,
    then the schedule is active at all times other than the specified time ranges.
  .EXAMPLE
    New-TeamsAutoAttendantSchedule -WeeklyRecurrentSchedule -BusinessDays MonToFri -BusinesHours 9to5
 
    Creates a weekly recurring schedule for business hours Monday to Friday from 9am to 5pm
  .EXAMPLE
    New-TeamsAutoAttendantSchedule -WeeklyRecurrentSchedule -BusinessDays MonToSat -BusinessHoursStart 09:15 -BusinessHoursEnd 17:45
 
    Creates a weekly recurring schedule for business hours Monday to Saturday from 09:15 to 17:45
  .EXAMPLE
    New-TeamsAutoAttendantSchedule -WeeklyRecurrentSchedule -BusinessDays SunToThu -DateTimeRange @($TR1, $TR2)
 
    Creates a weekly recurring schedule for business hours Sunday to Thursday with custom TimeRange(s) provided with the Objects $TR1 and $TR2
  .EXAMPLE
    New-TeamsAutoAttendantSchedule -Fixed -DateTimeRange @($TR1, $TR2)
 
    Adds a fixed schedule for the TimeRange(s) provided with the Objects $TR1 and $TR2
  .INPUTS
    System.String, System.Object
  .OUTPUTS
    System.Object
  .NOTES
    Combinations of BusinesHours and BusinessDays are numerous but not exhaustive.
    For simplicity, this command assumes the same hours of operation for each day that the business is open.
    With the following Parameters, these three options are available:
    1. BusinessHours - Choose time range from a predefined list (amend in Admin Center afterwards, if needed)
    2. BusinessHoursStart and BusinessHoursEnd - Provide a Start and End Time for the Time Range (15 minute increments)
    3. DateTimeRange - Provide a DateTimeRange Object manually defined with New-CsOnlineTimeRange and New-CsOnlineSchedule
  .COMPONENT
    TeamsAutoAttendant
  .FUNCTIONALITY
    Creates a Schedule Object for use in an AutoAttendant
  .LINK
    https://github.com/DEberhardt/TeamsFunctions/tree/main/docs/New-TeamsAutoAttendantSchedule.md
  .LINK
    https://github.com/DEberhardt/TeamsFunctions/tree/main/docs/about_TeamsAutoAttendant.md
  .LINK
    https://github.com/DEberhardt/TeamsFunctions/tree/main/docs/
  #>


  [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'Low', DefaultParameterSetName = 'WeeklyBusinessHours')]
  [Alias('New-TeamsAASchedule')]
  [OutputType([System.Object])]
  param(
    [Parameter(Mandatory)]
    [string]$Name,

    [Parameter(Mandatory, ParameterSetName = 'WeeklyBusinessHours2')]
    [Parameter(Mandatory, ParameterSetName = 'WeeklyBusinessHours')]
    [Parameter(Mandatory, ParameterSetName = 'WeeklyTimeRange')]
    [switch]$WeeklyRecurrentSchedule,

    [Parameter(Mandatory, ParameterSetName = 'FixedTimeRange')]
    [switch]$Fixed,

    [Parameter(Mandatory, ParameterSetName = 'WeeklyBusinessHours2')]
    [Parameter(Mandatory, ParameterSetName = 'WeeklyBusinessHours')]
    [Parameter(Mandatory, ParameterSetName = 'WeeklyTimeRange')]
    [ValidateSet('MonToFri', 'MonToSat', 'MonToSun', 'SatToThu', 'SunToThu', 'SunToFri')]
    [string]$BusinessDays,

    [Parameter(Mandatory, ParameterSetName = 'WeeklyBusinessHours')]
    [ValidateSet('9to6', '9to5', '9to4', '8to6', '8to5', '8to4', '7to6', '7to5', '7to4', '6to6', '10to6', '0830to1700', '0830to1730', '0800to1730', '0830to1800', '0900to1730', '0930to1730', '0930to1800', '8to12and13to17', '8to12and13to18', '9to12and13to17', '9to12and13to18', '9to13and14to18', '8to12and14to18', 'AllDay')]
    [string]$BusinessHours,

    [Parameter(Mandatory, ParameterSetName = 'WeeklyBusinessHours2')]
    [ValidateScript( {
        if ($_ -match '^(?:[01]?\d|2[0-3])(?::)(00|15|30|45)[:space:]?([AP]M)?') { return $true } else {
          throw [System.Management.Automation.ValidationMetadataException] "Time can be specified in 12 or 24h notation, leading zeros may be omitted. Minutes must be specified and as a multiple of 15, for example '09:00 AM', '9:15', '5:00PM', '17:15'"
        } })]
    [string]$BusinessHoursStart,

    [Parameter(ParameterSetName = 'WeeklyBusinessHours2')]
    [ValidateScript( {
        if ($_ -match '^(?:[01]?\d|2[0-3])(?::)(00|15|30|45)[:space:]?([AP]M)?') { return $true } else {
          throw [System.Management.Automation.ValidationMetadataException] "Time can be specified in 12 or 24h notation, leading zeros may be omitted. Minutes must be specified and as a multiple of 15, for example '09:00 AM', '9:15', '5:00PM', '17:15'"
        } })]
    [string]$BusinessHoursEnd,

    [Parameter(Mandatory, ParameterSetName = 'WeeklyTimeRange')]
    [system.Object[]]$TimeRanges,

    [Parameter(Mandatory, ParameterSetName = 'FixedTimeRange')]
    [system.Object[]]$DateTimeRanges,

    [Parameter(ParameterSetName = 'WeeklyBusinessHours2')]
    [Parameter(ParameterSetName = 'WeeklyBusinessHours')]
    [Parameter(ParameterSetName = 'WeeklyTimeRange')]
    [switch]$Complement
  ) #param

  begin {
    Show-FunctionStatus -Level Live
    Write-Verbose -Message "[BEGIN ] $($MyInvocation.MyCommand)"

    # Asserting AzureAD Connection
    if ( -not $script:TFPSSA) { $script:TFPSSA = Assert-AzureADConnection; if ( -not $script:TFPSSA ) { break } }

    # Asserting MicrosoftTeams Connection
    if ( -not (Assert-MicrosoftTeamsConnection) ) { break }

    # Setting Preference Variables according to Upstream settings
    if (-not $PSBoundParameters.ContainsKey('Verbose')) { $VerbosePreference = $PSCmdlet.SessionState.PSVariable.GetValue('VerbosePreference') }
    if (-not $PSBoundParameters.ContainsKey('Confirm')) { $ConfirmPreference = $PSCmdlet.SessionState.PSVariable.GetValue('ConfirmPreference') }
    if (-not $PSBoundParameters.ContainsKey('WhatIf')) { $WhatIfPreference = $PSCmdlet.SessionState.PSVariable.GetValue('WhatIfPreference') }
    if (-not $PSBoundParameters.ContainsKey('Debug')) { $DebugPreference = $PSCmdlet.SessionState.PSVariable.GetValue('DebugPreference') } else { $DebugPreference = 'Continue' }
    if ( $PSBoundParameters.ContainsKey('InformationAction')) { $InformationPreference = $PSCmdlet.SessionState.PSVariable.GetValue('InformationAction') } else { $InformationPreference = 'Continue' }

  } #begin

  process {
    Write-Verbose -Message "[PROCESS] $($MyInvocation.MyCommand)"

    #region Prep
    # Initialising Splatting Object
    $Parameters = @{}

    # Adding generic parameters
    $Parameters.Name = "$Name"
    #$Parameters.ErrorAction' = $Stop }

    if ($Complement) {
      Write-Verbose -Message '[PROCESS] Processing Complement'
      $Parameters.Complement = $true
    }
    #endregion

    #region Defining recurrance Fixed/Weekly
    if ($PSBoundParameters.ContainsKey('WeeklyRecurrentSchedule')) {
      Write-Verbose -Message '[PROCESS] Processing WeeklyRecurrentSchedule'
      $Parameters.WeeklyRecurrentSchedule = $true

      #region Defining $TimeFrame
      if ($PSBoundParameters.ContainsKey('TimeRanges')) {
        Write-Verbose -Message '[PROCESS] Processing TimeRanges'
        Write-Information 'INFO: The TimeRanges provided are not validated, just passed on to New-CsOnlineSchedule as is. Handle with care'
        $TimeFrame = $TimeRanges
      }
      else {
        # Differentiating between BusinessHours and BusinessHoursStart/End
        if ($PSBoundParameters.ContainsKey('BusinessHoursStart')) {
          Write-Verbose -Message "[PROCESS] Processing BusinessHoursStart '$BusinessHoursStart'"
          if ( $BusinessHoursStart -match 'AM|PM') { $BusinessHoursStart = '{0:HH:mm}' -f [datetime]$Businesshoursstart }
          if ($PSBoundParameters.ContainsKey('BusinessHoursEnd')) {
            Write-Verbose -Message "[PROCESS] Processing BusinessHoursEnd '$BusinessHoursEnd'"
            if ( $BusinessHoursEnd -match 'AM|PM') { $BusinessHoursEnd = '{0:HH:mm}' -f [datetime]$BusinessHoursEnd }
          }
          else {
            Write-Verbose -Message '[PROCESS] Assuming BusinessHoursEnd is at midnight'
            $BusinessHoursEnd = '00:00'
          }

          Write-Verbose -Message "[PROCESS] Processing BusinessHoursStart '$BusinessHoursStart' and BusinessHoursEnd '$BusinessHoursEnd'"
          if ($BusinessHoursStart -gt $BusinessHoursEnd) {
            Write-Warning -Message 'BusinessHoursEnd not specified or set before BusinessHoursStart. Assuming setup to midnight!'
            $BusinessHoursEnd = '00:00'
            $TimeFrame = New-CsOnlineTimeRange -Start $BusinessHoursStart -End 1.$BusinessHoursEnd
          }
          else {
            $TimeFrame = New-CsOnlineTimeRange -Start $BusinessHoursStart -End $BusinessHoursEnd
          }
        }
        else {
          Write-Verbose -Message "[PROCESS] Processing BusinessHours '$BusinessHours'"
          switch ($BusinessHours) {
            # Defining time of Day ($TimeFrame)
            'AllDay' { $TimeFrame = New-CsOnlineTimeRange -Start 00:00 -End 1.00:00 }
            '9to6' { $TimeFrame = New-CsOnlineTimeRange -Start 09:00 -End 18:00 }
            '9to5' { $TimeFrame = New-CsOnlineTimeRange -Start 09:00 -End 17:00 }
            '9to4' { $TimeFrame = New-CsOnlineTimeRange -Start 09:00 -End 16:00 }
            '8to6' { $TimeFrame = New-CsOnlineTimeRange -Start 08:00 -End 18:00 }
            '8to5' { $TimeFrame = New-CsOnlineTimeRange -Start 08:00 -End 17:00 }
            '8to4' { $TimeFrame = New-CsOnlineTimeRange -Start 08:00 -End 16:00 }
            '7to6' { $TimeFrame = New-CsOnlineTimeRange -Start 07:00 -End 18:00 }
            '7to5' { $TimeFrame = New-CsOnlineTimeRange -Start 07:00 -End 17:00 }
            '7to4' { $TimeFrame = New-CsOnlineTimeRange -Start 07:00 -End 16:00 }
            '6to6' { $TimeFrame = New-CsOnlineTimeRange -Start 06:00 -End 18:00 }
            '10to6' { $TimeFrame = New-CsOnlineTimeRange -Start 10:00 -End 18:00 }
            '0800to1730' { $TimeFrame = New-CsOnlineTimeRange -Start 09:00 -End 17:00 }
            '0830to1700' { $TimeFrame = New-CsOnlineTimeRange -Start 09:00 -End 17:00 }
            '0830to1730' { $TimeFrame = New-CsOnlineTimeRange -Start 09:00 -End 17:00 }
            '0830to1800' { $TimeFrame = New-CsOnlineTimeRange -Start 09:00 -End 17:00 }
            '0900to1730' { $TimeFrame = New-CsOnlineTimeRange -Start 09:00 -End 17:30 }
            '0930to1730' { $TimeFrame = New-CsOnlineTimeRange -Start 09:30 -End 17:30 }
            '0930to1800' { $TimeFrame = New-CsOnlineTimeRange -Start 09:30 -End 18:00 }
            '8to12and13to17' {
              $Range1 = New-CsOnlineTimeRange -Start 08:00 -End 12:00
              $Range2 = New-CsOnlineTimeRange -Start 13:00 -End 17:00
              $TimeFrame = @($Range1, $Range2)
            }
            '8to12and13to18' {
              $Range1 = New-CsOnlineTimeRange -Start 08:00 -End 12:00
              $Range2 = New-CsOnlineTimeRange -Start 13:00 -End 18:00
              $TimeFrame = @($Range1, $Range2)
            }
            '9to12and13to17' {
              $Range1 = New-CsOnlineTimeRange -Start 09:00 -End 12:00
              $Range2 = New-CsOnlineTimeRange -Start 13:00 -End 17:00
              $TimeFrame = @($Range1, $Range2)
            }
            '9to12and13to18' {
              $Range1 = New-CsOnlineTimeRange -Start 09:00 -End 12:00
              $Range2 = New-CsOnlineTimeRange -Start 13:00 -End 18:00
              $TimeFrame = @($Range1, $Range2)
            }
            '9to13and14to18' {
              $Range1 = New-CsOnlineTimeRange -Start 09:00 -End 13:00
              $Range2 = New-CsOnlineTimeRange -Start 14:00 -End 17:00
              $TimeFrame = @($Range1, $Range2)
            }
            '8to12and14to18' {
              $Range1 = New-CsOnlineTimeRange -Start 08:00 -End 12:00
              $Range2 = New-CsOnlineTimeRange -Start 14:00 -End 18:00
              $TimeFrame = @($Range1, $Range2)
            }
            default { $TimeFrame = @($(New-CsOnlineTimeRange -Start 09:00 -End 17:00)) }
          }
        }
      }
      #endregion

      #region Defining $BusinessDays
      # Then Using $TimeFrame to define full Schedule for $BusinessDays
      if ($BusinessDays) {
        Write-Verbose -Message "[PROCESS] Processing BusinessDays '$BusinessDays'"
        switch ($BusinessDays) {
          'MonToFri' {
            $Parameters.MondayHours = @($TimeFrame)
            $Parameters.TuesdayHours = @($TimeFrame)
            $Parameters.WednesdayHours = @($TimeFrame)
            $Parameters.ThursdayHours = @($TimeFrame)
            $Parameters.FridayHours = @($TimeFrame)
          }
          'MonToSat' {
            $Parameters.MondayHours = @($TimeFrame)
            $Parameters.TuesdayHours = @($TimeFrame)
            $Parameters.WednesdayHours = @($TimeFrame)
            $Parameters.ThursdayHours = @($TimeFrame)
            $Parameters.FridayHours = @($TimeFrame)
            $Parameters.SaturdayHours = @($TimeFrame)
          }
          'MonToSun' {
            $Parameters.MondayHours = @($TimeFrame)
            $Parameters.TuesdayHours = @($TimeFrame)
            $Parameters.WednesdayHours = @($TimeFrame)
            $Parameters.ThursdayHours = @($TimeFrame)
            $Parameters.FridayHours = @($TimeFrame)
            $Parameters.SaturdayHours = @($TimeFrame)
            $Parameters.SundayHours = @($TimeFrame)
          }
          'SatToThu' {
            $Parameters.SaturdayHours = @($TimeFrame)
            $Parameters.SundayHours = @($TimeFrame)
            $Parameters.MondayHours = @($TimeFrame)
            $Parameters.TuesdayHours = @($TimeFrame)
            $Parameters.WednesdayHours = @($TimeFrame)
            $Parameters.ThursdayHours = @($TimeFrame)
          }
          'SunToThu' {
            $Parameters.SundayHours = @($TimeFrame)
            $Parameters.MondayHours = @($TimeFrame)
            $Parameters.TuesdayHours = @($TimeFrame)
            $Parameters.WednesdayHours = @($TimeFrame)
            $Parameters.ThursdayHours = @($TimeFrame)
          }
          'SunToFri' {
            $Parameters.SundayHours = @($TimeFrame)
            $Parameters.MondayHours = @($TimeFrame)
            $Parameters.TuesdayHours = @($TimeFrame)
            $Parameters.WednesdayHours = @($TimeFrame)
            $Parameters.ThursdayHours = @($TimeFrame)
            $Parameters.FridayHours = @($TimeFrame)
          }
          default {
            $Parameters.MondayHours = @($TimeFrame)
            $Parameters.TuesdayHours = @($TimeFrame)
            $Parameters.WednesdayHours = @($TimeFrame)
            $Parameters.ThursdayHours = @($TimeFrame)
            $Parameters.FridayHours = @($TimeFrame)
          }
        }
      }
      #endregion
    }
    elseif ($PSBoundParameters.ContainsKey('Fixed')) {
      Write-Verbose -Message '[PROCESS] Processing Fixed'
      $Parameters.Fixed = $true

      if ($PSBoundParameters.ContainsKey('DateTimeRanges')) {
        Write-Verbose -Message '[PROCESS] Processing DateTimeRanges'
        Write-Information 'INFO: The DateTimeRanges provided are not validated, just passed on to New-CsOnlineSchedule as is. Handle with care'
        $TimeFrame = @($DateTimeRanges)
        $Parameters.DateTimeRanges = @($TimeFrame)
      }
      else {
        #?
      }
    }
    #endregion


    # Creating Schedule
    Write-Verbose -Message '[PROCESS] Creating Schedule'
    if ($PSBoundParameters.ContainsKey('Debug') -or $DebugPreference -eq 'Continue') {
      " Function: $($MyInvocation.MyCommand.Name) - Parameters (New-CsOnlineSchedule)", ($Parameters | Format-Table -AutoSize | Out-String).Trim() | Write-Debug
    }

    if ($PSCmdlet.ShouldProcess("$Name", 'New-CsOnlineSchedule')) {
      New-CsOnlineSchedule @Parameters
    }

  } #process

  end {
    Write-Verbose -Message "[END ] $($MyInvocation.MyCommand)"
  } #end
} #New-TeamsAutoAttendantSchedule