azure-functions-powershell-worker icon indicating copy to clipboard operation
azure-functions-powershell-worker copied to clipboard

PowerShell global variable not retrieved correctly

Open yihchuang opened this issue 2 years ago • 3 comments

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:

  1. What has been changed in PowerShell 7 kernel in function app?
  2. Is it required to declare global variables with 'global' keyword?

yihchuang avatar Aug 17 '22 00:08 yihchuang

@Ved2806 any updates on this?

yihchuang avatar Sep 07 '22 23:09 yihchuang

Hi @Francisco-Gamino Could you please help with this issue?

Ved2806 avatar Oct 04 '22 13:10 Ved2806

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.

Francisco-Gamino avatar Oct 19 '22 20:10 Francisco-Gamino

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?

yihchuang avatar Oct 20 '22 18:10 yihchuang

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 ".." }.

Francisco-Gamino avatar Oct 20 '22 20:10 Francisco-Gamino

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 avatar Oct 20 '22 22:10 yihchuang

@yihchuang -- Sounds good, thank you. I will follow up with you via the support ticket. Closing issue.

Francisco-Gamino avatar Oct 27 '22 19:10 Francisco-Gamino