Another Microsoft API that I’ve come across needing a solution for Modern Auth.
This one’s a bit different. You don’t need to register an AD app, but you can connect to S4B with a token, and you can store the token in a Byte Array (in a file or database).
This method uses Microsoft.IdentityModel.Clients.ActiveDirectory.dll to acquire a token.
Wrote this function to handle the token stuff. And the function below to create the Token to store (as a byte array) and how to recall it to use it for unattended authentication.
Thanks again to Elliot Munro from GCITS for helping me figure this one out using a method we found for connecting to Microsoft InTune Graph API.
function Get-MSAuthToken
{
[cmdletbinding()]
param
(
[Parameter(Mandatory=$true)]
$User,
[Parameter(Mandatory=$true)]
$TenantId,
[Parameter(Mandatory=$true)]
$ClientId,
[Parameter(Mandatory=$true)]
$RedirectUri,
[Parameter(Mandatory=$true)]
$ResourceAppIdURI,
[Parameter(Mandatory=$true)]
$Authority,
[Parameter(Mandatory=$false)]
$StoredTokenByteArray,
[Parameter(Mandatory=$false)]
$ReturnTokenByteArray
)
Write-Host "Looking for AzureAD module..."
$AadModule = Get-Module -Name "AzureAD" -ListAvailable
if ($AadModule -eq $null)
{
Write-Host "AzureAD PowerShell not found, look for AzureADPreview"
$AadModule = Get-Module -Name "AzureADPreview" -ListAvailable
}
if ($AadModule -eq $null)
{
throw "AzureAD Powershell module not installed..."
}
# Getting path to ActiveDirectory Assemblies
# If the module count is greater than 1 find the latest version
if ($AadModule.count -gt 1)
{
$Latest_Version = ($AadModule | select version | Sort-Object)[-1]
$aadModule = $AadModule | ? { $_.version -eq $Latest_Version.version }
# Checking if there are multiple versions of the same module found
if($AadModule.count -gt 1)
{
$aadModule = $AadModule | select -Unique
}
$adal = Join-Path $AadModule.ModuleBase "Microsoft.IdentityModel.Clients.ActiveDirectory.dll"
$adalforms = Join-Path $AadModule.ModuleBase "Microsoft.IdentityModel.Clients.ActiveDirectory.Platform.dll"
}
else
{
$adal = Join-Path $AadModule.ModuleBase "Microsoft.IdentityModel.Clients.ActiveDirectory.dll"
$adalforms = Join-Path $AadModule.ModuleBase "Microsoft.IdentityModel.Clients.ActiveDirectory.Platform.dll"
}
[System.Reflection.Assembly]::LoadFrom($adal) | Out-Null
[System.Reflection.Assembly]::LoadFrom($adalforms) | Out-Null
try
{
$authContext = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext" -ArgumentList $authority
# https://msdn.microsoft.com/en-us/library/azure/microsoft.identitymodel.clients.activedirectory.promptbehavior.aspx
# Change the prompt behaviour to force credentials each time: Auto, Always, Never, RefreshSession
$platformParameters = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.PlatformParameters" -ArgumentList "Auto"
$userId = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.UserIdentifier" -ArgumentList ($User, "OptionalDisplayableId")
if ($storedTokenByteArray -ne $null)
{
$authContext.TokenCache.Deserialize($storedTokenByteArray)
}
$authResult = $authContext.AcquireTokenAsync($resourceAppIdURI,$clientId,$redirectUri,$platformParameters,$userId).Result
if($authResult.AccessToken)
{
if ($ReturnTokenByteArray)
{
$blobAuth = $authContext.TokenCache.Serialize();
return $blobAuth
}
else
{
return $authResult
}
}
else
{
Write-Host
Write-Host "Authorization Access Token is null, please re-run authentication..." -ForegroundColor Red
Write-Host
break
}
}
catch
{
write-host $_.Exception.Message -f Red
write-host $_.Exception.ItemName -f Red
write-host
break
}
}
And the below function authenticates once (prompting you) and then writes the stored token byte array out to a file:
$clientId = "7716031e-6f8b-45a4-b82b-922b1af0fbb4" #S4B
$redirectUri = "https://adminau1.online.lync.com/OcsPowershellOAuth"
$resourceAppIdURI = "https://adminau1.online.lync.com/OcsPowershellOAuth"
$authority = "https://login.microsoftonline.com/common"
$user = $SessionInfo.Account.Id
#get S4B auth token in to Byte Array
$byteArrayToken = Get-MSAuthToken -User $user -TenantId $tenantId -ClientId $clientId -RedirectUri $redirectUri -ResourceAppIdURI $resourceAppIdURI -Authority $authority -ReturnTokenByteArray $true
#store byte array
$byteArrayToken | Out-File C:\bytes.txt
And this method reads the byte array back in, serializes it and then uses it to authenticate.
$byteArrayToken = Get-Content D:\bytes.txt
$user = "mysuer@tenant.onmicrosoft.com"
$clientId = "7716031e-6f8b-45a4-b82b-922b1af0fbb4" #S4B
$redirectUri = "https://adminau1.online.lync.com/OcsPowershellOAuth"
$resourceAppIdURI = "https://adminau1.online.lync.com/OcsPowershellOAuth"
$authority = "https://login.microsoftonline.com/common"
$s4bAuth = Get-MSAuthToken -User $user -TenantId $tenantId -ClientId $clientId -RedirectUri $redirectUri -ResourceAppIdURI $resourceAppIdURI -Authority $authority -StoredTokenByteArray $byteArrayToken
$secureToken = ConvertTo-SecureString $s4bAuth.AccessToken -AsPlainText -Force
New-CsOnlineSession -OAuthAccessToken $secureToken
There may be another step in this – getting the right Lync Online URL for your S4B tenant. This can be obtained from the LyncDiscover process and I believe can be obtained through doing an HTTP Get on the LyncDiscover URL for your tenant.
ie: http://yourtenant.lyncdiscover.onmicrosoft.com.
I haven’t got to this LyncDiscover bit yet.. may need to create a function that does this to get the correct admin URL…