Use PowerShell to manage your Shifts connection to Blue Yonder Workforce Management

Overview

The Microsoft Teams Shifts connector for Blue Yonder enables you to integrate the Shifts app in Microsoft Teams with Blue Yonder Workforce Management (Blue Yonder WFM). After you set up a connection, your frontline workers can seamlessly view and manage their schedules in Blue Yonder WFM from within Shifts.

You can use the Shifts connector wizard in the Microsoft 365 admin center or PowerShell to set up a connection. After a connection is set up, you can manage it by using Shifts connector PowerShell cmdlets.

This article describes how to use PowerShell to do the following:

This article assumes that you've already set up a connection to Blue Yonder WFM, either by using the wizard or PowerShell.

Note

You can also manage your connection in the Microsoft 365 admin center. For example, you can check the health status and access the wizard to change connection settings. To learn more, see Use the Microsoft 365 admin center to manage your Shifts connection to Blue Yonder Workforce Management.

Before you begin

To complete the steps in this article, you must be a Microsoft 365 global admin or a Shifts connector admin.

The Shifts connector admin role is a custom role that you create in Azure AD and assign to a user. The name of the role must be "Shifts connector admin". The role doesn't need to have any specific permissions, although, at least one permission must be set when you create it. The service relies on the presence of the role on the user, and not its permissions. To learn more, see Create and assign a custom role in Azure AD and Assign Azure AD roles to users. Keep in mind that it can take up to 24 hours for the role to be created and applied to a user.

Set up your environment

Note

Make sure you follow these steps to set up your environment before running any of the commands or scripts in this article.

  1. Install PowerShell version 7 or later. For step-by-step guidance, see Installing PowerShell on Windows.

  2. Run PowerShell in administrator mode.

  3. Install the Microsoft Graph PowerShell module.

    Install-Module Microsoft.Graph
    Import-Module Microsoft.Graph
    

    Verify that it's version 1.6.1 or later.

    Get-InstalledModule Microsoft.Graph 
    
  4. Install the Teams Preview PowerShell module.

    Install-Module -Name MicrosoftTeams -AllowPrerelease -Force
    Import-Module MicrosoftTeams 
    

    Verify that it's at least version 4.7.0 and contains the Shifts connector cmdlets.

    Get-Command -Module MicrosoftTeams -Name *teamsshiftsconnection* 
    
  5. Set PowerShell to exit if an error occurs when running the script.

    $ErrorActionPreference = "Stop" 
    
  6. Enable scripts to run in Windows.

    Set-ExecutionPolicy bypass 
    
  1. Connect to Teams.

    Connect-MicrosoftTeams
    

    When you're prompted, sign in using your admin credentials. You're now set up to run the scripts in this article and Shifts connector cmdlets.

Check connection setup status

