The Script


In our first example we'll create a script that restarts a list of computers. The list will come from a text file that contains one computer name per line. The file name will be specified as a parameter of the script. We're assuming the person running the script is a local administrator on each listed computer. With those basic requirements stated, you'll find the complete script in the listing Restart-Computers.ps1. You can run this script by double-clicking it in Windows.

Security Precautions

You may have trouble getting this script to run if PowerShell is still in its default configuration on your computer. Don't worry about this for now since we'll dive into security restrictions and the reason this script might not run in the next chapter. By default PowerShell is quite "locked-down", to the point that when you first install it, it won't run any scripts at all.

Restart-Computers.ps1

image from book
 # Define input parameters param (   [string] $filename = $(throw "Filename is required!") ) Write-Host "Reading computer names from $filename" # Read file $computers = get-content $filename foreach ($computer in $computers) {   # Connect to WMI   $wmi = get-wmiobject -class "Win32_OperatingSystem" `    -namespace "root\cimv2" -computer $computer   # Restart computer   foreach ($item in $wmi) {     $wmi.reboot()     write-host "Restarted " + $computer   } } 
image from book

So how does this work? Let's look at each line. First, the script defines its input parameters. This is done in a Param block that simply defines the input parameters for a script. Notice that we've specified a specific data type, [string], for the input parameter. Also notice that we've given the input parameter a special default value. Normally, the default value is assigned to the variable if the parameter isn't specified. However, in this case, our "default" is to throw an exception, which means the rest of the script won't run unless the $filename parameter is specified. The Throw keyword simply means "produce an error", and it's followed by the error message we wanted to produce.

If our parameter was specified, we'd just write out the filename using Write-Host. The Write-Host cmdlet outputs whatever you tell it such as descriptive messages. Notice that the $filename variable will be evaluated by PowerShell, and its contents will be displayed because the string it is contained within is delimited by double quotation marks.

 # Define input parameters param (   [string] $filename = $(throw "Filename is required!") ) Write-Host "Reading computer names from $filename" 

Next, we will read the file using the Get-Content cmdlet, which needs the filename. We'll save the results into the $computers variable that will basically be a collection (or array) of string objects, with each string object being one computer name. Recall that the file is formatted with one computer name per line.

Note 

A complete cmdlet reference is provided in Chapter 14.

We'll use a foreach loop to go through the collection of names. Each time through this loop, the variable $computer will represent the current item or computer name. The foreach loop will be covered in greater detail in Chapter 8.

 # Read file $computers = get-content $filename foreach ($computer in $computers) { 

Now it's time to connect to WMI. Since this code is contained within the foreach loop, it will execute one time for each computer in the file. Notice the accent mark at the end of the second line. That character, which is located on the same key as the tilde ~ character on your keyboard, tells PowerShell that the line of code is continued on the next line of the script. In other words, the second and third lines may be two physical lines, but they act as one logical line of script code. The ` character allows the line to be "broken" so it's easier to read-also so that it will fit in this book!

The Get-Wmiobject cmdlet is given the WMI namespace class and computer name. The computer name is in the $computer variable that is populated by the foreach loop. What comes back from Get-Wmiobject is a collection of WMI class instances. In this case, it will only be one instance since you have only one operating system running at a time. However, it's still a collection or list, so we'll store the collection in the $wmi variable.

 # Connect to WMI $wmi = get-wmiobject -class "Win32_OperatingSystem" `  -namespace "root\cimv2" -computer $computer 

Shortcuts

If you look at the help for the Get-WMIObject cmdlet, you'll notice that the correct parameter name for the remote computer is actually -computername, not -computer. PowerShell actually lets you type as little of the parameter name as possible, provided you've typed at least enough to distinguish it from other parameters. In this case, simply typing -comp would actually have been sufficient.

A foreach loop can enumerate any collection including our collection of one contained in $wmi. Each time through the loop, the variable $item will represent the current item from the collection. In other words, $item represents a single instance of the Win32_OperatingSystem class we retrieved with Get-Wmiobject.

Since $item represents a WMI class, it will have all the properties and methods of that class including the Reboot method. Therefore, we'll call that method and write the name of the computer so we know it has been restarted.

   # Restart computer   foreach ($item in $wmi) {     $wmi.reboot()     write-host "Restarted " + $computer   } } 

This is a good time to ask, "How did you know the Win32_OperatingSystem class had a Reboot method?" More to the point, you might ask, "Where did you find the Win32_OperatingSystem class in the first place?" We could tell you that we read the WMI documentation, which we did - but that's not the answer you probably want to hear. That's okay, because we have another answer. This one involves exploring and using PowerShell. We knew WMI could be used for nearly any kind of computer inventory task. We also knew basic stuff like shutting down and restarting computers could be done. So we needed to get a list of all available WMI classes. No sweat:

 PS:> Get-wmiobject -list 

