Writing powershell script notes

As I write my first powershell script and do more, notes from there:

  1. Functions in powershell
    1. Return value
      1. Return value is not only the value returned by the ‘return var1’ statement.
      2. It returns all values (array) that are returned by each of the commands in the function block.
      3. For example: function below will return an array with two values: ‘hi’, ‘hello’
        function myFunction()
        {
            echo 'hi';
            return ‘hello';
        }
        
      4. Placing [Void] Cast before the command, will ensure value ‘hi’ is not returned.
        function myFunction()
        {
            [Void](echo 'hi';)
            return ‘hello';
        }
        
  2. Invoking a function
    1. Typically coming from programming context, one would write like this: 
      1. myFunc(param1, param2);
    2. This is incorrect. Syntax to invoke a function is same as how cmdlet is invoked in powershell shell
      1. myFunc param1 param2
    3. Defining a simple function
      function myFunction($param1, $param2)
      {
          ...
      }
      
      1. Note that each parameter must be prefixed with ‘$’
      2. There is syntax for putting parameter type and attributes like in c#. But for simple function, this much knowledge was fine.
  3. Operators in powershell
    1. Most of the operators have ‘-‘ (dash) prefix. e.g. -and, -or, -eq, -neq etc.
    2. Equality operator
      1. Remember dotnet Object::Equals method to understand its semantics. I was using to compare my custom object type. I overwrote Equals method to get the right semantics for equality. (and also overwrote GetHashCode to fix the warning!)
      1. Equality for arrays. -eq operator does not work for arrays. Need to write one based on blogosphere feedback on the same. Net result is
    function global:areArrayEqual($a1, $a2)
    {
        return (Compare-Object $a1 $a2 -sync 0).length -eq 0;
    }
    
  4. Scope in powershell scipts
    1. Function in a script seems to have script scope by default. I have to prefix global to make them visible in the powershell command window, after the script is executed. That helped to test them adhoc.
  5. Array usage
    1. initialize an empty array
      1. $myarray = @();
    2. Append to an array
      1. $myarray += ‘new item’;
  6. Working with .net objects
    1. creating and initializing my dotnet object with required properties
      1. new-object myObjectType @{Property1=’Value1’; Property2=’Value2’;}
    2. search for an object with a predicate in a collection
      1. $users | where { $_.UserId –eq 196 }
      2. silly mistake like this can modify all users since = operator is assignment in powershell and where cmdlet does not complain.
        1. $users | where { $_.UserId = 196 }
    3. referencing member name inside a string
      1. incorrect: “user name is $user.Name”
      2. correct: “user name is $($user.Name)”
    4. something like delegate to invoke ps function through a indirection
    function myFunction1()
    {
        echo 'hi there';
    }
    $myDelegate = { myFunction1 }; # using script block
    invoke-command $myDelegate;
  7. Property bag
    1. create my own property bag with firstName and lastName
      1. $myObj = new-object object | add-member @{ firstName = ‘Mike’, lastName = ‘Johnson’ } –passthru
    2. create a property bag to represent ps test suite with name, initialize script block, cleanup script block and set of tests. test1, test2 below are ps functions in the script.
      1. $myTestSuite = new-object object | add-member @{name = ‘unit test suite’; initialize = { initialize }; cleanup = { cleanup }; tests = { { test1 }, { test2 } } –passthru
  8. Output on console
    1. Output color text on console
      1. write-host ‘hi there’ -foregroundcolor green -backgroundcololr black
    2. Echo “hi there $myvar”
      1. Variables are resolved in double quoted string.
    3. Simple trace function helped report & debug script progress.
      function global:trace($tracetype, $message)
      {
          $forecolor = switch ($tracetype)
          {
              "info" { 'green' }
              "error" { 'red' }
              "fail" { 'red' }
              "pass" { 'green' }
              "warning" { 'yellow' }
          }
       
          write-host $message -foregroundcolor $forecolor -backgroundcolor "black";
      }
      
      1. trace ‘info’ ‘this is info’
      2. trace ‘error’ ‘this is error’
      3. trace ‘warning’ ‘this is warning’
  9. Tools
    1. Found powershell_ise.exe – launch it from powershell command prompt. Provides nice gui, keywords coloring, indentation etc basics expected in an editor.
      1. I have to disable intellisense using tools->option since it was slowing the typing. Otherwise – tool comes handy to read & write .ps1 files.
      1. I have used View->script pane on right, to make good use of my laptop wide display.
  10. Writing powershell scripts
    1. I found writing powershell complex script incrementally one command at a time helpful.
    2. learning one command at a time, test it in powershell shell, build up function, test it there and then put it in the script to build it incrementally.
    3. powershell language specification comes handy for reference. it is long document and hard to read in one go. Nevertheless, keep refering it for exact syntax and semantics of operators, statements etc.
    4. Use script modules .psm1 files to reuse and share commonly used script functions in multiple ps scripts. Details found here.
    5. using script module in a script
      1. sample.ps1 file
        1. import-module myCommonLib;
        2. ….script code…
        3. remove-module myCommonLib;
      2. I found that remove-module was required. otherwise – modifying commonlib.psm1 file and rerunning in same ps shell was not picking up changes.
  11. Errror handling
    1. $? contains the last operation status : $true on success, otherwise $false.
    2. $_ : contains the error record in a catch block.
    3. exiting script on critical error
      function exitOnError()
      {
          if (!$?)
          {
              exit 1;
          }
      }
      
      script-initialization-code;
      exitOnError;
    4. using try-catch at outermost level to report failures.
      try
      {
          …
      catch 
      {
          trace ‘error’ “----exception during script::$_----“;
          $pass = ‘fail’;
      }
          Advertisements
          This entry was posted in Uncategorized. Bookmark the permalink.

          Leave a Reply

          Fill in your details below or click an icon to log in:

          WordPress.com Logo

          You are commenting using your WordPress.com account. Log Out / Change )

          Twitter picture

          You are commenting using your Twitter account. Log Out / Change )

          Facebook photo

          You are commenting using your Facebook account. Log Out / Change )

          Google+ photo

          You are commenting using your Google+ account. Log Out / Change )

          Connecting to %s