Introducing the ScriptingHelp PowerShell Module

Over the last few weeks I’ve posted articles on the different parameter validation options in Windows PowerShell. More than one person suggested consolidating the articles. That seemed like a good idea. There were a variety of ways to handle this but I wanted something more PowerShell-oriented. Then I realized, why not produce PowerShell About topics? I could create a module that primarily was a collection of about topics on scripting in PowerShell. Import the module and you get the documentation.

In fact, this is a slick idea you might want to take advantage of: create a PowerShell module with nothing but documentation delivered via About_* files. If you are spending a lot of time in the shell, stay there! But before I get sidetracked, let’s look at the module I’m calling ScriptingHelp.

As I said the module is mostly a collection of About_* topics based on some of my blog articles. Then I realized I wanted to make it easier to expose them so I threw together a brief function called Get-ScriptingHelp.

The About topics are edited and revised versions of material previously posted on my blog.

I plan on contributing additional content over time based on previous blog articles, suggestions or anything that comes to mind that I think can help you write more effective PowerShell scripts and functions.

To that end, I have also included a function to help you start scripting even faster. It is a new function wizard called Invoke-FunctionWizard. When you run the wizard, you will be prompted for information about your new function such as its name and parameter information. The wizard will then write a string object with the skeletal outline of your new function, complete with comment-based help. If you run the wizard in the ISE it will automatically insert the text into the currently open file.

But perhaps you’d like to see all of this in action.

I hope you’ll let me know what you think and if you find this useful or worthy of continued development. You can download a zip file of ScriptingHelp_0_9. Extract the folder as a subfolder under C:\Users\\Documents\WindowsPowerShell\Modules. Then import the ScriptingHelp module. This should work in both the console and the PowerShell ISE. Enjoy!

Post to Twitter Post to Plurk Post to Yahoo Buzz Post to Delicious Post to Digg Post to Facebook Post to FriendFeed Post to Google Buzz Post to Ping.fm Post to Reddit Post to Slashdot Post to StumbleUpon Post to Technorati

Posted in PowerShell, PowerShell v2.0, Scripting, Training | Tagged , , , | 2 Comments

PowerShell Scripting with [ValidateNotNullorEmpty]

I’ve been writing about the different parameter validation attributes that you can use in your PowerShell scripting. One that I use in practically every script is [ValidateNotNullorEmpty()]. This validation will ensure that something is passed as a parameter value. I’m not talking about making a parameter mandatory; only that if the user decides to use the parameter that something is passed. Let’s look at my demo.

#requires -version 2.0

Param (
[Parameter(Position=0,Mandatory=$True,HelpMessage="Enter a process name like lsass")]
[ValidateNotNullorEmpty()]
[string]$Name,
[Parameter(Position=1)]
[ValidateNotNullorEmpty()]
[string]$Computername=$env:computername

)

Try {
    Get-Process -Name $name -ComputerName $computername -errorAction "Stop" | Select *,
    @{Name="Runtime";Expression={(Get-Date)-$_.StartTime}}
}

Catch {
    Write-Warning $_.Exception.Message
}

I’ve used the attribute on both parameters. The first parameter I’ve also made mandatory which makes it more likely that something will be entered. But if not, then the script will fail.

I would get a similar message if the user forgot to complete the command.

Even though I’m using a default value for Computername, as soon as the parameter is detected PowerShell assumes I’m going to use a different value.

Validation should work for missing values, a variable that might be null, or in general anything that is meaningless. However, it won’t prevent something quirky like this:

PS S:\> $p=" "
PS S:\> .\demo-ValidateNotNull.ps1 -name $p
WARNING: Cannot find a process with the name " ". Verify the process name and
call the cmdlet again.

The variable, while semantically meaningless to us, is not null or empty but a string of 1 space. If there’s the chance you might run into this situation then you can add additional validation checks to the parameter.

If you’d like, feel free to download Demo-ValidateNotNull and see for yourself.

Post to Twitter Post to Plurk Post to Yahoo Buzz Post to Delicious Post to Digg Post to Facebook Post to FriendFeed Post to Google Buzz Post to Ping.fm Post to Reddit Post to Slashdot Post to StumbleUpon Post to Technorati

Posted in PowerShell v2.0, Scripting | Tagged , , | Leave a comment

SQL Saturday 129 Session Material

I spoke this past weekend at a SQL Saturday event in Rochester, NY. My first SQL Saturday event and it was a lot of fun. A great turnout and some very interested attendees. I did three PowerShell sessions on jobs, scheduled jobs/tasks and an intro to workflows. The latter talk I think blew out some neurons on a few people, but I believe they were still enthusiastic about it.

For SQL Saturday attendees, I’ve posted my slide deck and demo files on the conference site. For everyone else, if you are interested, I’ll also make them available here.

