April 2010 - Posts

Scripting Games Comments II

With Event 5 now available

http://blogs.technet.com/heyscriptingguy/archive/2010/04/30/2010-scripting-games-advanced-event-5.aspx

http://blogs.technet.com/heyscriptingguy/archive/2010/04/30/2010-scripting-games-beginner-event-5.aspx

we have reached half way.

This event is concerned with retrieving information about the hardware in a machine.  The retrieval is straight forward so this would a good time to go to town on the other aspects that can earn you style points.

To carry on the theme of my last post while there are a lot of good scripts coming through – my definition of  a good script is one that does the required job in  a reasonable time – there are still some pointers that can be given about using PowerShell. I’ve just finished judging the latest submissions and I make about 470 entries at this time. In those there are some things that leapt out as needing comments.

One script had a very interesting way of using the pipeline in that it looked like this

Get-Process `

| select name, Handles `

| format-table

 

A ` (backtick) is used as a continuation marker and then the pipeline symbol starts the line.  I had to actually test this to see if it would work.  It does.

A simpler syntax is to do this

get-Process |

select name, Handles |

format-table

 

The pipeline symbol will automatically give continuation and save the use of `.  I would really recommend using the second style as a ` can be very difficult to spot when trying to debug a script. The absence of a ` is even more difficult to spot.

 

The other point that can be made is that we can simplify to

get-Process |

format-table name, Handles

which will give the same result.

 

Many of the scripts I’ve seen have over complicated the code. Keeping it simple makes it easier to debug.

Posted by RichardSiddaway | with no comments

Scripting Games Comments I

I’m going to produce a few general posts with comments about the scripts I’ve seen.  Some specific points I’ll save until after the Games as they may affect the way you write your entries.

The Events in this years Games are very admin orientated and could well be representative of the sort of tasks you will meet.

I’ve been surprised by how few VBScript entries have come through.  The overwhelming majority of scripts I’ve seen have been PowerShell. Is VBScript disappearing as an admin tool or are VBScripters just not bothering.

In a few cases the rules of the event haven’t been read properly which has detracted from what was a good script – it just wasn’t solving the problem that was asked.

A couple of general points I think are worth repeating:

  1. using aliases is generally not good in production scripts – it also makes the scripts harder to read which makes me grumpy (grumpier?). You don’t want a grump judge  :-)
  2. I would also recommend sticking with the standard verbs when creating function names – it won’t affect the score but its a good habit to get into.  If you don’t know what they are – use get-verb

Scripting Games Event 4 Scenario

The Games continue at a break neck pace with event 4 available as well

 

http://blogs.technet.com/heyscriptingguy/archive/2010/04/29/2010-scripting-games-beginner-event-4.aspx

http://blogs.technet.com/heyscriptingguy/archive/2010/04/29/2010-scripting-games-advanced-event-4.aspx

 

In this one we get to play with environmental variables. 

 

The deadline for Event 1 is looming as that event closes on 3 May.

Posted by RichardSiddaway | with no comments
Filed under:

A couple of PowerShell thoughts

I’ve been looking at a lot of scripts over the last few days and a couple of thoughts occurred while judging.  These have nothing to do with the Scripting Games but are more concerned with PowerShell in general.

Write-Host is used to output to the screen.  That works fine but its not so easy if you want to be able to run the script and output to screen or file.  Consider this

PS> $date = Get-Date
PS> Write-Host "Started at $date"
Started at 04/28/2010 22:54:17

PS>  "Started at $date"
Started at 04/28/2010 22:54:17

We can use write-host to output to screen. We can put the same output by having a line with a string on it – its treated as output.

If we want to write to a file

PS> Write-Host "Started at $date" | out-file test1.txt
Started at 04/28/2010 22:54:17
PS> cat test1.txt
PS>

Write-host will always write to the screen.

PS>  "Started at $date" | out-file test1.txt
PS> cat test1.txt
Started at 04/28/2010 22:54:17

Output via a string can be redirected to a file.

