Performing admin activities with single token
Opened this issue · 5 comments
I'm sure I'm just missing something, but I've written a script to grab all users and pull their mailbox rules. The rule works fine against my account, but when I try to run against other mailboxes it tells me I don't have an access token.
I have the app registered, granted app permissions, created a self-signed cert, updated the manifest and used the cert and cert pw to connect to my mailbox.
Here's part of my script so you can see what I'm trying to do:
Connect-EXRMailbox -MailboxName 'mymailbox@domain.com' -certificateFileName C:\temp\cert.pfx -clientId xxxx-xxxx-xxxx-xxxx -certificateFilePassword $password -ResourceURL graph.microsoft.com
#get enabled users
$users = get-exrusers -filter 'userType eq ''member'' and accountEnabled eq true'
$forwardAbuseRules = @()
#loop through users
foreach ($user in $users){
#get mailbox rules
$mbxRules = Get-EXRInboxRule -MailboxName $user.userPrincipalName
#loop through rules and add to RuleObj if "forwardTo" is a property of actions
foreach ($rule in $mbxRules){
If ($rule.actions | get-member forwardTo){
$RuleObj = [PSCustomObject]@{
UserName = $user.displayName
UserUPN = $user.userPrincipalName
RuleName = $rule.displayName
RuleID = $rule.id
RuleEnabled = $rule.isEnabled
RuleAction = 'forwardTo'
RuleConditions = $rule.conditions
ForwardAddress = $rule.actions.forwardTo.emailAddress.address
Domain = $rule.actions.forwardTo.emailAddress.address.split("@")[1]
}
$forwardAbuseRules += $ruleObj
$ruleObj = $null
}```
Here's what I get when I try to run against other mailboxes:
```Get-EXRAccessToken : No Access Token for user@domain.com
At line:49 char:20
+ ... $AccessToken = Get-EXRAccessToken -MailboxName $MailboxName
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException
+ FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Get-EXRAccessToken
Get-EndPoint : Cannot bind argument to parameter 'AccessToken' because it is null.
At line:57 char:48
+ $EndPoint = Get-EndPoint -AccessToken $AccessToken -Segment ...
+ ~~~~~~~~~~~~
+ CategoryInfo : InvalidData: (:) [Get-EndPoint], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Get-EndPoint
App Token has expired
At line:124 char:25
+ throw "App Token has expired"
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : OperationStopped: (App Token has expired:String) [], RuntimeException
+ FullyQualifiedErrorId : App Token has expired```
Figured out that I needed to use Get-ERAppOnlyToken to make the requests. Now I can't get my token to refresh when it expires. I put logic in my loop to check the expires_on property of the token and to get a new token if it's less than the current epoch time.
How are others handling token refreshes for long running scripts? I have 60k mailboxes to work with.
I only have about 30 mailboxes I'm dealing with at any given time, but I grab a new token for each mailbox. My script only run for about 15 minutes per mailbox (at most).
In my case, adding even 1 second to each loop iteration would add about 16 hours to my run time. Hopefully there is a more elegant solution.
Do you run the script in a single thread then? Have you tried multiple jobs running in parallel to reduce the overall runtime?
Sorry I've been on holidays and just catching up. Yes you need your own code to manage the certificate expiry for App only certs. Checking the epoch after each mailbox is this easy solution it shouldn't be that costly in terms of time unless your making external calls to work out the epoch's. A background task https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/start-job?view=powershell-6 would be the best approach but complex to handle and code well.
The other thing that may help speed wise is that this code is still using the beta endpoint so if you open the file (Get-EXRInboxRule in Exch-Rest\functions\mailrules) and modify line 53 from
$EndPoint = Get-EndPoint -AccessToken $AccessToken -Segment "users" -beta
to
$EndPoint = Get-EndPoint -AccessToken $AccessToken -Segment "users"
You should get better performance