azure-functions-powershell-worker
azure-functions-powershell-worker copied to clipboard
PowerShell global variable not retrieved correctly
Variables are defined at the beginning of the PowerShell script; without the “global” keyword Assuming these variables are in global scope.
$accessTokenTest = ""`
$accessToken = ""`
Here is a function to renew the SQL access token and persist it to a JSON file.
In Get-SQLToken function, global variables were saved differently, with and without "global" keyword.
This was the workaround for the issue:
$Global:accessToken = $tokenResponse.access_token
function Get-SQLToken {
WriteToLog -message "Token Start..."
try {
$resourceURI = "https://database.windows.net/"
$tokenAuthURI = $env:MSI_ENDPOINT + "?resource=$resourceURI&api-version=2017-09-01"
$tokenResponse = Invoke-RestMethod -Method Get -Headers @{"Secret" = "$env:MSI_SECRET" } -Uri $tokenAuthURI
WriteToLog -message "Create new SQLSetting file"
$tokenResponse | ConvertTo-Json | Out-File SQLSettings.json
$Global:accessToken = $tokenResponse.access_token
$accessTokenTest = $tokenResponse.access_token
if ($null -eq $accessTokenTest || [string]::IsNullOrEmpty($accessTokenTest)) {
WriteToLog -message "[DBG] Failed to save access token value to a global variable. accessTokenTest is $($accessTokenTest)"
}
else {
WriteToLog -message "[DBG] Successfully save access token value to a global variable accessTokenTest. accessTokenTest is $($accessTokenTest)"
}
}
catch [System.Exception] {
WriteToLog -message "Error occured $($_.Exception.Message)" -Exception $_
$tokenResponse = ""
}
WriteToLog -message "Token end"
}
We retrieve the value of the global variables later on.
However, the variable $accessTokenTest was not retrieved correctly
$SQLSettings = Get-Content SQLSettings.json | ConvertFrom-Json
if ([datetime]$SQLSettings.expires_on -gt ((Get-Date).AddHours(23))) { # DBG AddMinutes(30)
$accessToken = $SQLSettings.access_token
WriteToLog -message "Token from SQLSettings"
}
else {
WriteToLog -message "Old Token need a new Token... create new SQLSettings"
Get-SQLToken
if ($null -eq $accessTokenTest || '' -eq $accessTokenTest || [string]::IsNullOrEmpty($accessTokenTest)) {
WriteToLog -message "[DBG] Failed to retrieve token value from a global variable. accessTokenTest is $($accessTokenTest)"
}
else {
WriteToLog -message "[DBG] Successfully retrieved token value from a global variable accessTokenTest. accessTokenTest is $($accessTokenTest)"
}
$accessToken = $Global:accessToken
}
In order to work around the hurdle, we applied the work around which seems redundant.
Save the value to the global variable $accessToken with global keyword
$Global:accessToken = $tokenResponse.access_token
Retrieve the value of the global variable $accessToken with global keyword
$accessToken = $Global:accessToken
From the logs,
2022-08-06T23:42:54.398 [Information] INFORMATION: [DBG] Successfully save access token value to a global variable accessTokenTest. accessTokenTest is<
no value got retrieved, or no printable value got retrieved
2022-08-06T23:42:54.399 [Information] INFORMATION: [DBG] Successfully retrieved token value from a global variable accessTokenTest. accessTokenTest is<
We have been running this script without work around since August 2021 under PowerShell 7 kernel until the issue started surfacing in early March this year. We would like to learn:
- What has been changed in PowerShell 7 kernel in function app?
- Is it required to declare global variables with 'global' keyword?
@Ved2806 any updates on this?
Hi @Francisco-Gamino Could you please help with this issue?
Hello @Ved2806 -- The global variable is available within the same PowerShell session. Functions invocations might or might not use the same PowerShell session, depending on your hosting plan, concurrency settings and workload. As a result, one instance of this variable initialized by one function invocation might not be visible to the next function invocation. If you need to share data between function invocation, you should consider using external storage.
Hi @Francisco-Gamino, thank you for the reply.
In our case, the same global variable is used within the same PowerShell session.
Also, this issue started showing up in last June, were there any changes in PowerShell 7.x or Function App by that time?
Hello @yihchuang -- Could you please open a support ticket so we can take a closer look? To do so, please follow this instructions: https://docs.microsoft.com/en-us/azure/azure-portal/supportability/how-to-create-azure-support-request. Please include your function code, the time stamp for when you observed this behavior as well as your function logs.
Lastly, I took a look at the code you shared, and I have a follow-up question:
$SQLSettings = Get-Content SQLSettings.json | ConvertFrom-Json
if ([datetime]$SQLSettings.expires_on -gt ((Get-Date).AddHours(23))) { # DBG AddMinutes(30)
$accessToken = $SQLSettings.access_token
WriteToLog -message "Token from SQLSettings"
}
else {
WriteToLog -message "Old Token need a new Token... create new SQLSettings"
Get-SQLToken
if ($null -eq $accessTokenTest || '' -eq $accessTokenTest || [string]::IsNullOrEmpty($accessTokenTest)) {
WriteToLog -message "[DBG] Failed to retrieve token value from a global variable. accessTokenTest is $($accessTokenTest)"
}
else {
WriteToLog -message "[DBG] Successfully retrieved token value from a global variable accessTokenTest. accessTokenTest is $($accessTokenTest)"
}
$accessToken = $Global:accessToken
}
What are you trying to accomplish with this branch?
if ($null -eq $accessTokenTest || '' -eq $accessTokenTest || [string]::IsNullOrEmpty($accessTokenTest)) {
Is the goal to validate against null or empty? With the current logic, you can only detect when $accessTokenTest
is $null
; however, it does not detect empty or white space. I would replace this line with
if ([string]::IsNullOrWhiteSpace($accessTokenTest)) { Write-Host ".." }
.
Hi @Francisco-Gamino,
Thank you for the reply, I will create a support ticket and provide the info as requested.
For those lines of code that you pointed out, were added just for providing the Support additional info. Not in the production code.
@yihchuang -- Sounds good, thank you. I will follow up with you via the support ticket. Closing issue.