Consider what you are trying to achieve. If you want the comments in a file then done use write-host.

The other thought was around how scripts close.  Very often our pipeline will finish with a format-table (or list).  I try to use a select instead.  That means I can add a simple format-table to the end or can write straight out to file – again think about what is being achieved.

Posted by RichardSiddaway | 1 comment(s)
Filed under:

Scripting Games Event 1 Scenario

The Scripting Games have started with Event 1 officially open.

For the beginners section

http://blogs.technet.com/heyscriptingguy/archive/2010/04/26/2010-scripting-games-beginner-event-1-updating-and-creating-registry-keys.aspx

You need to check a registry key exists, create it if not, & update it with the date & time of the check

 

For the Advanced section

http://blogs.technet.com/heyscriptingguy/archive/2010/04/26/2010-scripting-games-advanced-event-1-updating-and-creating-registry-keys.aspx

This is the beginners scenario plus a number of other features including reading file of computer names, running remotely, code reuse – and some others you need to read the scenario for

Good Luck. 

Deadline is 3 may 2010.  After which I’ll post my efforts.

Posted by RichardSiddaway | with no comments
Filed under:

PowerShell Admin Modules

I have created the first download for the PowerShell Admin Modules. This will be a set of of modules including code previously published on my blogs at:

http://msmvps.com/blogs/RichardSiddaway/Default.aspx

http://itknowledgeexchange.techtarget.com/powershell/

http://richardsiddaway.spaces.live.com/

 

The first release comprises a module for working with shares and can be found at:

http://psam.codeplex.com/

 

It has the following functions:

  • Get-Share
  • Get-ShareAccessMask
  • Get-ShareSecurity
  • New-Share
  • Remove-Share
  • Set-Share

There have been a series of posts on my IT Knowledge Exchange blog (see above) about the functions.  Select Shares from the

Browse This Blog’s Tags box

More to follow soon. Enjoy

Technorati Tags: ,,,
Posted by RichardSiddaway | with no comments
Filed under: , ,

Office 2010

Office 2010 recently went RTM and is now available fro download from MSDN/TechNet.  Downloaded and installed without a problem.  I removed the beta versions – having remembered to export my auto correct entries.  Install went smooth and import the auto correct entries.

Tested each of the applications and everything seems to work.

After using the beta for so long I’d forgotten it was a beta – everything worked perfectly for me.

I expect the RTM version to be the same.  You’ll only hear more about Office if I find a problem or I’m using PowerShell against it.

One quick test

$xl = New-Object -ComObject "Excel.Application"
$xlbooks = $xl.workbooks.Add()
$xl.Visible = $true

Works for creating an Excel spreadsheet – at least it does under en-GB culture.  If it doesn’t work elsewhere I’d be interested in hearing about it.

 

Technorati Tags:

Binging PowerShell

I posted recently about PowerShell help information being available in the Visual Search galleries on Bing - http://msmvps.com/blogs/richardsiddaway/archive/2010/04/19/powershell-on-bing.aspx

The URLs are available to find this directly.  For the time being its only available on the US version of Bing but if you are using PowerShell v2 you can do this

