Issue
I have an ASG cfn template with a user data script inside it:
<powershell>
cfn-init.exe -v --stack ${STACK} --resource LaunchTemplate --region ${REGION}
# Set the environment variables for all users
[System.Environment]::SetEnvironmentVariable("SERVICE_ENV", "${SERVICE_ENV}", [System.EnvironmentVariableTarget]::Machine)
[System.Environment]::SetEnvironmentVariable("SERVICE_REGION", "${SERVICE_REGION}", [System.EnvironmentVariableTarget]::Machine)
[System.Environment]::SetEnvironmentVariable("SERVICE", "${SERVICE_NAME}", [System.EnvironmentVariableTarget]::Machine)
[System.Environment]::SetEnvironmentVariable("BRANCH", "${BRANCH}", [System.EnvironmentVariableTarget]::Machine)
[System.Environment]::SetEnvironmentVariable("ARTIFACT", "${ARTIFACT}", [System.EnvironmentVariableTarget]::Machine)
[System.Environment]::SetEnvironmentVariable("ARTIFACTORY_USERNAME", "${ARTIFACTORY_USERNAME}", [System.EnvironmentVariableTarget]::Machine)
[System.Environment]::SetEnvironmentVariable("ARTIFACTORY_PASSWORD", "${ARTIFACTORY_PASSWORD}", [System.EnvironmentVariableTarget]::Machine)
# Refresh the environment variables for the current session
$Env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User")
#The service will only start in the appropriate account and environment
aws s3 cp s3://bucket/scripts/Deployment.ps1 .
Start-Sleep -s 60
& .\Deployment.ps1
cfn-signal.exe -e 0 --stack ${STACK} --resource AutoScaling --region ${REGION}
</powershell>
Basically it sets some environment variables and then tries to execute the Deployment.ps1 script, which looks like this:
$ErrorActionPreference = "Stop"
# Defining URL
$SERVICE = $env:SERVICE
$BRANCH = $env:BRANCH
$ARTIFACT = $env:ARTIFACT
$JFROGURL= "https://tr1.jfrog.io/artifactory/generic-local/CTT/app/app/" + $BRANCH + "/app." + $ARTIFACT + ".zip"
Write-Host "SERVICE: $SERVICE"
Write-Host "BRANCH: $BRANCH"
Write-Host "ARTIFACT: $ARTIFACT"
Write-Host "jfrog URL: $JFROGURL"
# Verify if the service already exist
$existingService = Get-Service -Name $SERVICE -ErrorAction SilentlyContinue
if ($existingService) {
Write-Host "Restarting service $SERVICE..."
Restart-Service -Name $SERVICE
break
}
# Download artifact
$ARTIFACTORY_USERNAME= $env:ARTIFACTORY_USERNAME
$ARTIFACTORY_PASSWORD= $env:ARTIFACTORY_PASSWORD
Invoke-WebRequest -Uri $JFROGURL -OutFile "${SERVICE}.zip" -Headers @{ Authorization = "Basic "+ [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes("${ARTIFACTORY_USERNAME}:${ARTIFACTORY_PASSWORD}")) }
# unZIP the file
Expand-Archive .\$SERVICE.zip -DestinationPath C:\projects\$SERVICE\ -Force
# Copying config files to System32 folder
Copy-Item -Path "C:\projects\$SERVICE\Config\log4Net.config" -Destination C:\Windows\System32\Config\
Copy-Item -Path "C:\projects\$SERVICE\appsettings.json" -Destination C:\Windows\System32\
# # Create windows service
New-Service -name "${SERVICE}" -binaryPathName C:\projects\$SERVICE\app.exe -displayName $SERVICE -startupType Automatic
start-service "${SERVICE}"
Remove-Item -Path .\${SERVICE}.zip -Recurse -Force -Confirm:$false
Write-Host "Done."
The issue is that the second scripts fails on the bootstrap and after searching the logs I found that the script is taking the environment variables as null values. The curious part is if I run the script manually after the instance creation it works well (also I checked and the env variables are there). Any ideas why the second script is not reading the env variables? I tried to pass the variables as arguments like:
aws s3 cp s3://bucket/scripts/Deployment.ps1 .
& .\Deployment.ps1 -SERVICE ${SERVICE_NAME} -BRANCH ${BRANCH} -ARTIFACT ${ARTIFACT} -ARTIFACTORY_USERNAME ${ARTIFACTORY_USERNAME} -ARTIFACTORY_PASSWORD ${ARTIFACTORY_PASSWORD}
but I had not luck neither.
Solution
Given that you scoped the variables to machine
, to get the value of the environment variable in Deployment.ps1
you would have to use:
[Environment]::GetEnvironmentVariables('machine').SERVICE_ENV
...
Note that this is not needed in your case, you could simply do:
$env:SERVICE_ENV="$SERVICE_ENV"
...
& .\Deployment.ps1
and in Deployment.ps1
:
[Environment]::GetEnvironmentVariable('test')
That said, when you want to call a Powershell script from another, you should not use environment variables. You should use parameters.
So in the caller script:
& .\Deployment.ps1 "$SERVICE_ENV" ...
and in Deployment.ps1
:
param(
[parameter(Position=0,Mandatory=$true)][string] $SERVICE_ENV
)
...
Answered By - Paolo Answer Checked By - Mary Flores (WPSolving Volunteer)