Lambda Powershell Layer

Sean Mckeon
3 min readJul 12, 2021

Running Powershell with NodeJS and Lambda

Background

I’m a NodeJS developer who was asked to write Powershell. I had zero experience writing Powershell prior to this project. I took a NodeJS developer approach to the problem. I had a lot of reusable code already written in NodeJS … things like a REST API, Security, Lambda, Secrets … and I didn’t really want to figure out all that “stuff” again if I didn’t need to. I discovered node-powershell which provided a way to call Powershell scripts from NodeJS. Great! However, I found some issues once I started running it against any sort of load. It would hang randomly, which turned out to be a known issue (https://github.com/rannn505/node-powershell/issues/94). That led me to a wonderful alternative called full-powershell.

Powershell Layer

AWS provides “Powershell” but that doesn’t include the Microsoft powershell libraries I needed. I added the “Powershell” executables using layers. This allowed me to run node-powershell and full-powershell from AWS Lambda. In my case I was using NodeJS, but the same approach could be used to add the Powershell executables to other runtimes (like Python).

Why would you do this?

Well … good question. You might be able to use the Powershell runtime managed by AWS. If that’s the case then you should do that. I tried that first. In our case we were trying to connect to Outlook and that requires a library called WSMan. As it turns out this library is broken in MacOS and Linux — see this post for more about that fun issue. But good news there is a “patch” called PSWSMan that you can download which “overwrites” your local copy of WSMan with a working version. So, I overwrote WSMan locally and then turned it into a layer that my lambda functions reference. Essentialy, my Node Lambdas have Powershell + the PSWSMan patch.

How to build a custom powershell layer

In summary:

  1. Run lambda Docker locally.
  2. Install Powershell plus whatever custom stuff you need (in my case PSWSMan)
  3. Copy everything from your Docker folder: /opt/microsoft/powershell/7
  4. Paste to your layer project: /layer/bin
  5. Deploy your layer.
  6. Deploy your lambda (referencing the layer).

Run the Lambda Docker image locally

I followed these instructions for setting up a docker container locally: https://docs.aws.amazon.com/lambda/latest/dg/images-test.html

I picked Node 12.x because that’s what we’ve been using in our existing project.

First, I downloaded powershell-7.1.3-1.rhel.7.x86_64.rpm from the powershell releases page. You might not need to do this, but my network would not install it otherwise for some reason. Proxy issues.

Next, I downloaded PSWSMan, which is a fix for the broken WSMan Powershell library in MacOS / Linux. I found through testing that the .so files under lib/glibc-1.0 work on Amazon Linux 2 (what Lambda uses).

Download PSWSMan 2.2.0 from the Powershell gallery (manual download). Change the file extension from .nupkg to .zip and you’ll be able to extract it. The files you need for Amazon Linux 2 are under lib/glibc-1.0.

Then create your Dockerfile in the same folder as the .rpm file you just downloaded.

Dockerfile:

FROM public.ecr.aws/lambda/nodejs:12# my lambda code (typescript)
COPY .npmrc tsconfig.json package.json powershell-7.1.3-1.rhel.7.x86_64.rpm /var/task/
COPY src/*.ts /var/task/src/
RUN npm install
RUN npm run build
# install powershell (I downloaded the rpm file locally)
RUN yum -y install powershell-7.1.3-1.rhel.7.x86_64.rpm
# copy the libmi.* files from PSWSMan glibc-1.0 (overwriting what came with powershell)
COPY libmi.* /opt/microsoft/powershell/7/
# This just points to my lambda handler
CMD [ "build/app.handler" ]

Copy all the stuff in the /opt/microsoft/powershell/7 folder on the docker image to the layer/bin folder in your layer project.

The CDK takes the files from the layer folder:

const layer = new LayerVersion(this, 'lambda-powershell-layer', { layerVersionName: 'lambda-powershell-layer', code: new AssetCode('layer'), compatibleRuntimes: [Runtime.NODEJS_12_X], description: 'A layer that contains Powershell + libmi.so which fixes WSMan on Linux. AWS Powershell runtime does not work with WSMan', });

These files get unpacked to the /opt/bin folder and Lambda can run pwsh!

--

--

Sean Mckeon
0 Followers

Software Engineer with 15+ years of industry experience.