'Powershell Azure Function Fails

First and foremost I'm new to Azure Functions and have only been working with it for a couple of weeks, so please bear with me. I was tasked with taking one of our Powershell script that gets users and licenses from our Office 365 Tenants, output them to CSV and then email them to a monitored email box, and porting it over to an Azure Function.

After a lot of work I've managed to get it to work using a call to Powershell.exe from within my script, due to the fact that some objects are returned "Un-serialized", preventing them from being iterated. (Known Issue on GitHub)

Everything was working via Test + Code and I set the time trigger to run at 12:00am, however when I checked my inbox the following day I had no emails. When I checked monitoring on function, I had the following listed for each of the Tenants that was iterated, which would seems to be something failing with the call to Powershell.exe:

HResult : -2146233087 CategoryInfo : OperationStopped: (:) [], CryptographicException FullyQualifiedErrorId : System.Security.Cryptography.CryptographicException InvocationInfo : ScriptLineNumber : 77 OffsetInLine : 5 HistoryId : -1 ScriptName : C:\home\site\wwwroot\License_Report_a-f\run.ps1 Line : $ScriptResult = (&$64bitPowerShellPath -WindowStyle Hidden -NonInteractive -Command $Script -Args $ApplicationId,$credential,$refreshToken,$tenantID,$client.TenantID) PositionMessage : At C:\home\site\wwwroot\License_Report_a-f\run.ps1:77 char:5 + $ScriptResult = (&$64bitPowerShellPath -WindowStyle Hidden -NonIn … +

PSScriptRoot : C:\home\site\wwwroot\License_Report_a-f PSCommandPath : C:\home\site\wwwroot\License_Report_a-f\run.ps1 CommandOrigin : Internal ScriptStackTrace : at , C:\home\site\wwwroot\License_Report_a-f\run.ps1: line 77

I did some investigation on this and found someone elude that there were occasions where the Function can't read "Profile.ps1", which is where I'd but the declaration of the Powershell.exe env variable, so as a test I moved the assignment locally within the script. I then set an hourly schedule on the TimeTrigger and it was running fine on the hour. However, changing the TimeTrigger back to only run at 12:00am, I was greeted with no emails again this morning and the same error, seemingly ruling out the "Profile.ps1" issue.

My frustration at the moment is that the function works fine in Code + Test, but it seems like if the the function is idle for an extended period of time, when it spins up again it can't load something properly. I had successful running on the hour yesterday at 10:00, 11:00, 12:00, 13:00, 14:00 and 15:00. It was then left with no spin ups for 9 hours and then it failed. This morning, I have updated the TimeTrigger again to run every hour to see what happens and now once again, I'm getting the emails coming through to me, so I'm baffled. Again, I've made a change and almost "woke the machine up" and now everything works fine again.

Has anyone seen this before or anything similar as I'm not sure where to look next. Is there maybe some sort of cache that get's cleared if you don't run a function for x minutes / x hours which is causing the issue? I've had a couple of hours looking on the net, but I can't see anything similar. Any help / points are gratefully appreciated.



Solution 1:[1]

So it seems like I may have found the issue myself, however it doesn't really explain what exactly is going on, but it seems to be related to Generating the "Graph Access Tokens" to access Office 365 itself.

After some playing around last week, I got to a point where I was no longer able to run the script without the above error, even in "Test + Run" on the Azure Functions interface. I decided to do some testing on the script that was ran by the External PowerShell call and when I removed the code that was generating the "Graph Access Tokens", the script executed successfully. I then re-structured the whole code so that I would generate the tokens before calling the External PS script, and then pass in the access tokens instead.

After testing over the weekend, I can confirm that I've correctly generated and sent the export files via email so it looks to be all working fine now. Below is a rough outlay of the start of the script, just to showcase what I've ended up with.

# Import Modules
Import-Module MsOnline -UseWindowsPowershell
Import-Module PartnerCenter -UseWindowsPowershell
# Get Tokens
$aadGraphToken = New-PartnerAccessToken -ApplicationId $ApplicationId -Credential $credential -RefreshToken $refreshToken -Scopes 'https://graph.windows.net/.default' -ServicePrincipal -Tenant $tenantID
$graphToken = New-PartnerAccessToken -ApplicationId $ApplicationId -Credential $credential -RefreshToken $refreshToken -Scopes 'https://graph.microsoft.com/.default' -ServicePrincipal -Tenant $tenantID
#Connect to Msol
Connect-MsolService -AdGraphAccessToken $aadGraphToken.AccessToken -MsGraphAccessToken $graphToken.AccessToken
# Get Client List
$clientList = Get-MsolPartnerContract -All | Sort-Object -Property Name
# Loop Clients
ForEach ($client in $clientList)
{
    $Script = {
        param (
            [Object]$aadGraphTkn,
            [Object]$graphTkn,
            [string]$clientTenantID
        )        
        # Import Modules
        Import-Module MsOnline
        Import-Module PartnerCenter
        #Connect to Msol
        Connect-MsolService -AdGraphAccessToken $aadGraphTkn.AccessToken -MsGraphAccessToken $graphTkn.AccessToken
        
        # DO OTHER THINGS HERE AND RETURN SOMETHING
    }
    $ScriptResult = (&$env:64bitPowerShellPath -WindowStyle Hidden -NonInteractive -Command $Script -Args $aadGraphToken,$graphTkn)
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Nick Scotney