PowerShell 3 Jobs and Tasks
PowerShell Background Jobs
PowerShell Workflow Basics

I expect I’ll be covering this material again in the future here as well as in my Prof. PowerShell column. And as always, if your organization is thinking about some private PowerShell training or mentoring, let me know.

Post to Twitter Post to Plurk Post to Yahoo Buzz Post to Delicious Post to Digg Post to Facebook Post to FriendFeed Post to Google Buzz Post to Ping.fm Post to Reddit Post to Slashdot Post to StumbleUpon Post to Technorati

Posted in Conferences, PowerShell, Powershell 3.0, Windows 8 | Tagged , , , , , , | Leave a comment

Friday Fun: PowerShell ISE Function Finder

At the PowerShell Deep Dive in San Diego, I did a lightning session showing off something I had been working on. Sometimes I don’t know what possesses me, but I felt the need for a better way to navigate my PowerShell scripts files that had many functions. Some files, especially modules, can get quite long and contain a number of functions. When using the PowerShell ISE I wanted a faster way to jump to a function. The problem is I don’t always remember what I called a function or where it is in the file. It is very easy to jump to a particular line in the ISE using the Ctrl+G shortcut.

So I started with some basics.

$Path=$psise.CurrentFile.FullPath

I decided I’d use a regular expression pattern to find my functions. I write my functions like this:

Function Get-Foo {

Param()
...

So I came up with a regex pattern to match the first line and to include the Filter keyword as well.

[regex]$r="^(Function|Filter)\s\S+\s{"

I first thought of searching the content of the current file, but that won’t give me a line number. Then I thought of Select-String. With my regex pattern, I can get the content of the current file and pipe it to Select-String. The match object that comes out the other end of the pipeline includes a line number property (awesome) and the matching line. I decided to do a little string parsing on the later to drop off the trailing curly brace.

$list=get-content $path |
 select-string $r | Select LineNumber,
 @{Name="Function";Expression={$_.Line.Split()[1]}}

Because I’m in the ISE I felt the need to stay graphical, so my first thought was to pipe the results to Out-Gridview.

$list | out-gridview -Title $psise.CurrentFile.FullPath

Here’s a sample result.

Now I can see the function name and line number. In the ISE I can do Ctrl+G and jump to the function. Of course, if I modify the file and line numbers change I need to close the grid and re-run my command. But wait, there’s more….

I’ve never done much with the WPF and figured this would be a great opportunity to do something with the ShowUI module. I already had the data. All I had to do was create a form with ShowUI. This is what I ended up with.

[string]$n=$psise.CurrentFile.DisplayName
ScrollViewer -ControlName $n -CanContentScroll  -tag $psise.CurrentFile.FullPath -content {
     StackPanel  -MinWidth 300 -MaxHeight 250  `
     -orientation Vertical -Children {
        #get longest number if more than one function is found
        if ($count -eq 1) {
            [string]$i=$list.Linenumber
        }
        else {
            [string]$i=$list[-1].Linenumber
        }
        $l=$i.length
        foreach ($item in $list) {
           
            [string]$text="{0:d$l}    {1}" -f $item.linenumber,$item.function
           
            Button $text -HorizontalContentAlignment Left -On_Click {
                #get the line number
                [regex]$num="^\d+"
                #parse out the line number
                $goto = $num.match($this.content).value
                #grab the file name from the tab value of the parent control
                [string]$f= $parent | get-uivalue
                #Open the file in the editor
                psedit $f
                #goto the selected line
                $psise.CurrentFile.Editor.SetCaretPosition($goto,1)
               #close the control
               Get-ParentControl | Set-UIValue -PassThru |Close-Control
            } #onclick
        } #foreach
     }
     } -show

The result is a stack panel of buttons in a scroll control. The button shows the line number and function name.

When a button is clicked, the function gets the line number and automatically jumps to it. Originally I was leaving the control open, but this means the function is still running. And if I change the script the line numbers are off so I simply close the form after jumping to the function.

In the end, I packaged all of this as a script file that adds a menu choice. If ShowUI is available, the function will use it. Otherwise the function defaults to Out-GridView.

Function Get-ISEFunction {

[cmdletbinding()]
Param([string]$Path=$psise.CurrentFile.FullPath)

#import ShowUI if found and use it later in the functoin
if (Get-module -name ShowUI -listavailable) {
    Import-Module ShowUI
    $showui=$True
}
else {
    Write-Verbose "Using Out-GridView"
    $showui=$False
}

#define a regex to find "function | filter NAME {"
[regex]$r="^(Function|Filter)\s\S+\s{"

$list=get-content $path |
 select-string $r | Select LineNumber,
 @{Name="Function";Expression={$_.Line.Split()[1]}}

#were any functions found?
if ($list) {
    $count=$list | measure-object | Select-object -ExpandProperty Count
    Write-Verbose "Found $count functions"
    if ($showui) {
     <#
        display function list with a WPF Form from ShowUI
        Include file name so the right tab can get selected
     #>


    [string]$n=$psise.CurrentFile.DisplayName
    Write-Verbose "Building list for $n"
   
    ScrollViewer -ControlName $n -CanContentScroll  -tag $psise.CurrentFile.FullPath -content {
     StackPanel  -MinWidth 300 -MaxHeight 250  `
     -orientation Vertical -Children {
        #get longest number if more than one function is found
        if ($count -eq 1) {
            [string]$i=$list.Linenumber
        }
        else {
            [string]$i=$list[-1].Linenumber
        }
        $l=$i.length
        foreach ($item in $list) {
           
            [string]$text="{0:d$l}    {1}" -f $item.linenumber,$item.function
            Write-Verbose $text
            Button $text -HorizontalContentAlignment Left -On_Click {
                #get the line number
                [regex]$num="^\d+"
                #parse out the line number
                $goto = $num.match($this.content).value
                #grab the file name from the tab value of the parent control
                [string]$f= $parent | get-uivalue
                #Open the file in the editor
                psedit $f
                #goto the selected line
                $psise.CurrentFile.Editor.SetCaretPosition($goto,1)
               #close the control
               Get-ParentControl | Set-UIValue -PassThru |Close-Control
            } #onclick
        } #foreach
     }
     } -show

    } #if $showui
    else {
        #no ShowUI module so use Out-GridView
        $list | out-gridview -Title $psise.CurrentFile.FullPath
    }
 }
