The First Month With PowerShell

About a month ago, I decided that it was time.  I had written(i.e. copy and pasted) a couple of PowerShell scripts in the past to accomplish something but that was no longer good enough.  To be completely honest, I don’t even remember now what gave me the itch to learn PowerShell a month ago but here I am.  Sifting through many resources, watching videos, reading blog posts, rediscovering Twitter.  It’s been a very interesting ride so far.  What have I learned in the last month?  I still know nothing…well, next to nothing now.

My journey began with a trip to Google.  “learn powershell”  Low and behold, the second link is the Microsoft Virtual Academy.  Having perused this wondrous resource before, I knew it would have videos and some great content so I started there.  Getting Started with PowerShell 3.0 Jump Start.  I burned though that in about a day and wanted more so I searched for other PowerShell videos on the MVA.  Wow!  There are a ton on there so away I went.  I have to say, if you are behind like I am, that is probably one of the best places to start.  Fantastic content.

Let’s go over some things that I have learned so far.  First of all, the help system in PowerShell is absolutely fantastic.  Get-Help will be your best friend.  Second, the syntax of the cmdlets is very easy to remember.  Verb-Noun.  It couldn’t be more simple and easy to remember.  So for example you want get information about an AD user.  Hmm, sure enough.  Get-ADUser is the name the cmdlet.

Since I had to take two programming courses in college (why I chose C++ is beyond me), some common concepts in programming I already understood to a degree.  Things such as loops, and operators.  Those courses were finally good for something.  Become familiar with how these work as soon as possible.  They are invaluable to understand and be able to use.

One of the coolest things in my opinion about PowerShell happens to be, at least for myself, the hardest concept to really wrap your head around.  Everything is an object.  Well what does that mean?  The easiest way I know how to explain it is with an example.  Let’s pick something really easy like Get-Date.  Let’s just type that in and see what we get.

Get-Date

Well, that gave us what you probably thought.
Thursday, December 03, 2015 10:49:38 PM

I think I did this next part by accident and figured out what it really meant that everything was an object. Let’s assign that to a variable and then display it’s contents.

$date = Get-Date
$date

Ok, so we saved the current date and time into a variable. So what. Here is the cool part. Each object in PowerShell has some functions that you can use with them. The next best thing to Get-Help is something called Get-Member. If you pipe an object into Get-Member, it gives you all kinds of information about what methods can be used on that object as well as that objects properties. At this point in my learning, it’s the properties that interested me. Let’s take that variable that we saved the current date and time to.

$date | Get-Member

The first thing that I want you to really take notice to besides that wall of text that just floated by is the very first line of output. “TypeName: System.DateTime”. The variable that we saved the current date to is actually saving a DateTime object. Ok, so looking through some of the properties I see “DayOfWeek”. So what does that do? That looks interesting. Let’s try it.

$date.DayOfWeek

That returned just what it sounds like. The day of the week that you saved as part of the current date time from Get-Date. Go ahead and test some of the others. Pretty cool right? Oh it gets better.

Lets say that you want to see the services on your PC.

Get-Service

OK, but you really only wanted to see the running services. Notice the headers of each column. Those are properties that you can filter with. This is when you utilize the pipeline to pass the output of one cmdlet as the input of another cmdlet.

Get-Service | Where-Object Status -eq 'Running'

Great, but I still see a status column which is now not needed. I know the status already because I told it to only give me the services that are running. Also, that name column contains some funny things. I just want the “English” name of the services. Remember where I said previously that objects have properties. Well the column headers are some properties. And we just want the “DisplayName”. We could save that to a variable and see that property from the variable but that is two separate steps. The other way(which again, I think I figured this out by accident) is to wrap the command in parentheses and run methods or view properties that way.

(Get-Service | Where-Object Status -eq 'Running').DisplayName

I have to say, I use this like crazy now if I want to see just one property of something(which is usually the).name.

These are just barely scratching the surface of the capabilities of PowerShell. As I said in the last post, if you are a System Administrator and not already using PowerShell, do yourself a favor and get cracking. Start with the MVA jump start video and go to town. You’ll be glad that you did.

As always, any tips, comments, feedback, or questions are welcome. Thanks for dropping by and I’ll see you soon.

Advertisements
The First Month With PowerShell

Let’s Talk Some Powershell

It has been roughly 2 weeks since I began the journey into PowerShell.  In that short amount of time, I have learned a ton.  I have to say, if you are a system admin and you don’t already know PowerShell, get on it.  It is such a time saver.  Let’s take one example in particular.  Just think about for a moment one of the most time consuming tasks you will ever do.  Server maintenance.  With PowerShell and Pester, no more will you painstakingly remote into every server to verify that the correct services are running.  No more will you open a web browser to verify that the site loads.  With a little bit of up front work, you will run a single command and check every server you have in minutes.  Yes, I said minutes.  I’ll give you a moment to let that sink in.

A little back story.  In my endless search of PowerShell information, I came across something called Pester.  What is Pester you ask?  Pester was designed to give PowerShell developers a way to do test driven development.  What it does is evaluate the result of a command or set of commands.  The evaluation will either pass or fail and give a visual representation of that pass or fail as either green, or red.  Very interesting.  In doing some more searching on Pester itself, I came across a blog post from last week showing how they were using Pester to do operational validation on their SQL server.  Even more interesting.  Seeing as how I just did server maintenance the weekend before that and it takes roughly an hour+ to verify everything is good after rebooting all the servers, the pain was still fresh in my memory.

