Section 2.1. Load and Save Scripts


2.1. Load and Save Scripts

All of the examples so far have followed the same procedure: MSH presents a prompt and waits for your input, you type a command, the command is processed, the output is displayed, and the cycle repeats. This is useful for interactive command line use, invoking cmdlets one by one, building pipelines, and general day-to-day use.

However, like cmd.exe, MSH can take its instructions from a file instead of receiving commands from a keyboard. This enables us to create complex sequences that perform one or more tasks and save these scripts to disk. In this way, it's possible to build up a library of scripts that encapsulate common repetitive tasks. With this library on hand, it's easy to save time and quickly recall and rerun previously stored scripts.

Creating a Script Library

There are often cases where what appears to be a one-off script can actually be applied to many scenarios that crop up in the future. Saving scripts with well-chosen filenames that follow the verb-noun syntax of cmdlets can be a real timesaver. If possible, it's a good idea to keep scripts as generic as possible to increase the opportunities for reuse in the future.


2.1.1. How Do I Do That?

MSH scripts can be stored in simple text files with a .msh extension in much the same way as command-shell scripts can be stored in text files with a .bat or .cmd extension. Using your favorite text editor, let's put together a simple script that filters the output of get-process. Save the script, shown in Example 2-1, as get-processHandlesGt500.msh in a convenient directory. (We'll use D:\MshScripts in the examples that follow.)

Example 2-1. get-processHandlesGt500.msh
 get-process | where-object { $_.Handles -gt 500 }

Once saved, the script can be run in the shell simply by typing in its path and name. If the script is located in the current working directory, the current path must also be specified as .\get-processHandlesGt500.msh:

     MSH C:\> D:\MshScripts\get-processHandlesGt500.msh     Handles  NPM(K)    PM(K)      WS(K) VS(M)   CPU(s)     Id ProcessName     -------  ------    -----      ----- -----   ------     -- -----------         788      14    13832      16132    70   202.02   1656  CcmExec         764      12    36760      34084   175    20.41   1864  msh        1792      54    22476      24336   106   418.00    824  svchost         557      60     7352       3820    51    58.92    488  winlogon

It doesn't stop there: with MSH, a script is part of a pipeline. For example, if we want to rearrange the results of the script and present them differently, it's simply a case of piping to the relevant cmdlets we've already met:

     MSH C:\> D:\MshScripts\get-processHandlesGt500.msh | sort-object  Handles | format-list ProcessName,Handles     ProcessName : winlogon     HandleCount : 557     ProcessName : CcmExec     HandleCount : 785     ProcessName : msh     HandleCount : 800     ProcessName : svchost     HandleCount : 1792

Now, let's move to a slightly longer example. We'll create a new script, get-processReport.msh, as shown in Example 2-2, that generates a quick snapshot of the current process state and calls out high-priority processes in a separate list.

Example 2-2. get-processReport.msh
 # # This script generates a report about active processes # "Report generated at " + (get-date) ""                    # insert blank line "Processes sorted by handle count" get-process | sort-object Handles | format-table ""                    # insert blank line "High memory usage (>100MB)" get-process | where-object { $_.WorkingSet -gt 50000000 } | format-table

This time, let's run the script from the current working directory, after making sure that we're in the right folder (D:\MshScripts):

     MSH D:\MshScripts> .\get-processReport.msh     Report generated at 12/1/2005 3:41:06 PM     Processes sorted by handle count     Handles  NPM(K)    PM(K)      WS(K) VS(M)   CPU(s)     Id ProcessName     -------  ------    -----      ----- -----   ------     -- -----------        4344      75   138108     100852  1093 ...82.52   7404  OUTLOOK        1785      54    21852      23708   106   414.66    824  svchost         788      14    13980      16452    70   201.03   1656  CcmExec         560      12    35252      32584   175    17.43   1864  msh         557      60     7352       3820    51    57.46    488  winlogon         438       5     1832       3212    24   236.38    464  csrss         438      10     4728       2228    42    77.94    544  lsass         363      11     9420      13324    58 2,582.09    212  explorer         296       0        0        168     2   328.87      4  System         266      13     1524       3264    34    94.29    756  svchost         261       6     1316       2276    24    41.11    532  services         248       7     2192       2996    37    19.84    940  svchost         222       7     6356       6152    65    10.47   1708  wuauclt         182       5     2316       3276    57     5.83    720  svchost         137       3     1564       3420    23     3.98    320  wmiprvse         132       3     3480       3204    25     9.67   1920  wmiprvse         123       5     1008       2500    32     1.44   1844  alg          96       4     2428       2364    26     2.19   1088  spoolsv          89       4     1064       2252    29    10.04    896  svchost          25       2      600       2228    25     1.10   3572  notepad          25       2      692       2472    25     5.61   1792  notepad          21       1      168        264     4     1.31    308  smss           0       0        0         16     0               0  Idle     High memory usage     Handles  NPM(K)    PM(K)      WS(K) VS(M)   CPU(s)     Id ProcessName     -------  ------    -----      ----- -----   ------     -- -----------        4344      75   138108     100852  1093 ...82.52   7404  OUTLOOK