else {
 Write-Host "No functions found in $($psise.CurrentFile.FullPath)" -ForegroundColor Magenta
}

} #close function

#Add to the Add-ons menu
$PSISE.CurrentPowerShellTab.AddOnsMenu.Submenus.Add("List Functions",{Get-ISEFunction},$null)

#optional alias
set-alias gif get-isefunction

Now, I can click the List Functions menu choice and I’ll get a graphical list of any functions in the current file. I’m sure the regex could be tweaked. I’m also sure there are improvements I could make to the ShowUI code, but it works.

Download Get-ISEFunction and let me know what you think.

Post to Twitter Post to Plurk Post to Yahoo Buzz Post to Delicious Post to Digg Post to Facebook Post to FriendFeed Post to Google Buzz Post to Ping.fm Post to Reddit Post to Slashdot Post to StumbleUpon Post to Technorati

Posted in Friday Fun, PowerShell, PowerShell ISE, Scripting | Tagged , , , , , , | Leave a comment

Quick and Dirty Excel from PowerShell

I continue to tinker with Office applications and Windows PowerShell. I was looking at an Excel issue related to opening a new workbook. To verify the problem wasn’t PowerShell related I offered a suggestion to try creating an Excel workbook in VBScript.

In VBScript creating a blank workbook in Microsoft Excel can be accomplished with three lines of code.

set xl=wscript.createObject("Excel.Application")
set wb=xl.workbooks.add()
xl.Visible=vbTrue

In Windows PowerShell we essentially use the same 3 lines.

$xl=new-object -com "excel.application"
$sb=$xl.Workbooks.Add()
$xl.Visible=$True

But PowerShell is all about the objects, so how about a quick and dirty approach? Something perhaps in one line:

PS S:\> ((new-object -com "excel.application").Workbooks.Add()).application.Visible=$True

You could easily build a simple function to run the 3 lines it takes to open a new Excel workbook but one-liners like this make me smile. Granted, I’m probably not likely to use it, but if nothing else I think it reinforces the object nature of Windows PowerShell.

Each expression nested in () is treated as an object. The inner most expression using New-Object, creates the Excel application object which has a Workbooks property that is an object with an Add() method. Invoking this method creates the workbook object. If I stopped there Excel would be running but not visible. So I get the Application property of the workbook object, and set the Visible property to True.

This command doesn’t offer any way to continue working with Excel from PowerShell; it only opens a new workbook. Let me be clear, I’m not advocating that this is how you work with Excel from PowerShell. I think you will need scripts like the ones I posted from my Deep Dive session. But this one-liner demonstrates what is possible with PowerShell and maybe it will add a little smile to your day as well.

Post to Twitter Post to Plurk Post to Yahoo Buzz Post to Delicious Post to Digg Post to Facebook Post to FriendFeed Post to Google Buzz Post to Ping.fm Post to Reddit Post to Slashdot Post to StumbleUpon Post to Technorati

Posted in Miscellaneous, PowerShell | Tagged , , | 2 Comments