To check the status of the connection you set up using the operation ID that you received in email:

  1. Set up your environment (if you haven't already).

  2. Run the following command. This command gives you the overall status of the team mappings for the connection.

    Get-CsTeamsShiftsConnectionOperation -OperationId <YourOperationId>
    

To learn more, see Get-CsTeamsShiftsConnectionOperation.

View an error report for a connection

You can run a report that shows error details for a connection. The report lists team and user mappings that succeeded and failed. It also provides information about any issues related to the accounts associated with the connection.

  1. Set up your environment (if you haven't already).

  2. Get a list of error reports for a connection.

    Get-CsTeamsShiftsConnectionErrorReport -ConnectorInstanceId <ConnectorInstanceId>
    
  3. To view a specific error report, run the following command:

    Get-CsTeamsShiftsConnectionErrorReport -ErrorReportId <ErrorReportId>
    

To learn more, see Get-CsTeamsShiftsConnectionErrorReport.

Note

For a complete list of error messages, see List of error messages later in this article.

Resolve connection errors

User mapping errors

User mapping errors may occur if one or more users in a WFM instance isn't a member of the mapped team in Teams. To resolve this issue, make sure that the users in the mapped team match the users in the WFM instance.

To view details of unmapped users, set up your environment (if you haven't already), and then run the following script.

#View sync errors script
Write-Host "View sync errors"
Start-Sleep 1

#Ensure Teams module is of version x
Write-Host "Checking Teams module version"
try {
    Get-InstalledModule -Name "MicrosoftTeams" -MinimumVersion 4.7.0
} catch {
    throw
}

#List connection instances available
Write-Host "Listing connection instances"
$InstanceList = Get-CsTeamsShiftsConnectionInstance
write $InstanceList

#Get an instance
if ($InstanceList.Count -gt 0){
    $InstanceId = Read-Host -Prompt 'Input the instance ID that you want to retrieve user sync results from'
}
else {
    throw "Instance list is empty"
}

#Get a list of the mappings
Write-Host "Listing team mappings"
$mappings = Get-CsTeamsShiftsConnectionTeamMap -ConnectorInstanceId $InstanceId
write $mappings

#For each mapping, retrieve the failed mappings
ForEach ($mapping in $mappings){
    $teamsTeamId = $mapping.TeamId
    $wfmTeamId = $mapping.WfmTeamId
    Write-Host "Failed mapped users in the mapping of ${teamsTeamId} and ${wfmTeamId}:"
    $userSyncResult = Get-CsTeamsShiftsConnectionSyncResult -ConnectorInstanceId $InstanceId -TeamId $teamsTeamId
    Write-Host "Failed AAD users:"
    write $userSyncResult.FailedAadUser
    Write-Host "Failed WFM users:"
    write $userSyncResult.FailedWfmUser
}

Account authorization errors

Account authorization errors may occur if the WFM service account or Microsoft 365 system account credentials are incorrect or don't have the required permissions.

To change your WFM service account or Microsoft 365 system account credentials for the connection, you can run the Set-CsTeamsShiftsConnectionInstance cmdlet or use the PowerShell script in the Change connection settings section of this article.

Change connection settings

Use this script to change connection settings. Settings that you can change include your WFM service account and password, Microsoft 365 system account, team mappings, and sync settings.

Sync settings include the sync frequency (in minutes) and the schedule data that's synced between your WFM system and Shifts. Schedule data is defined in the following parameters, which you can view by running Get-CsTeamsShiftsConnectionConnector.

  • The enabledConnectorScenarios parameter defines data that's synced from your WFM system to Shifts. Options are Shift, SwapRequest, UserShiftPreferences, OpenShift, OpenShiftRequest, TimeOff, TimeOffRequest.

  • The enabledWfiScenarios parameter defines data that's synced from Shifts to your WFM system. Options are SwapRequest, OpenShiftRequest, TimeOffRequest, UserShiftPreferences.

    Note

    If you choose not to sync open shifts, open shift requests, swap requests, or time off requests between Shifts and your WFM system, there's another step you need to do to hide the capability in Shifts. After you run this script, make sure you follow the steps in the Disable open shifts, open shifts requests, swap requests, and time off requests section later in this article.

Important

For settings that you don't want to change, you'll need to re-enter the original settings when you're prompted by the script.

Set up your environment (if you haven't already), and then run the following script.

#Update connector instance and mapping script
Write-Host "Update Connector instance and mapping"
Start-Sleep 1

#Ensure Teams module is at least version x
Write-Host "Checking Teams module version"
try {
    Get-InstalledModule -Name "MicrosoftTeams" -MinimumVersion 4.7.0
} catch {
    throw
}

#Connect to MS Graph
Connect-MgGraph -Scopes "User.Read.All","Group.ReadWrite.All"

#List connector types available (comment out if not implemented for preview)
Write-Host "Listing connector types available"
$BlueYonderId = "6A51B888-FF44-4FEA-82E1-839401E9CD74"
$connectors = Get-CsTeamsShiftsConnectionConnector
write $connectors
$blueYonder = $connectors | where {$_.Id -match $BlueYonderId}

#List connection instances available
Write-Host "Listing connection instances available"
$InstanceList = Get-CsTeamsShiftsConnectionInstance | where {$_.ConnectorId -match $BlueYonderId}
write $InstanceList

#Prompt for the WFM username and password
$WfmUserName = Read-Host -Prompt 'Input your WFM user name'
$WfmPwd = Read-Host -Prompt 'Input your WFM password' -AsSecureString
$plainPwd =[Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($WfmPwd))

#Get the instance ID
$InstanceId = Read-Host -Prompt 'Input the instance ID that you want to update'
$Instance = Get-CsTeamsShiftsConnectionInstance -ConnectorInstanceId $InstanceId
$Etag = $Instance.etag

#Change sync setting
$designatorName = Read-Host -Prompt "Input designated actor's user name"
$designator = Get-MgUser -UserId $designatorName
$teamsUserId = $designator.Id
$UpdatedInstanceName = Read-Host -Prompt 'Input new connection instance name'
$updatedConnectorScenarioString = Read-Host -Prompt 'Input new enabled connector scenarios'
$updatedWfiScenarioString = Read-Host -Prompt 'Input new enabled WFI scenarios'
$Delimiters = ",", ".", ":", ";", " ", "`t"
$updatedConnectorScenario = $updatedConnectorScenarioString -Split {$Delimiters -contains $_}
$updatedConnectorScenario = $updatedConnectorScenario.Trim()
$updatedConnectorScenario = $updatedConnectorScenario.Split('',[System.StringSplitOptions]::RemoveEmptyEntries)
$updatedWfiScenario = $updatedWfiScenarioString -Split {$Delimiters -contains $_}
$updatedWfiScenario = $updatedWfiScenario.Trim()
$updatedWfiScenario = $updatedWfiScenario.Split('', [System.StringSplitOptions]::RemoveEmptyEntries)
$adminApiUrl = $Instance.ConnectorSpecificSettingAdminApiUrl
$cookieAuthUrl = $Instance.ConnectorSpecificSettingCookieAuthUrl
$essApiUrl = $Instance.ConnectorSpecificSettingEssApiUrl
$federatedAuthUrl = $Instance.ConnectorSpecificSettingFederatedAuthUrl
$retailWebApiUrl = $Instance.ConnectorSpecificSettingRetailWebApiUrl
$siteManagerUrl = $Instance.ConnectorSpecificSettingSiteManagerUrl
$syncFreq = Read-Host -Prompt 'Input new sync frequency'

#Read admin email list
[psobject[]]$AdminEmailList = @()
while ($true){
$AdminEmail = Read-Host -Prompt "Enter admin's email to receive error report"
$AdminEmailList += $AdminEmail
$title    = 'Adding another email'
$question = 'Would you like to add another admin email?'
$choices  = '&Yes', '&No'
$decision = $Host.UI.PromptForChoice($title, $question, $choices, 1)
if ($decision -eq 1) {
    break
}
}
$UpdatedInstance = Set-CsTeamsShiftsConnectionInstance `
    -ConnectorInstanceId $InstanceId `
    -ConnectorId $BlueYonderId `
    -ConnectorAdminEmail $AdminEmailList `
    -DesignatedActorId $teamsUserId `
    -EnabledConnectorScenario $updatedConnectorScenario `
    -EnabledWfiScenario $updatedWfiScenario `
    -Name $UpdatedInstanceName `
    -SyncFrequencyInMin $syncFreq `
    -ConnectorSpecificSettings (New-Object Microsoft.Teams.ConfigAPI.Cmdlets.Generated.Models.ConnectorSpecificBlueYonderSettingsRequest `
    -Property @{
        AdminApiUrl = $adminApiUrl
        SiteManagerUrl = $siteManagerUrl
        EssApiUrl = $essApiUrl
        RetailWebApiUrl = $retailWebApiUrl
        CookieAuthUrl = $cookieAuthUrl
        FederatedAuthUrl = $federatedAuthUrl
        LoginUserName = $WfmUserName
        LoginPwd = $plainPwd
    }) `
    -IfMatch $Etag
if ($UpdatedInstance.Id -ne $null) {
    Write-Host "Success"
}
else {
    throw "Update instance failed"
}
#Get a list of the mappings
Write-Host "Listing mappings"
$TeamMaps = Get-CsTeamsShiftsConnectionTeamMap -ConnectorInstanceId $InstanceId
write $TeamMaps

#Modify a mapping
#Remove a mapping
Write-Host "Removing a mapping"
$TeamsTeamId = Read-Host -Prompt 'Input the Teams team ID that you want to unlink'
$WfmTeamId = Read-Host -Prompt 'Input the WFM team ID that you want to unlink'
Remove-CsTeamsShiftsConnectionTeamMap -ConnectorInstanceId $InstanceId -TeamId $TeamsTeamId
Write-Host "Success"

#Add a mapping
Write-Host "Adding a mapping"
$TeamsTeamId = Read-Host -Prompt 'Input the Teams team ID that you want to link'
$WfmTeamId = Read-Host -Prompt 'Input the WFM team ID that you want to link'
New-CsTeamsShiftsConnectionTeamMap -ConnectorInstanceId $InstanceId -TeamId $TeamsTeamId -TimeZone "America/Los_Angeles" -WfmTeamId $WfmTeamId
Write-Host "Success"

Disable open shifts, open shifts requests, swap requests, and time off requests

Important

Follow these steps only if you chose to disable open shifts, open shift requests, swap requests, or time off requests using the script in the Change connection settings section earlier in this article or by using the Set-CsTeamsShiftsConnectionInstance cmdlet. Completing this step hides the capability in Shifts. Without this second step, users will still see the capability in Shifts, and will get an "unsupported operation" error message if they try to use it.

To hide open shifts, swap requests, and time off requests in Shifts, use the Graph API schedule resource type to set the following parameters to false for each team that you mapped to a WFM instance:

  • Open shifts: openShiftsEnabled
  • Swap requests: swapShiftsRequestsEnabled
  • Time off requests: timeOffRequestsEnabled

To hide open shifts requests in Shifts, go to Settings in Shifts, and then turn off the Open shifts setting.

Unmap a team from one connection and map it to another connection

Note

The Microsoft 365 system account must be the same for both connections. If it isn't, you'll get a "This designated actor profile doesn't have team ownership privileges" error message.

If you want to unmap a team from one connection and map it to another connection:

  1. Set up your environment (if you haven't already).

  2. View a list of all team mappings for a connection.

    Get-CsTeamsShiftsConnectionTeamMap -ConnectorInstanceId <ConnectorInstanceId>
    
  3. Remove a team mapping from the connection.

    Remove-CsTeamsShiftsConnectionTeamMap -ConnectorInstanceId <ConnectorInstanceId> -TeamId <TeamId>
    
  4. Map the team to another connection.

    New-CsTeamsShiftsConnectionTeamMap -ConnectorInstanceId <ConnectorInstanceId> -TeamId <TeamId> -WfmTeamId <SiteId> -TimeZone <TimeZone>
    

To learn more, see Get-CsTeamsShiftsConnectionTeamMap, Remove-CsTeamsShiftsConnectionTeamMap, and New-CsTeamsShiftsConnectionTeamMap.

Disable sync for a connection

Use this script to disable sync for a connection. Keep in mind this script doesn't remove or delete a connection. It turns off sync so that no data is synced between Shifts and your WFM system for the connection that you specify.

Set up your environment (if you haven't already), and then run the following script.

#Disable sync script
Write-Host "Disable sync"
Start-Sleep 1

#Ensure Teams module is at least version x
Write-Host "Checking Teams module version"
try {
    Get-InstalledModule -Name "MicrosoftTeams" -MinimumVersion 4.7.0
} catch {
    throw
}

#List connection instances available
$BlueYonderId = "6A51B888-FF44-4FEA-82E1-839401E9CD74"
Write-Host "Listing connection instances"
$InstanceList = Get-CsTeamsShiftsConnectionInstance | where {$_.ConnectorId -match $BlueYonderId}
write $InstanceList

#Get an instance
if ($InstanceList.Count -gt 0){
    $InstanceId = Read-Host -Prompt 'Input the instance ID that you want to disable sync'
    $Instance = Get-CsTeamsShiftsConnectionInstance -ConnectorInstanceId $InstanceId
    $Etag = $Instance.etag
    $InstanceName = $Instance.Name
    $DesignatedActorId = $Instance.designatedActorId
    $adminApiUrl = $Instance.ConnectorSpecificSettingAdminApiUrl
    $cookieAuthUrl = $Instance.ConnectorSpecificSettingCookieAuthUrl
    $essApiUrl = $Instance.ConnectorSpecificSettingEssApiUrl
    $federatedAuthUrl = $Instance.ConnectorSpecificSettingFederatedAuthUrl
    $retailWebApiUrl = $Instance.ConnectorSpecificSettingRetailWebApiUrl
    $siteManagerUrl = $Instance.ConnectorSpecificSettingSiteManagerUrl
    $ConnectorAdminEmail = $Instance.ConnectorAdminEmail
}
else {
    throw "Instance list is empty"
}

#Remove scenarios in the mapping
Write-Host "Disabling scenarios in the team mapping"
$UpdatedInstanceName = $InstanceName + " - Disabled"
$BlueYonderId = "6A51B888-FF44-4FEA-82E1-839401E9CD74"
$WfmUserName = Read-Host -Prompt 'Input your WFM user name'
$WfmPwd = Read-Host -Prompt 'Input your WFM password' -AsSecureString
$plainPwd =[Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($WfmPwd))

$UpdatedInstance = Set-CsTeamsShiftsConnectionInstance `
    -ConnectorInstanceId $InstanceId `
    -ConnectorId $BlueYonderId `
    -ConnectorAdminEmail $ConnectorAdminEmail `
    -DesignatedActorId $DesignatedActorId `
    -EnabledConnectorScenario @() `
    -EnabledWfiScenario @() `
    -Name $UpdatedInstanceName `
    -SyncFrequencyInMin 10 `
    -ConnectorSpecificSettings (New-Object Microsoft.Teams.ConfigAPI.Cmdlets.Generated.Models.ConnectorSpecificBlueYonderSettingsRequest `
        -Property @{
            AdminApiUrl = $adminApiUrl
            SiteManagerUrl = $siteManagerUrl
            EssApiUrl = $essApiUrl
            RetailWebApiUrl = $retailWebApiUrl
            CookieAuthUrl = $cookieAuthUrl
            FederatedAuthUrl = $federatedAuthUrl
            LoginUserName = $WfmUserName
            LoginPwd = $plainPwd
        }) `
    -IfMatch $Etag

if ($UpdatedInstance.Id -ne $null) {
    Write-Host "Success"
}
else {
    throw "Update instance failed"
}

List of error messages

Here's the list of error messages that you may encounter and information to help you resolve them.

Error type Error details Resolution
Unable to authenticate workforce management system. The workforce management system account credentials you've provided are invalid or this account doesn't have the required permissions. Update your WFM service account credentials in the connection settings. To do this, do one of the following:
Unable to authenticate Graph. Authentication failed. Ensure that you've entered valid credentials for the designated actor and have the required permissions. Make sure that your Microsoft 365 system account (also known as designated actor) is added as a team owner.
Or, update your Microsoft 365 system account credentials in the connection settings.
Some users have failed to map correctly Mapping failed for some users: <X> succeeded, <X> failed AAD user(s) and <X> failed workforce management system user(s). Use the Get-CsTeamsShiftsConnectionSyncResult cmdlet or this PowerShell script to identify the users for whom the mapping failed. Make sure that the users in the mapped team match the users in the WFM instance.
Unable to map a team or teams in this batch. This designated actor profile doesn't have team ownership privileges. Make sure your Microsoft 365 system account (also known as designated actor) is added as a team owner.
If you’ve changed your Microsoft 365 system account, add that account as a team owner, and update the connection settings to use that account.
This team is already mapped to an existing connector instance. Unmap the team from the existing connection by using the Remove-CsTeamsShiftsConnectionTeamMap cmdlet. Or, create a new connection to remap the team.
This timezone is invalid. The timezone passed in is not using tz database format. Make sure that the time zone is correct, and then remap the team.
We can't find this connector instance. Map the team to an existing connection.
This AAD team couldn't be found. Make sure that the team exists or create a new team.

Shifts connector cmdlets

For help with Shifts connector cmdlets, search for CsTeamsShiftsConnection in the Teams PowerShell cmdlet reference. Here are links to some commonly used cmdlets.