First thing was first, get Pester installed.  Fortunately, I’m running Windows 10 now on my work laptop and Pester is preinstalled.  It was a sign.  Opened up PowerShell, created a new directory for my validation test and created my first Pester fixture.

New-Fixture -Name server

This will create two new files:
server.ps1
server.Tests.ps1

If you open up server.ps1, you’ll notice that all that is there is an empty function named “server”.  This file must remain in the same directory as the server.Tests.ps1 file otherwise when you go to run your pester tests, it will throw an error.  Found this out the hard way.  Best thing to do is try to ignore the fact that there is an extra file.  It isn’t needed for our purpose.

Opening up the server.Tests.ps1 file, you will see the following.

$here = Split-Path -Parent $MyInvocation.MyCommand.Path
$sut = (Split-Path -Leaf $MyInvocation.MyCommand.Path).Replace(".Tests.", ".")
. "$here\$sut"

Describe "server" {
It "does something useful" {
$true | Should Be $false
}
}

Always leave those first four lines alone.  We are concerned with the rest of it to configure our tests.  Just to see what happens, from within the directory containing our test, let’s test it.

Invoke-Pester

You will immediately see a block of the dreaded PowerShell red text.  Let’s take a look at what it actually is telling us compared to what the file had in it line by line.

The first thing Pester tells us when we run our test is “Describing server”.

Describe "server" {

Ok, so now we know where that comes from in the test file.

The next thing Pester tells us is “does something useful”.

It "does something useful" {

So far so good.  The rest of what Pester is telling us is that it was expecting false but got true.  This is explained here:

$true | Should Be $false

With me so far?  This is where the fun part begins.  Let’s just say that we want to verify that BITS is running on our server.  This is what we would change in our test file.

It "The BITS service should be running." {
(Invoke-Command -ComputerName server {Get-Service -Name bits}).status |
Should Be 'Running'
}

Now, when you “Invoke-Pester”, it will show a pretty green line of success.  A couple of things to take note of.  I placed the entire command in () because we needed to pipe the status of the object returned by the command(which in this case was a service object, we just as easily could have checked the .name of a get-aduser object).  The last line reads just like it says.  The status of the bits service “Should Be ‘Running'”.  We are telling Pester what to verify.

I have created all of my base tests for services as well as port connection for my servers.  A good example of a port connection test is for a file server.  You know that it will need to answer requests via SMB.  So add another test to the test file for that server.  Make sure you add the -InformationalLeve Quiet so it only returns $true or $false.

It "Should accept connections on port 445(SMB)." {
Test-NetConnection -ComputerName server -Port 445 -InformationalLevel Quiet |
Should Be $true
}

I think you get the idea now.  Any kind of information you can grab with PowerShell, you can verify.  For example, this could be a basic test file for a SQL server.


$ComputerName = 'SQLServer'
$Session = New-PSSession -ComputerName $ComputerName

Describe "SQLServer" {
It "Should be listening on port 1433(SQL Server)" {
Test-NetConnection -ComputerName $ComputerName -Port 1433 -InformationLevel Quiet |
Should be $true
}
It "Is SQL Server running?" {
(Invoke-Command -Session $Session {get-service -name MSSQLSERVER}).status |
Should be 'Running'
}
It "Is SQL Server Agent Service running?" {
(Invoke-Command -Session $Session {get-service -name SQLSERVERAGENT}).status |
Should be 'Running'
}
}

Remove-PSSession -Session $Session

One thing I’ve learned in the very short time learning/using PowerShell.  Create a variable for anything you will use more than once in a script.  Also, if you need to run multiple commands on a single remote machine, create a PSSession for it.  The commands will run faster.  It doesn’t seem like much of a gain on these small scripts, but if you have a very large test file with tons of commands being sent to the remote server, the speed gains add up.  Especially if you are going to run tests on 10s to 100s of servers(see below).  Also, create a separate Pester fixture for each server.  This way you can test one server if you need to.

Invoke-Pester -TestName server

This will run Pester on just that one test file.  If you “Invoke-Pester” without any arguments, it will run every test file in the current directory.

The last little thing I will leave you is this.  Let’s say that you want to add many services to test with Pester.  I wrote a small script that will basically generate the test code for Pester for services.  It dumps it to a test.ps1 file which you can then manually copy and paste into your actual test file.  This could probably be better to be more automated, but as I haven’t been using this very long, it was a good start and did save me a ton of time.

$Services = get-service -DisplayName sql* -ComputerName server | where status -eq 'running'

Remove-Item -Path "C:\Scripts\test.ps1" -Force

foreach ($S in $Services){

$DisplayName = $S.DisplayName
$Name = $S.Name

$test = "It `"Is the $DisplayName service running?`" {
(Invoke-Command -Session `$Session {Get-Service -Name $Name}).status |
Should Be 'Running'
}"

$test | Out-File -FilePath "C:\Scripts\test.ps1" -Append

}

As always, any tips, comments, feedback, or questions are welcome.  Thanks for dropping by and I’ll see you soon.

Let’s Talk Some Powershell