windowspowershellamazon-ec2windows-server-2022ec2-userdata

Running UserData with Powershell >= 7.0 on Windows Server 2022 on EC2


UserData by default will run with Powershell V5.1 on the Windows Server 2022 AMI on an AWS EC2 instance that spins up. However, I want to use some cmdlets that are only supported in Powershell version 7 and greater.

How am I best able to run a script with Powershell 7+ when booting the instance with UserData?

I currently have a script that installs powershell 7, but then from that point I am not sure how to use v7 to run the rest of the commands that I have.

Invoke-WebRequest -Uri https://github.com/PowerShell/PowerShell/releases/download/v7.3.1/PowerShell-7.3.1-win-x64.msi -OutFile PowerShell.msi
Start-Process msiexec.exe -ArgumentList '/i PowerShell.msi /quiet' -Wait

I am using the WINDOWS_SERVER_2022_ENGLISH_FULL_BASE AMI.

I have tried using something like Invoke-Expression, and also have tried to get the script to call itself recursively with some conditionals, e.g.

# First Run with ps 5.1
if ($PSVersionTable.PSVersion -lt [Version]"7.0") {
    Invoke-WebRequest -Uri https://github.com/PowerShell/PowerShell/releases/download/v7.3.1/PowerShell-7.3.1-win-x64.msi -OutFile PowerShell.msi
    Start-Process msiexec.exe -ArgumentList '/i PowerShell.msi /quiet' -Wait
    cd "C:\Program Files\PowerShell\7"
    # Run this same script with ps7
    ./pwsh $PSCommandPath
    exit
}

# 
if ($PSVersionTable.PSVersion -gt [Version]"7.0") {
    # Do the things I need to do with ps7...
}

Both of my attempts have been silently failing, and with ec2 userdata it is very hard to get info on why.


Solution

  • The approach that ended up working was to have 2 different scripts. The first script installs PS7, and then downloads the second script from S3 and executes it using PS7.

    User Data exectued with PS5:

    #init.ps1
    <powershell>
    Invoke-WebRequest -Uri https://github.com/PowerShell/PowerShell/releases/download/v7.3.1/PowerShell-7.3.1-win-x64.msi -OutFile PowerShell.msi
    Start-Process msiexec.exe -ArgumentList '/i PowerShell.msi /quiet' -Wait
    cd "C:\Program Files\PowerShell\7"
    mkdir (Split-Path -Path 'C:/temp/setupGateway.ps1' ) -ea 0
    Read-S3Object -BucketName 'my-bucket' -key 'setupGateway.ps1' -file 'C:/temp/setupGateway.ps1' -ErrorAction Stop
    & "C:\Program Files\PowerShell\7\pwsh" "C:\temp\setupGateway.ps1"
    </powershell>
    <persist>true</persist>
    

    PS7 script, executed separately:

    # setup.ps1
    Write-Output $PSVersionTable
    Write-Output "Hello from PS7"
    

    All that needs to happen to make this work is to make sure that you copy the setup.ps1 script to an S3 location. Which can be achieved in lots of different ways depending on the rest of your setup.