2.1.2. What Just Happened?

MSH recognizes script files by the .msh extension. Upon coming across a script file, MSH will open the file and execute the commands within it line by line. A script isn't any different from typing commands into the shell by hand; it uses the same idea and execution order of a pipeline and is subject to the same output-formatting rules, although there are some subtle differences caused by scoping (which we'll discuss in Chapter 4).

In Example 2-1, note that the objects representing the four processes from get-processHandlesGt500.msh are actually emerging from the script into the pipeline. In this manner, it's easy to blend script output with interactive mode and build a pipeline that seamlessly includes aspects of both.

Assuming you may reuse a script in the future, it's always good practice to add comments to areas where the behavior might not be immediately obvious later. If you come back to a script in six months, will you still remember exactly why you chose to sort by a given property? Comments can be added to a script by using the pound symbol, #. Once a # symbol appears on a line, any characters following it (on the same line) are ignored when the script is run. To the same end, it's a good practice to use the long form of commands (e.g., get-childitem instead of gci or dir) for legibility.

The get-date cmdlet hasn't been introduced yet, but its name should betray its function. When used without parameters, it returns the current system date and time in the short format (as defined by the system's Regional Settings).

In the final version of MSH, a tighter security policy will be enforced around script execution. Unlike the beta builds, scripts will not be permitted to execute unless they are signed with a trusted certificate.

MSH provides two cmdlets that assist with the signing process. get-authenticodesignature shows information about the signature on a script, whereas set-authenticodesignature is used to actually apply the signature.

The following steps are required to sign a script:

     MSH D:\MshScripts> $cert = get-childitem cert:\CurrentUser\My -CodeSigning     MSH D:\MshScripts> set-AuthenticateSignature myscript.msh $cert

It is a good practice to get into the habit of signing scripts to prevent accidental modification or malicious tampering.


2.1.3. What About...

...Running scripts as Scheduled Tasks? MSH has a command-line option, -command, that takes the filename of a script to run. Instead of loading up into interactive mode, it will immediately execute the script and exit:

     msh -command D:\MshScripts\get-processHandlesGt500.msh

In fact, even the -command part is optional, so just passing the full filename is sufficient:

     msh D:\MshScripts\get-processHandlesGt500.msh

What's more, if the D:\MshScripts folder is in the %PATH% environment variable, just the filename is enough:

     msh get-processHandlesGt500.msh

In addition to the simple script invocation format with just a path and filename, there's another method called dot sourcing. A script file can be dot sourced by placing a period and space (. ) before the script's filename. The distinction is important when variables and functions are used within the script, as the two methods treat variable and function scope differently. We'll look at dot sourcing more in Chapter 3.

After moving scripts into a file, it can be difficult to see what exactly is happening, especially when debugging. MSH has a debugging system that can help.

Try set-mshdebug -trace 1 to report each line of the script as it is run. Change the 1 to a 2 to have MSH report variable assignments as well. set-mshdebug -step can be used to walk through scripts line by line.


2.1.4. Where Can I Learn More?

Running the command msh -? will give more details about the available command-line options.




Monad Jumpstart
Monad Jumpstart
ISBN: N/A
EAN: N/A
Year: 2005
Pages: 117

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