Jekyll2018-09-13T13:24:20+00:00http://overpoweredshell.com//OverPoweredShell.comBy David ChristianAWS PowerShell - Intro to PowerShell Lambdas, Creating An Automatic Shutdown Policy for EC2 Instances2018-09-13T00:00:00+00:002018-09-13T00:00:00+00:00http://overpoweredshell.com//AWS%20PowerShell%20-%20Intro%20to%20PowerShell%20Lambdas%20Creating%20An%20Automatic%20Shutdown%20Policy%20for%20EC2%20Instances<p>AWS has finally released support for PowerShell lambdas!
Lambdas are pieces of code that can be called from just about anywhere in AWS (or outside for that matter).
Even better lambdas don’t require a server to run, this means that you only pay for the compute that you actually use.
Don’t worry the first 1M hits per month are free.
Let’s dive in and see how we can start using our existing PowerShell skills to start building lambdas.</p>
<p><strong>The Good Stuff:</strong>
Start writing <a href="https://aws.amazon.com/lambda/">AWS Lambdas</a> in PowerShell.</p>
<!-- more -->
<!-- TOC -->
<ul>
<li><a href="#automatic-shutdown-for-ec2-instances">Automatic Shutdown for EC2 Instances</a></li>
<li><a href="#installing-the-aws-powershell-lambda-module">Installing the AWS PowerShell Lambda Module</a></li>
<li><a href="#lambda-templates">Lambda Templates</a></li>
<li><a href="#creating-a-powershell-lambda">Creating A PowerShell Lambda</a>
<ul>
<li><a href="#powershell-lambda-inputs">PowerShell Lambda Inputs</a></li>
<li><a href="#ec2-shutdown-code">EC2 Shutdown Code</a></li>
</ul>
</li>
<li><a href="#publishing-a-powershell-lambda">Publishing A PowerShell Lambda</a></li>
<li><a href="#testing-the-lambda">Testing the Lambda</a></li>
<li><a href="#granting-the-lambda-permission-to-ec2">Granting The Lambda Permission To EC2</a>
<ul>
<li><a href="#testing-with-the-right-permissions">Testing with the right permissions</a></li>
</ul>
</li>
<li><a href="#scheduling-a-lambda">Scheduling a Lambda</a></li>
<li><a href="#wrapping-up">Wrapping Up</a></li>
</ul>
<!-- /TOC -->
<h1 id="automatic-shutdown-for-ec2-instances">Automatic Shutdown for EC2 Instances</h1>
<p>One cool thing about Azure is their machine auto-shutdown policy.
More than once I’ve been bitten by accidentally leaving my test machines on in AWS.
In fact, my bill for August was a <em>little</em> higher than I was expecting.
Once I saw that AWS is supporting PowerShell lambdas, I knew that the auto-shutdown policy was something I wanted to implement.
Let’s go step by step and set one up.</p>
<h1 id="installing-the-aws-powershell-lambda-module">Installing the AWS PowerShell Lambda Module</h1>
<p>There’s a couple of prerequisites needed before we can start to create PowerShell lambdas.
The first is the <a href="https://www.microsoft.com/net/download">Dotnet core 2.1 SDK</a>.
The AWS team is actually cheating a little bit here.
What they did was find a way to wrap PowerShell core in a dot net project.
This means that our PowerShell script actually gets compiled (more on that in the publishing section).
Since they are wrapping our script, we also need their <code class="highlighter-rouge">AWSLambdaPSCore</code> module.
This install is a little easier since they put it up on the PowerShell gallery.</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Install-Module AWSLambdaPSCore -Force -Verbose
</code></pre></div></div>
<h1 id="lambda-templates">Lambda Templates</h1>
<p>After we have the required software we can start creating our own lambdas.
One of the commands in the <code class="highlighter-rouge">AWSLambdaPSCore</code> module is <code class="highlighter-rouge">Get-AWSPowerShellLambdaTemplate</code>.
This command will list all the pre-canned templates that we can leverage for different AWS products.</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Get-AWSPowerShellLambdaTemplate
</code></pre></div></div>
<p>output:</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Template Description
-------- -----------
Basic Bare bones script
CodeCommitTrigger Script to <span class="k">process </span>AWS CodeCommit Triggers
DetectLabels Use Amazon Rekognition service to tag image files <span class="k">in </span>S3 with detected labels.
KinesisStreamProcessor Script to be <span class="k">process </span>a Kinesis Stream
S3Event Script to <span class="k">process </span>S3 events
SNSSubscription Script to be subscribed to an SNS Topic
SQSQueueProcessor Script to be subscribed to an SQS Queue
</code></pre></div></div>
<h1 id="creating-a-powershell-lambda">Creating A PowerShell Lambda</h1>
<p>Since this is a learning experience, I wanted to start with the basic template.
Below is the command that I ran to create a new script called <code class="highlighter-rouge">ShutDownEC2</code> in my <code class="highlighter-rouge">C:\AWS</code> directory.</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>New-AWSPowerShellLambda -Template Basic -ScriptName ShutDownEC2 -Directory C:\aws\
</code></pre></div></div>
<p>This created the below file.
Notice that it comes with a ton of boiler plate, and a little bit of instructions.</p>
<p><img src="/images/aws/newlambda.png" alt="_config.yml" /></p>
<h2 id="powershell-lambda-inputs">PowerShell Lambda Inputs</h2>
<p>Reading the help file, we can see that we get a couple of variables for free.
The first is a variable called <code class="highlighter-rouge">$LambdaInput</code>.
Any JSON posted to our Lambda will be converted into an object and saved in this variable.
It’s automatically there and will be available to our code.</p>
<h2 id="ec2-shutdown-code">EC2 Shutdown Code</h2>
<p>I wanted my lambda to be flexible.
So if you pass a valid instanceID, we’ll shut down just that specific instance.
If not, I want to shut down all of my instances.
The idea here being I can schedule the second use case to run every night and clean up after me.
Here’s what my final PowerShell lambda ended up looking like.</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">#Requires -Modules @{ModuleName='AWSPowerShell.NetCore';ModuleVersion='3.3.313.0'}</span>
<span class="k">if</span> <span class="o">(</span><span class="nv">$null</span> -ne <span class="nv">$LambdaInput</span>.InstanceID<span class="o">)</span>
<span class="o">{</span>
<span class="nv">$instances</span> <span class="o">=</span> Get-EC2Instance -InstanceId <span class="nv">$LambdaInput</span>.InstanceID |
<span class="nb">Select-Object</span> -ExpandProperty Instances
<span class="o">}</span>
<span class="k">else</span>
<span class="o">{</span>
<span class="c1">#No Specific Instance passed, so let's stop all of them</span>
<span class="nv">$instances</span> <span class="o">=</span> Get-EC2Instance |
<span class="nb">Select-Object</span> -ExpandProperty Instances
<span class="o">}</span>
<span class="k">foreach</span> <span class="o">(</span><span class="nv">$instance</span> <span class="k">in</span> <span class="nv">$instances</span><span class="o">)</span>
<span class="o">{</span>
<span class="k">if</span> <span class="o">(</span><span class="nv">$instance</span>.State.Name.Value -ne <span class="s1">'stopped'</span><span class="o">)</span>
<span class="o">{</span>
<span class="nb">Write-Host</span> <span class="s2">"Stopping instance id [</span><span class="k">$(</span><span class="nv">$instance</span>.InstanceId<span class="k">)</span><span class="s2">]"</span>
Stop-EC2instance -InstanceId <span class="nv">$instance</span>.InstanceId
<span class="o">}</span>
<span class="k">else</span>
<span class="o">{</span>
<span class="nb">Write-Host</span> <span class="s2">"instance id [</span><span class="k">$(</span><span class="nv">$instance</span>.InstanceId<span class="k">)</span><span class="s2">] already stopped"</span>
<span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>
<p>One little thing, that I like to point out is that the <code class="highlighter-rouge">Write-Output</code> command does not seem to work inside the context of a lambda.
However, <code class="highlighter-rouge">Write-Host</code> and <code class="highlighter-rouge">Write-Verbose</code> (or any <code class="highlighter-rouge">-Verbose</code> switch) will properly display output.</p>
<h1 id="publishing-a-powershell-lambda">Publishing A PowerShell Lambda</h1>
<p>Now that we have our lambda written it’s time to publish it to AWS.
Remember how I said that they are compiling our script?
This means that there is no way to create a PowerShell lambda through the UI.
Don’t believe me, here’s the current list of options in the AWS console.</p>
<p><img src="/images/aws/exsitingLam.png" alt="_config.yml" /></p>
<p>Luckily, the <code class="highlighter-rouge">AWSLambdaPSCore</code> has a function to do the compilation and publish.
Below is the command line I used for <code class="highlighter-rouge">Publish-AWSPowerShellLambda</code> to upload my new lambda.
Notice that lambdas are region specific.</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Publish-AWSPowerShellLambda -Name ShutDownEC2 -ScriptPath C:\aws\ShutDownEC2.ps1 -Region us-west-2
</code></pre></div></div>
<p>Here’s part of the output where we can see the actual compilation happening.
This runs every time we publish.</p>
<p><img src="/images/aws/compileLambda.png" alt="_config.yml" /></p>
<p>Also, the first time that you publish a lambda, it will ask you to create a role to use for running the lambda.
I created one called <code class="highlighter-rouge">overpowershelledLambda</code>.
I also granted him full lambda access.</p>
<p><img src="/images/aws/iamlambda.png" alt="_config.yml" /></p>
<p>After a few seconds that will complete and if we head to our console, we’ll see our new lambda.
Again notice, how the project is technically a dot net core 2.1 app.</p>
<p><img src="/images/aws/lambdaConsole.png" alt="_config.yml" /></p>
<h1 id="testing-the-lambda">Testing the Lambda</h1>
<p>Now that we have our lambda created, we will want to start testing.
Before we can do that we need to create tests events.
Click the drop-down in the upper right-hand corner to open the pop-up.</p>
<p><img src="/images/aws/testevents.png" alt="_config.yml" /></p>
<p>The first test event I want to create is an empty one to simulate our scheduled run.
For the body, I’m just going to use <code class="highlighter-rouge">{}</code>.</p>
<p><img src="/images/aws/testempty.png" alt="_config.yml" /></p>
<p>The next test event is to handle use cases where we pass a specific instance.
Below is an example I created using one of my existing EC2 machines.
If you want to follow along, make sure you update your body to match something in your environment.</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">{</span>
<span class="s2">"InstanceID"</span>: <span class="s2">"i-03a5ed219d178f53c"</span>
<span class="o">}</span>
</code></pre></div></div>
<p>Here’s what the full event looks like:</p>
<p><img src="/images/aws/testID.png" alt="_config.yml" /></p>
<p>With all of that in place, there’s nothing left to do but click the test button.</p>
<p><img src="/images/aws/permissionError.png" alt="_config.yml" /></p>
<p>Wait an error?!?!
What happened?
Well, it says that we don’t have permission to perform this action.
After scratching my head for a little while it hit me.
The default lambda role doesn’t grant any write permissions to EC2!</p>
<h1 id="granting-the-lambda-permission-to-ec2">Granting The Lambda Permission To EC2</h1>
<p>What we need to do is update the role we created as part of the wizard to grant it permission to take actions on EC2.
To do this head over to IAM -> Roles.
Once your there select the role that you created.</p>
<p><img src="/images/aws/lambdaroledefault.png" alt="_config.yml" /></p>
<p>From here click on attach policies.
From the filter, we can select which additional policy I want to attach to my role.
To make things easy, I’m going to grant my lambda full control to EC2 (please don’t do this in production).
When we’re done the <code class="highlighter-rouge">overpoweredshelllambda</code> role looks like this.</p>
<p><img src="/images/aws/lambdafull.png" alt="_config.yml" /></p>
<h2 id="testing-with-the-right-permissions">Testing with the right permissions</h2>
<p>Now that we have all the right access in place, let’s re-run our test.
First I want to see if I can stop a specific instance.
To do this, I’ll run my instance specific test.</p>
<p><img src="/images/aws/lambdainstancetestresults.png" alt="_config.yml" /></p>
<p>Great that worked!
Now let’s see what happens when I run the empty test.
If all goes well, we should see it stop all my instances.</p>
<p><img src="/images/aws/lambdatestresultsall.png" alt="_config.yml" /></p>
<p>That one works too.
With our lambda working, the last thing to do is set up a schedule to have this run every night.</p>
<h1 id="scheduling-a-lambda">Scheduling a Lambda</h1>
<p>To schedule the lambda, we need to add a Cloud Watch event trigger.
From the designer on the right select Cloud Watch event.
Once that is added, click on configure.
For our example, I want this to run every day.
To do this I’ll use the below cron pattern.</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cron<span class="o">(</span>0 4 <span class="k">*</span> <span class="k">*</span> ? <span class="k">*</span><span class="o">)</span>
</code></pre></div></div>
<p>What’s a little weird, is that the schedule is in UTC.
Also if your a little rusty on cron syntax, be sure to check out <a href="https://docs.aws.amazon.com/AmazonCloudWatch/latest/events/ScheduledEvents.html">this page</a> for a great reference.
Here’s what my final Cloud Watch event rule looked like:</p>
<p><img src="/images/aws/cloudwatchTrigger.png" alt="_config.yml" /></p>
<h1 id="wrapping-up">Wrapping Up</h1>
<p>That’s all for today.
I can’t stress how huge being able to leverage PowerShell from a lambda is.
This is a game changer for sure.
Got some cool lambda use cases?
Please be sure to share them below.
I’m excited to see what our amazing community comes up with.</p>
<p>For more articles about PowerShell and AWS please check out:</p>
<ul>
<li><a href="https://overpoweredshell.com//AWS-PowerShell-Setting-up-AWS-Tools-on-PowerShell-Core/">Setting up AWS Tools on PowerShell Core</a></li>
<li><a href="https://overpoweredshell.com//AWS-PowerShell-Finding-the-Right-EC2-Image/">Finding the Right EC2 Image</a></li>
<li><a href="https://overpoweredshell.com//AWS-PowerShell-Creating-Ec2-Instances-and-Basic-Machine-Management/">Creating Ec2 Instances and Basic Machine Management</a></li>
<li><a href="https://overpoweredshell.com//AWS-PowerShell-EC2-Key-Pairs,-Credentials-and-Connecting/">EC2 Key Pairs, Credentials and Connecting</a></li>
<li><a href="https://overpoweredshell.com//AWS-PowerShell-EC2-Tags-and-Filtering/">EC2 Tags and Filtering</a></li>
<li><a href="https://overpoweredshell.com//AWS-PowerShell-Intro-to-PowerShell-Lambdas-Creating-An-Automatic-Shutdown-Policy-for-EC2-Instances/">Intro to PowerShell Lambdas, Creating An Automatic Shutdown Policy for EC2 Instances</a></li>
</ul>AWS has finally released support for PowerShell lambdas! Lambdas are pieces of code that can be called from just about anywhere in AWS (or outside for that matter). Even better lambdas don’t require a server to run, this means that you only pay for the compute that you actually use. Don’t worry the first 1M hits per month are free. Let’s dive in and see how we can start using our existing PowerShell skills to start building lambdas. The Good Stuff: Start writing AWS Lambdas in PowerShell.AWS PowerShell - EC2 Tags and Filtering2018-08-28T00:00:00+00:002018-08-28T00:00:00+00:00http://overpoweredshell.com//AWS%20PowerShell%20-%20EC2%20Tags%20and%20Filtering<p>One of the biggest shifts in moving to the cloud is getting used to the fact that servers don’t matter.
You have a workload, you build a couple of instances and it runs.
If there’s an issue you’re not going to troubleshoot a server.
Tear it down and spin up a new one.
With all these servers coming and going, it’s important to be able to keep everything organized.
One way AWS solves this is through the use of instance tags.
Let’s dive in and learn to work with them in PowerShell.</p>
<p><strong>The Good Stuff:</strong>
Start leveraging tags to organize your AWS instances!</p>
<!-- more -->
<!-- TOC -->
<ul>
<li><a href="#creating-tags">Creating Tags</a>
<ul>
<li><a href="#amazonec2modeltag">Amazon.EC2.Model.Tag</a></li>
<li><a href="#a-better-tag-creation-function">A Better Tag Creation Function</a></li>
</ul>
</li>
<li><a href="#searching-for-tags">Searching for Tags</a>
<ul>
<li><a href="#the-built-in-filters">The Built-in Filters</a></li>
<li><a href="#a-better-filter-function">A Better Filter Function</a></li>
</ul>
</li>
<li><a href="#wrapping-up">Wrapping Up</a></li>
</ul>
<!-- /TOC -->
<h1 id="creating-tags">Creating Tags</h1>
<p>So it’s important to remember that a tag is a label.
You give your tag a name and a value.
Some common examples would be a tag for an environment or for an application that an instance is running.</p>
<h2 id="amazonec2modeltag">Amazon.EC2.Model.Tag</h2>
<p>To create a tag we need instantiate a new <code class="highlighter-rouge">Amazon.EC2.Model.Tag</code> object.
Here’s an example of creating a tag for the Dev environment.</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">[</span>Amazon.EC2.Model.Tag]::new<span class="o">(</span><span class="s2">"Environment"</span>,<span class="s2">"Dev"</span><span class="o">)</span>
</code></pre></div></div>
<p>Now that we know how to create tags, we can start assigning them to instances.
Here’s a sample script to create a new instance and assign it our Dev tag.</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$instance</span> <span class="o">=</span> Get-EC2ImageByName -Name WINDOWS_2016_CONTAINER |
New-EC2Instance -InstanceType t2.micro
<span class="nv">$tag</span> <span class="o">=</span> <span class="o">[</span>Amazon.EC2.Model.Tag]::new<span class="o">(</span><span class="s2">"Environment"</span>,<span class="s2">"Dev"</span><span class="o">)</span>
New-EC2Tag -Tag <span class="nv">$tag</span> -Resource <span class="nv">$instance</span>.Instances.Instanceid
</code></pre></div></div>
<h2 id="a-better-tag-creation-function">A Better Tag Creation Function</h2>
<p>This works, but it seems clunky to me.
For starters, we should be able to pipe from the output of <code class="highlighter-rouge">New-EC2Instance</code> right into the tag function.
Plus why do I need to create their special hashtable object?
It would be nice if we could pass a hashtable instead and let the tag function do the heavy lifting.
To make creating tags a little more user friendly, I created the below function.</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">Function </span><span class="nb">Set</span>-EC2Tag
<span class="o">{</span>
<span class="o">[</span><span class="na">CmdletBinding</span><span class="o">(</span><span class="na">DefaultParameterSetName</span> <span class="o">=</span> <span class="s1">'EC2Instance'</span><span class="o">)]</span>
<span class="k">Param</span><span class="o">(</span>
<span class="o">[</span>Parameter<span class="o">(</span>
ValueFromPipeline,
ValueFromPipelineByPropertyName,
ParameterSetName <span class="o">=</span> <span class="s1">'InstanceID'</span><span class="o">)]</span>
<span class="o">[</span><span class="kt">String</span><span class="o">[]]</span>
<span class="nv">$InstanceId</span>,
<span class="o">[</span>Parameter<span class="o">(</span>
ValueFromPipeline,
ValueFromPipelineByPropertyName,
ParameterSetName <span class="o">=</span> <span class="s1">'EC2Instance'</span><span class="o">)]</span>
<span class="o">[</span>PSCustomObject]
<span class="nv">$InputObject</span>,
<span class="o">[</span>Parameter<span class="o">(</span>
Mandatory,
ValueFromPipeline,
ValueFromPipelineByPropertyName<span class="o">)]</span>
<span class="o">[</span>Hashtable]
<span class="nv">$Tags</span>
<span class="o">)</span>
<span class="k">Process</span>
<span class="o">{</span>
<span class="k">if</span> <span class="o">(</span><span class="nv">$null</span> -ne <span class="nv">$InputObject</span>.Instances.InstanceID<span class="o">)</span>
<span class="o">{</span>
<span class="nv">$InstanceId</span> <span class="o">=</span> <span class="nv">$InputObject</span>.Instances.InstanceID
<span class="o">}</span>
<span class="k">if</span> <span class="o">(</span><span class="nv">$null</span> -ne <span class="nv">$InputObject</span>.InstanceID<span class="o">)</span>
<span class="o">{</span>
<span class="nv">$InstanceId</span> <span class="o">=</span> <span class="nv">$InputObject</span>.InstanceID
<span class="o">}</span>
<span class="nv">$ec2Tags</span> <span class="o">=</span> <span class="k">foreach</span><span class="o">(</span><span class="nv">$key</span> <span class="k">in</span> <span class="nv">$Tags</span>.Keys<span class="o">)</span>
<span class="o">{</span>
<span class="o">[</span>Amazon.EC2.Model.Tag]::new<span class="o">(</span><span class="nv">$key</span>,<span class="nv">$Tags</span><span class="o">[</span><span class="nv">$key</span><span class="o">])</span>
<span class="o">}</span>
<span class="k">foreach</span><span class="o">(</span><span class="nv">$insID</span> <span class="k">in</span> <span class="nv">$InstanceId</span><span class="o">)</span>
<span class="o">{</span>
New-EC2Tag -Resource <span class="nv">$insID</span> -Tag <span class="nv">$ec2Tags</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>
<p>With our new function in place, the pipeline feels much better.
Here’s what the new workflow looks like when we need to create a machine and assign it a couple of tags.</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$tags</span> <span class="o">=</span> @<span class="o">{</span>
<span class="s1">'Environment'</span> <span class="o">=</span> <span class="s2">"Dev"</span>
<span class="s1">'App'</span> <span class="o">=</span> <span class="s2">"WebSvc1"</span>
<span class="o">}</span>
Get-EC2ImageByName -Name WINDOWS_2016_CONTAINER |
New-EC2Instance -InstanceType t2.micro |
<span class="nb">Set</span>-EC2Tag -Tags <span class="nv">$tags</span>
</code></pre></div></div>
<h1 id="searching-for-tags">Searching for Tags</h1>
<p>The whole purpose of creating a tag is to be able to query for it later.
If we inspect an instance we can see what tags it has by diving into its details.</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$instance</span> <span class="o">=</span> <span class="o">(</span>Get-EC2Instance -InstanceId i-0546a9b32ab6be6d7<span class="o">)</span>
<span class="nv">$instance</span>.Instances.tags
</code></pre></div></div>
<p>Output:</p>
<p><img src="/images/aws/taggedInstance.png" alt="_config.yml" /></p>
<p>If you notice, that’s not terribly helpful since I already knew which instance I wanted.
A better solution is to search all instances by a tag filter.</p>
<h2 id="the-built-in-filters">The Built-in Filters</h2>
<p>The <code class="highlighter-rouge">Get-EC2instance</code> Cmdlet does take a filter.
Tags are key-value pairs, so let’s try to pass a hashtable to them.</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$searchFor</span> <span class="o">=</span> @<span class="o">{</span>
<span class="s1">'Environment'</span> <span class="o">=</span> <span class="s2">"Dev"</span>
<span class="o">}</span>
Get-EC2Instance -Filter <span class="nv">$searchFor</span>
</code></pre></div></div>
<p>Output:</p>
<p><img src="/images/aws/hastableFail.png" alt="_config.yml" /></p>
<p>Ok, so that was a bust…
Time to check the documentation.
I’ll save you the trouble of searching the AWS site.
It turns out that a filter needs a specific format.
The filter parameter takes an array of hashtables, even if there is going to be one value to filter on.
Moreover, these hashtables require specific keys.
One named <code class="highlighter-rouge">name</code> (all lower case) for the name of the filter value.
We also need another key named <code class="highlighter-rouge">values</code> (again case sensitive) to match against.
Another caveat is that if we are filtering on tags, we need to prefix them with <code class="highlighter-rouge">tag:</code>.
Here’s what that original filter would look like.</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$searchFor</span> <span class="o">=</span>@<span class="o">(</span>
@<span class="o">{</span>
name <span class="o">=</span> <span class="s1">'tag:Environment'</span>
values <span class="o">=</span> <span class="s2">"Dev"</span>
<span class="o">}</span>
<span class="o">)</span>
Get-EC2Instance -Filter <span class="nv">$searchFor</span>
</code></pre></div></div>
<p>Output:</p>
<p><img src="/images/aws/tagHit.png" alt="_config.yml" /></p>
<p>Now we’re getting somewhere!</p>
<h2 id="a-better-filter-function">A Better Filter Function</h2>
<p>I still don’t like that fact that I need to craft that special hashtable by hand.
Plus, what if we wanted to filter on multiple tags?
To make working with filters easier, I created the below function.</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">Function </span>ConvertTo-EC2Filter
<span class="o">{</span>
<span class="o">[</span><span class="na">CmdletBinding</span><span class="o">()]</span>
<span class="k">Param</span><span class="o">(</span>
<span class="o">[</span>Parameter<span class="o">(</span>
ValueFromPipeline,
ValueFromPipelineByPropertyName<span class="o">)]</span>
<span class="o">[</span>HashTable]
<span class="nv">$Filter</span>
<span class="o">)</span>
<span class="k">Begin</span>
<span class="o">{</span>
<span class="nv">$ec2Filter</span> <span class="o">=</span> @<span class="o">()</span>
<span class="o">}</span>
<span class="k">Process</span>
<span class="o">{</span>
<span class="nv">$ec2Filter</span> <span class="o">=</span> <span class="k">Foreach</span> <span class="o">(</span><span class="nv">$key</span> <span class="k">in</span> <span class="nv">$Filter</span>.Keys<span class="o">)</span>
<span class="o">{</span>
@<span class="o">{</span>
name <span class="o">=</span> <span class="nv">$key</span>
values <span class="o">=</span> <span class="nv">$Filter</span><span class="o">[</span><span class="nv">$key</span><span class="o">]</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="k">End</span>
<span class="o">{</span>
<span class="nv">$ec2Filter</span>
<span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>
<p>Since this new function handles the heavy lifting of creating the filter.
We can do some cool stuff like this:</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$searchFor</span> <span class="o">=</span> @<span class="o">{</span>
<span class="s1">'tag:Environment'</span> <span class="o">=</span> <span class="s2">"Dev"</span>
<span class="s1">'tag:App'</span> <span class="o">=</span> <span class="s2">"WebSvc1"</span>
<span class="o">}</span>
<span class="nv">$ec2Filter</span> <span class="o">=</span> ConvertTo-EC2Filter -Filter <span class="nv">$searchFor</span>
Get-EC2Instance -filter <span class="nv">$ec2Filter</span>
</code></pre></div></div>
<p>Output:</p>
<p><img src="/images/aws/multitaghit.png" alt="_config.yml" /></p>
<p>Remember there’s also way more things that we can filter on.
To see what I mean, try checking the help for <code class="highlighter-rouge">Get-EC2Instance</code>.</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Get-Help Get-EC2Instance -Parameter <span class="k">filter</span>
</code></pre></div></div>
<p>Output:</p>
<p><img src="/images/aws/fitlerhelp.png" alt="_config.yml" /></p>
<p>For example, let’s say we wanted all windows machines, that were launched with the OverPoweredShell key, in the us-west-2c availability zone, running the WebSVC2 application.</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$searchFor</span> <span class="o">=</span> @<span class="o">{</span>
<span class="s1">'platform'</span> <span class="o">=</span> <span class="s1">'windows'</span>
<span class="s1">'key-name'</span> <span class="o">=</span> <span class="s1">'OverPoweredShell'</span>
<span class="s1">'availability-zone'</span> <span class="o">=</span> <span class="s1">'us-west-2c'</span>
<span class="s1">'tag:App'</span> <span class="o">=</span> <span class="s2">"WebSvc2"</span>
<span class="o">}</span>
<span class="nv">$ec2Filter</span> <span class="o">=</span> ConvertTo-EC2Filter -Filter <span class="nv">$searchFor</span>
Get-EC2Instance -filter <span class="nv">$ec2Filter</span>
</code></pre></div></div>
<h1 id="wrapping-up">Wrapping Up</h1>
<p>That’s all for today.
Remember that tags are your friends.
I hope this new function helped and makes managing all the cattle a little easier.</p>
<p>For more articles about PowerShell and AWS please check out:</p>
<ul>
<li><a href="https://overpoweredshell.com//AWS-PowerShell-Setting-up-AWS-Tools-on-PowerShell-Core/">Setting up AWS Tools on PowerShell Core</a></li>
<li><a href="https://overpoweredshell.com//AWS-PowerShell-Finding-the-Right-EC2-Image/">Finding the Right EC2 Image</a></li>
<li><a href="https://overpoweredshell.com//AWS-PowerShell-Creating-Ec2-Instances-and-Basic-Machine-Management/">Creating Ec2 Instances and Basic Machine Management</a></li>
<li><a href="https://overpoweredshell.com//AWS-PowerShell-EC2-Key-Pairs,-Credentials-and-Connecting/">EC2 Key Pairs, Credentials and Connecting</a></li>
<li><a href="https://overpoweredshell.com//AWS-PowerShell-EC2-Tags-and-Filtering/">EC2 Tags and Filtering</a></li>
<li><a href="https://overpoweredshell.com//AWS-PowerShell-Intro-to-PowerShell-Lambdas-Creating-An-Automatic-Shutdown-Policy-for-EC2-Instances/">Intro to PowerShell Lambdas, Creating An Automatic Shutdown Policy for EC2 Instances</a></li>
</ul>One of the biggest shifts in moving to the cloud is getting used to the fact that servers don’t matter. You have a workload, you build a couple of instances and it runs. If there’s an issue you’re not going to troubleshoot a server. Tear it down and spin up a new one. With all these servers coming and going, it’s important to be able to keep everything organized. One way AWS solves this is through the use of instance tags. Let’s dive in and learn to work with them in PowerShell. The Good Stuff: Start leveraging tags to organize your AWS instances!AWS PowerShell - EC2 Key Pairs, Credentials and Connecting2018-08-07T00:00:00+00:002018-08-07T00:00:00+00:00http://overpoweredshell.com//AWS%20PowerShell%20-%20EC2%20Key%20Pairs,%20Credentials%20and%20Connecting<p>Now that we know how to provision machines, I want to dive deeper into KeyPairs and how we can connect.
When working with on perm machines, credentials are easy.
Traditionally all you have to pass is your domain credentials and go.
While you can extend active directory to the cloud (or use a hosted version), this is becoming less and less common.
Let’s dig in and see how we can use key pairs to create credentials and connect.</p>
<p><strong>The Good Stuff:</strong>
Helper functions that speed up PsSession and RDP Creation for Windows EC2 Instances.</p>
<!-- more -->
<h1 id="generating-key-pairs">Generating Key Pairs</h1>
<p>Creating a new key pair is actually trivial.
To set up a new key pair run <code class="highlighter-rouge">New-EC2KeyPair -KeyName myNewKeyPair</code>.
While this does create a key pair, all the relevant information is sent to the screen.
What we need is the private key saved to a file so we can use it.
The first thing you want to do is save the key to a variable.</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$keyPair</span> <span class="o">=</span> New-EC2KeyPair -KeyName OverPoweredShell
</code></pre></div></div>
<p>Your key pair should have 3 properties, <code class="highlighter-rouge">KeyName</code>, <code class="highlighter-rouge">KeyFingerprint</code>, and <code class="highlighter-rouge">KeyMaterial</code>.
The property that we need to save (and you need to keep safe) is the <code class="highlighter-rouge">KeyMaterial</code>.
This is your private key and what we’ll use to decrypt the passwords.</p>
<p><img src="/images/aws/keypair.png" alt="_config.yml" /></p>
<p>The last thing to do is save this private key so we can use it later.
The below command is what I use if I want to store my private key in the <code class="highlighter-rouge">C:\AWS</code> folder.</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">Set-Content</span> -Path <span class="s1">'C:\AWS\OverPoweredShell.pem'</span> -Value <span class="nv">$keyPair</span>.KeyMaterial -Force
</code></pre></div></div>
<h2 id="getting-passwords">Getting Passwords</h2>
<p>Now that we have a new key created, let’s provision a new EC2 instance using that key pair.
Below is the command I used to create a new Server 2016 image.
In this example, I pass the name to my key and a image size.</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Get-EC2ImageByName -Name WINDOWS_2016_BASE |
New-EC2Instance -KeyName OverPoweredShell -InstanceType t2.micro
</code></pre></div></div>
<p>After a couple of minutes, your new instance will be up and running.
To get the default administrator password, we can use the builtin <code class="highlighter-rouge">Get-EC2PasswordData</code> Cmdlet.
Here I pass it my instance ID and the location of my pem file.</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Get-EC2PasswordData -InstanceId i-05b5d0777c8445761 -PemFile C:\aws\OverPoweredShell.pem
</code></pre></div></div>
<p>Output:</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>V.ki.<span class="o">(</span>rW@a-ptJJ4K!gcGSGBd<span class="o">)</span>?DEr<span class="o">)</span><span class="nb">r</span>
</code></pre></div></div>
<h2 id="creating-pscredentials">Creating PSCredentials</h2>
<p>I like to point out that it’s a little lame that I can’t pipe from <code class="highlighter-rouge">Get-EC2Instance</code>, right into <code class="highlighter-rouge">Get-EC2PasswordData</code>.
I can work around it, but this command isn’t very friendly…</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Get-EC2Instance |
<span class="nb">Select-Object</span> -ExpandProperty Instances |
<span class="nb">Where</span>-Object KeyName -eq <span class="s1">'OverPoweredShell'</span> |
Get-EC2PasswordData -PemFile C:\aws\OverPoweredShell.pem
</code></pre></div></div>
<p>And since I’m complaining, I don’t like that I get back a string.
It would be much better if this came back as a <code class="highlighter-rouge">PSCredential</code>.
Here’s a simple function that I came up with to make creating the credentials easier.</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">Function </span>Get-EC2Credential
<span class="o">{</span>
<span class="o">[</span><span class="na">CmdletBinding</span><span class="o">(</span><span class="na">DefaultParameterSetName</span> <span class="o">=</span> <span class="s1">'EC2Instance'</span><span class="o">)]</span>
<span class="k">Param</span><span class="o">(</span>
<span class="o">[</span>Parameter<span class="o">(</span>
ValueFromPipeline,
ValueFromPipelineByPropertyName,
ParameterSetName <span class="o">=</span> <span class="s1">'InstanceID'</span><span class="o">)]</span>
<span class="o">[</span><span class="kt">String</span><span class="o">[]]</span>
<span class="nv">$InstanceId</span>,
<span class="o">[</span>Parameter<span class="o">(</span>
ValueFromPipeline,
ValueFromPipelineByPropertyName,
ParameterSetName <span class="o">=</span> <span class="s1">'EC2Instance'</span><span class="o">)]</span>
<span class="o">[</span>PSCustomObject]
<span class="nv">$InputObject</span>,
<span class="o">[</span>Parameter<span class="o">(</span>
Mandatory,
ValueFromPipeline,
ValueFromPipelineByPropertyName<span class="o">)]</span>
<span class="o">[</span>ValidateScript<span class="o">(</span>
<span class="o">{</span>
<span class="k">if</span> <span class="o">(</span>-not<span class="o">(</span><span class="nb">Test-Path</span> -Path <span class="nv">$PSItem</span><span class="o">))</span>
<span class="o">{</span>
<span class="k">throw</span> <span class="s2">"Unable to find PemFile at path [</span><span class="nv">$psitem</span><span class="s2">]"</span>
<span class="o">}</span>
<span class="k">else</span>
<span class="o">{</span>
<span class="nv">$true</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="o">)]</span>
<span class="o">[</span><span class="kt">string</span><span class="o">]</span>
<span class="nv">$PemFile</span>
<span class="o">)</span>
<span class="k">Process</span>
<span class="o">{</span>
<span class="k">if</span> <span class="o">(</span><span class="nv">$null</span> -ne <span class="nv">$InputObject</span>.Instances.InstanceID<span class="o">)</span>
<span class="o">{</span>
<span class="nv">$InstanceId</span> <span class="o">=</span> <span class="nv">$InputObject</span>.Instances.InstanceID
<span class="o">}</span>
<span class="k">if</span> <span class="o">(</span><span class="nv">$null</span> -ne <span class="nv">$InputObject</span>.InstanceID<span class="o">)</span>
<span class="o">{</span>
<span class="nv">$InstanceId</span> <span class="o">=</span> <span class="nv">$InputObject</span>.InstanceID
<span class="o">}</span>
<span class="k">foreach</span><span class="o">(</span><span class="nv">$insID</span> <span class="k">in</span> <span class="nv">$InstanceId</span><span class="o">)</span>
<span class="o">{</span>
<span class="nv">$securePassword</span> <span class="o">=</span> Get-EC2PasswordData -InstanceId <span class="nv">$insID</span> -PemFile <span class="nv">$PemFile</span> |
<span class="nb">ConvertTo-SecureString</span> -AsPlainText -Force
<span class="o">[</span>PSCredential]::new<span class="o">(</span><span class="s1">'administrator'</span>, <span class="nv">$securePassword</span><span class="o">)</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>
<p>Once you have the command loaded you can start doing cool things like the below pipeline.
This will return a PSCredential and the flow just feels more like traditional PowerShell.</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$cred</span> <span class="o">=</span> Get-EC2Instance -InstanceId i-05b5d0777c8445761 |
Get-EC2Credential -PemFile C:\aws\OverPoweredShell.pem
</code></pre></div></div>
<h1 id="connecting">Connecting</h1>
<h2 id="creating-pssession">Creating PsSession</h2>
<p>Now that we have a way to return our credential as an object, let’s see if we can take it up a notch.
This is a PowerShell blog, so we’ll make a PSSession using what the new cmdlet we just created.
Here’s a helper function that wraps the logic needed to create PSSessions.</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">Function </span>New-EC2PSSession
<span class="o">{</span>
<span class="o">[</span><span class="na">CmdletBinding</span><span class="o">(</span><span class="na">DefaultParameterSetName</span> <span class="o">=</span> <span class="s1">'EC2Instance'</span><span class="o">)]</span>
<span class="k">Param</span><span class="o">(</span>
<span class="o">[</span>Parameter<span class="o">(</span>
ValueFromPipeline,
ValueFromPipelineByPropertyName,
ParameterSetName <span class="o">=</span> <span class="s1">'InstanceID'</span><span class="o">)]</span>
<span class="o">[</span><span class="kt">String</span><span class="o">]</span>
<span class="nv">$InstanceId</span>,
<span class="o">[</span>Parameter<span class="o">(</span>
ValueFromPipeline,
ValueFromPipelineByPropertyName,
ParameterSetName <span class="o">=</span> <span class="s1">'EC2Instance'</span><span class="o">)]</span>
<span class="o">[</span>PSCustomObject]
<span class="nv">$InputObject</span>,
<span class="o">[</span>Parameter<span class="o">(</span>
Mandatory,
ValueFromPipeline,
ValueFromPipelineByPropertyName<span class="o">)]</span>
<span class="o">[</span>ValidateScript<span class="o">(</span>
<span class="o">{</span>
<span class="k">if</span> <span class="o">(</span>-not<span class="o">(</span><span class="nb">Test-Path</span> -Path <span class="nv">$PSItem</span><span class="o">))</span>
<span class="o">{</span>
<span class="k">throw</span> <span class="s2">"Unable to find PemFile at path [</span><span class="nv">$psitem</span><span class="s2">]"</span>
<span class="o">}</span>
<span class="k">else</span>
<span class="o">{</span>
<span class="nv">$true</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="o">)]</span>
<span class="o">[</span><span class="kt">string</span><span class="o">]</span>
<span class="nv">$PemFile</span>
<span class="o">)</span>
<span class="k">Process</span>
<span class="o">{</span>
<span class="k">if</span><span class="o">(![</span><span class="kt">string</span><span class="o">]</span>::IsNullOrEmpty<span class="o">(</span><span class="nv">$InstanceId</span><span class="o">))</span>
<span class="o">{</span>
<span class="nv">$InputObject</span> <span class="o">=</span> Get-EC2Instance -InstanceId <span class="nv">$InstanceId</span>
<span class="o">}</span>
<span class="k">foreach</span><span class="o">(</span><span class="nv">$instance</span> <span class="k">in</span> <span class="nv">$InputObject</span>.Instances<span class="o">)</span>
<span class="o">{</span>
<span class="k">if</span> <span class="o">(</span><span class="nv">$null</span> -eq <span class="nv">$instance</span><span class="o">)</span>
<span class="o">{</span>
<span class="nb">Write-Error</span> -Message <span class="s2">"Invalid EC2 Instance"</span>
<span class="o">}</span>
<span class="nv">$publicIP</span> <span class="o">=</span> <span class="nv">$instance</span>.PublicIpAddress
<span class="k">if</span><span class="o">([</span><span class="kt">String</span><span class="o">]</span>::IsNullOrEmpty<span class="o">(</span><span class="nv">$publicIP</span><span class="o">))</span>
<span class="o">{</span>
<span class="nb">Write-Error</span> -Message <span class="s2">"No public IP address for instance [</span><span class="k">$(</span><span class="nv">$instance</span>.InstanceId<span class="k">)</span><span class="s2">]"</span>
<span class="o">}</span>
<span class="nv">$cred</span> <span class="o">=</span> <span class="nv">$instance</span> |
Get-EC2Credential -PemFile <span class="nv">$PemFile</span>
New-PSSession -ComputerName <span class="nv">$publicIP</span> -Credential <span class="nv">$cred</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>
<p>With this new helper function in place, we’re getting somewhere.
Here’s the command I run to create a PSSession to all my machines at once!
From there <code class="highlighter-rouge">Invoke-Command</code> works like I expect.</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$sessions</span> <span class="o">=</span> Get-EC2Instance |
New-EC2PsSession -PemFile C:\aws\OverPoweredShell.pem
Invoke-Command -PSSession <span class="nv">$sessions</span> -Scriptblock <span class="o">{</span> Hostname<span class="o">}</span>
</code></pre></div></div>
<h2 id="wrapping-rdp-sessions">Wrapping RDP Sessions</h2>
<p>Another thing I wanted to do is make an easy way to connect to RDP.
I use Jaap Brasser’s <a href="https://gallery.technet.microsoft.com/scriptcenter/Connect-Mstsc-Open-RDP-2064b10b">Connect-Mstsc</a> pretty heavily at work.
Using my <code class="highlighter-rouge">Connect-EC2Mstsc</code> function, we can wrap the logic needed to find the public IP, generate a credential, then call Jaap’s function to connect.
Here’s what the function definition looks like.</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">Function </span>Connect-EC2Mstsc
<span class="o">{</span>
<span class="o">[</span><span class="na">CmdletBinding</span><span class="o">(</span><span class="na">DefaultParameterSetName</span> <span class="o">=</span> <span class="s1">'EC2Instance'</span><span class="o">)]</span>
<span class="k">Param</span><span class="o">(</span>
<span class="o">[</span>Parameter<span class="o">(</span>
ValueFromPipeline,
ValueFromPipelineByPropertyName,
ParameterSetName <span class="o">=</span> <span class="s1">'InstanceID'</span><span class="o">)]</span>
<span class="o">[</span><span class="kt">String</span><span class="o">]</span>
<span class="nv">$InstanceId</span>,
<span class="o">[</span>Parameter<span class="o">(</span>
ValueFromPipeline,
ValueFromPipelineByPropertyName,
ParameterSetName <span class="o">=</span> <span class="s1">'EC2Instance'</span><span class="o">)]</span>
<span class="o">[</span>PSCustomObject]
<span class="nv">$InputObject</span>,
<span class="o">[</span>Parameter<span class="o">(</span>
Mandatory,
ValueFromPipeline,
ValueFromPipelineByPropertyName<span class="o">)]</span>
<span class="o">[</span>ValidateScript<span class="o">(</span>
<span class="o">{</span>
<span class="k">if</span> <span class="o">(</span>-not<span class="o">(</span><span class="nb">Test-Path</span> -Path <span class="nv">$PSItem</span><span class="o">))</span>
<span class="o">{</span>
<span class="k">throw</span> <span class="s2">"Unable to find PemFile at path [</span><span class="nv">$psitem</span><span class="s2">]"</span>
<span class="o">}</span>
<span class="k">else</span>
<span class="o">{</span>
<span class="nv">$true</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="o">)]</span>
<span class="o">[</span><span class="kt">string</span><span class="o">]</span>
<span class="nv">$PemFile</span>
<span class="o">)</span>
<span class="k">Process</span>
<span class="o">{</span>
<span class="k">if</span><span class="o">(![</span><span class="kt">string</span><span class="o">]</span>::IsNullOrEmpty<span class="o">(</span><span class="nv">$InstanceId</span><span class="o">))</span>
<span class="o">{</span>
<span class="nv">$InputObject</span> <span class="o">=</span> Get-EC2Instance -InstanceId <span class="nv">$InstanceId</span>
<span class="o">}</span>
<span class="k">foreach</span><span class="o">(</span><span class="nv">$instance</span> <span class="k">in</span> <span class="nv">$InputObject</span>.Instances<span class="o">)</span>
<span class="o">{</span>
<span class="k">if</span> <span class="o">(</span><span class="nv">$null</span> -eq <span class="nv">$instance</span><span class="o">)</span>
<span class="o">{</span>
<span class="nb">Write-Error</span> -Message <span class="s2">"Invalid EC2 Instance"</span>
<span class="o">}</span>
<span class="nv">$publicIP</span> <span class="o">=</span> <span class="nv">$instance</span>.PublicIpAddress
<span class="k">if</span><span class="o">([</span><span class="kt">String</span><span class="o">]</span>::IsNullOrEmpty<span class="o">(</span><span class="nv">$publicIP</span><span class="o">))</span>
<span class="o">{</span>
<span class="nb">Write-Error</span> -Message <span class="s2">"No public IP address for instance [</span><span class="k">$(</span><span class="nv">$instance</span>.InstanceId<span class="k">)</span><span class="s2">]"</span>
<span class="o">}</span>
<span class="nv">$cred</span> <span class="o">=</span> <span class="nv">$instance</span> |
Get-EC2Credential -PemFile <span class="nv">$PemFile</span>
Connect-Mstsc -ComputerName <span class="nv">$publicIP</span> -Credential <span class="nv">$cred</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>
<p>With the function in place, connecting to the machines is pretty straightforward.
This below command will create an RDP session for each of my EC2 instances!</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Get-EC2Instance |
Connect-EC2Mstsc -PemFile C:\aws\OverPoweredShell.pem
</code></pre></div></div>
<p>That’s all for today.
I hope these functions make connecting and managing EC2 instances feel a little more like working with on perm machines.</p>
<p>For more articles about PowerShell and AWS please check out:</p>
<ul>
<li><a href="https://overpoweredshell.com//AWS-PowerShell-Setting-up-AWS-Tools-on-PowerShell-Core/">Setting up AWS Tools on PowerShell Core</a></li>
<li><a href="https://overpoweredshell.com//AWS-PowerShell-Finding-the-Right-EC2-Image/">Finding the Right EC2 Image</a></li>
<li><a href="https://overpoweredshell.com//AWS-PowerShell-Creating-Ec2-Instances-and-Basic-Machine-Management/">Creating Ec2 Instances and Basic Machine Management</a></li>
<li><a href="https://overpoweredshell.com//AWS-PowerShell-EC2-Key-Pairs,-Credentials-and-Connecting/">EC2 Key Pairs, Credentials and Connecting</a></li>
<li><a href="https://overpoweredshell.com//AWS-PowerShell-EC2-Tags-and-Filtering/">EC2 Tags and Filtering</a></li>
<li><a href="https://overpoweredshell.com//AWS-PowerShell-Intro-to-PowerShell-Lambdas-Creating-An-Automatic-Shutdown-Policy-for-EC2-Instances/">Intro to PowerShell Lambdas, Creating An Automatic Shutdown Policy for EC2 Instances</a></li>
</ul>Now that we know how to provision machines, I want to dive deeper into KeyPairs and how we can connect. When working with on perm machines, credentials are easy. Traditionally all you have to pass is your domain credentials and go. While you can extend active directory to the cloud (or use a hosted version), this is becoming less and less common. Let’s dig in and see how we can use key pairs to create credentials and connect. The Good Stuff: Helper functions that speed up PsSession and RDP Creation for Windows EC2 Instances.AWS PowerShell - Creating Ec2 Instances and Basic Machine Management2018-07-25T00:00:00+00:002018-07-25T00:00:00+00:00http://overpoweredshell.com//AWS%20PowerShell%20-%20Creating%20Ec2%20Instances%20and%20Basic%20Machine%20Management<p>The AWS Tools for PowerShell let you manage all your EC2 instances with cmdlets.
With full coverage for machine creation, deletion and updating, virtually all settings are configurable from the PowerShell console.
Let’s dive in and learn to create and manage EC2 Instances from PowerShell!</p>
<p><strong>The Good Stuff:</strong>
Check out the AWS Tools for Powershell and start managing EC2 from your shell today</p>
<!-- more -->
<!-- TOC -->
<ul>
<li><a href="#creating-ec2-instances">Creating EC2 Instances</a>
<ul>
<li><a href="#instance-size">Instance Size</a></li>
<li><a href="#choosing-a-key-pair">Choosing a key pair</a></li>
<li><a href="#passing-user-data">Passing User Data</a></li>
<li><a href="#choosing-security-groups">Choosing Security Groups</a></li>
<li><a href="#so-many-more-options">So Many More Options</a></li>
</ul>
</li>
<li><a href="#ec2-lifecycle">EC2 Lifecycle</a></li>
</ul>
<!-- /TOC -->
<h1 id="creating-ec2-instances">Creating EC2 Instances</h1>
<p>Creating an EC2 instance with all the defaults couldn’t be simpler.
If all you need is an instance you can pipe from one of the <code class="highlighter-rouge">Get-EC2Image</code> cmdlets to <code class="highlighter-rouge">New-EC2Instance</code>.
Here’s the command I could run to create a new Windows Server 2016 host, setup for docker.
Since I’m using <code class="highlighter-rouge">Get-EC2ImageByName</code> I know I’ll be getting the latest version for my region.</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Get-EC2ImageByName -Name WINDOWS_2016_CONTAINER |
New-EC2Instance
</code></pre></div></div>
<p>Ok, that was easy.
But EC2 wouldn’t be so popular unless we could customize our instances and tweak our settings.
Here are some of the most popular switches and settings that you will need to change.</p>
<h2 id="instance-size">Instance Size</h2>
<p>Instance type is definitely one of the first things you’ll want to tweak.
By default, if you don’t supply an instance, it will default to <code class="highlighter-rouge">m1.small</code>.
This can be a little pricey if we’re testing things out.
To change your instance size, use the <code class="highlighter-rouge">InstanceType</code> parameter.
Here’s an example setting the size to <code class="highlighter-rouge">t2.micro</code></p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Get-EC2ImageByName -Name WINDOWS_2016_CONTAINER |
New-EC2Instance -InstanceType t2.micro
</code></pre></div></div>
<p>I’m always too lazy to look up all the possible sizes.
This is one place PowerShell and the PSReadLine module really come in handy.
When working at the shell you can type <code class="highlighter-rouge">-InstanceType</code> and then press <code class="highlighter-rouge">ctrl</code> + <code class="highlighter-rouge">space</code>.
This will pop the autocomplete and show you a list of all available sizes.
Take a look at this to see it in action.</p>
<p><img src="/images/aws/ec2Instance.gif" alt="_config.yml" /></p>
<h2 id="choosing-a-key-pair">Choosing a key pair</h2>
<p>One of the neat things about AWS is its key pairs and the ability to generate admin passwords at machine creation.
If you’ve been following best practices and using multiple key pairs for different purposes, this is something you often need to pass at machine provisioning.
To select a different key pair, use the <code class="highlighter-rouge">KeyName</code> parameter.
Here’s what that would look like if I wanted to use a key pair named “dscKey”</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Get-EC2ImageByName -Name WINDOWS_2016_CONTAINER |
New-EC2Instance -InstanceType t2.micro -KeyName dscKey
</code></pre></div></div>
<h2 id="passing-user-data">Passing User Data</h2>
<p>User data is a way for you to pass instance-specific information into the machine.
In the past as part of a deployment workflow, I’ve used this to tag a machine with the information it would need to connect to a DSC pull server.
To use user data, pass your PowerShell script inside <code class="highlighter-rouge"><powershell></code> tags.
The instance also requires you to base64 encode the script.
To get around this, make sure you pass both the <code class="highlighter-rouge">UserData</code> parameter with the <code class="highlighter-rouge">EncodeUserData</code> switch.
Here’s a super simple example.</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$userData</span> <span class="o">=</span> @<span class="s1">'
<powershell>
$file = "C:\TestFile-$((Get-Date).ToString("MM-dd-yy-hh-mm")).txt"
Set-Content -Path $file -Value "Hi from OverPoweredShell!" -Force
</powershell>
'</span>@
Get-EC2ImageByName -Name WINDOWS_2016_CONTAINER |
New-EC2Instance -InstanceType t2.micro -UserData <span class="nv">$userData</span> -EncodeUserData
</code></pre></div></div>
<h2 id="choosing-security-groups">Choosing Security Groups</h2>
<p>There are two ways to assign a security group when creating an EC2 instance.
We could either use the <code class="highlighter-rouge">SecurityGroup</code> or <code class="highlighter-rouge">SecurityGroupId</code> parameters.
Let’s keep things simple and use the friendly group names in our example.
Here’s what it looks like assigning a new instance to both the “SoCalPoshDSCDemo” and “AdminAccess” group.</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Get-EC2ImageByName -Name WINDOWS_2016_CONTAINER |
New-EC2Instance -InstanceType t2.micro -SecurityGroup SoCalPoshDSCDemo,AdminAccess
</code></pre></div></div>
<h2 id="so-many-more-options">So Many More Options</h2>
<p>At the time of this writing, there are 61 different parameters you can pass to <code class="highlighter-rouge">New-EC2Instance</code>.
If you don’t believe me, run <code class="highlighter-rouge">(Get-Command New-EC2Instance).Parameters.Count</code>.
With so many parameters we could spend weeks diving into each one.
Chances are if you can set it in the AWS console, you can set in the command line.
Remember, <code class="highlighter-rouge">Get-Help New-EC2Instance</code> and the online AWS Tools documentation is your best friend.</p>
<h1 id="ec2-lifecycle">EC2 Lifecycle</h1>
<p>When it comes to general care and feeding of EC2 Instances, the AWS tools module has plenty of options.
If you want to generate this list yourself, run <code class="highlighter-rouge">Get-Command -Noun EC2Instance</code>.</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>CommandType Name Version Source
----------- ---- ------- ------
Cmdlet Get-EC2Instance 3.3.313.0 AWSPowerShell.NetCore
Cmdlet New-EC2Instance 3.3.313.0 AWSPowerShell.NetCore
Cmdlet Remove-EC2Instance 3.3.313.0 AWSPowerShell.NetCore
Cmdlet Restart-EC2Instance 3.3.313.0 AWSPowerShell.NetCore
Cmdlet <span class="nb">Start</span>-EC2Instance 3.3.313.0 AWSPowerShell.NetCore
Cmdlet Stop-EC2Instance 3.3.313.0 AWSPowerShell.NetCore
</code></pre></div></div>
<p>Since all of these use common verbs, it is trivial to tell what each command does.
If you’ve been following along in this article, you now have a bunch of machines sitting in your console.
Here’s a simple way (and very PowerShell way) to clean them all up.
Be careful as this will <strong>remove all</strong> your instances.</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Get-EC2Instance |
Remove-EC2Instance -Verbose -Force
</code></pre></div></div>
<p>For more articles about PowerShell and AWS please check out:</p>
<ul>
<li><a href="https://overpoweredshell.com//AWS-PowerShell-Setting-up-AWS-Tools-on-PowerShell-Core/">Setting up AWS Tools on PowerShell Core</a></li>
<li><a href="https://overpoweredshell.com//AWS-PowerShell-Finding-the-Right-EC2-Image/">Finding the Right EC2 Image</a></li>
<li><a href="https://overpoweredshell.com//AWS-PowerShell-Creating-Ec2-Instances-and-Basic-Machine-Management/">Creating Ec2 Instances and Basic Machine Management</a></li>
<li><a href="https://overpoweredshell.com//AWS-PowerShell-EC2-Key-Pairs,-Credentials-and-Connecting/">EC2 Key Pairs, Credentials and Connecting</a></li>
<li><a href="https://overpoweredshell.com//AWS-PowerShell-EC2-Tags-and-Filtering/">EC2 Tags and Filtering</a></li>
<li><a href="https://overpoweredshell.com//AWS-PowerShell-Intro-to-PowerShell-Lambdas-Creating-An-Automatic-Shutdown-Policy-for-EC2-Instances/">Intro to PowerShell Lambdas, Creating An Automatic Shutdown Policy for EC2 Instances</a></li>
</ul>The AWS Tools for PowerShell let you manage all your EC2 instances with cmdlets. With full coverage for machine creation, deletion and updating, virtually all settings are configurable from the PowerShell console. Let’s dive in and learn to create and manage EC2 Instances from PowerShell! The Good Stuff: Check out the AWS Tools for Powershell and start managing EC2 from your shell todayAWS PowerShell - Finding the Right EC2 Image2018-07-20T00:00:00+00:002018-07-20T00:00:00+00:00http://overpoweredshell.com//AWS%20PowerShell%20-%20Finding%20the%20Right%20EC2%20Image<p>Now that we have the AWS Tools installed and our shell setup, it’s time to start creating machines.
The most basic and probably most used feature of AWS is EC2.
There are literally thousands of different images to choose from.
With so many options and settings to tweak, finding the right image and starting a machine can sometimes feel overwhelming.
Luckily with the AWS tools for PowerShell, we’ll have everything we need to find the right image.</p>
<p><strong>The Good Stuff:</strong>
Learn how to find and start an EC2 Image with PowerShell.</p>
<!-- more -->
<p>The first command we need to learn is <code class="highlighter-rouge">Get-EC2Image</code>.
When I ran this command with no parameters in us-west-2 this returned over 84,000 images.
That’s not going to work, so let’s see if we can narrow down our choices a little.</p>
<p>A helpful command to use if we’re trying to find a Window’s image is <code class="highlighter-rouge">Get-EC2ImageByName</code>.
When this command is run with no parameters, it will output all of the code names for the Windows images.</p>
<p>Output:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>WINDOWS_2016_BASE
WINDOWS_2016_NANO
WINDOWS_2016_CORE
WINDOWS_2016_CONTAINER
WINDOWS_2016_SQL_SERVER_ENTERPRISE_2016
WINDOWS_2016_SQL_SERVER_STANDARD_2016
WINDOWS_2016_SQL_SERVER_WEB_2016
WINDOWS_2016_SQL_SERVER_EXPRESS_2016
WINDOWS_2012R2_BASE
WINDOWS_2012R2_CORE
WINDOWS_2012R2_SQL_SERVER_EXPRESS_2016
WINDOWS_2012R2_SQL_SERVER_STANDARD_2016
WINDOWS_2012R2_SQL_SERVER_WEB_2016
WINDOWS_2012R2_SQL_SERVER_EXPRESS_2014
WINDOWS_2012R2_SQL_SERVER_STANDARD_2014
WINDOWS_2012R2_SQL_SERVER_WEB_2014
WINDOWS_2012_BASE
WINDOWS_2012_SQL_SERVER_EXPRESS_2014
WINDOWS_2012_SQL_SERVER_STANDARD_2014
WINDOWS_2012_SQL_SERVER_WEB_2014
WINDOWS_2012_SQL_SERVER_EXPRESS_2012
WINDOWS_2012_SQL_SERVER_STANDARD_2012
WINDOWS_2012_SQL_SERVER_WEB_2012
WINDOWS_2012_SQL_SERVER_EXPRESS_2008
WINDOWS_2012_SQL_SERVER_STANDARD_2008
WINDOWS_2012_SQL_SERVER_WEB_2008
WINDOWS_2008R2_BASE
WINDOWS_2008R2_SQL_SERVER_EXPRESS_2012
WINDOWS_2008R2_SQL_SERVER_STANDARD_2012
WINDOWS_2008R2_SQL_SERVER_WEB_2012
WINDOWS_2008R2_SQL_SERVER_EXPRESS_2008
WINDOWS_2008R2_SQL_SERVER_STANDARD_2008
WINDOWS_2008R2_SQL_SERVER_WEB_2008
WINDOWS_2008RTM_BASE
WINDOWS_2008RTM_SQL_SERVER_EXPRESS_2008
WINDOWS_2008RTM_SQL_SERVER_STANDARD_2008
WINDOWS_2008_BEANSTALK_IIS75
WINDOWS_2012_BEANSTALK_IIS8
VPC_NAT
</code></pre></div></div>
<p>Now, that we know these code names, let’s run the same command using that for the <code class="highlighter-rouge">Name</code> parameter.
This time we should get the image details.
Here’s what that looks like when I query for the Windows Server 2016 Base image.</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Get-EC2ImageByName -Name WINDOWS_2016_BASE
</code></pre></div></div>
<p>Output:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Architecture : x86_64
BlockDeviceMappings : {/dev/sda1, xvdca, xvdcb, xvdcc...}
CreationDate : 2018-07-11T22:51:13.000Z
Description : Microsoft Windows Server 2016 with Desktop Experience Locale English AMI provided by Amazon
EnaSupport : True
Hypervisor : xen
ImageId : ami-6d336015
ImageLocation : amazon/Windows_Server-2016-English-Full-Base-2018.07.11
ImageOwnerAlias : amazon
ImageType : machine
KernelId :
Name : Windows_Server-2016-English-Full-Base-2018.07.11
OwnerId : 801119661308
Platform : Windows
ProductCodes : {}
Public : True
RamdiskId :
RootDeviceName : /dev/sda1
RootDeviceType : ebs
SriovNetSupport : simple
State : available
StateReason :
Tags : {}
VirtualizationType : hvm
</code></pre></div></div>
<p>There’s a couple of reasons this command is so helpful.
The first is that we create EC2 images by referencing the <code class="highlighter-rouge">ImageID</code>, not a name.
These images ID’s can change depending on the region, or when Amazon makes a change to the OS, for example, applying the latest patches.
By using the above command, we can ensure that we have the most up to date and the appropriate image ID for the OS we’re looking for.</p>
<p>Ok, now that we know the basics, let’s take a second look at <code class="highlighter-rouge">Get-EC2Image</code>.
One of the few parameters on this cmdlet is <code class="highlighter-rouge">Filter</code>.
The <code class="highlighter-rouge">Filter</code> parameter takes an <code class="highlighter-rouge">Amazon.EC2.Model.Filter[]</code> type.
What’s neat is that we can actually create a hashtable with some special keys and the cmdlet will cast it to the correct object under the hood.
This hashtable should have 2 entries.
The first is a key named <code class="highlighter-rouge">name</code>.
This is the field that we want to search.
The second key is <code class="highlighter-rouge">value</code>.
This is, you guessed it, the value to search for in the name field.
To get a list of available filter options run this command.</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Get-Help Get-EC2Image -Parameter <span class="k">filter</span>
</code></pre></div></div>
<p>Let’s say, I was looking for a Red Hat image.
I could use this command to search the description and return all images with “Red Hat” in the description.</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$filter</span> <span class="o">=</span> @<span class="o">{</span>
Name <span class="o">=</span> <span class="s1">'description'</span>
Values <span class="o">=</span> <span class="s1">'Red Hat *'</span>
<span class="o">}</span>
Get-EC2Image -Filter <span class="nv">$filter</span> |
<span class="nb">Select-Object </span>Name, Description, ImageId
</code></pre></div></div>
<p>It’s important to point out that both the name parameter and the values are case sensitive.
For example, if you try using <code class="highlighter-rouge">Name = 'Description'</code> you would get an invalid filter error.
Here’s a neat experiment that will demonstrate what I mean.
Try running the below two commands and see how different the output is.</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$filter</span> <span class="o">=</span> @<span class="o">{</span>
Name <span class="o">=</span> <span class="s1">'name'</span>
Values <span class="o">=</span> <span class="s1">'Red*'</span>
<span class="o">}</span>
Get-EC2Image -Filter <span class="nv">$filter</span> |
<span class="nb">Select-Object </span>ImageId, Name
</code></pre></div></div>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$filter</span> <span class="o">=</span> @<span class="o">{</span>
Name <span class="o">=</span> <span class="s1">'name'</span>
Values <span class="o">=</span> <span class="s1">'red*'</span>
<span class="o">}</span>
Get-EC2Image -Filter <span class="nv">$filter</span> |
<span class="nb">Select-Object </span>ImageId, Name
</code></pre></div></div>
<p>Once you finally find the image, starting a new instance (with all default parameters) really couldn’t be easier.
Simply pipe you image into <code class="highlighter-rouge">New-Ec2Instance</code>.
Here’s what launching a new Windows Server 2016 Container host would look like.</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Get-EC2ImageByName -Name WINDOWS_2016_CONTAINER |
New-EC2Instance
</code></pre></div></div>
<p>And just like, in a few minutes, we’ll have a new instance ready to use!
Stay tuned for a follow-up article where we’ll dive deep into some of the <code class="highlighter-rouge">New-Ec2Instance</code> parameters, learn to manage existing instances and cleanup old machines.</p>
<p>For more articles about PowerShell and AWS please check out:</p>
<ul>
<li><a href="https://overpoweredshell.com//AWS-PowerShell-Setting-up-AWS-Tools-on-PowerShell-Core/">Setting up AWS Tools on PowerShell Core</a></li>
<li><a href="https://overpoweredshell.com//AWS-PowerShell-Finding-the-Right-EC2-Image/">Finding the Right EC2 Image</a></li>
<li><a href="https://overpoweredshell.com//AWS-PowerShell-Creating-Ec2-Instances-and-Basic-Machine-Management/">Creating Ec2 Instances and Basic Machine Management</a></li>
<li><a href="https://overpoweredshell.com//AWS-PowerShell-EC2-Key-Pairs,-Credentials-and-Connecting/">EC2 Key Pairs, Credentials and Connecting</a></li>
<li><a href="https://overpoweredshell.com//AWS-PowerShell-EC2-Tags-and-Filtering/">EC2 Tags and Filtering</a></li>
<li><a href="https://overpoweredshell.com//AWS-PowerShell-Intro-to-PowerShell-Lambdas-Creating-An-Automatic-Shutdown-Policy-for-EC2-Instances/">Intro to PowerShell Lambdas, Creating An Automatic Shutdown Policy for EC2 Instances</a></li>
</ul>Now that we have the AWS Tools installed and our shell setup, it’s time to start creating machines. The most basic and probably most used feature of AWS is EC2. There are literally thousands of different images to choose from. With so many options and settings to tweak, finding the right image and starting a machine can sometimes feel overwhelming. Luckily with the AWS tools for PowerShell, we’ll have everything we need to find the right image. The Good Stuff: Learn how to find and start an EC2 Image with PowerShell.AWS PowerShell - Setting up AWS Tools on PowerShell Core2018-07-16T00:00:00+00:002018-07-16T00:00:00+00:00http://overpoweredshell.com//AWS%20PowerShell%20-%20Setting%20up%20AWS%20Tools%20on%20PowerShell%20Core<p>It’s almost impossible to talk about DevOps these days without mentioning the cloud.
People are incredibly passionate about which service is the best and why.
Whatever your opinion, it’s undeniable that Amazon Web Services (AWS) is one of the most mature and feature-rich providers in this space.
They treat PowerShell like a first-class citizen and best of all, you can run AWS tools for Powershell in PowerShell core!</p>
<p><strong>The Good Stuff:</strong>
Check out <a href="https://docs.aws.amazon.com/powershell/latest/userguide/pstools-using.html">AWS Tools for Windows PowerShell</a></p>
<!-- more -->
<h1 id="installation">Installation</h1>
<p>The AWS tools module is available on the PowerShell gallery.
To install them on PowerShell core, we can run the below command.</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Install-Module -Name AWSPowerShell.NetCore -Verbose -Force
</code></pre></div></div>
<p>If you’re not using PowerShell Core, but Windows PowerShell instead, you can use this command:</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Install-Module -Name AWSPowerShell -Verbose -Force
</code></pre></div></div>
<h1 id="setting-up-our-session">Setting Up Our Session</h1>
<p>Once you have the module loaded, the next thing to do is to set up the credentials used to connect to AWS.
What’s a little different here, is that you don’t supply a PSCredential.
Instead, you create an access key inside the AWS console and use that.
To do this from the main AWS console follow these steps:</p>
<ol>
<li>Click on IAM</li>
<li>Click users</li>
<li>Click the username you want to create the access key for</li>
<li>Click the security credentials tab</li>
<li>Finally, click create access key</li>
</ol>
<h2 id="manually-setting-credentials">Manually Setting Credentials</h2>
<p>Once you have the access key created, we can run the below PowerShell command.
Here’s an example, using my access key and secret.</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">Set</span>-AWSCredential -AccessKey <span class="s1">'AKIAIK4OGJRXYXEDOKZA'</span> -SecretKey <span class="s1">'rLw8vTBhoH6CZqUjOOnb/1mg3gfY9gRB8TEZxdMP'</span>
</code></pre></div></div>
<p>It’s important to note that this only sets credentials in your current session.
If you want to store them permanently use the <code class="highlighter-rouge">-StoreAs</code> switch.
You can give the credential any name, but if you use <code class="highlighter-rouge">default</code>, these will get loaded automatically whenever AWS tools needs a credential.</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$awsCreds</span> <span class="o">=</span> @<span class="o">{</span>
AccessKey <span class="o">=</span> <span class="s1">'AKIAIK4OGJRXYXEDOKZA'</span>
SecretKey <span class="o">=</span> <span class="s1">'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'</span>
StoreAs <span class="o">=</span> <span class="s1">'default'</span>
<span class="o">}</span>
<span class="nb">Set</span>-AWSCredential @awsCreds
</code></pre></div></div>
<p>Another option is saving the credentials to a file.
Helpful if you are working with multiple credentials or some automated process needs to use them.
Be careful with this approach though, since the credentials and profile get stored in clear text.
Here’s an example of what that looks like:</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$awsCreds</span> <span class="o">=</span> @<span class="o">{</span>
AccessKey <span class="o">=</span> <span class="s1">'AKIAIK4OGJRXYXEDOKZA'</span>
SecretKey <span class="o">=</span> <span class="s1">'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'</span>
StoreAs <span class="o">=</span> <span class="s1">'dchristian3188'</span>
ProfileLocation <span class="o">=</span> <span class="s1">'C:\AWS\demoProfile'</span>
<span class="o">}</span>
<span class="nb">Set</span>-AWSCredential @awsCreds
</code></pre></div></div>
<h2 id="managing-credentials">Managing Credentials</h2>
<p>Like you would expect we can also manage the credentials on our machine with PowerShell.
To get a list of saved credentials we can run <code class="highlighter-rouge">Get-AWSCredential -ListProfileDetail</code>.
Here’s what that looked like on my machine.</p>
<p><img src="/images/aws/getcred.png" alt="_config.yml" /></p>
<p>To remove a credential that is no longer in use just run <code class="highlighter-rouge">Remove-AWSCredentialProfile</code>.
Here’s what the command I used to delete the dchristian3188 profile.</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Remove-AWSCredentialProfile -ProfileName dchristian3188 -Force -Verbose
</code></pre></div></div>
<p>I like to point out, that you cannot pipe from <code class="highlighter-rouge">Get-AWSCredential</code> to <code class="highlighter-rouge">Remove-AWSCredentialProfile</code>.
I think that’s so you don’t accidentally remove all profiles on your machine.
This makes senses but does make removing all credentials a pain.
Here’s a one-liner to get the job done.</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Get-AWSCredential -ListProfileDetail |
<span class="k">ForEach</span>-Object <span class="o">{</span> Remove-AWSCredentialProfile -ProfileName <span class="nv">$PSItem</span>.ProfileName -Force <span class="o">}</span>
</code></pre></div></div>
<h2 id="setting-a-default-region">Setting a Default Region</h2>
<p>The last thing you’ll probably want to do is set a default region.
Almost all of the AWS Cmdlets require that you supply a region.
If you have a region that you primarily work in, setting a default can save you a lot of time.</p>
<p>You’ll need to use technical region name, not the friendly one.
To get a list of regions, just run <code class="highlighter-rouge">Get-AWSRegion</code>.
I primarily work out of the US West Oregon.
Here’s what setting that as my default would look like.</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">Set</span>-DefaultAWSRegion -Region us-west-2
</code></pre></div></div>
<p>To update the region, just run the command again.
Optionally you can clear all defaults by running <code class="highlighter-rouge">Clear-DefaultAWSRegion</code>.</p>
<p>Alright with all this in place, your ready to get started automating AWS!</p>
<p>For more articles about PowerShell and AWS please check out:</p>
<ul>
<li><a href="https://overpoweredshell.com//AWS-PowerShell-Setting-up-AWS-Tools-on-PowerShell-Core/">Setting up AWS Tools on PowerShell Core</a></li>
<li><a href="https://overpoweredshell.com//AWS-PowerShell-Finding-the-Right-EC2-Image/">Finding the Right EC2 Image</a></li>
<li><a href="https://overpoweredshell.com//AWS-PowerShell-Creating-Ec2-Instances-and-Basic-Machine-Management/">Creating Ec2 Instances and Basic Machine Management</a></li>
<li><a href="https://overpoweredshell.com//AWS-PowerShell-EC2-Key-Pairs,-Credentials-and-Connecting/">EC2 Key Pairs, Credentials and Connecting</a></li>
<li><a href="https://overpoweredshell.com//AWS-PowerShell-EC2-Tags-and-Filtering/">EC2 Tags and Filtering</a></li>
<li><a href="https://overpoweredshell.com//AWS-PowerShell-Intro-to-PowerShell-Lambdas-Creating-An-Automatic-Shutdown-Policy-for-EC2-Instances/">Intro to PowerShell Lambdas, Creating An Automatic Shutdown Policy for EC2 Instances</a></li>
</ul>It’s almost impossible to talk about DevOps these days without mentioning the cloud. People are incredibly passionate about which service is the best and why. Whatever your opinion, it’s undeniable that Amazon Web Services (AWS) is one of the most mature and feature-rich providers in this space. They treat PowerShell like a first-class citizen and best of all, you can run AWS tools for Powershell in PowerShell core! The Good Stuff: Check out AWS Tools for Windows PowerShellExploring PowerShell 6 - A Better Split-Path2018-01-24T00:00:00+00:002018-01-24T00:00:00+00:00http://overpoweredshell.com//Exploring%20PowerShell%206%20-%20A%20Better%20Split-Path<p>PowerShell Core 6.0 is out!
There’s a ton of new features and even some old commands are getting some love.
Today we’re gonna talk about some of the improvements that made it into <code class="highlighter-rouge">Split-Path</code>.
Let’s dive in and see what the team brought us.</p>
<p><strong>The Good Stuff:</strong>
There’s a new improved <code class="highlighter-rouge">Split-Path</code> with a couple quality of life changes, check it out!
<!-- more --></p>
<h2 id="getting-an-extension">Getting an Extension</h2>
<p>Finding a file extension is a pretty common task.
We had a couple of ways to do this before Powershell 6.0 was released, but none of which were straightforward.
The first way was using <code class="highlighter-rouge">Get-Item</code>.
This worked because <code class="highlighter-rouge">Get-Item</code> returned a <code class="highlighter-rouge">System.IO.FileInfo</code> object with an extension property we could inspect.
Here’s an example that will get the extension of our PowerShell profile (spoiler alert, it’s going to be <code class="highlighter-rouge">.ps1</code>).</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">(</span><span class="nb">Get-Item</span> <span class="nv">$PROFILE</span><span class="o">)</span>.Extension
</code></pre></div></div>
<p>Now if you didn’t have a profile, you might have noticed the first disadvantage of this method.
For <code class="highlighter-rouge">Get-Item</code> to work, your file must exist.
As you can imagine there’s plenty of scripting scenarios where this isn’t possible.
To get around this, we can call a dot net method from <code class="highlighter-rouge">System.IO.Path</code> class, <code class="highlighter-rouge">GetExtension</code>.
Here’s an example trying this on a file that doesn’t exist.</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">[</span>System.IO.Path]::GetExtension<span class="o">(</span><span class="s1">'C:\temp\fakefile.txt'</span><span class="o">)</span>
</code></pre></div></div>
<p>This works but doesn’t feel PowerShelly.
Well now in PowerShell 6, all we have to do is call <code class="highlighter-rouge">Split-Path</code>.
There’s been a new switch added, <code class="highlighter-rouge">-Extension</code> that does just this.
Here’s what it looks like.
Noticed it also works for non-existent files.</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">Split-Path</span> <span class="s1">'C:\temp\fakefile.txt'</span> -Extension
</code></pre></div></div>
<h2 id="getting-just-the-filename">Getting Just The Filename</h2>
<p>Another common scenario we run into is when you have a path, and you need the filename without the extension.
Previously there were two ways to accomplish this.
The first was using <code class="highlighter-rouge">Get-Item</code> but this time returning <code class="highlighter-rouge">BaseName</code> property.</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">(</span><span class="nb">Get-Item</span> <span class="nv">$PROFILE</span><span class="o">)</span>.BaseName
</code></pre></div></div>
<p>Remember though, this only worked if our file existed.
Again we could use dot net to work around this.</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">[</span>System.IO.Path]::GetFileNameWithoutExtension<span class="o">(</span><span class="s1">'C:\temp\fakefile.txt'</span><span class="o">)</span>
</code></pre></div></div>
<p>In PowerShell 6, we can do the same thing with <code class="highlighter-rouge">Split-Path</code>, this time we’ll use the <code class="highlighter-rouge">-LeafBase</code>.
Here’s what that looks like.</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">Split-Path</span> <span class="s1">'C:\temp\fakefile.txt'</span> -LeafBase
</code></pre></div></div>
<h2 id="splitting-a-unc">Splitting a UNC</h2>
<p>Here’s a neat one.
Previous to PowerShell 6, the <code class="highlighter-rouge">Split-Path</code> command didn’t work on UNC roots.
For example, if ran <code class="highlighter-rouge">Split-Path -Path \\server\share</code> you would get a null result.
To get this info, we would need to use Regex.
Here’s what that would look like to get the server name for a UNC path.</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">if</span><span class="o">(</span><span class="s2">"\\server\share"</span> -match <span class="s1">'(?<ServerName>^\\\\([a-z0-9_.$-]+))\\(?<ShareName>([a-z0-9_.$-]+))'</span><span class="o">)</span>
<span class="o">{</span>
<span class="nv">$Matches</span>.ServerName
<span class="o">}</span>
</code></pre></div></div>
<p>Simple right…
Here’s a similar approach to pick out the leaf, or share name.</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">if</span><span class="o">(</span><span class="s2">"\\server\share"</span> -match <span class="s1">'(?<ServerName>^\\\\([a-z0-9_.$-]+))\\(?<ShareName>([a-z0-9_.$-]+))'</span><span class="o">)</span>
<span class="o">{</span>
<span class="nv">$Matches</span>.ShareName
<span class="o">}</span>
</code></pre></div></div>
<p>Thankfully in PowerShell 6,<code class="highlighter-rouge">Split-Path</code> just works on UNC roots.
You can use both <code class="highlighter-rouge">-Parent</code> or <code class="highlighter-rouge">-Leaf</code> and forget all about that regex gibberish.
Pretty cool right?
So what’s your favorite new little feature of PowerShell 6?</p>PowerShell Core 6.0 is out! There’s a ton of new features and even some old commands are getting some love. Today we’re gonna talk about some of the improvements that made it into Split-Path. Let’s dive in and see what the team brought us. The Good Stuff: There’s a new improved Split-Path with a couple quality of life changes, check it out!Exploring PowerShell 6 - SpeedFreaks2018-01-23T00:00:00+00:002018-01-23T00:00:00+00:00http://overpoweredshell.com//Exploring%20PowerShell%206%20-%20SpeedFreaks<p>PowerShell Core 6.0 is out!
Along with all the new features, there has been a ton of performance improvements.
But just really how much faster is it?
Today I’m going to revisit an old article by Dave Wyatt and see if version 6 has the numbers to back up all the claims.
So with that, let’s dive into the filtering performance improvements in the latest version.</p>
<p><strong>The Good Stuff:</strong>
PowerShell version 6, now with faster filters!
<!-- more --></p>
<p>Dave Wyatt MVP put together a fantastic <a href="https://powershell.org/2013/11/17/powershell-performance-filtering-collections/">article</a> over PowerShell.org a few years back.
I’ve referred to this article many times over the years and it’s a definite must-read for any true PowerShell enthusiast.
In today’s post, I’ll be building off (shamelessly stealing) his script to measure different methods to filter in PowerShell.
We’ll also be running this same script in both version 5 and 6 to get some good comparison data.
First off, let’s meet our filtering contenders.</p>
<ul>
<li>Where-Object - the standard filter command that’s been with us since version 1</li>
<li>Simplified Where - The friendly where syntax introduced in PowerShell 3</li>
<li>.Where - This method was first introduced in PowerShell 4 to filter collections</li>
<li>The filter keyword - Often overlooked, hardly used and with us since version 1</li>
<li>Foreach - Standard loop built into the language</li>
<li>Advanced Function - This one essentially measures the performance of the process block in PowerShell</li>
</ul>
<p>Here’s what our speed test will look like.
It will filter the Get-Process command looking for notepad.
To make things fair, we’ll execute each filter a thousand times.</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$loop</span> <span class="o">=</span> 1000
<span class="nv">$v2</span> <span class="o">=</span> <span class="o">(</span><span class="nb">Measure-Command</span> <span class="o">{</span>
<span class="k">for</span> <span class="o">(</span><span class="nv">$i</span> <span class="o">=</span> 0; <span class="nv">$i</span> -lt <span class="nv">$loop</span>; <span class="nv">$i</span>++<span class="o">)</span>
<span class="o">{</span>
<span class="nb">Get-Process</span> | <span class="nb">Where</span>-Object <span class="o">{</span> <span class="nv">$_</span>.Name -eq <span class="s1">'notepad'</span> <span class="o">}</span>
<span class="o">}</span>
<span class="o">})</span>.TotalMilliseconds
<span class="nv">$v3</span> <span class="o">=</span> <span class="o">(</span><span class="nb">Measure-Command</span> <span class="o">{</span>
<span class="k">for</span> <span class="o">(</span><span class="nv">$i</span> <span class="o">=</span> 0; <span class="nv">$i</span> -lt <span class="nv">$loop</span>; <span class="nv">$i</span>++<span class="o">)</span>
<span class="o">{</span>
<span class="nb">Get-Process</span> | <span class="nb">Where </span>Name -eq <span class="s1">'notepad'</span>
<span class="o">}</span>
<span class="o">})</span>.TotalMilliseconds
<span class="nv">$v4</span> <span class="o">=</span> <span class="o">(</span><span class="nb">Measure-Command</span> <span class="o">{</span>
<span class="k">for</span> <span class="o">(</span><span class="nv">$i</span> <span class="o">=</span> 0; <span class="nv">$i</span> -lt <span class="nv">$loop</span>; <span class="nv">$i</span>++<span class="o">)</span>
<span class="o">{</span>
<span class="o">(</span><span class="nb">Get-Process</span><span class="o">)</span>.Where<span class="o">(</span> <span class="o">{</span> <span class="nv">$_</span>.Name -eq <span class="s1">'notepad'</span> <span class="o">})</span>
<span class="o">}</span>
<span class="o">})</span>.TotalMilliseconds
<span class="nv">$filter</span> <span class="o">=</span> <span class="o">(</span><span class="nb">Measure-Command</span> <span class="o">{</span>
<span class="k">filter </span>notepadFilter <span class="o">{</span> <span class="k">if</span> <span class="o">(</span><span class="nv">$_</span>.Name -eq <span class="s1">'notepad'</span><span class="o">)</span> <span class="o">{</span> <span class="nv">$_</span> <span class="o">}</span> <span class="o">}</span>
<span class="k">for</span> <span class="o">(</span><span class="nv">$i</span> <span class="o">=</span> 0; <span class="nv">$i</span> -lt <span class="nv">$loop</span>; <span class="nv">$i</span>++<span class="o">)</span>
<span class="o">{</span>
<span class="nb">Get-Process</span> | notepadFilter
<span class="o">}</span>
<span class="o">})</span>.TotalMilliseconds
<span class="nv">$foreachLoop</span> <span class="o">=</span> <span class="o">(</span><span class="nb">Measure-Command</span> <span class="o">{</span>
<span class="k">for</span> <span class="o">(</span><span class="nv">$i</span> <span class="o">=</span> 0; <span class="nv">$i</span> -lt <span class="nv">$loop</span>; <span class="nv">$i</span>++<span class="o">)</span>
<span class="o">{</span>
<span class="k">foreach</span> <span class="o">(</span><span class="nv">$process</span> <span class="k">in</span> <span class="o">(</span><span class="nb">Get-Process</span><span class="o">))</span>
<span class="o">{</span>
<span class="k">if</span> <span class="o">(</span><span class="nv">$process</span>.Name -eq <span class="s1">'notepad'</span><span class="o">)</span>
<span class="o">{</span>
<span class="c1"># Do something with $process</span>
<span class="nv">$process</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="o">})</span>.TotalMilliseconds
<span class="nv">$AdvancedFunction</span> <span class="o">=</span> <span class="o">(</span><span class="nb">Measure-Command</span> <span class="o">{</span>
<span class="k">function </span>Get-Notepad
<span class="o">{</span>
<span class="o">[</span><span class="na">CmdletBinding</span><span class="o">()]</span>
<span class="k">Param</span><span class="o">(</span>
<span class="o">[</span>Parameter<span class="o">(</span>ValueFromPipeline<span class="o">)]</span>
<span class="o">[</span>PSCustomObject]
<span class="nv">$InputObject</span>
<span class="o">)</span>
<span class="k">process</span>
<span class="o">{</span>
<span class="k">if</span> <span class="o">(</span><span class="nv">$InputObject</span>.Name -eq <span class="s1">'notepad'</span><span class="o">)</span>
<span class="o">{</span>
<span class="nv">$InputObject</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="k">for</span> <span class="o">(</span><span class="nv">$i</span> <span class="o">=</span> 0; <span class="nv">$i</span> -lt <span class="nv">$loop</span>; <span class="nv">$i</span>++<span class="o">)</span>
<span class="o">{</span>
<span class="nb">Get-Process</span> | Get-Notepad
<span class="o">}</span>
<span class="o">})</span>.TotalMilliseconds
<span class="nb">Write-Host</span> <span class="o">(</span><span class="s2">"PowerShell Version: </span><span class="k">$(</span><span class="nv">$PSVersionTable</span>.PSVersion.ToString<span class="o">(</span><span class="k">)</span><span class="s2">)"</span><span class="o">)</span>
<span class="nb">Write-Host</span> <span class="o">(</span><span class="s1">'Where-Object -FilterScript: {0:f2} ms'</span> -f <span class="nv">$v2</span><span class="o">)</span>
<span class="nb">Write-Host</span> <span class="o">(</span><span class="s1">'Simplfied Where syntax: {0:f2} ms'</span> -f <span class="nv">$v3</span><span class="o">)</span>
<span class="nb">Write-Host</span> <span class="o">(</span><span class="s1">'.Where() method: {0:f2} ms'</span> -f <span class="nv">$v4</span><span class="o">)</span>
<span class="nb">Write-Host</span> <span class="o">(</span><span class="s1">'Using a filter: {0:f2} ms'</span> -f <span class="nv">$filter</span><span class="o">)</span>
<span class="nb">Write-Host</span> <span class="o">(</span><span class="s1">'Conditional in foreach loop: {0:f2} ms'</span> -f <span class="nv">$foreachLoop</span><span class="o">)</span>
<span class="nb">Write-Host</span> <span class="o">(</span><span class="s1">'Advanced Function: {0:f2} ms'</span> -f <span class="nv">$AdvancedFunction</span><span class="o">)</span>
</code></pre></div></div>
<p>Moment of truth, here’s what the results were in PowerShell 5.</p>
<p><img src="/images/SpeedFreaks/powershell5.png" alt="_config.yml" /></p>
<p>And here’s what that same script looks like in Powershell 6.</p>
<p><img src="/images/SpeedFreaks/powershell6.png" alt="_config.yml" /></p>
<p>The numbers are undeniable.
Regardless of version, the fastest filters remain unchanged.</p>
<ol>
<li>Foreach</li>
<li>Filter Keyword</li>
<li>Advanced functions (process block)</li>
<li>.Where</li>
<li>Simplified Where</li>
<li>Where-Object</li>
</ol>
<p>What is the most surprising is that on average PowerShell 6 is twice as fast as the previous version!
That’s pretty damn impressive.
So what do you think?
Are these speed gains enough to make you switch over?</p>PowerShell Core 6.0 is out! Along with all the new features, there has been a ton of performance improvements. But just really how much faster is it? Today I’m going to revisit an old article by Dave Wyatt and see if version 6 has the numbers to back up all the claims. So with that, let’s dive into the filtering performance improvements in the latest version. The Good Stuff: PowerShell version 6, now with faster filters!Exploring PowerShell 6 - Character Ranges2018-01-22T00:00:00+00:002018-01-22T00:00:00+00:00http://overpoweredshell.com//Exploring%20PowerShell%206%20-%20Character%20Ranges<p>PowerShell Core 6.0 is now out and available for download.
Today I want to talk about a feature that may have taken PowerShell golf to a new level.
New with this release we can now enumerate character ranges, and skip the whole cast to char step!
Let’s dive in and take a look.</p>
<p><strong>The Good Stuff:</strong>
Take a look at <code class="highlighter-rouge">"a".."z"</code> and enumerate characters the easy way.</p>
<!-- more -->
<p>Being able to enumerate a range of letters has always been possible in PowerShell.
But before PowerShell 6, the way you did this was by casting an integer to it’s ASCII equivalent.
ASCII is the standard computers use to represent all characters we see.
Remember a computer has no idea what “A” is but it can understand the number 65.
Take a look at this <a href="http://www.asciitable.com/">chart</a> for a full breakdown ASCII codes to their numeric values.</p>
<p>Looking at the chart if we wanted to enumerate all letters from A to Z, we need to ask for the ASCII codes between 65 and 90.
The trick was we needed to cast each integer to a <code class="highlighter-rouge">Char</code>.
By casting to <code class="highlighter-rouge">Char</code> we are able to see the ASCII character the integer corresponds too.
Here’s what this looks like in PowerShell, leveraging the range operator, <code class="highlighter-rouge">..</code>.</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>65..90 | <span class="k">ForEach</span>-Object <span class="o">{[</span><span class="kt">Char</span><span class="o">]</span><span class="nv">$PSItem</span><span class="o">}</span>
</code></pre></div></div>
<p>Similarly, if we wanted all lower case letters, we could use the range 97 through 122.</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>97..122 | <span class="k">ForEach</span>-Object <span class="o">{[</span><span class="kt">Char</span><span class="o">]</span><span class="nv">$PSItem</span><span class="o">}</span>
</code></pre></div></div>
<p>Now with PowerShell 6, the range operator just works with letters.
Here’s what this command looks like in the new syntax.</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="s2">"A"</span>..<span class="s2">"Z"</span>
</code></pre></div></div>
<p>One important caveat here is that the letters must be surrounded in quotes (doesn’t matter if single or double).
If you don’t do this PowerShell will give you a nasty error message about the command not being recognized.
I think it’s a little lame that we can’t use <code class="highlighter-rouge">A..Z</code> but to be fair, you get the same message when you enter an unquoted string at the command line, so I get it.</p>
<p>What’s interesting are some of the side effects that this new feature introduced.
What it’s doing under the covers is checking if the first character is a string.
If it is, then it essentially treats that as the ASCII code and evaluates the range from there.
For example, what do you think this range does?</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="s2">"1"</span>..45
</code></pre></div></div>
<p>Well in the previous version of PowerShell 6, it did what you would expect it too.
But if you run this command in the latest version you’ll get this.</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>1
0
/
<span class="nb">.</span>
-
</code></pre></div></div>
<p>The reason for this is that it treats the <code class="highlighter-rouge">"1"</code> as ASCII code 49, so this gets evaulated to range <code class="highlighter-rouge">49..45</code>.
This means we can also step over weird ranges like this:</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">(</span><span class="s2">" "</span>..<span class="s2">"/"</span><span class="o">)</span> -join <span class="s2">" "</span>
</code></pre></div></div>
<p>Output:</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="o">!</span> <span class="s2">" # </span><span class="nv">$ </span><span class="s2">% & ' ( ) * + , - . /
</span></code></pre></div></div>
<p>In closing, I want to point out a pretty serious bug with the new character range operators.
I don’t believe all of the logic to convert the character range has been fully fleshed out.
Take a look at this example:</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="s2">"a"</span>..<span class="s2">"z"</span> | <span class="k">ForEach</span>-Object <span class="o">{</span><span class="nv">$PSItem</span><span class="o">}</span>
</code></pre></div></div>
<p>Output:</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Cannot convert value <span class="s2">"a"</span> to <span class="nb">type</span> <span class="s2">"System.Int32"</span><span class="nb">.</span> Error: <span class="s2">"Input string was not in a correct format."</span>
At line:1 <span class="kt">char</span>:1
+ <span class="s2">"a"</span>..<span class="s2">"z"</span> | <span class="k">ForEach</span>-Object <span class="o">{</span><span class="nv">$PSItem</span><span class="o">}</span>
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: <span class="o">(</span>:<span class="o">)</span> <span class="o">[]</span>, RuntimeException
+ FullyQualifiedErrorId : InvalidCastFromStringToInteger
</code></pre></div></div>
<p>The team is aware of this and tracking it under Github bug number <a href="https://github.com/PowerShell/PowerShell/issues/5519">#5519.</a>
I feel this is pretty unfortunate since being able to enumerate the range and then take some action on it, is kind of the whole point…
The current work around would be to force the range into an array, then step over it.
Something like this:</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">(</span><span class="s2">"a"</span>..<span class="s2">"z"</span><span class="o">)</span> | <span class="k">ForEach</span>-Object <span class="o">{</span><span class="nv">$PSItem</span><span class="o">}</span>
</code></pre></div></div>
<p>That’s all for today.
So what do you think?
Char ranges home run or swing and a miss?</p>PowerShell Core 6.0 is now out and available for download. Today I want to talk about a feature that may have taken PowerShell golf to a new level. New with this release we can now enumerate character ranges, and skip the whole cast to char step! Let’s dive in and take a look. The Good Stuff: Take a look at "a".."z" and enumerate characters the easy way.Exploring PowerShell 6 - Service Cmdlets Easy Mode2018-01-19T00:00:00+00:002018-01-19T00:00:00+00:00http://overpoweredshell.com//Exploring%20PowerShell%206%20-%20Service%20Cmdlets%20Easy%20Mode<p>I’m not sure if you guys have heard, but PowerShell Core 6.0 is out.
Today I want to talk about some of my favorite quality of life improvements.
There have been some changes to the *-Service cmdlets.
Let’s dive in and take a look.</p>
<p><strong>The Good Stuff:</strong>
Start playing with the new features on the Service cmdlets in PowerShell 6.</p>
<!-- more -->
<p>Now if you’re a CIM guru like Mr. Richard Siddaway, you know all about the Win32_Service CIM class.
But if your a mere mortal like me, interacting with CIM can be a little scary.
The PowerShell team was kind enough to create the Service cmdlets for us, which hides the direct interaction making it much more user-friendly.
Unfortunately, there was a couple of common scenarios that weren’t cover by the cmdlets and required us to dive into the CIM methods.</p>
<h2 id="changing-a-services-credential">Changing A Service’s Credential</h2>
<p>Any admin worth his salt has had to update a credential on a service.
Surprisingly before PowerShell 6, there was no easy way to do this without interacting with Win32_Service.
Here’s a little code snippet I would use update the credential on a service.</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$cred</span> <span class="o">=</span> <span class="nb">Get-Credential</span>
<span class="nv">$service</span> <span class="o">=</span> <span class="nb">Get-CimInstance</span> -ClassName Win32_Service -Filter <span class="s2">"Name='MyService'"</span>
<span class="nv">$serviceParams</span> <span class="o">=</span> @<span class="o">{</span>
StartName <span class="o">=</span> <span class="nv">$cred</span>.UserName
StartPassword <span class="o">=</span> <span class="nv">$cred</span>.GetNetworkCredential<span class="o">()</span>.Password
<span class="o">}</span>
<span class="nb">Invoke-CimMethod</span> -InputObject <span class="nv">$service</span> -MethodName Change -Arguments <span class="nv">$serviceParams</span>
</code></pre></div></div>
<p>Powershell 6 makes this super easy by adding a new parameter, Credential, to the <code class="highlighter-rouge">Set-Service</code> cmdlet.
Let’s take a look at what that previous command looks like in PowerShell 6.</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$cred</span> <span class="o">=</span> <span class="nb">Get-Credential
Set-Service</span> -Name MyService -Credential <span class="nv">$cred</span>
</code></pre></div></div>
<p>And that’s all there is to it.
No more CIM gibberish and our script is much more legible.</p>
<h2 id="removing-a-service">Removing a Service</h2>
<p>This one use to always blow my mind.
The PowerShell team added support for creating and updating a service but if you wanted to delete it, you were out of luck.
This is another scenario were CIM could come to the rescue.
Here’s what removing a service looked like before Version 6.</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">Get-CimInstance</span> -ClassName Win32_Service -Filter <span class="s2">"Name='MyService'"</span> |
<span class="nb">Invoke-CimMethod</span> -MethodName Delete
</code></pre></div></div>
<p>While this method totally works, you have to know it’s there to leverage it.
Starting in PowerShell 6, we finally have a <code class="highlighter-rouge">Remove-Service</code> cmdlet.
Here’s the PowerShell 6 equivalent.</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Remove-Service -Name MyService
</code></pre></div></div>
<p>What I love about this is the discoverability.
Plus it gives us full CRUD Coverage (Create, Read, Update, Delete) in the cmdlets.
So what’s your biggest quality of life improvement in Powershell 6?
Leave a comment and let us know.</p>I’m not sure if you guys have heard, but PowerShell Core 6.0 is out. Today I want to talk about some of my favorite quality of life improvements. There have been some changes to the *-Service cmdlets. Let’s dive in and take a look. The Good Stuff: Start playing with the new features on the Service cmdlets in PowerShell 6.