Monday, April 2, 2012

Month of Lunches - Day 17


Day 17 - You call this scripting

Today we get into PowerShell and scripting with PowerShells Integrated Scripting environment or ISE. So far we have been using single line commands and lthough they are powerful there is a lot more we can do. If the shell prompt is like a new world opened up to us, then the ISE is like the final frontier.

Don likens basic PowerShell scripting to writing a batch file, and he is correct. Basic PowerShell scripts are nothing more than a series of commands written one after the other that run in sequence. We can link anything that we have learned so far (as long as there is a reason for the madness) into a couple of lines of PowerShell code in the ISE script pane and save it as a PS1 file (PowerShell script file). We glossed over the ISE and what it is in a little bit in the first couple of chapters. Just a couple of notes on the ISE. It has a couple of really nice features such as tab completion (same as in the command shell), script color coding to make it easier to read, and run all or just a portion of the code you have written with the click of a button. Here is an example I wrote during this learning process:

                $computerSystem = Get-WmiObject win32_computerSystem
                write-host -NoNewLine "Computer Manufacturer: "
                Write-Host -ForeGroundColor red ` $computerSystem.manufacturer
                write-host -NoNewLine "Computer Model: "
                Write-Host -ForeGroundColor red ` $computerSystem.model

Basically what this is (and I reset it to lookup the local host information) is a way to return the manufacturer and model. The -NoNewLine parameter just makes the information return on the same line as the title. Just for fun I returned them in red.

In this script I would have to define the variable but say I wanted to give it out for someone else's use. The next section of the book covers parameterizing commands. It would be a simple change to Get-WmiObject to have it looking up remote PC's from text files, csv files, or return result queries, but if you paramatize it then you don’t have to worry about it. Like so:

                param (
                    $computer = 'localhost'
                    )
                $computerSystem = Get-WmiObject -ComputerName $computer win32_computerSystem
                    write-host -NoNewLine "Computer Manufacturer: "
                    Write-Host -ForeGroundColor red ` $computerSystem.manufacturer
                    write-host -NoNewLine "Computer Model: "
                    Write-Host -ForeGroundColor red ` $computerSystem.model

Now you only need to save this file under whatever name in whatever directory you want ( in this example C:\Man_Mod.PS1) and use the -computer parameter to specify which one you want. now you can change directory to the C: drive and run:
               
                .\man_mod.ps1 -computername *Whatever you want*

