Search
Linkup
Powered by Squarespace
What Im Reading
  • Stuff Christians Like
    Stuff Christians Like
    by Jonathan Acuff
  • Daemon
    Daemon
    by Daniel Suarez
  • Freedom (TM)
    Freedom (TM)
    by Daniel Suarez
  • The 4-Hour Work Week: Escape 9-5, Live Anywhere, and Join the New Rich (Library Edition)
    The 4-Hour Work Week: Escape 9-5, Live Anywhere, and Join the New Rich (Library Edition)
    by Timothy Ferriss
Sunday
Jun062010

Powershell for the Intermediate Programmer: Part 2a

Anyone familiar with the NIX variety of operating systems is aware that at the bash prompt you are able to pipe the output of one set of commands to another.  With Powershell, this functionality has finally come to windows without the need for using GNU tools or NIX tools compiled for Windows.

The ability to pipe results to other command does a few things.  The first is that it reduces complexity of scripts, reduces the number of times variables have to be used, and increases efficiency.

Before going any further with Powershell it is important to get this concept down.  The idea of piping commands has been seen if you’ve seen any of my other Powershell posts.  In fact, the line of code I’ve used it in before is

foreach($item in gci “c:\users” | where-object {$_.PSIsContainer})

Lets break this down. 

If we look at the two components of the script we see that on the left hand side, its getting all items under the c:\users folder using the GCI command discussed earlier.  It then passes the results of this command, without using a variable, to the right hand side of the pipe.  This second command takes the list of items returned from the previous command and only returns those items which fit the condition, in this case, only items which are folders.

Another example of this is used in exchange all the time to find out who is the linked master of an email account.  The command is below.

Get-Mailbox –identity “paul.e.dearment.jr@imaginarydomain.com” | select linkedmasteraccount

What this does it gets all properties of the mailbox paul.e.dearment.jr@imaginarydomain.com and then passes it to the select command.  Using the select command, you can specify exactly what information to return instead of returning all information using just the get-mailbox command alone.

This is an important concept to grasp at.  When piping data, the piped information is not necessarily just strings, but can be objects or arrays of objects as well to be processed by the next command.  Just like NIX,the output of the piped commands can be piped into other commands.  For example the following command will return five items as an end result. Lets look at the command:

Get-Process | sort –property WS | select –Last 5

The breakdown and the sequence of the commands is broken down below.

  • The Get-Process command returns an array of objects of all the processes currently running on the computer.  The output of this command is shown below.  Notice how none of the columns are sorted in this output.

  image

  • The second step of this command is to pipe the above output to the sort command.  The sort command, second in line, will sort the array of objects sent to it by the value in the WS property of each of the objects in the array.  The output is shown below.  Notice how the WS column is now sorted in the below output, where the original data was not sorted.

image

  • The results of the sort command is then sent to the select command.  The select command takes the sorted list of items and then selects only the last five items from the list and then outputs these items to the screen.  To see that I am not lying to you, I have included the end of the previous command as well as the output of the full command below.  If you notice, only the last five items from the list are displayed

image

 

 

This is just a basic example of piping commands, but shows how it makes it easy to quickly gather, sort and work with information without having to store each piece of data in a variable.

 

Pretty simple huh?

Friday
May212010

Basics Of Powershell for the semi programmer: Part 1a

Received only one question last week, but before going onto the next segment I wanted to address this one.

The question is as follows:

however for using partial folder paths that do not include the drive name, is there a way to set the variable to a string/path?

for instance:
$docs1 = C:\users
$docs2= (not sure how to declare it, but for instance a user name) - basically all the folders in c:\users, but not subfolders
$docs3= “\AppData\Local\Microsoft\Windows\Temporary Internet Files"

that way you could have a loop go through each folder in c:\users,

Thankfully, there is a very simple way to do what you are wanting to do.

Here is what we will need to do:

1) get a list of all users on the computer

2) delete all files in Temporary Internet Files

3) move on to the next user until we don’t have any more