001
002
if ($psculture -ne "en-US") {Start-Process http://go.microsoft.com/fwlink/?LinkID=190436}
else {Start-Process http://www.bing.com/visualsearch?mkt=en-us&g=powershell_cmdlets}

 

The culture is checked to see if you are in the US and if so you are pointed straight to Bing. otherwise you are directed to the US version of Bing. As the PowerShell reference is rolled out on other versions of Bing you can always alter the comparison to test your culture – change it to $psuiculture which will probably return en-US.

Technorati Tags: ,,
Posted by RichardSiddaway | with no comments
Filed under:

Scripting Games – very very soon

The Scripting Games are almost upon us but this year there is a slight change for me.  I’m not going to be taking part.

Oh no you lucky people I’m going to be a judge - he he he – even more of an insane cackle than usual.

I will expect a superior standard in the PowerShell scripts submitted otherwise there will be extra work after school.

 

Seriously – good luck to everyone planning to enter the games and if you haven't registered yet skip over to http://2010sg.poshcode.org/ and register now.

Posted by RichardSiddaway | with no comments
Filed under:

Summing and counting

One problem that seems to keep arising is counting the number of records in a file and summing the contents of one or more files.  If we start with a couple of files:

test.txt

Green,123.45
Brown,456.77
Black,890.12
White,679.43

and test.csv

Name,Amount
Green,123.45
Brown,456.77
Black,890.12
White,679.43

The only difference is that the csv file has a header row.

If we start with the csv file we can do this

PS> Import-Csv c:\test\test.csv | Measure-Object -Property Amount -Sum

Count    : 4
Average  :
Sum      : 2149.77
Maximum  :
Minimum  :
Property : Amount

Nice and easy – just the way we like.  Working with the text file may be a bit more difficult as we can’t use Measure-Object directly. The traditional approach would be

001
002
003
004
005
006
007
008
009
010
$count = 0
$amount = 0.00

Get-Content c:\test\test.txt |
foreach {
    $data = $_ -split ","
    $count++   
    $amount += $data[1]
}
Write-Host "$count records and $amount in total"

 

Set a couple of variables – one as a counter and one to hold the sum.  Use Get-Content to read the file on to the pipeline. We then use foreach to sum the amounts. Our final action is to write out the answers.

There is a better way. In PowerShell v2 we get some extra parameters that enable us to add a header to the file before we add it to the pipeline.

PS> Import-Csv c:\test\test.txt -Header "Name","Amount" | Measure-Object -Property Amount -Sum

Count    : 4
Average  :
Sum      : 2149.77
Maximum  :
Minimum  :
Property : Amount

If we change the delimiter to something other than a comma e.g. a semi-colon

Green;123.45
Brown;456.77
Black;890.12
White;679.43

We can still add the header.  We just need to define the delimiter. Check the import-csv help file for full details.

PS> Import-Csv c:\test\test.txt -Header "Name","Amount" -Delimiter ";" | Measure-Object -Property Amount -Sum

Count    : 4
Average  :
Sum      : 2149.77
Maximum  :
Minimum  :
Property : Amount

Just because a file doesn’t have a header doesn’t mean we can’t work with it as a csv!

Technorati Tags: ,
Posted by RichardSiddaway | with no comments
Filed under:

WMI posts

Couple of WMI based posts you may be interested in:

 

Finding the current logged on user

http://itknowledgeexchange.techtarget.com/powershell/current-logged-on-user/

 

and the Windows System Assessment Tool

http://itknowledgeexchange.techtarget.com/powershell/windows-system-assessment-tool/

Technorati Tags: ,

You are unique

Lets start with some data

$data =@(1,1,1,1,12,23,4,5,4643,5,3,3,3,3,3,3,37,7,7,8,9,9,0,0,12)

We now want to select the unique values out of this list

if I’ve wanted only the unique values I’ve tended to do this

$data | select –Unique

 

there are other options. If you want the output sorted you may be tempted by

$data | sort | select –Unique

 

but you can do this instead

$data | sort –Unique

 

or even

$data | sort -Unique –Descending

 

A final option is

$data | sort | Get-Unique

 

The input to Get-Unique must be sorted – it isn’t important to the other two methods

More info in the help files.  Looks like PowerShell doesn’t have a unique method of getting unique values

Technorati Tags: ,
Posted by RichardSiddaway | with no comments

PowerShell UG Recording April 20

Thanks to everyone who came on to the Live Meeting tonight.  For anyone who missed it:

The slides and demo are available on my sky drive at

http://cid-43cfa46a74cf3e96.skydrive.live.com/browse.aspx/PowerShell%20User%20Group/April%202010

The recording of the meeting is available from

Richard Siddaway has invited you to view a Microsoft Office Live Meeting recording.
View Recording
Recording Details
    Subject: PowerShell Modules
    Recording URL: https://www.livemeeting.com/cc/usergroups/view
    Recording ID: B3FG29
    Attendee Key: Zft%D4B7H

This Office Live Meeting invitation is a personal invitation meant only for you. It should not be forwarded. If you received this email by mistake or require Live Meeting Assistance, please refer to the Live Meeting Assistance Center at http://r.office.microsoft.com/r/rlidLiveMeeting?p1=12&p2=en_US&p3=LMInfo&p4=support

 

Next meeting is 18 May when we look at PowerShell eventing

Technorati Tags: ,

PowerShell on Bing

The PowerShell team blogged about a new visual search capability for Powershell help care of Bing

http://blogs.msdn.com/powershell/archive/2010/04/19/windows-powershell-in-bing-visual-search.aspx

Couple of points

- make sure that you are looking at the US version of Bing – it doesn’t show in others (at least it doesn’t in the UK version)

  - click on the country name at top right on the bing welcome page and select United States – English

- select Visual Search

- select Reference

- scroll down for PowerShell – under the Scripting heading

 

Only the core PowerShell cmdlets are available – hopefully other teams will follow suit.

Technorati Tags: ,,
Posted by RichardSiddaway | 1 comment(s)
Filed under:

UG Reminder

The PowerShell UG Live Meeting is tomorrow night (20 April) at 7.30pm BST.  Subject is modules.

Details from http://msmvps.com/blogs/richardsiddaway/archive/2010/04/12/powershell-user-group-live-meeting-modules.aspx

Technorati Tags: ,,

Advanced Functions: part 3

Lets start looking at validation of parameter values. We have a few options to try

  [ValidateCount(1,n)] 
  [ValidateLength(1,m)] 
  [ValidatePattern("[A-Z][A-Z]A-Z][0-9]")] 
  [ValidateRange(0,10)] 
  [ValidateScript({$_ -lt 4})] 
  [ValidateSet("red","blue","green")] 

  [ValidateNotNull()] 
  [ValidateNotNullOrEmpty()]

 

lets start with validating a range of values

001
002
003
004
005
006
007
008
function test1 {
    param (
        [int]
        [validateRange(1,5)]
        $p1  
)
    $p1 * 3   
}

We have a simple function that defines 1 parameter – in my recent post showing all of the possible parameters [datatype] referred to the data type we were assigning to the parameter in this case an integer.

We’ll define a valid range of 1-5 for this value

Our function does a simple multiplication to show its working.

As a test

PS> 1..5 | foreach {test1 $_}
3
6
9
12
15

Everything works.  what happens if we submit a value outside the allowed range?

PS> 4..7 | foreach {test1 $_}
12
15
test1 : Cannot validate argument on parameter 'p1'. The 6 argument is greater than the m
aximum allowed range of 5. Supply an argument that is less than 5 and then try the comma
nd again.
At line:1 char:22
+ 4..7 | foreach {test1 <<<<  $_}
    + CategoryInfo          : InvalidData: (:) [test1], ParameterBindingValidationExcep
   tion
    + FullyQualifiedErrorId : ParameterArgumentValidationError,test1
test1 : Cannot validate argument on parameter 'p1'. The 7 argument is greater than the m
aximum allowed range of 5. Supply an argument that is less than 5 and then try the comma
nd again.
At line:1 char:22
+ 4..7 | foreach {test1 <<<<  $_}
    + CategoryInfo          : InvalidData: (:) [test1], ParameterBindingValidationExcep
   tion
    + FullyQualifiedErrorId : ParameterArgumentValidationError,test1

 

4 and 5 are accepted but 6 and 7 are rejected.

If we fall outside the lower range

PS> 2..0 | foreach {test1 $_}
6
3
test1 : Cannot validate argument on parameter 'p1'. The 0 argument is less than the mini
mum allowed range of 1. Supply an argument that is greater than 1 and then try the comma
nd again.
At line:1 char:22
+ 2..0 | foreach {test1 <<<<  $_}
    + CategoryInfo          : InvalidData: (:) [test1], ParameterBindingValidationExcep
   tion
    + FullyQualifiedErrorId : ParameterArgumentValidationError,test1

A simple test that protects the function. Using this supposes we know what the range of values should be

IE History

Saw a post on the forums that looked interesting.

Problem

Convert  this VBScript into PowerShell

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
HISTORY_LIST = 34
ITEM_NAME = 0
ITEM_DATE = 2
Set objShell = CreateObject("Shell.Application")
Set objHistory = objShell.NameSpace(HISTORY_LIST)
Set objHistoryFolder = objHistory.Self
Wscript.Echo vbCrLf & "Location of History"
Wscript.Echo objHistoryFolder.Path


For Each objPeriod In objHistory.Items

  Wscript.Echo vbCrLf & objPeriod.Name
  Wscript.Echo String(Len(objPeriod.Name), "=")

 If objPeriod.IsFolder Then
    Set objSiteFolder = objPeriod.GetFolder


    For Each objSite In objSiteFolder.Items
      Wscript.Echo vbCrLf & objSite.Name
      Wscript.Echo String(Len(objSite.Name), "-")

      If objSite.IsFolder Then
        Set objPageFolder = objSite.GetFolder

        For Each objPage In objPageFolder.Items
          strURL = objPageFolder.GetDetailsOf(objPage,ITEM_NAME)
          WScript.Echo vbCrLf & "URL: " & strURL
          strDateVisited = objPageFolder.GetDetailsOf(objPage,ITEM_DATE)
          WScript.Echo "Date Visited: " & strDateVisited
        Next

      End If

   Next

  End If
Next

 

The script came from http://gallery.technet.microsoft.com/ScriptCenter/en-us/28696fd5-2a90-4766-9b96-d4bc38c9db12 and interestingly was only stated to work on Windows 2000 and Windows XP

For my first go I did a straight conversion

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
$shell = New-Object -ComObject Shell.Application
$hist = $shell.NameSpace(34)
$folder = $hist.Self
$folder.Path

$periods = $hist.Items()
foreach ($period in $periods){
    ""
    ""
    $period.Name
   
    if ($period.IsFolder) {
        $siteFolder = $period.GetFolder
        $sites = $siteFolder.Items()
       
        foreach ($site in $sites) {
            ""
            $site.Name
           
            if ($site.IsFolder) {
                $pageFolder  = $site.GetFolder
                $pages = $pageFolder.Items()
               
                foreach ($page in $pages) {
                    $url = $pageFolder.GetDetailsOf($page,0)
                    $date =  $pageFolder.GetDetailsOf($page,2)
                    "$date visited $url" 
                }
            }
        }
    } 
}

 

We start off the same in creating a COM object and access special folder 34 – the IE history.

After displaying the folder path we get the periods and iterate through them, displaying the name – this will be the day of the week or Last week etc

We check if the period is a folder and if it is we get the items in the folder.

We can then iterate through them displaying the site name and checking if it is a folder.

if it is we can get the pages visited and display the URL and the date visited.

While this worked I was 100% happy with it because of the nested foreachs.  I wanted to do more on the pipeline so I had another go

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
$shell = New-Object -ComObject Shell.Application
$hist = $shell.NameSpace(34)
$folder = $hist.Self
$folder.Path

$hist.Items() | foreach {
    ""; ""; $_.Name
     if ($_.IsFolder) {
         $siteFolder = $_.GetFolder
         $siteFolder.Items() | foreach {
            $site = $_
            ""; $site.Name
            if ($site.IsFolder) {
                $pageFolder  = $site.GetFolder
                $pageFolder.Items() | foreach {
                    $url = $pageFolder.GetDetailsOf($_,0)
                    $date =  $pageFolder.GetDetailsOf($_,2)
                    "$date visited $url" 
                }
            }
         }
     }
}

 

This does exactly the same as the first attempt. It could be made more compact but is already getting a bit hard to understand. For once the more verbose way may be better.

BTW I did this on Windows 7

More Posts Next page »