Bookmark and Share

 

Hey, Scripting Guy! Question

Hey, Scripting Guy! I have been reading your articles about working with Windows PowerShell profiles, and they are pretty cool. However, I have a question. You mentioned on Monday that I could add a function to a Windows PowerShell profile. I am not sure how I would do that. Can you add a function to the profile you have been working on all week to give me a better idea?

-- AM

 

Hey, Scripting Guy! AnswerHello AM,

Microsoft Scripting Guy Ed Wilson here. As the hour hand creeps closer to the top of the clock and the evening chill fills the air, my taste in music changes. I am listening to Charlie Daniels on my Zune HD and sipping a cup of Constant Comment tea, and munching on a slice of a Virginia mountain apple that the Scripting Wife picked up on her recent trip to Kentucky. A chunk of artisan cheese rounds out the late-night snack.

AM, in addition to writing the Hey Scripting Guy! column, one of my favorite things in life is writing Windows PowerShell scripts. I know you asked specifically about adding a function to your profile, and here I am talking about writing Windows PowerShell scripts. This is because a Windows PowerShell profile is basically a script. As I mentioned in Monday’s Hey Scripting Guy! post, it is somewhat akin to the old fashioned AUTOEXEC.BAT file that you may have messed around with 20 years ago. It has a special name, and it is located in a special location. Other than that, it is a plain old everyday Windows PowerShell script.

A more confusing line in Windows PowerShell 2.0 blurs between functions/advanced functions and Windows PowerShell scripts. Functions, and in particular advanced functions, have the same elements that a Windows PowerShell script possesses. A function can accept parameters, produce Help, and…but wait, we will be talking about Windows PowerShell functions in a couple weeks (the week of December 21, 2009). We’ll save that discussion for then.

Image of Windows PowerShell 2.0 Best Practices book

Note: Portions of today's Hey Scripting Guy! post are excerpted from the Microsoft Press book, Windows PowerShell 2.0 Best Practices by Ed Wilson. The book is available for pre-order.

The easiest way to explain adding a function to the Windows PowerShell profile is to go ahead and add one to it.

This assumes you have created a Windows PowerShell profile. If you have not, refer back to Monday’s Hey, Scripting Guy! post.

Open your profile in Notepad. You can do this from inside the Windows PowerShell console by typing Notepad followed by the $profile automatic variable. This is seen here:

Notepad $profile

The Windows PowerShell profile we have been working on all week is displayed. It is seen in the following image:

Image of the Windows PowerShell profile from this week


On Monday when we were creating our Windows PowerShell profile, we added comments to create sections of the profile for each of the four things commonly placed in a profile. We now want to add a function, which goes in the (wait for it) function section. One function you will want to add to your Windows PowerShell profile is one that opens your profile in Notepad so that you can edit it. To do this, use the Function keyword to tell Windows PowerShell you are creating a function, and then give the function a name. As a best practice when writing Windows PowerShell scripts, you should always use a two-part name that comprises a verb and a noun. For ideas of good verbs to use, you can use the Get-Verb function to provide a list of approved verbs:

Image of results from Get-Verb function


Because the Get-Profile function will open the profile in Notepad, it “gets” the profile. This is why I named the function Get-Profile. The command you wish to execute is placed between the two curly brackets. As a Windows PowerShell best practice, you should add a comment to your closing curly brackets that indicates what the closing bracket is doing. This will greatly facilitate troubleshooting your scripts.

I learned this best practice when I was taking the ICE train from Regensburg to Hamburg in Germany a few years ago. It is a five-hour trip, and shortly after the train departed the HBF in Regensburg, I introduced an error into the script I was writing. I did not find the error until the train crossed the final bridge before entering the Hamburg HBF. The problem, of course, was a missing curly bracket. As a direct result of that experience, I began adding closing comments to my curly brackets.

The Get-Profile function is seen here:

Function Get-Profile
{
 Notepad $profile
} #end function get-profile

The other thing I like to do is to create an alias for a function that I add to my Windows PowerShell profile. The reason I am adding the function to the profile in the first place is because I anticipate I will be using it on a regular basis. If I am going to be using the function on a regular basis, it makes sense to create a alias for it.

Before creating a new alias, it is a best practice to see if there is a suitable alias already created for the cmdlet in question. By default, Windows PowerShell ships with more than 130 predefined aliases for its 271 cmdlets, and many of them are two-letter aliases. The two-letter aliases are shown here:

PS C:\> Get-Alias ??