So lets break it down.

Step 1

lets get a list of all user profiles on the computer:

The first command we will need is:

$docs1 = gci “c:\users” | where-object {$_.PSIsContainer}

note that this will only work for vista and windows 7.  To get this to work for Windows XP you will have to navigate through the c:\documents and settings directory.  Pretty simple switch to flip based upon the operating system executing the code.  Since we are not using the recurse parameter, it will only return the items which are immediately a part of the directory.  The last part of the code - 

|where-object {$_.PSIsContainer}

This bit of code will take the returned items from c:\users and then only return items which are container objects, or folders.  This way you do not attempt to run any code against a file which may happen to be in c:\users.  You can leave the last bit of code out, but when you run the script you will see some errors appear on the screen.  Nothing will be damaged, it just looks bad to see a bunch of red text scrolling on your screen.

Step 2

Create a loop to go through all of the users profile.  The following will just output to the screen the full path to the temp files based on usernames

foreach($item in $docs1)

{

     $path = “c:\users"+$item+”\AppData\Local\Microsoft\Windows\Temporary Internet Files"

     write-host $path

}

STEP 3

Now to get it to delete the items we will need to invoke the remove-item command.  This is akin to the delete command from the old days of the command prompt.  If we combine this with the loop we can remove all temporary internet files from internet explorer quite easily.  One thing that we have to be careful of when invoking the remote item command is that you can accidentally delete the directory you are working in.  If you look below, the path variable has been expanded to include \* at the end of it so it reads as

$path = “c:\users"+$item+”\AppData\Local\Microsoft\Windows\Temporary Internet Files\*”

By doing this, you prevent the actually Temporary Internet Files folder from being deleted, although that is not that big a problem for this folder, but for other folders it may be an issue in the future.

foreach($item in $doc1)

{

     $path = “c:\users"+$item+”\AppData\Local\Microsoft\Windows\Temporary Internet Files\*”

     Remove-Item -path $path -force -include “*” -recurse

}

Notice that there are a few switches/parameters which are called with Remove-Item.  

The -path switch indicates the path which the command will need to be run against.  In this case, it is where the temporary internet files are located at.  

The -force command is essential for scripts like this. Any files which are hidden or protected system files will not be visible to powershell and the gci command or other commands unless the -force switch is applied.  The force switch forces powershell to enumerate these items to the screen or the commands which are running (such as Remote-Item).  

The -recurse command forces the command to look at all subfolders.  Like GCI, by default, the command will only show the first level of items tbe they folders or files unless the recurse command is called.

The -include command tells the command what it can delete.  Wildcards are permitted with this.  So if you wanted to delete only text files from a directory (or subfolders of the directory), then you can use -include “*.txt” to delete only files which have a .txt extension.  This allows the remove-item command to be as broad or as granular as you want on what it deletes.

If we combine our first command with the second set of commands, we get the following small script which deletes all temporary internet files for all users on a computer, provided they have powershell installed on their computer and execution-policy for powershell is set correctly. When you run this, if you are logged in, you will see some error messages scroll along the screen, but these can be ignored as they are related to files which can’t be deleted(index.dat, other files in use currently) or to files which can’t be delated due to the permissions of the current user.

The final basic script is below:

foreach($item in gci “c:\users” | where-object {$_.PSIsContainer})

{

     $path = “c:\users"+$item+”\AppData\Local\Microsoft\Windows\Temporary Internet Files\*”

     Remove-Item -path $path -force -include “*” -recurse

}

There you go, you can now delete all internet explorer temporary files in vista or windows 7 with powershell!

Friday
May142010

Basics Of Powershell for the semi programmer: Part 1

Whenever attempting to learn a new programming language, I have always found the most daunting tasks are those first few scripts/commands which are attempted to run.  I have found that the best way to learn these new languages is to not only read over the syntax documentation but to also to work with some basic examples.  That is the goal of what I want to accomplish.  I want to provide a series of documentation which provides a solid basis and reference for using Powershell, from the basics of looking for files to the advanced manipulation of databases and Active Directory.   I do not want it to be a directory of commands, but instead a resource to build upon.  I hope to provide more than just commands, but a way to structure commands in an order which provides multiple small utilities that independently are useful and linked together are even more useful.

Before we begin, you will need a few items installed on your computer.  For starters, you will need Powershell 2.0.  If you are running Windows XP or Windows Vista, you will need to visit Microsoft’s site to download the software: Microsoft Powershell 2.0  If you are running Windows 7, you are in luck.  This operating system comes with Powershell 2.0 installed.

The second piece of software you will need installed to help with the scripts is called Power Gui.  Power GUI is nice in that it allows you to type and run your scripts without having to re-type the commands each time as you would have to do if you entered the scripts in the command line.

The next thing that needs to be covered is variables in powershell.  All variables are named with a $ in front of the variable, so for example, if I had a variable named test_variable I would use $test_variable as the variable name in powershell.  With powershell, by default, variables are not limited by typecasting and needing to declare the type of variable ahead of time.  There are a few times, however, when this rule is broken, but for the majority of the times, you can use a variable without declaring it ahead of time or declaring the type of data which will be stored in it.  Most people who program for a living will probably pull their hair out over this little “feature” but it makes writing scripts quicker.  Variables in powershell are capable of holding not only a value, but objects as well.   This is important to remember as this affects how we get data out of a variable.

So with that out of the way, lets learn a little powershell.

Commands covered: gci, write-host, get-date, cls, foreach

Topics: Loops, variables, objects

Difficulty: 1

With this lesson, for the final script, I am assuming that you have some concepts of programming including knowing the concepts of variables, basics of loops, and a basic understanding of objects.  If you do not, the concepts covered here may not make total sense, but over time Im sure you will grasp the concepts.

Goal: To create a script to list files which were created before or after a set amount of days from the current date.

Part 1 : Lets define the commands

CLS: Clears the screen of all output.  Often good to use at the start of a script to confuse output from previous run.

GCI: This has multiple uses, but in the context of searching through files, it retrieves a list of all items under the parent directory list.

Write-Host: When working in the command line, Write-Host writes some text to a screen.  This may be a predetermined message, the results stored in a variable or a host of other information which you need to display on the screen

Get-Date: Returns the current system date.  This can either be stored in a variable or displayed directly to the screen depending on how its used

For-Each: Enumerates all the objects in a variable and processes each one.  Depending on what your goal is, you may run a command on each object, or you may run the value of the object through conditional statement to determine if any code is to be run.

if: Basic logic operator

gt: Basic comparison operator for greater than

fl: The alias for format-list which is used to control output to the screen.  This is one of the more powerful built in powershell commands.

Part 2: Basic usage of the commands

Each of the commands has both some simple and complex uses.  For today’s purpose, we are going to go over the simple uses of the commands.

Use of cls:

CLS is by chance the simplest command to use.  CLS clears the command line of all output currently on the screen.  This is useful so that if you need to re-run a script multiple times, you can clear the screen and prevent confusion on which iteration the output belongs to.  CLS is used on the line by itself, with no parameters needed

Use of GCI:

One of the more powerful features of powershell is the use of the alias feature.  Aliases allow for you to use a shorter command name on a longer complex command.  For instance, the alias GCI is equivalent to typing out Get-ChildItem.  GCI is just simpler to type and use multiple times.  By default, without being used in other commands, GCI returns all the items under a parent directory which is provided as a required parameter for the CMDLT.  For example, I store all of my scripts on a drive with a drive letter of U in a folder named powershell.  If I wanted to list all of my files in the directory, I would run the command:

GCI “U:\powershell”

This would result in a listing of all the files in that directory.  Any directories would be listed in there as well, but the contents of those directories would not be listed.  That can be accomplished by using a switch, but we will cover this in a later segment.

