Summary: Learn how to use Windows PowerShell to download code snippets from the Internet and install them for use in the Windows PowerShell ISE.
Microsoft Scripting Guy Ed Wilson here. It seems as if there is an old song that rather describes things right now. It goes somewhat like this:
The weather outside is frightful,
But the code inside is delightful,
Since there is no place to go,
Let us code, let us code let us code.
Oh, my PowerShell code is so sweet,
And the syntax is so neat,
Since there is no place to go,
Let us code, let us code let us code.
Or words to that effect. It seems that many of my friends on Facebook are complaining that they are getting snowed out. Even some of my mates at the university are getting into the act—in an ambivalent sort of way. They really love their classes, but they would not mind a day off. Of course, a day in which one is stuck in the dormitory is not much of a day off.
The Scripting Wife and I decided to evacuate from Charlotte and the possibility of inclement weather, and we headed to the coast. The photo shown here is one I took on the beach.
The nice thing about sitting on the balcony, listening to the seagulls, and watching the waves as they roll in and out is that it is a great place to write Windows PowerShell code. Last weekend’s blog posts about code snippets generated several comments via the comment button and in email. The long and the short of the comments was that browsing to a folder and copying the content of a script is not a code snippet. And that, of course, is correct.
To be truly useful, a code snippet needs to be pretty much set up as a code snippet. In Visual Studio, there is actually a feature called code snippets, and to write your own code snippets, you need to monkey around with some XML, which means that there is an actual code snippet schema. Well, that is all fine and dandy, but it is a bit more than I want to do on a Saturday morning. (PowerGUI has actual snippets with an XML schema and everything.)
What I want to do is to provide an easy way to use the concept of code snippets without the heavy lifting of XML or the requirement to use third party software. So, let’s review where I am a in my code snippet project. First, I talked about using code snippets, and I wrote code that displays an open file dialog box and allows me to select a file. After I select the file, the code reads the content of the file and inserts it at the current insertion point of my script. On Sunday, I wrote a script that creates a custom .snip file extension and sets it up in the registry, associated with Notepad. This was the second step in the process.
Today I need to create a bunch of .snip files that will become my code snippet collection. I will put them all in a snip folder. The .snip files will be my code snippets. In addition, if I have special functions that I like to reuse, there is no need to translate them into .snip files, so I will add the .snip file extension to the filter for my open file browser. The nice thing about the .snip files being simple plain text files is that anyone can create their own code snippet by adding the file to the directory that contains the snippets. I thought about adding a snippet directory off the root, but I think it might actually be a better practice to add the snippet directory to my user profile instead. I figured I would create a snip folder in the same location that my Windows PowerShell profile resides. To find that location, I use the $profile automatic variable, and pass it to the Split-Path cmdlet. This appears here along with the results of the command.
PS C:\> Split-Path $profile
C:\Users\edwils\Documents\WindowsPowerShell
I created 11 .SNIP files. The files are available in a zipped file. The snip files do not include any comments and in most cases are bare shells of code. The code snippets save typing. In a few cases, I used generic variables such as $x and $y, as shown here.
if($x -gt $y)
{ }
Nevertheless, sometimes I did not include any generic variables because I did not want to clutter up the snippet. An example of this type of snippet is shown here:
Do
{
} Until ( )
The cool thing is this: The files are plain text, and if you do not like the way I formatted the code or failed to include comments, go ahead and change them. In fact, after you have added to the collection of snippets, feel free to upload them to the Scripting Guys Script Repository.
I wrote a really cool script that downloads the snippet.zip file from the Scripting Guys SkyDrive, creates a snippet folder under the Windows PowerShell folder in my personal profile, and then unzips the .SNIP files into the snippet folder. The Install-CodeSnippetsFromInternet.ps1 script is shown here.
Install-CodeSnippetsFromInternet.ps1
$source = “http://bit.ly/ga0k0i”
$folder = New-Item -Path (Split-Path -Path $profile -Parent) `
-Name snippet -ItemType directory
$destination = Join-Path -Path $folder -ChildPath snip.zip
$wc = New-Object system.net.webclient
$wc.downloadFile($source,$destination)
$shell = New-Object -ComObject shell.application
$files = $shell.namespace($destination).items()
$shell.NameSpace($folder.fullname).copyHere($files)
The actual destination for the $source file, which is the snippet.zip file, is really long. It is
$source = http://public.bay.livefilestore.com/y1pWfzVoKQeFsgOgBR6btSYG7ToGKfuivGSfP0z5eiDQ_erRBwRw9hZpd7Nue9wD_RSL6JQ9Jg2PlWqLSgMlrr0vw/snip.zip
but I think the code looks better with the shortened URL. The bit.ly URL works in my testing, but I know there were some problems with bit.ly recently, and therefore it is a potential source of disruption. In my actual script, I have the long URL in a commented out block, just in case. Discovering the actual URL to use for the download was rather cumbersome. I ended up using Fiddler and looking through the traces to find the actual path to the snip.zip file (but then I wrote a book on Network Monitoring and Analysis, so network traces do not bother me very much).
After I discovered the path to the snip.zip file that I want to download, using the System.Net.WebClient is pretty easy. After the webclient object is created, I call the downloadfile method and pass the source and the destination to the method. One thing to keep in mind is that the destination must point all the way to a file name:
$wc = New-Object system.net.webclient
$wc.downloadFile($source,$destination)
To unzip the files from the snip.zip file, I use the shell.application COM object. This technique is shown here:
$shell = New-Object -ComObject shell.application
$files = $shell.namespace($destination).items()
$shell.NameSpace($folder.fullname).copyHere($files)
Cool. Now that I have a bunch of .snip files, I will modify the snippet explorer that I created last week. Because I am making a couple of changes to the script, I modify the name. I am also adding a line to the bottom of the script that calls the function while passing the initial snippet directory to it. The revised Get-CodeSnippetV2.ps1 script appears here.
Get-CodeSnippetV2.ps1
Function Get-CodeSnippetV2
{
<#
.Synopsis
Either displays contents of a file in Notepad, or adds the content to
current insertion point of script.
.Description
The Get-CodeSnippetV2 function accepts an input folder of code snippets,
and displays a file dialog box that allows you to select a particular
file to either view the contents in Notepad, or add the content to
your script at the current insertion point.
.Example
Get-CodeSnippetV2 -InitialDirectory c:\fso
Opens a File dialog box situated on the c:\fso directory. Initial view
is .ps1 and .psm1 files, but you can choose to view all files. If you
select a file, its contents will be displayed in Notepad.
.Example
Get-CodeSnippetV2 -InitialDirectory c:\fso -add
Opens a File dialog box situated on the c:\fso directory. Initial view
is .ps1 and .psm1 files, but you can choose to view all files. If you
select a file, its contents will automatically be added at the current
insertion point of your script.
.Parameter InitialDirectory
The initial directory to be homed for the Open File dialog box
.Parameter Add
A switched parameter that will cause the function to add the content to
current script at current insertion point.
.Inputs
[string]
.Outputs
[string]
.Notes
NAME: Get-CodeSnippetV2
AUTHOR: Ed Wilson, Microsoft
LASTEDIT: 02/10/2011 13:14:07
KEYWORDS: Weekend Scripter, scripting techniques, scripting templates
HSG: WES-2-12-2011
.Link
Http://www.ScriptingGuys.com
#Requires -Version 2.0
#>
Param(
[Parameter(Mandatory=$true)]
[string]$InitialDirectory,
[switch]$add
)
If($ExecutionContext.Host.name -notmatch “ISE Host$”)
{
$response = Read-Host -Prompt “This script must run in Windows PowerShell ISE. <Y> to exit.”
if($response -match “y”) { Exit }
} #end if
Add-Type -AssemblyName “System.windows.forms”
$OpenFileDialog = new-object System.Windows.Forms.OpenFileDialog
$OpenFileDialog.initialDirectory = $initialDirectory
$OpenFileDialog.filter = “PowerShell Scripts (*.ps1;*.psm1;*.snip)|*.ps1;*.psm1;*.snip|All files (*.*)| *.*”
$OpenFileDialog.ShowDialog() | out-null
Try
{
if(!$add)
{ notepad $openfileDialog.filename }
if($add)
{
$content = Get-Content -Path $OpenFileDialog.filename -Encoding ascii -Delimiter `r`n
$psise.CurrentFile.Editor.InsertText($content)
} #end if $add
} #end try
Catch [System.Exception]
{ “No file was selected.” }
} #end function Get-CodeSnippet
Get-CodeSnippetV2 -InitialDirectory (Join-path -path (Split-Path -path $profile -Parent) -ChildPath snippet)
I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.
Ed Wilson, Microsoft Scripting Guy
0 comments