And it will run basically just like as if it was a cmdlet. Now notice that the script file is preceded with a .\ and this annotates for the shell to look in the current folder for a script file (which you specified by name. All scripts that are run in the shell must be preceded with the .\. Now im sure there are easier ways to do this (as with everything in PowerShell) but this is the one that worked for me.
                                                                                                                                                                                              
The next section is documenting your script. This is something that is very important to me as a person who is not good at writing his own scripts (YET!). Knowing what the script is doing and how makes it very easy to see what is going on, how to modify to get the results you want, and (if you’re a visual learner like me) learn how to put a script together.

The last thing that we covered today was PowerShell scopes. Each PowerShell session has its own scope and child scopes that are created when a script or command is run. These are created by other elements of PowerShell, aliases, variables, or functions (which we haven't learned about yet). These elements will search for whatever they are looking for inside there own scope first, if they don’t find what they want they will go to there parent scope. They will continue up the line until they either find what they want or run out of places to look once they reach the PowerShell session scope otherwise known as a global scope. They will not look into other sibling scopes for information.


Month of Lunches - Day 16


Day 16 - Input and Output

Today's lesson delves a little deeper into the how to get the most out of your information in PowerShell. It's all about input and output.

First up is Read-Host. This is used to prompt and collect input during a command or script and can be very useful. These inputs are done at the Shell prompt except for in the ISE, which is done in a GUI box. For example try this:

                Read-Host "Enter a computer name"

On the following line you will be Prompted with "Enter a computer name". Pretty cool. Place it in a variable ($PC = Read-Host "Enter a computer name") in a script that runs in the ISE and you will be prompted every time you run the scripts. Always want it to prompt you with a GUI box! Dons got you covered. It gets a lot trickier, and this is a two parter. The first part calls the portions of the .NET Framework required to make the box and loads it. The second part is actually the creation of the GUI input box from that .NET framework piece.

                [void][system.reflection.assembly]""LoadWithPartialName('Microsoft.VisualBasic')
                $computername = [microsoft.visualbasic.interaction]::inputbox('Enter a Computer Name','Computer Name','localhost')

In the second command you will notice the three parameters (Name, Computer Name, and Localhost). These can all be changed. The first is the Text of the prompt itself. Second is the title of the GUI box. Third is the default value you want to be in the input box (you can leave this parameter blank if you like).

The next cmdlet we covered is Write-Host. You can pretty much guess what this one does by the name. It writes data and values to the hosts screen. The cool thing about the cmdlet is its ability to change forground (text) and background colors of the output. For instance:

                Write-Host "STOP" -Foreground Black -background red

The Last major cmdlet we covered here was Write-Output. This command as it turns out is one of PowerShells default cmdlets that gets processed behind the scenes. This command as well as the previous command puts the input into the pipeline. Write-Output however does not allow formatting of text like Write-Host.


Wednesday, March 21, 2012

Month of Lunches - Day 15



Once again Don nails a chapter title. Today we are learning about variables and the different ways of working with them. In my past with PowerShell and working with other peoples scripts I can see that variables can and are used as a primary means of storing not only objects but also commonly used commands within a script.

To create a variable in PowerShell you need only declare a variable name preceded by a dollar sign ($) and then follow it with an equal sign (=) and what it contains. Lets give it a try.

                $computername = 'server1'

You just created a variable with server1 as its object. You can store multiple objects or collections into a variable as well.

                $computername = 'server1','server2','server3','localhost'

Now to recall the objects within the variable simply type the variables name.

                $computername

In your console you will see a list of all the objects stored within the variable. With the preceding example there is also something else that we learned in this chapter. Notice the single quotes around each name. This denotes to PowerShell that what is contained inside those single quotes is a literal string. This was a little confusing to me so I went over the examples in the book several times to make sure that I had it. Here is the example:

                $var = 'What does $var contain'
                $var

The output you will see on this is the string "What does $var contain". The second part of this example is what makes this make sense.

                $computername = 'server-r2'
                $phrase = "The computer name is $computername"
                $phrase

The output here will show "The computer name is server-r2". Give it a try. If we were to have enclosed the $phrase text string in single quotes the output would have been exactly as we had typed them, The computer name is $computername. Something to remember here. If you use a variable inside of another variable, as soon as you hit enter to store it, it parses it and stores that as the variable. If you happen to change the original variable, in this case $computername, the output of the $phrase would remain the same, The computer name is server-r2.

The second thing I found very useful in this chapter was the use of the backtick character. The backtick is an escape character in PowerShell. Basically it removes the Special meaning of other characters or adds special meaning to the characters following it. Here is the book example:

                $computername = 'Server-R2'
                $phrase = "`$computername contains $computername
                $phrase

The output of this variable will be "$computername contains Server-R2". Notice the first instance of the variable was not processed but the second was. That is because the backtick removes the power of the dollar sign to parse a variable.

Ok so you can store one or more objects in a variable, how is this useful. With the examples from the book we were simply using string values but in the lab work we take that a step farther. We are asked to pull information from the win32_Bios class for two computers stored as a variable and run it as a background job, receive that job information into a variable, View the variable, and then export that as a CLIXML document. Here is how I did it using variables and some of the other stuff I have learned along the way.

                $computer = 'mycomputername','localhost' (I only have one computer for this)
                $job = get-wmiobject win32_bios -computername $computer -asjob
                $biosinfo = Receive-Job -job $job
                $biosinfo
                $biosinfo | export-CLIXml -path c:\powershell\Bios_Info.xml
                import-clixml -path c:\powershell\bios_info.xml

Just to verify I imported the info to ensure it was stored properly. Variables can be pretty powerful stuff in PowerShell as you can see. There is so much more to learn about variables but I just don’t have the space today. I believe I will revisit this in another post. Until tomorrow, happy powershelling

Tuesday, March 20, 2012

Month of Lunches - Day 14


In this chapter we are going over Security in windows PowerShell. Here we learn about the default security settings, how to manage PowerShell with them, and the ramifications of what PowerShell can do.

First and foremost Don points out that with the design of PowerShell security was of the utmost importance. This was well thought out and implemented within PowerShell. In essence if you cant change a setting with the GUI then PowerShell will not change that. Now as with anything there are ways around this but its like the ages old adage says, "It keeps Honest People Honest".

By default PowerShell does not allow for the execution of script files. That’s right, a scripting environment that will not allow you to run scripts by default. You can type standard commands in the console without issue however. This is set by the Execution Policy. If you try to run a script what you will see is an error message stating "The execution of scripts is disabled on this system", and in order to change the Execution Policy you must be an administrator on that piece of hardware. To change the execution policy PowerShell provides a cmdlet that is as simple to guess as most of the others, Set-ExecutionPolicy, and there are five different Execution Policy settings that can be set to. These are listed below.
                Restricted - This disallows the running of any script on that particular system. Keep in mind this does not mean that you cannot collect data from that machine with                                                                 PowerShell it only means that the scripts cannot physically run in the shell on that machine.
                AllSigned - This setting will allow the running of scripts that are digitally signed by a Trusted Certification Authority.
                RemoteSigned - Setting your PowerShell to this setting will allow any script that is run locally on the machine but as in the previous setting any remote script will need to have a certificate from a Trusted CA to run. This is the Microsoft recommended security level to allow the most functionality with the least restrictions.
                Unrestricted - This setting is actually the least restrictive and will allow for both local and remote scripts to run on the host.
                Bypass - The last setting is primarily used by Programmers as a way to integrate PowerShell within their application. It bypasses the execution policy entirely.

Don mentions two other security measures that are implemented by default within PowerShell. The first of which is file association. This is not so much a security restriction in my mind, as it is just general good practice. The default file association for the .PS1 file extension, which is a PowerShell script file, opens these files in Notepad or the default text editor. The second thing PowerShell does is not allow for scripts to be launched from within the shell simply by typing its name. For instance if you had a script file named Get_Services.PS1 on the root of your C: drive you could not run it simply by going to the root of C: and typing Get_Services.PS1. In order to run scripts from the console you have to preface the filename or path with .\ (dot Backslash).

That’s the basics and there is plenty more to cover on this topic including Active Directory group policy settings, ways to create your own certs or use locally asigned.

Month of Lunches - Day 13


In this chapter we are going to cover working with bunches of objects. This allows for the management of multiple PC's, services, or anything else to be managed across multiple computers with a single script or command. Don refers to this a Mass Management and it’s a very good interpretation of what you are doing.

There are a couple of different ways to accomplish tasks such as this. The first of which is the very basic ability to pipe objects from one cmdlet to another. For instance this example has come up in multiple chapters, but PLEASE DO NOT RUN THIS (unless you want to crash your computer).
               
                Get-Service | Stop-Service

Very simple what this command is doing is piping a collection of objects (in this case service objects) to the Stop-Service cmdlet and stopping them. This can be done with almost any of the Get cmdlets. This is the preferred way to work in PowerShell. If there is a cmdlet, use it. Don’t reinvent the wheel.

Sometimes cmdlets are not available and you have to find other ways to gather data and perform tasks against it. This is the case with WMI, and we covered this in more detail in chapter 11. Don uses a reference in the book of changing network configuration settings but a lot of the WMI objects have methods that allow for properties to be changed. You only need to know how to query for the information on your local as well as remote workstations and then pipe that information to the Invoke-WmiObjects to change the properties of that setting. This can be invaluable.

The next section is where things start to get a little trickier, especially for those of us that have no scripting or programming background. Enumerating of objects with the Foreach-Object cmdlet. Off to the help file I go and after about an hour of playing in my shell, reading the help, and web searching I think I have a better grasp of it. Basically it is a loop that checks each object of a collection and runs a command or set of commands that you designate. To put this as simply as possible here is an example from the help file.
               
                1, 2, $null, 4 | ForEach-Object {"Hello"}

What this will do is actually look at each string or variable as an object and display "HELLO" everytime it finds something. So what you will get as an output is: Hello, Hello, Hello, Hello. Imagine the possibilities of what can happen with this. I am still looking up info on this and ways that it can be used. Looking at scripts from my co-worker and basically anything that will be performed against multiple machines, accounts, services, etc… uses this method.

I Still have so much to learn and so far to go, but im loving every minute of it. Have a great day and happy powershelling. 

Month of Lunches - Day 12


So everybody wants to be more efficient with their work as well as at home. This chapter should help me solve at least half of that problem. This chapter covers multitasking and background jobs in PowerShell.

Normally with PowerShell you type a command and hit return, then you sit and wait for the command to finish. You cannot run another job until the first one completes. Now you could run a second window but what happens if you have specific modules loaded or have set variables for the task your completing. Or you could run the same command and have it moved to the background. The benefit of running a command as a job is that if it will be running for a while it will allow you to continue to use the shell and store the results for later.

There are some pitfalls that deal with having commands run in the background however. If it is in the background and prompts you for input then that job will not complete and stop eventually because you cannot reply. Running a command in the shell produces error messages for you to see, but background errors will not be visible until the job is retrieved. If the job is run in the shell you will see the display as soon as the command completes, however background jobs will have to be retrieved. And last but certainly not least remember this is not real time data but a snapshot of what was going on at the exact moment the job ran.

There are a couple kinds of background jobs discussed in this chapter. The first of which is a Local Job. A local job runs for the most part, as the title states, on your local workstation. It can request information from the remote PC's if necessary through the cmdlets, but allows your terminal to do the heavy lifting. The cmdlet for this is Start-Job. This cmdlet has a lot of really useful parameters so please read the help file for full details. The following is an example that will start a background job named Local_Process to Get-Process.

                Start-Job -scriptblock {get-service} -name 'Local_Process"

Some cmdlets have the ability to be run as jobs due to parameters. One of the major ones that Don lists is Get-WmiObject. There are others and If you want to see them do help * -parameter asjob.  You may also run jobs in the remoting tools we covered in Chapter 10. The cmdlet to do this is Invoke-Command.

To check the status of running or completed jobs type

                Get-Job

This will display the list of jobs in your current session only however. No previous jobs are cached. Note that when you do this that it displays an ID number, Name, State of the job, and HASMOREDATA column. This column shows if there is data to be retrieved for that job (PowerShell removes the data once the job is retrieved). To retrieve the results of the job you run Receive-Job. With this cmdlet you can bring up the table or list you created in your scriptblock, pipe it to the Format-List or Format-Table for custom formatting, or output it in any other way you like. It’s the same as any regular PowerShell object.

There are many ways to do background jobs, and as with anything in PowerShell, no two people do things alike. Just remember that if your getting your results it's not wrong.

Monday, March 19, 2012

Month of Lunches - Day 11


Today we are covering WMI or Windows Management Instrumentation. WMI is something that I have had some experience with in the past through SMS, CA Unicenter,  and other administrative applications. It opens up a whole new world of information that is ripe for the picking.

WMI is setup in a hierarchical structure similar to almost everything that Microsoft builds. WMI is held in Root\CIMv2. Under that you have the Namespaces. Below the namespaces you have the Classes and each class has a set of properties and methods, and a few other things. Don mentions something in this chapter I was not aware of and that can be a little tricky. Under the different classes there may be multiple instances of that class running for one reason or another (different user accounts, multiple instances of a service, etc…).

Exploring WMI can be a little bit daunting for the average administrator as there is no way of actually searching for anything. What this means is that everything is a hunt for the correct information you are looking for or you can use your trusty search engine.

The tools that you can use to look at the namespaces and properties can make this a little easier. Don mentions one in the book, and it is a good one, called WMI Explorer. It is a free tool that is found on on the www.primalscripts.com website under there downloads section. Now you do have to register for an account to download it, but it is worth the time as there are a lot of other useful tools from Primal that are free. There are also numerous downloads from www.CNET.com if you do a search for WMI Explorer. If you are in a bind and don’t have time to download anything (or cant in some cases), there is a WMI tool built into windows. It is called WBEMTEST, and works in a pinch but is a bit trickier to navigate. You can access this from the CMD prompt or the run box by typing WBEMTEST.exe This is a great article on Technet about its use and can be found here, http://technet.microsoft.com/en-us/library/cc785775%28v=ws.10%29.aspx

How does PowerShell access WMI? There is a handy little cmdlet called Get-WMIObject, or aliased as GWMI. Since PowerShell does not work directly with WMI there is a bit of a learning curve due to the difference in syntax structure and the way the WMI properties are referenced. For instance If you wanted to see a list of all namespaces from your console, type:
                Get-WMIObject –namespace root\cimv2 –list
This is a pretty expansive list but you can filter it if you have an idea of what you are looking for. The Help file will be of much more use than I could be trying to explain it so check it out (Help GWMI –full).

Point of note, PowerShell does not contain any help on the actual properties and methods for any of the classes of WMI. Also WMI has not been very well documented and was generally a use as you want it for the different product development groups within the company. That is until recently and now they are trying to change that. A good bit of information can be had from the Microsoft Developer Network (http://msdn.microsoft.com) now contains a lot of information, although search engines are still a good way of finding specific class info.

One thing I would like to add on here is that in the book Don references a way of showing all the software installed on a given machine with WMI. The class for this is Win32_Product, and can be a very bad thing to use in an enterprise. I have had issues in the past With SMS, CA Unicenter, and administrative scripts that called this class. Basically what this does is cause WMI to look at each software install and perform a Reconfiguration Operation as a way of verifying the application is installed. This will cause this query not only to be slow but is very processor and memory intensive on the servers that you run it against. You can verify this is happening by going to your event viewer under applications (I think), and you will see a Event ID 1035 for every program installed on your system. I would not recommend using this. The Registry is still a much safer bet.

Ill be updating tomorrow, but until then have a great day.