You can also store the returned list to a variable.  If you do this, then an array of objects will be stored in the variable.  You can accomplish this by using a command similar to the following:

$test_variable = GCI “U:\powershell”

While you can store data in a variable any time you like, it may not always be the optimal thing to do at the time.  As you use powershell more and more, you will be able to spot over time in which incidents it is best to use a variable and when it is best to call the actual command instead of the variable. 

Use of Write-Host:

Whenever you need to write some output to the screen, it is best to use the write-host command.  There may be some times(such as outputting error messages) that you may need to use other commands, but in general you will use the write-host command to display the necessary information to the screen.  The basic use of this command is simple as well. 

For instance, if you wanted to write to the command line the phrase “This script has come to an end” you would insert the following command at the specific point you needed to write the output:

Write-Host “The Script Has Come To An End”

This is nice and simple to use, but sometimes you need to return to the screen the results of the script you just ran.  In these instances, you can replace a variable as the required parameter for Write-Host.  Lets say in this case that we define a variable ($test_variable) as being equal to the result of a math equation and the final value stored in the variable is 180.  To output this to the screen, we would use the following command:

Write-Host $test_variable

This will result in a line written to the shell with the value of 180.  Write-Host is not limited to just outputing either a literal string or a variable, but can do both on the same line.  So for example, assuming that $test_variable still is equal to 180, and we run the command

Write-Host “Number in box:” $test_variable

The resulting output to the screen will be - Number in box: 180

There are ways to customize this output, but that will be covered at a later time.

Use of Get-Date:

 The Get-Date command queries the date of the local computer.  The returned date can be formatted in different ways, as well as specific parts(month, day, year) can be pulled out from the command as well.  This will be covered in a later post.  For now, the Get-Date command can be issued to retrieve the date as needed.  You can store the date in a variable or use it in a command at runtime.  The use of the command, as were running it not, is:

Get-Date

Use of ForEach:

ForEach is one of the basic loop commands in powershell.  First lets see an example of the use of the command then go through it.

foreach($item in GCI “U:\powershell)

