AWS Lambda and PowerShell

Recently, AWS announced that its serverless computing service, Lambda, now supports PowerShell 6 (aka PowerShell Core). As regular readers of this blog know, I have a long history of using PowerShell with AWS. Some of the most popular posts on this blog — and posts on which (according to my stats) people spend the most time — are examples of how to use AWS with PowerShell. In this post, I wanted to expand on the AWS Lambda doc for PowerShell with an example of my own, along with some screenshots of how it works.

There’s a lot to cover, so let’s dive in. Before I do, I want to emphasize that 100% of the example was done on macOS. The combination of Visual Studio Code, PowerShell Core and the AWS cmdlets for PowerShell Core is an unbeatable combination for DevOps productivity. I’ve been a fan of the AWS PowerShell cmdlets since the beta for two reasons. First, they are truly cross-system and, second, PowerShell is a language that was designed to fix the issues with more cryptic and less consistent scripting languages like bash.

This example expands on one of the templates you can create with New-AWSPowerShellLambdaTemplate by adding a simple Publish-SNSMessage to notify users via SMS and email that an S3 multipart upload has completed. The message content contains the name of the file and the size, converted to megabytes. While this is still a very simple example (and what it does could be done using other AWS services), it goes beyond the AWS doc by using a second AWS service when the Lambda PowerShell function is invoked. AFAIK, none of the templates do more than write to the CloudWatch log.

Here are some important considerations.

  • Make sure your Mac (or PC) is set up as described in the AWS doc. I also urge you to install Visual Studio Code and the vscode PowerShell extension. This combination of tools is free and elegant.
  • You will need an IAM role to assign permissions to the Lambda PowerShell function. Publish-AWSPowerShellLambda will offer to create one on the first deployment. This is very convenient but may not be as secure as you’d like or need. Just revise the automatically created IAM role.
  • I don’t detail below how to set up AWS SNS topics and subscriptions. You will need to make sure the Lambda PowerShell function has the ability to access SNS. Then all you need is the SNS ARN of the topic you wish to publish to.

Very important: When you run a Lambda PowerShell function, an input variable of type PSObject named $LambdaInput contains values that are specific to the type of event that triggered execution. AFAIK, there’s no documentation of what the possible object values are.

[Update: @socketnorm, who from his tweets appears to be one of the devs on PowerShell for Lambda, tweeted me with a helpful way to locate the values that will be in the $LambdaInput variable when you use a specific trigger.]

This means you need to tie the function to an event, run it and capture the output to CloudWatch so you can inspect the values you will be receiving. This can be easily done by uncommenting this line in the template script:

Write-Host (ConvertTo-Json -InputObject $LambdaInput -Compress -Depth 5)

Write-Host (and other output streams) automatically go to CloudWatch logs. This is very convenient for debugging and other internal monitoring of the function. If I had a nickel for every online environment that just throws console output into the bit bucket…

Here are the results of the function, a screenshot walkthrough of some of the things you should look for, along with the code that produced the output.

As mentioned above, this function publishes a custom message to an SNS topic that has been subscribed to both an SMS user and an email account when a multipart upload to an S3 bucket completes. Here’s what that output looks like as both an email and SMS text message.

PowerShell Lambda function output as SNS messages
PowerShell Lambda function output as SNS messages (click to enlarge)

This screenshot shows some important settings for the function once deployed. Pay special attention to the trigger that you select to invoke the function. The trigger you select will determine the values in the $LambdaInput PSObject variable. You will need to determine these values and then parse them in your Lambda PowerShell function.

Lambda PowerShell Function Settings
Lambda PowerShell Function Settings (click to enlarge)

And here is a screenshot showing the source code side-by-side with the output from the “dummy” execution. This is where you can find the contents of the PSObjects that are passed to the Lambda PowerShell function in $LambdaInput.

Lambda PowerShell Function Input Variables
Mapping Lambda PowerShell input variables (click to enlarge)

Once again, I think this last point is the most important lesson I learned while experimenting with Lambda PowerShell functions. You need to run a “dummy” invocation of the function and send the output to CloudWatch logs so that you can find out what input you get for which trigger.

Finally, here’s the code that produced this output. I hope this helps you exploit the power of AWS Lambda now that it (elegantly) supports cross-system PowerShell Core.

<#
    .SYNOPSIS
        A simple PowerShell Script that runs as an AWS Lambda PowerShell function.
    
    .DESCRIPTION
        Triggered by completion of an S3 multipart file upload, this function published to an SNS topic the name, bucket and size in megabytes of the uploaded file.
    
    .NOTES
        Alex Neihaus 2018-09-13
        (c) 2018 Air11 Technology LLC -- licensed under the Apache OpenSource 2.0 license, https://opensource.org/licenses/Apache-2.0
        Licensed under the Apache License, Version 2.0 (the "License");
        you may not use this file except in compliance with the License.
        You may obtain a copy of the License at
        http://www.apache.org/licenses/LICENSE-2.0
        
        Unless required by applicable law or agreed to in writing, software
        distributed under the License is distributed on an "AS IS" BASIS,
        WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
        See the License for the specific language governing permissions and
        limitations under the License.
        
        Author's blog: https://www.yobyot.com
#>

# When executing in Lambda the following variables will be predefined.
#   $LambdaInput - A PSObject that contains the Lambda function input data.
#   $LambdaContext - An Amazon.Lambda.Core.ILambdaContext object that contains information about the currently running Lambda environment.

# To include PowerShell modules with your Lambda function, like the AWSPowerShell.NetCore module, add a "#Requires" statement
# indicating the module and version.

#Requires -Modules @{ModuleName='AWSPowerShell.NetCore';ModuleVersion='3.3.343.0'}

# Uncomment to send the input event to CloudWatch Logs
# Recommend you ALWAYS do this as there's no other way to understand the PSObject that's available to the PowerShell script executing in Lambda
Write-Host (ConvertTo-Json -InputObject $LambdaInput -Compress -Depth 5)

foreach ($record in $LambdaInput.Records) {
    $bucket = $record.s3.bucket.name # Name of the bucket containing multi-part upload 
    $MpFileName = $record.s3.object.key # Name of multi-part file upload
    $MpFileSize = ($record.s3.object.size/1MB).ToString(".00") # Size of multi-part file uploaded by this event; use pwsh string formatting to convert to megabytes
    Write-Host "Processing event for: bucket = $bucket, key = $MpFileName" # Write MP file info to CloudWatch log

    $SNSMessage = "Backup file $MpFileName, size $MpFileSize MB written to bucket $bucket"
    Publish-SNSMessage -TopicArn arn:aws:sns:us-east-1:111111111111:YourSNSTopic -Subject "YourSubject" -Message $SNSMessage
}

 


Posted

in

, ,

by

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *