Use PowerShell
The Shell Is Calling
The Shell Is Calling
Apr 29th
If you’ve worked with cmd.exe or other shell environments, you might be familiar with environmental variables.
PowerShell exposes these variables in two different ways. (Actually it’s the same way, but don’t tell anyone..)
First, I can access environmental variables through the provider.
dir env:\
All my standard commands in navigating and retrieving items from a provider (Get-Item, Set-Item, New-Item, etc..) work in interacting with these variables.
The other access method also uses the provider, but it accesses it in a bit different way.. By using the "$" and the PSDrive name.
$env:username
NOTE: This syntax can be used with other providers as well (eg $c:Windows)
Apr 27th
Version 2 of PowerShell introduced Comment Based Help. This allows scripters and function writers to include structured help in their work, without having to write MAML help files.
One of the things I saw a good bit of in the Scripting Games this year was that people wrote their own help functions.
The usual pattern included if the script was run with a particular switch or no switch, like My-Script.ps1 –help, a little help text would be spewed out. I use that word (spewed) specifically, as the help text is often just printed to the console and does not work with Get-Help (and all the cool things I talked about with that yesterday..). Even if the author went through the trouble of making the output of his help function look like a PowerShell help file, you still loose the capabilities to do things like
get-help my-command.ps1 –parameter identity
With just a less work, you could turn that help function into Comment Based Help.
I say less work, because instead of having to write a function and set a parameter and logic to call that help function, the you can just wrap the help in block comments and put a period in front of the keywords.
<#
.Synopsis
Do-Something makes the magic happen
.Example Get-ADUser | Do-Something
Takes an ADUser and does something to that user.
.Parameter Identity
Takes an ADUser
.Notes
NAME: Do-Something
AUTHOR: Steve@UsePowerShell.com
LASTEDIT: 04/27/2011 12:11:58
KEYWORDS:
.Link
Http://blog.usepowershell.com
#>
Or if you really like the hash symbol
#.Synopsis #Do-Something makes the magic happen #.Example Get-ADUser | Do-Something #Takes an ADUser and does something to that user. #.Parameter Identity #Takes an ADUser #.Notes #NAME: Do-Something #AUTHOR: Steve@UsePowerShell.com #LASTEDIT: 04/27/2011 12:11:58 #KEYWORDS: #.Link #Http://blog.usepowershell.com
I won’t go into great detail on what the segments of help can be, as the Technet documentation does a great job, but I will highlight the different segments.
Comment Based Help can be stored at the beginning of a function,
function Do-Something()
{
<#
.Synopsis
Do-Something makes the magic happen
.Example Get-ADUser | Do-Something
Takes an ADUser and does something to that user.
.Parameter Identity
Takes an ADUser
.Notes
NAME: Do-Something
AUTHOR: Steve@UsePowerShell.com
LASTEDIT: 04/27/2011 12:11:58
KEYWORDS:
.Link
Http://blog.usepowershell.com
#>
param (
[Parameter(ValueFromPipeline=$true)
[Microsoft.ActiveDirectory.Management.ADUser]
$Identity)
process
{
#Do Something of Value here
}
}
at the end of a function,
function Do-Something()
{
param (
[Parameter(ValueFromPipeline=$true)
[Microsoft.ActiveDirectory.Management.ADUser]
$Identity)
process
{
#Do Something of Value here
}
<#
.Synopsis
Do-Something makes the magic happen
.Example Get-ADUser | Do-Something
Takes an ADUser and does something to that user.
.Parameter Identity
Takes an ADUser
.Notes
NAME: Do-Something
AUTHOR: Steve@UsePowerShell.com
LASTEDIT: 04/27/2011 12:11:58
KEYWORDS:
.Link
Http://blog.usepowershell.com
#>
}
or before the function keyword.
<#
.Synopsis
Do-Something makes the magic happen
.Example Get-ADUser | Do-Something
Takes an ADUser and does something to that user.
.Parameter Identity
Takes an ADUser
.Notes
NAME: Do-Something
AUTHOR: Steve@UsePowerShell.com
LASTEDIT: 04/27/2011 12:11:58
KEYWORDS:
.Link
Http://blog.usepowershell.com
#>
function Do-Something()
{
param (
[Parameter(ValueFromPipeline=$true)
[Microsoft.ActiveDirectory.Management.ADUser]
$Identity)
process
{
#Do Something of Value here
}
}
NOTE: In a script, you can only use the before the body of the script or after the body of the script, since the script is self contained in one file.
And if that’s not easy enough, there are several functions that have been written to help you create your comment based help.
Apr 26th
PowerShell contains a vast array of content in it’s help files. The help files are exposed by the Get-Help cmdlet. So, what’s really under the covers in the help system?
PowerShell has a growing surface of things that it can cover. WMI, COM, .NET, Exchange, Active Directory, SharePoint, and on and on. How are we ever supposed to find the commands and information we need to use PowerShell effectively. Get-Help gives us some options.
First off, Get-Help let’s us search all the help it has access to (see below on where the help comes from) by a keyword.
Let’s start with an example. I’m going to compete in the Beginner category of the Scripting Games for Event #1. That event wants me to find out if an program being run is a private build or not. Since the program is running, we need to deal with processes. But what can PowerShell do with processes?
PS C:\Users\smurawski> Get-Help process Name Category Synopsis ---- -------- -------- Get-Process Cmdlet Gets the processes that are running on the local computer or a remote co... Stop-Process Cmdlet Stops one or more running processes. Wait-Process Cmdlet Waits for the processes to be stopped before accepting more input. Debug-Process Cmdlet Debugs one or more processes running on the local computer. Start-Process Cmdlet Starts one or more processes on the local computer.
So, that gives me a list of commands that refer to process in their help. I’ve got a starting place now!
Now that I’ve narrowed down my search to a handful of commands, one really jumps out at me – Get-Process.
PS C:\Users\smurawski> Get-Help Get-Process
NAME
Get-Process
SYNOPSIS
Gets the processes that are running on the local computer or a remote computer.
SYNTAX
Get-Process [[-Name] ] [-ComputerName ] [-FileVersionInfo] [-Module] []
Get-Process -Id [-ComputerName ] [-FileVersionInfo] [-Module] []
Get-Process -InputObject
[-ComputerName ] [-FileVersionInfo] [-Module] []
DESCRIPTION
The Get-Process cmdlet gets the processes on a local or remote computer.
Without parameters, Get-Process gets all of the processes on the local computer. You can also specify a particular process by process name or process ID (PID) or pass a process object through the pipeline to Get-Process.
By default, Get-Process returns a process object that has detailed information about the process and supports methods that let you start and stop the process. You can also use the parameters of Get-Process to get file version information for the program that runs in the process and to get the modules that the process loaded.
RELATED LINKS
Online version: http://go.microsoft.com/fwlink/?LinkID=113324
Get-Process
Start-Process
Stop-Process
Wait-Process
Debug-Process
REMARKS
To see the examples, type: "get-help Get-Process -examples".
For more information, type: "get-help Get-Process -detailed".
For technical information, type: "get-help Get-Process -full".
Checking out the help provided, I can see the various ways that I can call Get-Process (also known as the Parameter Sets). I have a synopsis and description for the command, related commands, and finally some remarks.
The remarks offer us several options to how we can access Get-Help to provide additional information.
The first option is Detailed. Detailed help provides addition descriptions of each of the parameters, as well as examples of usage. For example:
PARAMETERS
-ComputerName
Gets the processes running on the specified computers. The default is the local computer.
Type the NetBIOS name, an IP address, or a fully qualified domain name of one or more computers. To specify the local computer, type the computer name, a dot (.), or "localhost".
This parameter does not rely on Windows PowerShell remoting. You can use the ComputerName parameter of Get-Process even if your computer is not configured to run remote commands.
and
-------------------------- EXAMPLE 1 -------------------------- C:\PS>Get-Process Description ----------- This command gets a list of all of the running processes running on the local computer. For a definition of each column, see the "Additional Notes" section of the Help topic for Get-Help.
The second option is Full. Full offers a further details on parameters like whether or not the value is required or can be filled with pipeline input.
PARAMETERS
-ComputerName
Gets the processes running on the specified computers. The default is the local computer.
Type the NetBIOS name, an IP address, or a fully qualified domain name of one or more computers. To specify the local computer, type the computer name, a dot (.), or "localhost".
This parameter does not rely on Windows PowerShell remoting. You can use the ComputerName parameter of Get-Process even if your computer is not configured to run remote commands.
Required? false
Position? named
Default value
Accept pipeline input? true (ByPropertyName)
Accept wildcard characters? false
Get-Help also allows you to do other interesting things like get a refresher on a particular parameter.
PS C:\Users\smurawski> get-help Get-Process -Parameter FileVersionInfo -FileVersionInfo [] Gets the file version information for the program that runs in the process. On Windows Vista and later versions of Windows, you must open Windows PowerShell with the "Run as administrator" option to use this parameter on processes that you do not own. Using this parameter is equivalent to getting the MainModule.FileVersionInfo property of each process object. When you use this parameter, Get-Process returns a FileVersionInfo object (System.Diagnostics.FileVersionInfo), not a process object. So, you cannot pipe the output of the command to a cmdlet that expects a process object, such as Stop-Process. Required? false Position? named Default value Accept pipeline input? false Accept wildcard characters? false
Sometimes you just need a quick example to get you going.
NAME
Get-Process
SYNOPSIS
Gets the processes that are running on the local computer or a remote computer.
-------------------------- EXAMPLE 1 --------------------------
C:\PS>Get-Process
Description
-----------
This command gets a list of all of the running processes running on the local computer. For a definition of each column, see the "Additional Notes" section of the Help topic for Get-Help.
...
NOTE:There are more examples for this command, I’ve just truncated the output to save space.
Get-Help is not limited to getting help for commands. PowerShell comes with a rich set of documentation, all available from the shell. Get-Help about_* will provide you a list of all the great help topics available.
If you’ve always had a burning desire to learn more about how PowerShell deals with quoting, you could use Get-Help about_Quoting_Rules.
The last tip/trick that Get-Help leaves us is the -Online parameter. If a help file is configured with a link, this parameter will open your default browser and go to that link. The effect is that you can always find the latest version of the online documentation for commands configured that way. All of the core commands include online help, and anyone who publishes scripts, functions, or modules can host their own online help as well.
The help files are stored in a couple of ways. First off, there are a series of XML files (using MAML – Microsoft Assistance Markup Language) that contain the help under a localized directory in $pshome (an automatic variable that points to where PowerShell is installed).
Snapin and module authors can include MAML files to provide help to users of those items (there is a tool to help create the MAML files – the Cmdlet Help Editor).
Finally, scripters can create Comment Based Help for their scripts and functions. The cool thing about that is that your scripts and functions can behave exactly like the built in commands in providing help on usage, parameters, and examples. If you are really ambitious, you can also create online documentation and link to that.
Apr 25th
My previous posts about the Scripting Games had many references to how parameters were used in scripts and functions. Since those posts, I’ve had several requests to expand on that, so here we go…
In PowerShell V1, when we wrote scripts or functions, we had two main ways to retrieve parameters.
First off, we could parse $Args.
function Do-Something ()
{
$FirstArgument = $args[0]
$SecondArgument = $args[1]
...
This was a particularly bad approach (in most cases), since users did not get any help from tab completion on parameter names and they had to get the right order to make things work (meaning they had to be very familiar with the order of things required.
PowerShell promised us a better, more enlightened manner of getting input into our functions and scripts, declaring parameters.
function Do-Something ()
{
param ($FirstArgument, $SecondArgument)
...
Declaring our parameters like this allows a user to specify the parameter name and let a user take advantage of tab completion to find the parameters allowed. Parameters could be specified in any order, so long as there was enough information to match them up.
Since PowerShell is an object-based environment and can use .NET, we also gained the ability to specify the type of input we were expecting. This lets us catch errors much sooner (for example if we were expecting a number and someone tried to pass in “hello”) and gives the user immediate feedback that something is not right.
function Do-Something ()
{
param ([string]$FirstArgument, [int]$SecondArgument)
...
One of the final benefits that this syntax allows for is that we can specify a default value (or through some trickery create a mandatory parameter).
function Do-Something ()
{
param ([string]$FirstArgument="PowerShell Rocks",
[int]$SecondArgument = $(throw "I'm Required!!")
...
Version 2 of PowerShell kicks parameters into high gear. All the cool things that developers could do in managed code writing a PowerShell cmdlet were now in the hands of scripters.
By building on to the parameter declarations and adding one or more “attributes”, we can do all sorts of wonderful things. (This is by no means an exhaustive list. Check the about_Advanced_Parameters help topic for further information.)
We can
[parameter(mandatory=$true)][string]$FirstParameter
[parameter(mandatory=$true, position=0)][string]$FirstParameter
[parameter(mandatory=$true, ValueFromPipeline=$true)][string]$FirstParameter
[parameter(mandatory=$true, ValueFromPipelineByPropertyName=$true)][string]$Name
[parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)]
[alias('Server','__Server', 'Name')]
[string]
$ComputerName
[parameter(ValueFromRemainingArguments=$true)][string]$Name
[parameter(HelpMessage="I want a name here")][string]$Name
[parameter(mandatory=$true, ValueFromPipelineByPropertyName=$true)] [ValidateNotNullOrEmpty()] [string] $Name
These different options throw open the doors for all sorts of cool scenarios and greatly reduce the amount of work we as scripters need to do to take input into our scripts and functions.
Once we’ve figured out how to make our parameters act like those of cmdlets, we can begin to leverage the same techniques we use with cmdlets (like scriptblock parameters).
Scriptblock parameters allow you to transform your pipeline input to any parameter that takes a value from the pipeline by property name.
For example, if I wanted to copy and rename a file based on the current file name, I could do something like
Get-childitem ~\documents\windowspowershell\*.ps1 | copy-item -destination {$_.fullname -replace 'windowspowershell','backup'}
Instead of having to transform the location inside of a foreach loop or create a mapping of the old location and new location, I can pass that transformation as an argument to the command and it will evaluate that for each item piped in.
My example uses cmdlets, but when I add the pipeline related parameter attributes to my parameters in my script or function, I gain that capability as well.