{

As mentioned before, the results of the GCI command returns an array or objects.  Each object in the array contains many attributes which can then be exposed.  The only problem is that when the array is declared in this way, we can not access the individual item.  To get access to those items, we can go through each object in the object array.  The foreach command assigns a specific item(the current item in the array) to the $item variable.  All the commands that then take place between the {} after foreach apply only to that one object.

Lets say I run

GCI “U:\powershell”

And I got the following output

U:\powershell\personal_email_disable.ps1

U:\powershell\compare_ad.ps1

U:\powershell\IN_WebAR.ps1

On the screen, you see just the list of items.  You do not see all the other attributes associated with the objects printed out on screen.  If you run the above foreach command example combined with the GCI command:

foreach($item in GCI “U:\powershell”)

{

<code>

}

What this would do is run and get the previous output as before, but store it in memory for use in the loop.  This would allow quick access to the data for use in the commands.  So if we were to follow the loop, the first time running through the code inbetween the {} we would run it against the value of $item being equal to U:\powershell\personal_email_disable.ps1.  Each successive run would go down the list as to what value is assigned to the variable $item. 

If and gt

The if statement is a basic logic statement used to determine what actions are to be taken next, if any, depending on the data contained in the () after the if statement.  When using if, you will often use comparison operators such as gt(or greater than).  Comparison operators are always used with a dash in front of them.  The basic comparison operators are greater than(-gt), and less than(-lt).The portion of the script that is then run if the condition is true is contained in {} after the if statement.  For example, if we wanted to only perform the write-host command whenever $test_variable contained a value which was greater than 180, we would issue the following command in our script

if($test_value -gt 180)

{

     write-host “Value is greater than 180”

}

Use of fl:

The fl command is used to control how output is seen on the screen.  The data to be used by the fl command is piped into the it by using the | between the data and the fl command.  So for example, if we choose to run

GCI “U:\powershell” | fl

We would get output similar to the following.  As you notice from each of the items, it contains multiple properties.  These are the properties of the object currently being used.  More about this below.

Part 3: Necessary Concepts

If you are a familiar with using the .NET framework, the concept of an object containing multiple parameters is nothing new.  If however, you have never used the .NET framework, this can be confusing the first few times you run into this concept.  Remember how I said that the command GCI returns an array of objects into a variable or memory.  Before when we referenced the variable, we used only the basic information of the object.  If we wish to perform more complex operations(such as comparing creation times) we need to expose the properties of the object which we are currently working with.  Using Powergui and the powershell command line makes this step easy, but until you use it a few times its function may remain a mystery. 

Lets use our above code example again but expand it a little.  For now, don’t worry abou trying to deceipher the code on the right hand side of the -gt command.

foreach($item in GCI “U:\powershell)

{

     if($item.creationtime -gt ($(Get-Date).AddDays(-15)))

In this above example we see that in the if statement a comparison is run against $item.creationtime.  Until now, we have not seen anything reference this, except when mentioning the fl command.  The fl command exposed all the properties of an object in order for us to see these items.  We can look and see that the objects returned by the GCI command have a creationtime property which contains date data.  We can get access to the data stored by the object by referencing the object and property in combination such as $item.creationtime.  If you look at the screenshot above and see what other commands are available, you see that you could also run $item.name, $item.lastwritetime, $item.length, etc.  Any of the exposed objects is available for using. 

In our above example, we are comparing the creation time of the currently selected object against the date to the right of the -gt.  If you notice, there is a weird syntax next to Get-Date.  The synax is ($(Get-Date).

By putting the command in in this way, the command is turning the segment $(Get-Date) into a variable which houses the Get-Date object.  This allows you to work with and manipulate objects on the fly without having to declare them in variable first.  Running the code listed above:

($(Get-Date).AddDays(-15))

Is the same as running the following code:

$date = Get-Date

$date.AddDays(-15)

Its cleaner and simpler to include the object in one line than dividing the data up into two lines.  With our modern computers, there shouldn’t be a performance hit which is large, but the simplification of the code should be more than enough to use this approach on a normal basis.

Now just as objects have data properties which are exposed when working with them, objects also can have commands which can be exposed against them.  Powergui, and to a lesser extent the Powershell shell, give you the ability to see what commands can be run against an object.  For instane, if we run the following command:

$date = Get-Date

We receive a variable containing an object with the data Get-Date returned.  If you type in your powershell window

$date.

You can then hit the tab buttn.  Each time you hit the tab button, the words after the period will change.  These are the commands or data which can be run/are exposed on the object. In this case, one of the commands is .AddDays() which accepts as a parameter in the () the number of days to add or subtract from the date held in the object returned from the Get-Date command.

Part 4: The Script

With all of these concepts you now have the necessary tools to create a script which will list all of the files which were creted less than fifteen days ago.  Below is the code on how to do this, as well as a brief explanation for each of the lines of code.  In powershell, the # denotes a comment in the code which is not processed.  You can copy the below code segment and allow it to run while keeping the notes in tack.

#clears the screen of all previous output

cls

#gets a list of all items in the U:\ drive and then runs

#the for each loop against each object in the object array

#in memory.  It assigns the value of the currently

#selected object to $item

 

foreach($item in gci u:\)
{

#Comparing the creation time of the currently selected object. 

#If the creation time is greater than the date on the right hand

#side(which is the current date minus fifteen days, then the

#code contained in the {} will be executed

    if($item.creationtime -gt ($(Get-Date).AddDays(-15)))
    {

      #The full file name, including the path, is written of

       #the selected object in the object array.  This is only

        #performed if the if statement is validated as true
         Write-Host $item.fullname
    }
}

 

This may seem a little complex at first, but study over the script and the various components and over time they will start to make sense more and more.  This is only the beginning of the journey through powershell, so brace yourself for a ride.

I hope you enjoyed and learned something from this longer than anticipated beginning tutorial to powershell.