Showing posts with label Arrays. Show all posts
Showing posts with label Arrays. Show all posts

Thursday, August 21, 2008

PowerShell and COM

I mentioned to a few people today that you can use PowerShell to create COM objects, but I think that warrants a little explaining.  VBScript automation examples use COM a lot, and if you're going to want to use PowerShell to automate Word documents or any of that other neat stuff, you'll need to use it as well.  

Consider the code below:

PS C:\> $sms_client = New-Object -COM 'CPApplet.CPAppletMgr'             #1
PS C:\> $sms_client | gm                                                 #2


   TypeName: System.__ComObject#{279463bb-1034-4fb5-878e-4a330a08beab}

Name                MemberType Definition
----                ---------- ----------
GetClientActions    Method     IClientActions GetClientActions ()
GetClientComponents Method     IClientComponents GetClientComponents ()
GetClientProperties Method     IClientProperties GetClientProperties ()

PS C:\> $actions = $sms_client.GetClientActions()                        #3
PS C:\> $actions | select Name                                           #4

Name
----
Software Inventory Collection Cycle
MSI Product Source Update Cycle
Hardware Inventory Collection Cycle
Standard File Collection Cycle
Discovery Data Collection Cycle
Request & Evaluate User Policy
Request & Evaluate Machine Policy
Software Metering Usage Report Cycle

PS C:\> $machine_policy = $actions | ?{$_.Name -like "*Machine Policy"}  #5
PS C:\> $machine_policy.PerformAction()                                  #6

In the code above, "CPApplet.CPappletMgr" is the name of the COM type that is equivalent tot he Systems Management applet in the control panel, so here's what the code does:

  1. Creates a new COM object of type 'CPApplet.CPAppletMgr'.  This is the equivalent of "sms_client = CreateObject('CPApplet.CPAppletMgr')" in VBScript.
  2. Runs Get-Member (gm) on the variable I just set to see what methods are available.
  3. Calls the GetClientActions method and stores the resulting array in $actions.
  4. Uses Select-Object (select) to get just the names of each action
  5. Uses Where-Object (?) to get just the action whose name is like "*Machine Policy" and assign it to $machine_policy
  6. Invokes the PerformAction() method of $machine_policy.

Worthy of note is that piping to where technically creates a one-element array, but PowerShell automatically converts that to a scalar by default, so I didn't have to use $machine_policy[0].  If I had actually wanted it to be treated as an array (let's say I'll be using the .Length() method of an array to see how many items were returned, I would have to use the @() syntax to force it:

PS C:\> $machine_policy = @($actions | ?{$_.Name -like "*Machine Policy"}) 

Tuesday, July 15, 2008

Arrays in PowerShell

Sometimes PowerShell weirds me out a little bit because some parts look a lot like Perl, but don't act like it. There are a lot of bits and pieces strewn about the Web about how to use arrays and hashtables (I'll get to those later), but I had to look up several of them to get all of the information I wanted, so I'll lay them out here.

Arrays

An array is an ordered list of variables that can be accessed via their index.  It's a lot simpler than it sounds.  First, there are two ways to explicitly create an array:

PS C:\> [array]$my_list = (1, 7, 3, 19, 24, 2)
PS C:\> $my_list = @(1, 7, 3, 19, 24, 2)

Most people will just use the @() format.  This tells PowerShell to return whatever's between the parentheses as an array (even if there's only one member).

So let's take a look at our new array:

PS C:\> $my_list
1
7
3
19
24
2

PS C:\> $my_list.Length
6

PS C:\> $my_list[2]
3

Note that on that last one I used [2] at the end of the array object to denote that I want to grab the third object in the array.  The code below shows what the array looks like:

PS C:\> foreach ($index in (0 .. ($my_list.Length - 1))) {
>>  echo ("`$my_list[$($index)] = $($my_list[$index])")
>> }
>>
$my_list[0] = 1
$my_list[1] = 7
$my_list[2] = 3
$my_list[3] = 19
$my_list[4] = 24

Note the '..' operator above.  This is a handy range operator, especially when working with arrays.  When I'm reading it in my head, I think of it as the word 'through', as in:

PS C:\> $count = (1..10)

Which would read: "$count equals one through 10".  This creates an array where the first 10 elements are the numbers 1 through 10.

Let's say I only want the first three elements of the array:

PS C:\> $count[0..2]
1
2
3

Or maybe I only want elements 1, 4, and 5

PS C:\> $count[1, 4, 5]
2
5
6

Here's a slightly trickier one:  Maybe I only want the last three elements.  By using negative numbers, you can count from the last element backwards:

PS C:\> $count[-1 .. -3]
10
9
8

Now what if I want everything from the second element on?  Naturally I would think that this would work:

PS C:\> $count[1 .. -1]
2
1
10

That didn't do what I expected.  It seems to have counted backwards, giving me the second element, but instead counting ahead until it reached the -1 element, it counts backwards to reach -1, so instead of getting $count[1, 2, 3, 4, 5, 6, 7, 8, 9], I got $count[1, 0, -1].

We can do it, though; we have the technology:

PS C:\> $count[1 .. ($count.Length - 1)]
2
3
4
5
6
7
8
9
10

The Length or Count property of an array will give us the total number of elements in the array, but we have to subtract 1 because because arrays start with an index of 0.

One last thing before I wrap this up:  remember $my_list?  It's all out of order, so let's sort it.

$my_list = $my_list | sort

There.  Much better.