We know this is a long list, but it's comprehensive. Browse through it until you see something that looks likely to have what you need. We actually looked at Win32_ComputerSystem first, but it didn't have a Restart or Reboot method. We eventually found the Win32_OperatingSystem, which does have a Restart or Reboot method. Now you might be asking, "How did you discover that?" The answer is pretty simple. First, ask PowerShell to retrieve an instance of the class. Next, using Get-Member, ask PowerShell to display the type information for the class. Get-Member will be discussed in greater detail in Chapter 4.

 PS > $wmi = get-wmiobject -class Win32_OperatingSystem -namespace root\cimv2 PS C:\> $wmi | get-member    TypeName: System.Management.ManagementObject#root\cimv2\Win32_Ope Name                                      MemberType           Defi ----                                      ----------           ---- Reboot                                    Method               Syst SetDateTime                               Method               Syst Shutdown                                  Method               Syst Win32Shutdown                             Method               Syst BootDevice                                Property             Syst BuildNumber                               Property             Syst BuildType                                 Property             Syst Caption                                   Property             Syst CodeSet                                   Property             Syst CountryCode                               Property             Syst CreationClassName                         Property             Syst CSCreationClassName                       Property             Syst CSDVersion                                Property             Syst CSName                                    Property             Syst CurrentTimeZone                           Property             Syst DataExecutionPrevention_32BitApplications Property             Syst DataExecutionPrevention_Available         Property             Syst DataExecutionPrevention_Drivers           Property             Syst DataExecutionPrevention_SupportPolicy     Property             Syst Debug                                     Property             Syst Description                               Property             Syst Distributed                               Property             Syst EncryptionLevel                           Property             Syst ForegroundApplicationBoost                Property             Syst FreePhysicalMemory                        Property             Syst FreeSpaceInPagingFiles                    Property             Syst FreeVirtualMemory                         Property             Syst InstallDate                               Property             Syst LargeSystemCache                          Property             Syst LastBootUpTime                            Property             Syst LocalDateTime                             Property             Syst Locale                                    Property             Syst Manufacturer                              Property             Syst MaxNumberOfProcesses                      Property             Syst MaxProcessMemorySize                      Property             Syst Name                                      Property             Syst NumberOfLicensedUsers                     Property             Syst NumberOfProcesses                         Property             Syst NumberOfUsers                             Property             Syst Organization                              Property             Syst OSLanguage                                Property             Syst OSProductSuite                            Property             Syst OSType                                    Property             Syst OtherTypeDescription                      Property             Syst PlusProductID                             Property             Syst PlusVersionNumber                         Property             Syst Primary                                   Property             Syst ProductType                               Property             Syst 

This output is a bit truncated to save space. However, basically we retrieved an instance of the class into the variable $wmi, and then piped that variable to Get-Member. That cmdlet's job is to display everything it can find out about an object. In this case, the information includes a full list of properties and methods.

To be sure, we much prefer reading the documentation. In particular, the WMI docs tell you what each method does, which is tremendously helpful.

So that's how our first script works. But let's take a few more minutes and look at some important characteristics of how this script is put together. Here's the complete script one more time:

 # Define input parameters param (   [string] $filename = $(throw "Filename is required!") ) Write-Host "Reading computer names from $filename" # Read file $computers = get-content $filename foreach ($computer in $computers) {   # Connect to WMI   $wmi = get-wmiobject -class "Win32_OperatingSystem" `    -namespace "root\cimv2" -computer $computer   # Restart computer   foreach ($item in $wmi) {     $wmi.reboot()     write-host "Restarted " + $computer   } } 

Notice that the lines starting with # are just comments. PowerShell completely ignores comments. So, comments are just there for our benefit. It's a great idea to thoroughly comment your scripts so that someone else-or yourself, six months later-can figure out what you were thinking.

Also notice how we've used indentation. Within each block, which includes the two foreach loops and the param statement, we've indented the lines just a bit. This indentation visually helps group those lines as a part of one block. When blocks start nesting, such as the second foreach loop within the first, it's easier to tell what code goes together.

Also notice how PowerShell delimits blocks using curly braces. You don't have to put the braces on separate lines as we've done. For example; the following is also legal:

 foreach ($item in $wmi) { $wmi.reboot()   write-host "Restarted " + $computer } 

This is also legal:

 foreach ($item in $wmi) {   $wmi.reboot()   write-host "Restarted " + $computer } 

Other variations are legal as well.

The last major thing we want to point out is that PowerShell allows you to put multiple commands that would normally be separate lines in a script, on a single physical line by using a semicolon to separate them:

 foreach ($item in $wmi) { $wmi.reboot(); write-host "Restarted " + $computer} 

The ; character is nearly the opposite of the ` character since the semicolon tells PowerShell that the second physical line is actually two logical lines of script. We point this out because you're sure to run across it when looking at other folks' scripts and other examples. However, we consider using the ; character to be a poor practice because it makes your scripts harder to read and doesn't offer any real advantage.

With your first PowerShell script out of the way, it's time to start learning more about what's going on under the hood. This process begins in Chapter 3 with we look at PowerShell's security features.



Windows PowerShell. TFM
Internet Forensics
ISBN: 982131445
EAN: 2147483647
Year: 2004
Pages: 289

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net