CommandType     Name                                                Definition
-----------     ----                                                ----------
Alias           ac                                                  Add-Content
Alias           cd                                                  Set-Location
Alias           cp                                                  Copy-Item
Alias           fc                                                  Format-Custom
Alias           fl                                                  Format-List
Alias           ft                                                  Format-Table
Alias           fw                                                  Format-Wide
Alias           gc                                                  Get-Content
Alias           gh                                                  Get-Help
Alias           gi                                                  Get-Item
Alias           gl                                                  Get-Location
Alias           gm                                                  Get-Member
Alias           gp                                                  Get-ItemProperty
Alias           gu                                                  Get-Unique
Alias           gv                                                  Get-Variable
Alias           ii                                                  Invoke-Item
Alias           lp                                                  Out-Printer
Alias           ls                                                  Get-ChildItem
Alias           md                                                  mkdir
Alias           mi                                                  Move-Item
Alias           mp                                                  Move-ItemProperty
Alias           mv                                                  Move-Item
Alias           ni                                                  New-Item
Alias           nv                                                  New-Variable
Alias           oh                                                  Out-Host
Alias           ps                                                  Get-Process
Alias           rd                                                  Remove-Item
Alias           ri                                                  Remove-Item
Alias           rm                                                  Remove-Item
Alias           rp                                                  Remove-ItemProperty
Alias           rv                                                  Remove-Variable
Alias           sc                                                  Set-Content
Alias           si                                                  Set-Item
Alias           sl                                                  Set-Location
Alias           sp                                                  Set-ItemProperty
Alias           sv                                                  Set-Variable

You do not want to go to all the trouble of editing your profile, and restarting Windows PowerShell only to find out there is a conflict with your alias choice. My first choice for an alias for the Get-Profile function would be gp. To see if it is available, use the Get-Alias cmdlet as seen here:

PS C:\> Get-Alias gp

CommandType     Name                                                Definition
-----------     ----                                                ----------
Alias           gp                                                  Get-ItemProperty


PS C:\>

As you can see, the alias gp is already taken unfortunately. We have two options, remove the gp alias by using the Remove-Item cmdlet, or choose something else. To remove the gp alias, you will need to use the Force parameter. This is because it is a read-only alias. This is seen here:

PS C:\> Remove-Item alias:\gp
Remove-Item : Alias was not removed because alias gp is constant or read-only.
At line:1 char:12
+ Remove-Item <<<<  alias:\gp
    + CategoryInfo          : WriteError: (gp:String) [Remove-Item], SessionStateUnauthorizedAccessException
    + FullyQualifiedErrorId : AliasNotRemovable,Microsoft.PowerShell.Commands.RemoveItemCommand

PS C:\> Remove-Item alias:\gp -Force
PS C:\>

In the end, I decided to use p as the alias for the Get-Profile function. This command is shown here:

New-Alias -name p -value Get-Profile -description MrEd_Alias

The newly modified profile is seen here.

Profile.ps1

# HSG_Profile_11_26_09.ps1
# HSG-11-26-09
# Ed Wilson, MSFT, 11/18/2009
# Version 1.0

# *** Variables ***
New-Variable -Name ProfileFolder -Value (Split-Path $PROFILE -Parent) `
   -Description MrEd_Variable
New-Variable -Name IseProfile `
   -Value (Join-Path -Path (Split-Path $PROFILE -Parent) `
   -ChildPath Microsoft.PowerShellISE_profile.ps1) `
   -Description MrEd_Variable
New-Variable -Name MyComputers -Value Hyperv,Win7-PC -Description MrEd_Variable
New-Variable -name temp -value $([io.path]::gettemppath()) -Description MrEd_Variable
Set-Variable -Name MaximumHistoryCount -Value 128 -Description MrEd_Variable

# *** Alias ***
Get-Command -CommandType cmdlet |
Foreach-Object {
 Set-Alias -name ( $_.name -replace "-","") -value $_.name -description MrEd_Alias
} #end Get-Command
New-Alias -name gh -value Get-Help -description MrEd_Alias
New-Alias -name i -value Invoke-History -description MrEd_Alias
New-Alias -name p -value Get-Profile -description MrEd_Alias

# *** PS Drive ***

# *** Function ***
Function Get-Profile
{
 Notepad $profile
} #end function get-profile

 

Well, AM, our Windows PowerShell profile is working well, and is reasonably complete. Feel free to add things to it as you think of new ways to customize the way that Windows PowerShell works for you. If you have a great idea for your Windows PowerShell profile, send e-mail to me at scripter@microsoft.com. If you would like to share your profile, upload it to the Script Repository. I would put it in the Scripting Techniques/Script Templates folder, and tag it as Profile. In fact, I just uploaded the profile we created this week to that exact location. Join us tomorrow for Quick-Hits Friday.  

If you want to know exactly what we will be looking at tomorrow, follow us on Twitter or Facebook. If you have any questions, send e-mail to us at scripter@microsoft.com or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, keep on scripting!

 

Ed Wilson and Craig Liebendorfer, Scripting Guys