Quantcast
Channel: Windows PowerShell - SAPIEN Blog
Viewing all 308 articles
Browse latest View live

New! Kindle Edition of Windows PowerShell 4.0 TFM

$
0
0

Windows PowerShell TFM, 4th Edition by Jason Helmick and Mike F. Robbins (SAPIEN Press 2014) is now available in both Kindle Edition and paperback from Amazon.com.

PSTFM4

This is a big win for eBook lovers, for our international friends, and for those of us who need a paperback by the laptop and a Kindle Edition for the road. You can read the Kindle Edition even without a Kindle device by downloading a free Kindle reading app for your computer, tablet, or smartphone.

For links to all editions of the book on U.S. and international Amazon sites, see: Windows PowerShell TFM 4.0.

Jason and Mike have combined a clear, comprehensive, and practical introduction to Windows PowerShell with the newest strategies for advanced automation to make the book useful for absolute beginners through expert users. It’s chock full of commands and scripts that you can use today to manage your enterprise, including an in-depth review of Windows PowerShell 4.0 features and modules for IIS, Active Directory, SQL Server, Exchange, System Center, Remote Desktop Services, and much more. The exercises and tasks make it feel like you’re in a hands-on lab with Jason and Mike.

If you haven’t had a chance to thumb through the book, see the table of contents and check out the Look Inside, which includes the overview, early chapters, and a several of the exercises. You can also download a sample of the Kindle book on any device.

And, please join us in thanking our awesome designer, Maricela Soria, for all of her hard work in producing the Kindle Edition.

 
[Google+] [Twitter] [Facebook] [LinkedIn] [StumbleUpon] [Digg] [Reddit] [Google Bookmark]

Parameter validation affects parameter variables

$
0
0

In a Google+ discussion this week, Edi Prinz demonstrated an effect of the ValidationRange parameter attribute that surprised many of us. When you validate a parameter value, the validation rules are enforced on the parameter variable — and that enforcement persists on the variable for the entire function scope.

EdiPrinz

For example, this function has a Value parameter. It uses the ValidateRange parameter attribute to allow only parameter values between 3 and 8, inclusive.

function Test-Validation {
    Param (
        [ValidateRange(3,8)]
        [Int32]
        $Value
    )
 
    $Value = 3 * $Value
    $Value
}

Let’s call the function with a value of 4 (between 3 and 8) for the parameter.

Test-Validation –Value 4

The variable cannot be validated because the value 
12 is not a valid value for the Value variable.
At C:\ps-test\Test-ParameterValidation.ps1:7 char:5
+     $Value = 3 * $Value
+     ~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : MetadataError: (:) [], ValidationMetadataException
    + FullyQualifiedErrorId : ValidateSetFailure

4

 

What’s happening here? Why is there an error when the Value parameter has a value of 4?

When you call the Test-Validation function with a value of 2 for the Value parameter, it returns a parameter validation error (“Cannot validate argument on parameter…”), as expected, because a parameter value of 2 is not between 3 and 8 inclusive.

PS C:\ps-test> Test-Validation -Value 2

Test-Validation : Cannot validate argument on parameter 'Value'. 
The 2 argument is less than the minimum allowed range of 3. 
Supply an argument that is greater than or equal to 3 and then try the command again.
At line:1 char:24
+ Test-Validation -Value 2
+                        ~
+ CategoryInfo          : InvalidData: (:) [Test-Validation], 
ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationError,Test-Validation

 

When you enter a parameter value that’s within the allowed range (such as 4), you don’t get a parameter validation error. Instead, the command that saves the product of “3 * $Value” (12) in the $Value variable causes a variable validation error (“…variable cannot be validated…”) error because 12 is not between 3 and 8 inclusive.

$Value = 3 * $Value

The variable value failed the range test, even though the parameter value satisfied it. Notice that the final $Value command returns a value of 4, because the command to assign a value of 12 failed.

PS C:\ps-test> Test-Validation -Value 4
The variable cannot be validated because the 
value 12 is not a valid value for the Value variable.
At C:\ps-test\Test-Validation.ps1:11 char:2
+     $Value = 3 * $Value
+     ~~~~~~~~~~~
+ CategoryInfo          : MetadataError: (:) [], ValidationMetadataException
+ FullyQualifiedErrorId : ValidateSetFailure

4

 

Surprisingly, the validation that we set on the Value parameter is enforced on the $Value variable, even though we didn’t set any validation on the variable.

Let’s see why it happens, when it happens, and how to fix it.

 

Why: Parameters and parameter variables

Why does this happen?

In Windows PowerShell, function parameters are automatically converted to variables so you can use them in function commands. For example, the -Value parameter automatically becomes a $Value variable. If Windows PowerShell didn’t do this for you, you might need to save the parameter value in local variable explicitly.

function Get-Triple
{
    Param ([Int32]$Value)   #<-— This parameter...
 
    $Value = 3 * $Value     #<—- becomes this variable.
}

 

But, in the Test-Validation function script block, we forgot about the parameter-ness of this parameter variable and just thought of it as a variable. And that’s fine. Most of the time. But not when you’re using parameter validation attributes.

 

Where: What’s the scope of this effect?

Windows PowerShell applies parameter validation to the parameter variable in the script.

  • Affects all Validate* attributes, such as ValidateSet and ValidatePattern, but not other attributes, such as Allow.
  • Occurs in Windows PowerShell 2.0 and later. (In the Google+ discussion, you’ll see mentions of 4.0 and 3.0 in the Google+ conversation, but it happens in 2.0, too.)

 

How to override the validation

Now that we know the effect, it’s easy to avoid an error.

  • Create a new variable and use the new variable in the calculations.For example, in this function, we create a second variable called $NewValue.
function Test-Validation {
    Param (
        [ValidateRange(3,8)]
        [Int32]
        $Value)
 
    $NewValue = 3 * $Value
    $NewValue
}
    • Beginning in Windows PowerShell 3.0, you can use the Validation attributes on variables, so you can set a new validation range on the parameter variable (or any other variable).
      When you use ValidateRange to set a range of 0 – 9999 for the $Value variable, this function now runs without error.
function Test-Validation {
    Param (
        [ValidateRange(3,8)]
        [Int32]
        $Value)
 
    [ValidateRange(0, 9999)]$Value = 3 * $Value
    $Value
}
Test-Validation -Value 4
12

But, to fix the problem, you have to know that it exists.

Many thanks to Edi Prinz for pointing this out and for filing a Connect documentation bug against the about_Functions_Advanced_Parameters help topic. I voted up the bug. Hope you do, too.

June Blender is a technology evangelist at SAPIEN Technologies, Inc. You can reach her at juneb@sapien.com or follow her on Twitter at @juneb_get_help.

 
[Google+] [Twitter] [Facebook] [LinkedIn] [StumbleUpon] [Digg] [Reddit] [Google Bookmark]

PowerShell Studio 2015 – What’s new?

$
0
0

The new version of PowerShell Studio is upon us. All major releases are included as a free upgrade for those with an active subscription.

 

PowerShell Studio 2015

image

We worked hard on overhauling the parser and other internal systems so that we can implement your requested features and improve the overall editing experience in PowerShell Studio 2015.

Here are some of the new additions to PowerShell Studio 2015:

 

Improved Syntax Coloring

We improved the syntax coloring so that it better reflects the complexities of Windows PowerShell.

 

Double Quote Strings

As per your request, variables and sub-expressions are now colored in double quote strings:

image

 

PrimalSense and Parameter Sets

PowerShell Studio 2015 will display the syntax for each parameter set defined in your functions:

image 

It also displays the syntax for dot sourced files:

image

 

And even project files:

image 

The comment-based help synopsis is now displayed as well.

 

Casting and Types

In PowerShell Studio 2015 we improved type coloring to include subtypes:

image

As always, PowerShell Studio only colors valid types in order to provide you with visual cues when something isn’t right:

image

 

Improved Contextual PrimalSense

We improved the PrimalSense to make it easier to pick up where you left off. PowerShell Studio’s PrimalSense is now more contextually aware.

Press [Ctrl + Space] to bring up the PrimalSense:

image 

The PrimalSense will list the appropriate items depending on the context.

 image

PrimalSense for parameter attributes:

image  

 

These internal changes are stepping stones to future improvements. Our current subscription model allows us to continuously release new features without holding back for the next major release.

Stay tuned for new feature announcements.

 
[Google+] [Twitter] [Facebook] [LinkedIn] [StumbleUpon] [Digg] [Reddit] [Google Bookmark]

Troubleshooting Comment-Based Help

$
0
0

A Windows PowerShell user group member recently came to me with a question about comment-based help in Windows PowerShell. It reminded me again that comment-based help is not as easy to use as you might think. Here are a few tips to help you avoid and fix obvious pitfalls.

TIP: When testing help, be sure to restart your session between each test. Windows PowerShell caches help for the session, so changes to the help are effective only in a new session.

 

image

 

RTFM: about_Comment_Based_Help

The best way to avoid errors is to read the about_Comment_Based_Help topic. It covers issues like the placement of comment-based help in functions, scripts, and script modules. It lists the keywords and provides some useful examples. Be sure to start there. This post is supplemental.

 

Use Only Valid Keywords

Comment-based help must include only valid keywords. If even one keyword is invalid, Get-Help ignores the entire comment-based help block and displays auto-generated help.

The keyword names are case-insensitive, but they must be spelled exactly as specified. None of the keywords are required* in comment-based help, but you can’t add or change keywords, even it you really want a new one (such as .FILENAME, which would be a really good idea). If you use .NOTE (instead of .NOTES) or .EXAMPLES (instead of .EXAMPLE), Get-Help doesn’t display any of it.

It’s very picky! If the format of a keyword is wrong, such as forgetting to place the parameter name on the same line as the .PARAMETER keyword, the entire comment-based help block is ignored.

.SYNOPSIS
.DESCRIPTION
.PARAMETER
.EXAMPLE
.INPUTS
.OUTPUTS
.NOTES
.LINK
.COMPONENT
.ROLE
.FUNCTIONALITY
.FORWARDHELPTARGETNAME
.FORWARDHELPCATEGORY
.REMOTEHELPRUNSPACE
.EXTERNALHELP

*.ExternalHelp is required for function with Help XML files, but it’s not required for the comment-based help display.

 

Distinguish HelpMessage from Parameter Comments and .PARAMETER

There are three ways to add a parameter description to function help. I’ve listed them below in precedence order.

Notice that Get-Help displays a parameter comment only when there is at least one valid comment-based help keyword for the command and it is not a .PARAMETER keyword for the same parameter. If the parameter comment is the only help for the command, it is ignored.

Also, the HelpMessage attribute is part of auto-generated help, not comment-based help.

 

  • The .PARAMETER keyword takes precedence over other parameter description types. Get-Help displays it even when it is the only comment-based help keyword for the function.
<#     .PARAMETER Name         Enter a unique name for the widget. #>
  • A parameter comment appears in the Get-Help display when there is valid comment-based help, but no .PARAMETER keyword for that parameter.
Param
(
    [Parameter(Mandatory = $true)]
    [string]
    # Enter a unique name for the widget.
    $Name
)
  • The HelpMessage attribute appears in the Get-Help display only when there is no help (of any type) for the command.
Param
(
    [Parameter(Mandatory = $true, HelpMessage = "Enter a unique name for the widget.")]
    [string]
    $Name
)

 

According to the MSDN docs, the HelpMessage attribute of a parameter appears when Windows PowerShell prompts for a mandatory parameter value, but Get-Help doesn’t display it. Based on my tests of Windows PowerShell 2.0 – 5.0 preview, Get-Help does display the HelpMessage attribute value in auto-generated help.

The HelpMessage attribute appears when you type !? in response to a mandatory parameter prompt.

function Get-CBHelp
{
    param
    (
        [Parameter(Mandatory = $true, 
                   HelpMessage = "Enter a unique name for the widget.")]
        [String]
        $Name
    )
    $Name
}
PS C:\> . .\Test-CBHelp.ps1"
PS C:\> Get-CBHelp
cmdlet Get-CBHelp at command pipeline position 1
Supply values for the following parameters:
(Type !? for Help.)
Name: !?
Enter a unique name for the widget.

However, it also appears in auto-generated help when there is no help for the command. To make Get-Help ignore the comment-based help and display auto-generated help, I’ll just delete the first “S” from .SYNOPSIS.

<# .YNOPSIS 
    Tests elements of comment-based help 
.DESCRIPTION 
    This function doesn't do anything. It was created only for testing. 
.PARAMETER Name 
    This is the parameter keyword. 
.EXAMPLE 
    PS C:\&gt; Get-CBHelp -Name Plebius
    Plebius
#>
function Get-CBHelp
{
    Param
    (
    [Parameter(Mandatory = $true, HelpMessage = "This is the HelpMessage attribute.")]
    # Here is the parameter comment.
    [string]
    $Name
)
    $Name
}

 

PS C:\> . .\Test-CBHelp.ps1
PS C:\> Get-Help -Full Get-CBHelp

NAME
Get-CBHelp

SYNTAX
Get-CBHelp [-Name] <string>  [<CommonParameters>]

PARAMETERS
-Name <string>
This is the HelpMessage attribute.

Required?                    true
Position?                    0
Accept pipeline input?       false
Parameter set name           (All)
Aliases                      None
Dynamic?                     false

 

Use .ExternalHelp for Function Help XML Files

There are no required keywords in comment-based help. For example, if you have a comment-based help block that contains only a .INPUTS keyword and its value, Get-Help displays the Inputs section that you specify and fills in the rest from auto-generated help.

The only keyword that might be thought of as required is .EXTERNALHELP. This comment keyword must appear when help for a function is written in a Help XML file. Unlike the help XML files for other command types, help XML files for functions do not have standard names or locations. Thus, without .EXTERNALHELP, Get-Help does not know where to look for an Help XML file, regardless of its name and location.

The value of the .EXTERNALHELP keyword is the name of the help XML file without a path. Get-Help looks for a file with that name in a language-specific subdirectory of the module directory.

For example, because of the value of the .EXTERNALHELP keyword, Get-Help knows that it should look for a help topic for my Update-OneGet function in the UpdateOneGet.psm1-help.xml file in the en-US (or de-DE, etc) directory of its module directory, ($home\Documents\WindowsPowerShell\Modules\UpdateOneGet\en-US\UpdateOneGet.psm1-help.xml).

# .EXTERNALHELP UpdateOneGet.psm1-help.xml
function Update-OneGet
{
    Param
    ...
(

For more information about naming help files so Get-Help can find them, see Naming Help Files.

 

 

Use great tools

I need to mention that great PowerShell tools help you to avoid these syntactic problems.

For example, in PowerShell Help Writer, you write help topics in an environment customized for authoring Windows PowerShell help. You don’t need to worry about syntax or any other implementation details. You select a module and PowerShell Help Writer generates starter help topics with the correct syntax. If you have existing help, including comment-based help, it converts it automatically. This is really the ultimate help authoring environment.

image

 

In PowerShell Studio, the Function Builder (Insert function/Edit function) lets you compose comment-based help for a function while you’re writing the function. It adds the correct syntax so you don’t have to think about it.

image

 

PowerShell Studio also generates comment-based help on demand.

image

And, when you’re editing comment-based help in PowerShell Studio, PrimalSense suggests and inserts keywords with the correct spelling and format.

image

 

Writing comment-based help seems a bit more complicated than it needs to be. But knowing the “gotchas” makes the task of writing valid comment-based help a bit easier.

[Thanks to Windows PowerShell MVP Aleksandar Nikolic for correcting the “!?” omission in the original post.]

June Blender is a technology evangelist at SAPIEN Technologies, Inc. You can reach her at juneb@sapien.com or follow her on Twitter at @juneb_get_help.

 
[Google+] [Twitter] [Facebook] [LinkedIn] [StumbleUpon] [Digg] [Reddit] [Google Bookmark]

Beyond custom objects: Create a .NET class

$
0
0

In yesterday’s blog post, I used the Select-String cmdlet to capture the table of keywords and references from the about_language_keywords help topic and then used the new ConvertFrom-String cmdlet in the Windows PowerShell 5.0 preview to convert each row of the table into a custom object (PSCustomObject). The custom object worked quite well. I could search, sort, format, and use the objects in Windows PowerShell.

PS C:\> $k = $table | ConvertFrom-String -TemplateContent $template 
    | Select-Object -Property Keyword, Reference

PS C:\> $k | where Keyword -eq "Trap"

Keyword    Reference                                                                                 
-------    ---------                                                                                 
Trap       about_Trap, about_Break, about_Try_Catch_Finally

But, it’s just a simple step from the generic custom object to a named dynamic .NET object that I can create, manage, and use in many different contexts. In this post, I’ll use the new class feature of the Windows PowerShell 5.0 preview to create a Keyword class and real Keyword objects.

The class feature is new and works somewhat differently in the September version of the preview ($PSVersionTable.PSVersion = 5.0.9814.0) than it does in the November version (5.0.9883.0), so it’s likely to continue to change until (and even after) the official release.

For background, see the release notes that come with the Windows PowerShell 5.0 preview and Windows PowerShell MVP Trevor Sullivan’s playful and informative blog post, Implementing a .NET Class in PowerShell v5, in which he creates a Beer class.

 

Custom Objects for Keywords

The ConvertFrom-String cmdlet returns custom objects with the properties that you specify, either by using the PropertyNames parameter or one of the template parameters, TemplateContent or TemplateFile.

To see the properties and method of the objects that it returns, pipe the output (in this case, saved in the $k variable) to the Get-Member cmdlet.

PS C:\> $k | Get-Member

   TypeName: Selected.System.Management.Automation.PSCustomObject

Name        MemberType   Definition                                                       
----        ----------   ----------                                                       
Equals      Method       bool Equals(System.Object obj)                                   
GetHashCode Method       int GetHashCode()                                                
GetType     Method       type GetType()                                                   
ToString    Method       string ToString()                                                
Keyword     NoteProperty System.String Keyword=Begin                                      
Reference   NoteProperty System.String Reference=about_Functions, about_Functions_Advanced

The objects have the Keyword and Reference properties that we need, but the methods are pretty generic and not particularly useful.

And, beginning in Windows PowerShell 5.0, it’s very easy to create a .NET class dynamically.

Create a Keyword Class

To create a class, begin with the class keyword followed by the name of the class, which, in this case, is Keyword. The content of the class is enclosed in curly braces.

To add properties to the class, just create global variables. In this case, I’ve added Name and Reference properties. (Yes, it’s that easy.)

class Keyword 
{
    #Properties
    [String]$Name
    [String]$Reference
}

 

To allow people to create objects that are instances of the class, add at least one constructor.

A constructor is a special type of method that creates new objects. It has the same name as the class and it never returns anything (the return type is [Void], which means nothing. You can have multiple constructors, but each one has to take different numbers and types of parameters.

In the Keyword class, I added one constructor that has two string parameters, Keyword and Reference. The commands in the constructor assign the value of the Keyword parameter to the Name property of the object and the value of the Reference parameter to the Reference property of the object.

class Keyword 
{
    #Properties
    [String]$Name
    [String]$Reference
 
    #Constructor
    Keyword (
        [String]$Keyword
        [String]$Reference
    )
    {
        $this.Name = $Keyword
        $this.Reference = $Reference
    }
}

Unlike the output types of functions, which are just notes, the output types of methods are enforced. If the method doesn’t return the declared output type, the method generates an error.

The parentheses that surround the parameters are required, even when the method doesn’t take any parameters.

As we discussed in the section about constructors, all method parameters are mandatory and positional. Each method has only one parameter set. Methods in a class can have the same name, but if they do, they must take different types and numbers of parameters.

Did you notice the $this automatic variable? Like $_ in pipelines, $this refers to the current object. Inside a class, when you refer to a property of the current object, you must use the $this prefix, a dot, and the property name.

For example, to refer to the Name property of the current object, type:

$this.Name

Requiring the $this variable lets you use parameters with the same names as the properties. Windows PowerShell uses the $this to distinguish the property from the parameter. For example, I used $Reference as a property of the object and a parameter of the constructor. To assign the $Reference parameter value to the $Reference property, I type:

        # Property      = Parameter               
	$this.Reference = $Reference

 

Create Keyword Objects

Now that our class is complete, we can create Keyword objects. To create an object that is an instance of a .NET class, call the New method. (The New-Object cmdlet doesn’t yet work for dynamically created .NET classes.) New is a static method — a method of the class, not of any particular object in the class. All .NET objects have the New method, because they inherit it from the System.Object class.

To call a static method, type the class name in square brackets, two colons (with no intervening spaces), the method name, New, and a set of parentheses.

This code calls the New method of the Keyword class:

[Keyword]::New()

Inside the parentheses, call the constructor. Enter a comma-separated list of the values (omit the names) of the constructor parameters. All constructor parameters are mandatory and positional, so pay attention to the order of the values.

The Keyword class constructor has $Keyword and $Reference string parameters (in that order). To create a keyword object for the “If” keyword, use a command like this one:

[Keyword]::New("If", "about_If")

To convert a custom object that has Keyword and Reference properties to a Keyword object, use a command like this one. It pipes the custom objects in the $k variable to the ForEach-Object cmdlet, which calls the New static method of the Keyword class on each object and then stores the results in the $keywords variable.

$keywords = $k | ForEach-Object { [Keyword]::new($_.Keyword, $_.Reference)

Let’s see the result. The display looks just like the custom objects.

PS C:\> $keywords

Name         Reference                                                                                 
----         ---------                                                                                 
Begin        about_Functions, about_Functions_Advanced                                                 
Break        about_Break, about_Trap                                                                   
Catch        about_Try_Catch_Finally                                                                   
Continue     about_Continue, about_Trap

But, when you pipe them to the Get-Member cmdlet, you can see that the type is Keyword.

PS C:\> $keywords | Get-Member

   TypeName: Keyword

Name        MemberType Definition                    
----        ---------- ----------                    
Equals      Method     bool Equals(System.Object obj)
GetHashCode Method     int GetHashCode()             
GetType     Method     type GetType()                
ToString    Method     string ToString()             
Name        Property   string Name {get;set;}        
Reference   Property   string Reference {get;set;}

The real value becomes evident when you add methods to the class.

 

Add a Method

The value of the Reference property of each keyword is a list of help topics that explain how the keyword is used in Windows PowerShell. Let’s add a GetHelp() method to the Keyword class that returns the first help topic in each reference set.

The syntax of a class method is as follows.

    [OutputType] Name (Parameters)
  • OutputType. Enclose in square brackets the .NET type of the objects that the method returns. If the method doesn’t return anything, that is, if the output type is [Void], you can omit the output type, because Void is the default. It’s nice to include it anyway.Unlike the output types of functions, which are just notes, the output types of methods are enforced. If the method doesn’t return the declared output type, the method generates an error.
  • Name. Specify the name of the method. Typically, method names are a single camel-cased string.
  • Parameters. The parameters of a method are always mandatory and positional. Each method has only one parameter set. Methods in a class can have the same name as other methods, but if they do, they must take different types and numbers of parameters. The parentheses that surround the parameters are required, even when the method doesn’t take any parameters.

 

Here’s the code for the GetHelp() method of Keyword objects. It returns the first help topic in the Reference value as a single string. I used a Try-Catch block in case the help topic isn’t on the computer. In that case, it just returns an empty string.

    [String] GetHelp() 
    {
        [String]$firstRef = $this.Reference.Split(",").Trim() | Select-Object -First 1
        try 
        {
            return Get-Help $firstRef
        }
        catch
        {
            return ""
       }
    }

 

Let’s run the new improved Get-LanguageKeywords.ps1 script that contains the class and save the results in the $keywords property. Now, when you pipe the Keyword objects in the $keywords variable to the Get-Member cmdlet, you can see the new GetHelp() method:

PS C:\> $keywords | Get-Member

   TypeName: Keyword

Name        MemberType Definition                    
----        ---------- ----------                    
Equals      Method     bool Equals(System.Object obj)
GetHashCode Method     int GetHashCode()             
GetHelp     Method     string GetHelp()
GetType     Method     type GetType()               
ToString    Method     string ToString()             
Name        Property   string Name {get;set;}        
Reference   Property   string Reference {get;set;}

And, you can call the GetHelp() method of any Keyword object. In these commands, I get the Keyword object whose name equals “If” and call its GetHelp() method. The method returns the text of the about_If help topic.

PS C:\> $if = $keywords | where Name -eq "If"
PS C:\> $if.GetHelp()
TOPIC
    about_If

SHORT DESCRIPTION
    Describes a language command you can use to run statement lists based 
    on the results of one or more conditional tests.


LONG DESCRIPTION
    You can use the If statement to run code blocks if a specified 
    conditional test evaluates to true. You can also specify one or more
...

Summary

It’s just a short hop from the custom object with its generic methods to a Keyword object with specialized methods.

One word of caution. When you create a class in Windows PowerShell, it’s not saved in a library like the standard .NET classes, so it exists only in your session. To save your class, save it in a script or script module file.

June Blender is a technology evangelist at SAPIEN Technologies, Inc. You can reach her at juneb@sapien.com or follow her on Twitter at @juneb_get_help.

 

Get-Keywords.ps1

You can copy the script code here or download a ZIP file from the SAPIEN Downloads site.

To download, sign in, in the left nav, click Sample Scripts, click Get-Keywords.ps1.zip, and in the top right corner, click Download.

 

<#    
    .NOTES
    ===========================================================================
     Created with:     SAPIEN Technologies, Inc., PowerShell Studio 2014 v4.1.74
     Created on:       11/30/2014 12:10 AM
     Organization:     SAPIEN Technologies, Inc.
     Contact:       June Blender, juneb@sapien.com, @juneb_get_help
     Filename:         Get-Keywords.ps1
    ===========================================================================
    .SYNOPSIS
        Creates Keyword objects from the Keyword-Reference table in the
        about_Language_Keywords help topic.

    .DESCRIPTION
        The Get-Keywords.ps1 script gets the Keyword-Reference table
        from the about_Language_Keywords help topic. It uses the ConvertFrom-String
        cmdlet to convert each row of the table to a custom object, and returns
        the custom objects. Then it uses a Keyword class defined in the script to
        create Keyword objects.

        The Script takes no parameters, but it requires the about_Language_Keyword help
        topic and Windows PowerShell version 5.0.

    .INPUTS
        None

    .OUTPUTS
        Keyword

    .EXAMPLE
        $keywords = .\Get-LanguageKeyword.ps1
        
        $keywords.Keyword.Contains("While")
        True
        
        $keywords.Keyword.Contains("Grapefruit")
        False
        
        $keywords | where Name -eq "Finally"| Format-Table -Autosize
        Keyword                  Reference
        ----                     ---------
        Finally                  about_Try_Catch_Finally

        Get-Help ($keywords | where Name -eq "Finally").Reference
#>


class Keyword{

    #Properties
    [String]$Name
    [String]$Reference

    #Constructors
    Keyword(
        [String]$Keyword,
        [String]$Reference     
       )
    {
        $this.Name = $Keyword
        $this.Reference = $Reference
    }
    
    #Methods
    [String] GetHelp()
    {
        [String]$firstRef = $this.Reference.Split(",").Trim() | Select-Object -First 1
        try
        {
            return Get-Help $firstRef
        }
        catch
        {
            return ""
        }
    }
}


$template = @"

        {Keyword*:Begin}   {Reference:about_Functions, about_Functions_Advanced}
        {Keyword*:Catch}       {Reference:about_Try_Catch_Finally}
        {Keyword*:Exit}    {Reference:Described in this topic.}
        {Keyword*:Workflow}          {Reference:about_Workflows}
"@

if (!($help = dir $pshome\en-us\about_language_keywords.help.txt))
{
    throw "Can't find the about_language_keywords help topic. Run Update-Help and try again."
}

#Get the line number of the Keyword-Reference table header
#Add 2 to get the line number of the first entry in the table
$start = (($help | Select-String -Pattern 'Keyword\s{7,}Reference').LineNumber) + 2

#Get the line number of the first blank line after the table
#Subtract one to get the line number of the last table entry
$end = $start + (($help[($start - 1) .. 999] | Select-string -Pattern '^\s*$').LineNumber | Select-Object -First 1) - 1

#Get only the Keyword-Reference table
#Subtract 1 from each line number to get the indexes
$table = $help[($start - 1) .. ($end - 1)]

#Create a custom object from the Keyword-Reference table
$k = $table | ConvertFrom-String -TemplateContent $template | Select-Object -Property Keyword, Reference

#Convert each custom object to a Keyword object
#Use the null constructor and a hash table
$keywords = $k | foreach { [Keyword]@{ Name = $_.Keyword; Reference = $_.Reference } }
 
[Google+] [Twitter] [Facebook] [LinkedIn] [StumbleUpon] [Digg] [Reddit] [Google Bookmark]

Hidden … sort of: The Hidden Keyword in Windows PowerShell 5.0 Preview

$
0
0

The Hidden keyword hides properties and methods (and other members, like events) in a scripted class. When a member is hidden, you can still view and change it, but the Get-Member cmdlet doesn’t display it without the Force parameter and the hidden members are not available to auto-completion features, such as PrimalSense and IntelliSense.

You can apply the Hidden keyword to any member (property, method, event, etc), including static members. It is not case sensitive and it can appear anywhere in the member signature before the member name. As a best practice, I suggest placing it first to simplify troubleshooting.

NOTE: In this post, I’m working with the Windows Management Framework 5.0, Build 5.0.10018.0

————————————————-

I’ve spent quite a bit of time playing with classes in the Windows PowerShell 5.0 preview. The ability to create and script with your own classes, and to create subclasses of those classes, is extremely powerful. I consider it to be the final frontier in the dev-ops continuum, so I’m determined to make sure that everyone understands it, even people who have no development background.

One of the little quirks of scripted classes in Windows PowerShell is that all properties of instances of the class are public, visible, and read-write. When you add properties to a class, Windows PowerShell automatically creates special methods called accessors that let users of the class get and set (view and change) the property values.

For example, I’ll create a little Tree class with a Species property. At this point, I haven’t created any methods, not even constructors.

class Tree
{
    [String] $Species
}

When I create an instance of the Tree class…

$myTree = [Tree]::new()

… Windows PowerShell adds get_Species and set_Species accessor methods so you can view and change the Species property value. These methods are hidden, but you can see them when you use the Force parameter of Get-Member.

PS C:\> $myTree | Get-Member -Name "*Species*"

   TypeName: Tree

Name    MemberType Definition               
----    ---------- ----------               
Species Property   string Species {get;set;}



PS C:\> $myTree | Get-Member -Name "*Species*" -Force

   TypeName: Tree

Name        MemberType Definition               
----        ---------- ----------               
get_Species Method     string get_Species()     
set_Species Method     void set_Species(string )
Species     Property   string Species {get;set;}

In fact, every variable that you create in a class outside of a method becomes a property of that class with accessor methods to view and change it.

For example, I’ve added a Height property and a Grow method to the Tree class, and a grow_times variable to hold the number of times that I’ve called the Grow method on my tree. But Windows PowerShell considers the grow_times variable to be a property, and adds get/set methods for it to the class.

class Tree
{
    # Properties
    [String] $Species
    [double] $Height
 
    # Methods
    [int] Grow ([int]$inches)
    {
        $this.Height += $inches
        $this.grow_times++
        return $this.Height
    }
 
    # Variables -- these are properties, too.
    [int] $grow_times = 0
}

When I create an instance of the Tree class, grow_times is a property with get and set accessor methods, just like Species and Height.

PS C:\> $myTree | Get-Member

TypeName: Tree

Name        MemberType Definition
----        ---------- ----------
Equals      Method     bool Equals(System.Object obj)
GetHashCode Method     int GetHashCode()
GetType     Method     type GetType()
Grow        Method     int Grow(int inches)
ToString    Method     string ToString()
grow_times  Property   int grow_times {get;set;}
Height      Property   int Height {get;set;}
Species     Property   string Species {get;set;}

 

And, when I type $myTree and a dot, IntelliSense suggest the grow_times property, along with the other properties of the tree.

image

I can’t make my variable completely private to the class – there is no Private keyword — but there is a Hidden keyword that hides members from auto-complete features and from Get-Member without –Force.

In this example, I add the Hidden keyword to the grow_times property. I can place “Hidden” anywhere in the statement before the name, that is, it can go before or after “[int]” or an attribute, but I think it’s best to place it first, especially for troubleshooting.

class Tree
{
    # Properties
    [String] $Species
    [double] $Height
 
    # Methods
    [int] Grow ([int]$inches)
    {
        $this.Height += $inches
        $this.grow_times++
        return $this.Height
    }
 
    # Hidden properties
    hidden [int] $grow_times = 0
}

 

Now, when I create a tree object and run Get-Member, the grow_times property is not displayed.

image

The property is visible to Get-Member only with –Force.

PS C:\> $myTree | Get-Member -MemberType Property

TypeName: Tree

Name    MemberType Definition
----    ---------- ----------
Height  Property   int Height {get;set;}
Species Property   string Species {get;set;}


PS C:\> $myTree | Get-Member -MemberType Property -Force

TypeName: Tree

Name       MemberType Definition
----       ---------- ----------
grow_times Property   int grow_times {get;set;}
Height     Property   int Height {get;set;}
Species    Property   string Species {get;set;}

 

Users of the class can get and set the grow_times property, but only if they know about it. It is not advertised to them. (You cannot override or redefine the property accessors.)

PS C:\> $myTree.grow_times
0

PS C:\ps-test> $myTree.grow_times++

PS C:\ps-test> $myTree.grow_times
1

 

And, even though it is hidden, grow_times is available to all members of the class, including the Grow() method that increments it.

PS C:\> $myTree.Height = 10

PS C:\> $myTree.grow_times
0

PS C:\> $myTree.Grow(2)
12

PS C:\> $myTree.grow_times
1

Classes in the Windows PowerShell 5.0 preview give you a whole new level of power. And, the Hidden keyword is a handy tool for making classes work the way you designed them.

June Blender is a technology evangelist at SAPIEN Technologies, Inc. You can reach her at juneb@sapien.com or follow her on Twitter at @juneb_get_help.

——————————

More SAPIEN blog posts about the Windows PowerShell 5.0 preview:

Beyond custom objects- Create a .NET class
Enumerated Types in Windows PowerShell 5.0
Find variables with class

 
[Google+] [Twitter] [Facebook] [LinkedIn] [StumbleUpon] [Digg] [Reddit] [Google Bookmark]

What’s new in PrimalScript 2015?

$
0
0

Our 2015 versions have been out for a while and most of you already know about some of the new features. But we want to make sure you don’t miss anything, so here is a brief recap.

PrimalScript 2015 now has a PowerShell dialog editor

Dialog Editor

If you create graphical user interfaces (GUI) in PowerShell all the time, you probably already have SAPIEN PowerShell Studio. But if you just want to create a dialog here or there to prompt for some user input or display a particular piece of data as output, you do not need to create full-fledged event driven applications. Design your dialog, handle the events you need and dot source it or integrate it with your script. Easy.

image

Go check it out. It is in the Tools pane in PrimalScript.

 

PrimalScript 2015 now also has PowerShell Studio’s function builder

Function builder

Building advanced functions is not something that only happens in GUI applications. Whether you write a module or just a command line script, you need functions. So click on the function builder within the context of an existing function to edit or outside a function to create a new one.

image

 

Packager settings are now available from the Home tab

Package settings

 

Packaging and running a packaged script have been available on the Home tab for a long time. To change the packager, installer or deployment settings you had to go to the Deploy tab. You still can do that, but a secondary way to access these settings has been added to the drop down menus on the Home tab.

 

SAPIEN applications are available from the Tools tab

Tools tab

All major SAPIEN applications can now be launched from the Tools tab. We assume of course that you have all our tools already pinned to the taskbar, but just in case you don’t use one or the other application frequently enough for that, we make it easier to find them.

 

Object browser now organizes items by namespace

Objectsbynamespace

The previous versions of the object browser organized .NET framework classes by assembly. While this coincided a lot of times with namespace names, it was not always the case and could lead to confusion. This new organization will make it easier for you to follow the path from a .NET type name to its methods and properties. Of course we are always eager to improve things, so if you find anything that can be added to the object browser to make it better or simpler to use, please let us know.

 

Object browser includes help information and PowerShell call samples

objectbrowser

Method and property names of the .NET runtime are usually not very cryptic and in most cases you easily determine the purpose of an item by its name. However it never hurts to have a little bit of documentation at your fingertips, so we added the basic synopsis for all methods and properties to the object browser. Please note that some assemblies do not include this information, so there are a few cases where this information is not available.
You will also find a sample PowerShell call for all methods in this new version of the object browser. Simply drag and drop the text to your code and you get all the parameters already cast to their correct type.

 

There are some other improvements within PrimalScript that will make it load and perform faster, which cannot be expressed in screenshots and may not be all that visible to you. But we want you to know that we always look for ways of making PrimalScript better and faster and we count on your feedback to do so. So do not hesitate; head over to our SAPIEN support forum and let us know if there is anything we can do differently or add to make writing code easier for you.

 
[Google+] [Twitter] [Facebook] [LinkedIn] [StumbleUpon] [Digg] [Reddit] [Google Bookmark]

Supporting Multiple PowerShell Versions

$
0
0

As you may know both PowerShell Studio and PrimalScript support multiple versions of Windows PowerShell and allow you to switch between versions depending on what versions of PowerShell are installed.

Supported Windows PowerShell Versions:

V2, V3, V4

Note: V5 will be officially supported after its release. We do not offer support for preview versions.

Side by Side Installations:

Windows PowerShell V2 is the only version that can be installed side by side with the newer versions of Windows PowerShell.

After Windows PowerShell V3 each new version replaces the previous iterations.

Note on Packaging Platforms:

When working with our Script Packager, you will notice that there is no option listed for V4 that is because the V3 Platform engines also works with V4. Therefore if you are ever in doubt, choose the V3 option.

 

Note on RegisterControls.exe:

When installing a new version of Windows PowerShell (see the related article below) you have to run the RegisterControls.exe.

SNAGHTML1191c3c

The version 3 options also applies to Windows PowerShell V4.

 

Related Articles:

How to Enable and Disable PowerShell V2 on Windows 8

What to do when you install a new version of PowerShell?

 
[Google+] [Twitter] [Facebook] [LinkedIn] [StumbleUpon] [Digg] [Reddit] [Google Bookmark]

Writing XML Help for Advanced Functions

$
0
0

The introduction of SAPIEN PowerShell HelpWriter has made writing XML help files as easy – actually easier – than writing comment-based help. XML help is more robust and less error-prone than comment-based help. It supports updatable help and help in multiple languages, and it lets you separate help files from script and modules files, which is a real advantage when you’re working with many people in a shared coding environment, like GitHub.

PowerShell HelpWriter makes it easy to create XML help files for all commands in a module, including the functions in a manifest module or script module: just click New/New Help File (from Module). But, you’re not quite done. It takes a few more steps to associate a function with the XML help file.

 

What do I name the XML Help file?

You need to give your XML help file a name that Get-Help expects. Otherwise, Get-Help won’t find your help file. Instead, it displays only auto-generated help.

In Windows PowerShell 3.0, the XML help files for cmdlets, providers, and CIM commands must be named for the file in which the commands are defined. (This requirement is changed for nested modules in Windows PowerShell 4.0 and later, but the change isn’t backwards compatible.)

There are no requirements for the names of function help files, but, as a best practice, they are usually named for the .psm1 file in which they are defined plus “-help.xml”.

For example:

MyModule.psm1-help.xml

But, this best practice isn’t required. If your module includes cmdlets, providers, workflows, and/or CIM commands, along with functions, it’s sometimes easier to add the XML help topics for functions to the existing help file.

For example, if you have a cmdlet/provider help file called MyModule.dll-help.xml, you can add your function help topics to that XML Help file.

For information about naming Windows PowerShell help files, see Naming Help Files.

 

Where do I put the XML Help file?

Get-Help looks in for the XML Help file in the module directory and in language-specific subdirectories of the module directory. If it can’t find the XML Help file, Get-Help searches in subdirectories of the module directory, but this is a risky strategy that doesn’t work for all module types.

You have two options for placing an XML Help file:

  • In the module directory, that is, the value of the ModuleBase property of your module.
     
    For example, if the module directory of MyModule is:
    PS C:> (Get-Module MyModule –ListAvailable).ModuleBase
    $home\Documents\WindowsPowerShell\Modules\MyModule

    you can place the XML help file for commands in my module here:

    $home\Documents\WindowsPowerShell\Modules\MyModule\MyModule.psm1-help.xml
  • In a language-specific subdirectory of the module directory.
     
    This is the preferred location, because it lets you support help topics in multiple languages. Even if you have help in only one language today, a friend or colleague might translate your help for you in the future.

    For example, you can place the US English XML help files for commands in my module in the en-US subdirectory:

    $home\Documents\WindowsPowerShell\Modules\MyModule\en-US\MyModule.psm1-help.xml

 

Special for functions: # .ExternalHelp

Get-Help doesn’t have any naming standards for XML help files for functions. Instead, to associate a function with the XML help file that contains its help topic, use the .ExternalHelp comment keyword (for details, see about_Comment_Based_Help).

The value of the .ExternalHelp comment keyword is the name of the help file that contains the help topic. Do not include any variables in the file name; they will be interpreted as literals. Also, do not specify a path. Get-Help looks for the help file in the module directory or language-specific subdirectory of the module directory.

For example, this comment line tells Get-Help that the help topic for MyFunction is in the MyModule.psm1-help.xml file.

# .ExternalHelp MyModule.psm1-help.xml
function MyFunction {...}

Be really careful here. The syntax is critical. If you have any syntax errors, Get-Help ignores the entire comment-based help block. For example, if the file name is on the line below the ExternalHelp keyword, the keyword is ignored.

In Windows PowerShell 4.0 and later, you can omit the .ExternalHelp comment keyword, but this works only for functions in manifest modules (not script modules) and only when the help file name is the name of the file in which the function is defined + “-help.xml”. To be safe (and backwards compatible), I add the .ExternalHelp comment keyword to every function that has an XML help file. The keyword also reminds me that the function has XML help so I don’t write comment-based help for it by mistake.

Precedence and XML Help

Just a quick word about precedence.

When a function has both comment-based help and an XML help file, Get-Help displays the comment-based help. But, if the comment-based help includes an ExternalHelp keyword, Get-Help ignores the comment-based help content and displays the XML help.

In fact, if the ExternalHelp keyword is present, Get-Help ignores the rest of comment-based help, even if it cannot find an XML help file that matches the value of the ExternalHelp keyword. Instead, it displays auto-generated help.

Also, if the comment-based help is invalid for any reason, like a typo in a comment keyword name, Get-Help ignores the comment-based help. For manifest modules, it gets XML help, if it exists, or displays auto-generated help. For script modules, it displays auto-generated help.

When writing a function, select comment-based help (x)or XML help. Including both is inviting errors. They’re bound to get out of sync and you’ll struggle to figure out why a new example isn’t displaying, only to find that you added the example to the format that isn’t being displayed.

 

Testing XML Help

To test an XML help file for a function, use Get-Help. When the module and the help are in the right place with the right name, Get-Help should find the help topic for the function even when the module is not imported into the session.

If you find an error, you can view the raw XML. A single function help topic consists of all content and elements within the <command:command> elements in the XML file.

image

 

To get the help topics in an XML help file, use the XML accelerator and the Get-Content cmdlet. For example, this command gets the help topics in Bitlocker.psm1-help.xml, the XML help file for the Bitlocker module.

[xml]$xml = Get-Content -Path $pshome\modules\Bitlocker\en-us\BitLocker.psm1-help.xml

To verify that a help topic is in the file, get the topic names. This command gets the names of topic in the Bitlocker.psm1-help.xml file.

PS C:\> $xml.HelpItems.command.Details.Name

Add-BitLockerKeyProtector
Backup-BitLockerKeyProtector
Clear-BitLockerAutoUnlock
Disable-BitLocker
Disable-BitLockerAutoUnlock
Enable-BitLocker
Enable-BitLockerAutoUnlock
Get-BitLockerVolume
Lock-BitLocker
Remove-BitLockerKeyProtector
Resume-BitLocker
Suspend-BitLocker
Unlock-BitLocker

 

You can also examine the XML help topic in the raw XML. This command gets the help topic for the Disable-Bitlocker function and saves it in the $disableBitlocker variable.

PS C:\> $disableBitlocker = $xml.helpItems.command | 
    where {$_.details.Name -eq "Disable-Bitlocker"}

Now, you can get the details, like the related links:

PS C:\ps-test> $disableBitlocker.relatedLinks.navigationLink

linkText                               uri
--------                               ---
Online Version:                        http://go.microsoft.com/fwlink/?linkid=287650
Enable-BitLocker
Lock-BitLocker
Resume-BitLocker
Suspend-BitLocker
Unlock-BitLocker
Get-BitLockerVolume

This command verifies that each function help topic has an online version link. It returns a custom object with the name and online version URI for each help topic.

PS C:\> $xml.helpItems.command | 
    Select-Object @{Label ="Name"; Expression ={$_.Details.Name}}, 
    @{Label="OnlineLink"; Expression={($_.relatedLinks.NavigationLink | 
    where LinkText -eq "Online Version:").uri}}

Name                                         OnlineLink
----                                         ----------
Add-BitLockerKeyProtector                    http://go.microsoft.com/fwlink/?linkid=287647
Backup-BitLockerKeyProtector                 http://go.microsoft.com/fwlink/?linkid=287648
Clear-BitLockerAutoUnlock                    http://go.microsoft.com/fwlink/?linkid=287649
Disable-BitLocker                            http://go.microsoft.com/fwlink/?linkid=287650
Disable-BitLockerAutoUnlock                  http://go.microsoft.com/fwlink/?linkid=287651
Enable-BitLocker                             http://go.microsoft.com/fwlink/?linkid=287652
Enable-BitLockerAutoUnlock                   http://go.microsoft.com/fwlink/?linkid=287653
Get-BitLockerVolume                          http://go.microsoft.com/fwlink/?linkid=287654
Lock-BitLocker                               http://go.microsoft.com/fwlink/?linkid=287655
Remove-BitLockerKeyProtector                 http://go.microsoft.com/fwlink/?linkid=287656
Resume-BitLocker                             http://go.microsoft.com/fwlink/?linkid=287657
Suspend-BitLocker                            http://go.microsoft.com/fwlink/?linkid=287658
Unlock-BitLocker                             http://go.microsoft.com/fwlink/?linkid=287659

 

I hope this helps. If you have a question about Windows PowerShell Help, post it in the Windows PowerShell forum or tweet it to me at @juneb_get_help. If you have a question about PowerShell HelpWriter, post it in the PowerShell HelpWriter forum or, for trial users, the Trial Software Questions forum.

June Blender is a technology evangelist at SAPIEN Technologies, Inc. You can reach her at juneb@sapien.com or follow her on Twitter at @juneb_get_help.

 
[Google+] [Twitter] [Facebook] [LinkedIn] [StumbleUpon] [Digg] [Reddit] [Google Bookmark]

Advanced Help for Advanced Functions – #PSBlogWeek

$
0
0

Writing help is often the last thing you do for an advanced function. But, instead of treating it as a disposable chore, write your help first — in advance — before you write your advanced function. Then, use the help as a design specification. The result is a better designed function and a better user experience.

If you’re using a test framework, like Pester, you can also use your help examples as test cases.

In this post, I’ll write help for the New-ValidationDynamicParam function that Adam Bertram (@adbertram) shares in #PSBloggingWeek – Dynamic Parameters and Parameter Validation. But we’ll write the help as a spec and revise it for the end user later.

You can view Adam’s script, including the end-user version of function help, at Get-TheAwesomeWithHelp.ps1.zip.


This post is part of the PowerShell Blogging Week (#PSBlogWeek) series on Windows PowerShell Advanced Functions, a series of coordinated posts designed to provide a comprehensive view of a particular topic.

In this series:

To suggest a PowerShell Blogging Week topic, leave a comment or tweet it to us with the #PSBlogWeek hashtag.


Description: Describe the function UI

Begin your spec with a description of the function UI. Command-line tools, like advanced functions, don’t have a GUI, but they certainly have a user interface. Use the Description section of your help topic to describe what the function does for the user and how to use it.

Do not explain how the functions works. If you need to describe any aspect of the implementation, such as a security or performance issue, save it for the Notes section.

This is also the place to disclose anything unexpected. Help should help users predict and avoid errors, so be generous with your warnings.

Let’s describe the user experience of Adam Bertram’s New-ValidationDynamicParam function.

  • This is a really advanced function that is designed for function/script authors, not end-users, so I’ll mention the audience immediately.
  • I want to associate this new thing with something familiar to this audience, like ValidateSet.
  • Adam’s function to be called in the DynamicParam block, which is novel, so I’ll explain that and remind users that they need the function in scope.
  • Finally, this has a limited use-case, so I’ll explain that this function doesn’t create other types of dynamic parameters.

image

 

Examples: Show how to use it

Help is really show and tell. The description is the “tell”. The examples are the “show.” And, the examples are really the most important part of help.

When writing help as a spec, write examples before parameters, because the examples really reveal which parameters you need and what names they should have. Write several examples for different use cases and think about using the parameters in combination.

Also, to use the examples as test cases, include expected output in the example.

To make the examples useful to readers, focus on one element in each example. For Adam’s function, the first example uses only the mandatory parameters, the second (shown below) uses several optional parameters, the third explains how to structure the DynamicParam block, and the final one explains how to refer to the dynamic parameter and its value outside of the DynamicParam block.

Write examples in complexity order beginning with the simplest. And, to encourage users to try the examples, use resources that all users have in their system, such as the C:\Windows directory.

Here is a relatively simple example. To see all the examples, see the help at Get-TheAwesomeWithHelp.ps1.zip.

image

 

Parameter Descriptions

When you feel comfortable with the examples, add the parameter descriptions. Each parameter description should tell you:

  • The effect of the parameter, that is, how it changes the function behavior.
  • Information about the parameter values and how to enter them, including syntax.
    (Think about your parameter validation, then tell users everything they need to know to avoid errors.)
  • If the parameter is optional, tell the default value.

image

Inputs and Outputs

Inputs and outputs are typically useful only to advanced users, but they’re critical in a spec.

  • Inputs lists the .NET types that you can pipe to the function by value. There’s no need to pipe to New-ValidationDynamicParam, so the value of Input is “none”.
  • Outputs tells the type of object the function returns. Adam’s function should return a RuntimeDefinedParameter value.

image

Revise for the end-user

That’s the extent of the spec version of help: a description, examples, parameters, inputs, and outputs. Defining these elements in advance forces you to think about and design an efficient and pleasing user experience for your function.

Before you write that first line of code, you’ll know that you need a few extra parameters, and maybe another parameter set. By writing examples, you discover that the ability to pipe input to the function is worth the extra time it takes to write a process block. By writing tests, you avoid coding an obvious error and you add extra error checking to the function.

The result is a well-designed function that is regarded as an asset to the community.

After the function is written and tested, add the synopsis, related links, etc. Also, consider deleting some of the input and output in the examples, so each example is focused on a single idea.

In the end, you’ll realize that when you write it in advance, the help that you once regarded as a chore is a vital tool for designing and testing advanced functions.

To view Adam Bertram’s function with comment-based help, see Get-TheAwesomeWithHelp.ps1.zip.

For information about the mechanics of function help, see:
about_Comment_Based_Help
Troubleshooting Comment-Based Help
Writing XML Help for Advanced Functions


June Blender is a technology evangelist at SAPIEN Technologies, Inc. You can reach her at juneb@sapien.com or follow her on Twitter at @juneb_get_help.

 
[Google+] [Twitter] [Facebook] [LinkedIn] [StumbleUpon] [Digg] [Reddit] [Google Bookmark]

PowerShell Studio 2015 – New Parameter Block Formatting

$
0
0

With release of the v4.2.83 build of PowerShell Studio 2015, we introduced new features which we will cover in detail over a series of articles.

This first feature added was in response to user feedback.

Parameter Block Formatting

Three new options were added to PowerShell Studio 2015 that allow you to control different aspects of parameter block formatting:

image

 

Insert new line after parameter attribute

This option places each parameter attribute in its own line.

Before:

image

After:

image

Insert new line after parameter type

This option inserts a line after the type of the parameter.

Before:

image

After:

image

Parameter line spacing

This option governs the line spacing between parameters. If set to a value greater than zero, PowerShell Studio will place the specified number of new lines after the parameter. To disable this option (leave the spacing as is) set the value to zero.

Before:

SNAGHTML177be18

After (Spacing = 2):

image

These new formatting options will help maintain your parameter blocks the way you want them. If you would like to see more formatting options, please let us know by posting on our Wish List and Feature Request forum.

 
[Google+] [Twitter] [Facebook] [LinkedIn] [StumbleUpon] [Digg] [Reddit] [Google Bookmark]

PowerShell Studio 2015 – New Navigation Bar

$
0
0

With release of the v4.2.83 build of PowerShell Studio 2015, we introduced new features that we are covering in detail over a series of articles.

The second major feature included in this release is:

The Navigation bar

The new navigation bar, located above the editor, allows you to jump between functions, workflows, events and more.

image

The function combo box on the left shows you the context of the caret position:

SNAGHTML18a01cc

Use the function combo box to jump to specific a function, event, workflow or configuration:

image

The navigation combo box on the right allows you to jump to specific positions that include the caret position,the last edited position, current debug position, breakpoints, tracepoints, bookmarks, and syntax errors:

image

For your convenience, the drop drown provides a preview of the line contents in order to help direct you to the correct position.

 

We hope that the new navigation bar becomes invaluable to your scripting experience.

 
[Google+] [Twitter] [Facebook] [LinkedIn] [StumbleUpon] [Digg] [Reddit] [Google Bookmark]

PowerShell Studio 2015 – New FolderBrowserModernDialog Control

$
0
0

With release of the v4.2.83 build of PowerShell Studio 2015, we introduced new features that we are covering in detail over a series of articles.

This next new feature was also added in response to user feedback. This particular user wanted to use the modern version of the folder browser dialog that is available in the later versions of Windows. Unfortunately, the user had to manually add code to the form to accomplish this. Therefore we added a new control to our toolbox:

FolderBrowserModernDialog

This control will display the modern version of the FolderBrowserDialog on Windows 7 or greater:

Modern Folder Browser

If running on a legacy OS, it will then display the original FolderBrowserDialog:

Legacy Folder Browser

You can find the new control in the ToolBox Panel:

Toolbox

To add the dialog, simply drag and drop it into your existing form.

The new FolderBrowserModernDialog has the following properties:

Properties
Title

This property sets the title of the folder browser dialog.

SelectedPath

This property sets the selected path of the dialog and returns the path the user selected.

 

Using the Dialog:

Here is an example of how to display the FolderBrowserModernDialog using its ShowDialog method:

    $folderbrowsermoderndialog1.SelectedPath = $textboxPath.Text
    if ($folderbrowsermoderndialog1.ShowDialog() -eq 'OK')
    {
        $textboxPath.Text = $folderbrowsermoderndialog1.SelectedPath
    }

 

The modern versions of the FolderBrowserDialog makes for a better user experience and we hope that your GUI users agree.

 
[Google+] [Twitter] [Facebook] [LinkedIn] [StumbleUpon] [Digg] [Reddit] [Google Bookmark]

PowerShell Studio 2015 – New Collection Project deployment options

$
0
0

With release of the v4.2.83 build of PowerShell Studio 2015, we introduced new features that we are covering in detail over a series of articles.

PowerShell Studio 2014 introduced the new Collection Project:

https://www.sapien.com/blog/2014/07/29/powershell-studio-2014-collection-project/

The Collection Project simply groups various files without creating a single script as in a normal project and each script file runs individually.

With this release, new options were added to the Collection Project in order to accommodate your deployment needs by controlling the behavior of the Packager, MSI, and Deployment as a whole or as individual files.

Collection ProjectOK

Two new project properties were added:

Properties

Deploy As

This determines the deployment behavior of the Project as a whole. There are two Deploy As options to choose from:

File Tells the project to handle each file individually when it comes to deployment. Each project file will maintain its own independent settings.When to use:
Use this settings when you are using the Collection Project to group individual files that don’t necessary interact with each other. With this setting you can package and deploy (publish) each script independently.
Project Tell the project to handle the deployment of all the files as a whole. You must define a primary file for the purposes of the Packager and MSI builder.When to use:
Use this setting when you have a group of files that interact and have a start / entry point script. For example, if you have a primary script that dot sources various secondary scripts. In this case, the primary script will get converted into an executable and you can create an installer that includes the primary packaged script and all the supporting files / scripts. The project files are also deployed (published) as a whole.

 

Primary File

This property tells the project, which file is the primary file when Deploy As is set to Project. The primary file will be the file that is packaged into an executable. All other files will be considered external “Content”.

 

Previously the deployment options were unavailable in the Collection Project unless you opened the files independent of the project. These new deployment settings now allow the Collection Project to fit your deployment needs.

 
[Google+] [Twitter] [Facebook] [LinkedIn] [StumbleUpon] [Digg] [Reddit] [Google Bookmark]

PowerShell Studio 2015 – Editing Script Parameters

$
0
0

If you have used PowerShell Studio’s Function Builder chances are probably you wished it could edit your script parameters. Now it can. With the v4.2.85 service release of PowerShell Studio 2015 we introduced the new Parameter Builder.

Parameter Builder:

Those familiar with the Function Builder will recognize the similarities between the two tools, with the exception of the Name portion of the builder. Otherwise the Parameter Builder and the Function Builder share the same functionality. You can use the Parameter Builder to insert a new parameter block or edit existing script parameters.

You can access the Parameter Builder using the Ribbon:

Ribbon - Edit Parameters

Or the editor’s context menu:

Context menu

Or press [Ctrl + Shift + P] on the keyboard.

Just like the Function Builder, you can specify the parameters, parameter sets, validation, and help comments:

Parameter Builder

When you are done editing the parameters, it will produce a parameter block for your script:

Parameter block

 

Please refer to the following blog articles for more details on how to use the Function Builder / Parameter Builder:

https://www.sapien.com/blog/2014/09/30/powershell-studio-2014-editing-functions/

https://www.sapien.com/blog/2014/10/02/adding-parameter-sets-to-a-function/

 
[Google+] [Twitter] [Facebook] [LinkedIn] [StumbleUpon] [Digg] [Reddit] [Google Bookmark]

PowerShell Studio 2015 – Updated Control Sets

$
0
0

In the v4.2.85 service release of PowerShell Studio 2015, we updated a few of the predefined control sets.

 

Updated Control Sets:

  • Button – Run Process now includes the Process Tracker framework, so you no longer have to include the Form – Process Tracker control set.
  • Button – Start Job now includes the Job Tracker framework, so you no longer have to include the Form – Job Tracker control set.
  • All the Form control sets have been modified so that they will not produce redundant event blocks when inserted multiple times.

 

New Append Option

The Form controls sets assign events on the form itself and if that particular form event is already assigned, PowerShell Studio will present you with the following dialog:

Replace event dialog

You can select from the following options:

  • Leave – Leaves the event assignment as is.
  • Replace – Replaces the existing assignment in the designer with the control set’s new event block.
  • Append – Leaves the event assignment as is, but also assigns the control set’s event block via the script editor. This allows the control to assign more than one script block to the event.

When you select the new Append option, the form’s event is assigned below the new event script block:

append event

Now you can use multiple controls sets that share the same events without them interfering with one another.

 

Related Articles:

https://www.sapien.com/blog/2012/05/16/powershell-studio-creating-responsive-forms/

 
[Google+] [Twitter] [Facebook] [LinkedIn] [StumbleUpon] [Digg] [Reddit] [Google Bookmark]

Copy to Clipboard in a GUI Application

$
0
0

During #PSBlogWeek, I shared with my co-authors a little GUI-based blogging tool that gets links to the online version of PowerShell help topics, including About topics. I didn’t think much of it, because it was my first GUI app, but I soon received a nice compliment from PowerShell MVP Jeffery Hicks with a suggestion to add a “Copy to clipboard” button to the app. It was a great suggestion, so I set aside some time to implement it.val

It didn’t take much time at all!

Using Clip.exe

I started by creating a little GUI app to isolate and test the copy-to-clipboard feature. When the user types text in the “Type here” text box and clicks Copy to clipboard,” the app copies the text in the textbox and saves it in the clipboard to be pasted elsewhere.

image

Implementation is pretty simple. When the text in the input textbox changes, I verify that it’s not an empty string and then enable the Copy to clipboard button.

$textboxInput_TextChanged={
    if ($textboxInput.Text.Trim() -ne "")
    {
        $buttonCopyToClipboard.Enabled = $true
    }
}

 

For my first try at implementing the copy-to-clipboard feature, in the Click event of the Copy to Clipboard button, I got the Text property of the input textbox ($textboxInput.Text), trimmed it, and piped it to Clip.exe.

$buttonCopyToClipboard_Click={
    $textboxInput.Text.Trim() | Clip
}

When I tested the app, it copied the text in the input text box to the clipboard as expected, but, in the process, it opened and closed a command prompt window. It was quick, but you could see the window flash and I wasn’t happy with the experience.

 

Using the Clipboard Class

Next, I tried the Copy to clipboard snippet in PowerShell Studio 2015. It invokes the SetText static method of the Clipboard class (System.Windows.Forms.Clipboard).

$buttonCopyToClipboard_Click={
    [System.Windows.Forms.Clipboard]::SetText($textboxInput.Text.Trim())
}

That worked perfectly! I could have stopped there, but I wanted to explore some other ways of copying to the clipboard.

 

Using the Copy Method

The Textbox class (System.Windows.Forms.Textbox) has a Copy method that copies the text in a Textbox to the clipboard. It’s very simple to read and to use, because it doesn’t have any parameters. Even better, Textbox controls actually “inherit” this method from their parent class, TextBoxBase, which means that the Copy method also works in other textbox controls with the same parent class, including RichTextbox and MaskedTextbox.

I was sold on the Copy() method … except for one problem.

$buttonCopyToClipboard_Click={
    $textBoxInput.Copy()
}

 

It didn’t work. It didn’t generate any errors, but it didn’t copy the text in the input textbox to the clipboard.

To figure out why, I read the Copy method description really carefully and examined the examples in C#, C++, and VB, because they don’t have PowerShell examples on the .NET reference pages.

“Copies the current selection in the text box to the Clipboard.”

Aha! Selection. It copies the “selected” text in the textbox to the clipboard.

To select text from the Textbox, you use the Select or SelectAll methods of the Textbox. To keep it simple, I used SelectAll.

$buttonCopyToClipboard_Click={
    $textboxInput.SelectAll()
    $textBoxInput.Copy()
}

Excellent. That’s another technique that I can use. Let’s see what lurks in the PowerShell 5.0 preview.

Using Set-Clipboard

The Windows PowerShell 5.0 preview includes new Get-Clipboard and Set-Clipboard cmdlets with cool parameters like Append, Format, and Raw. The Value parameter of Set-Clipboard takes value from the pipeline, so i just piped the trimmed text in the textbox to Set-Clipboard.

$buttonCopyToClipboard_Click={
    $textBoxInput.Text.Trim() | Set-Clipboard
}

This worked perfectly. The only problem is that it requires PowerShell 5.0, which is brand new and still in preview. I want my app to run on most platforms.

 

Finishing Touches: StatusBar

After experimenting with the variety of Copy techniques in the Copy to Clipboard form, I added the SetText() method to my blogging app. It worked just fine, but clicking the Copy to clipboard button wasn’t very satisfying to me without some confirmation that the copy operation actually worked.

After the copy operation, I wanted to confirm that the text on the clipboard matched the text in the input textbox, and then let the user know about it. But, none of the copy or set methods returns an object, or even an error.

I used the ContainsText (is there anything on the clipboard?) and GetText (get the text on the clipboard) static methods of the Clipboard class. Because an –AND statement in Windows PowerShell doesn’t test the second condition if the first fails, I used the –AND to invoke both the ContainsText()  and GetText  methods.

if ([System.Windows.Forms.Clipboard]::ContainsText() –AND
    [System.Windows.Forms.Clipboard]::GetText() ... )

 

Then, I compared the Text in the textbox – the text that I wanted to copy — to the text that GetText() found on the clipboard.

if ([System.Windows.Forms.Clipboard]::ContainsText() –AND
[System.Windows.Forms.Clipboard]::GetText() –eq $textboxInput.Text.Trim() )
...

 

Finally, I added a StatusBar to my form. If the copy succeeded, I set the Text in the StatusBar to “Copied to clipboard” and made the status bar visible. I didn’t want the StatusBar hanging around there all the time, so I used the Start-Sleep cmdlet to count 2 seconds, and then I changed the Visible property of the StatusBar to $false.

Here’s the Click event for the Copy to Clipboard button:

$buttonCopyToClipboard_Click={
    $copyText = $textBoxInput.Text.Trim()
 
    [System.Windows.Forms.Clipboard]::SetText($copyText)
 
    if ([System.Windows.Forms.Clipboard]::ContainsText() -AND
        [System.Windows.Forms.Clipboard]::GetText() -eq $copyText)
    {
        $statusbar1.Text = "Copied to clipboard."
        $statusbar1.Visible = $true
        Start-Sleep -Seconds 2
        $statusbar1.Visible = $false
    }
}

And, here’s a demo of it working in my GUI test app.

 

Finally, I added the copy code to my blogging tool, with just a few tweaks to get the control names right. The Copy to Clipboard feature is easy and quick to implement and it results in a more fluid experience. I guess Mr. Hicks knows his stuff!

June Blender is a technology evangelist at SAPIEN Technologies, Inc. You can reach her at juneb@sapien.com and follow her on Twitter at @juneb_get_help.

 
[Google+] [Twitter] [Facebook] [LinkedIn] [StumbleUpon] [Digg] [Reddit] [Google Bookmark]

WMI Explorer 2015 gets a PowerShell console

$
0
0

With the latest service build WMI Explorer 2015 has received an integrated Windows PowerShell console.

image

While previous versions had the ability to execute generated PowerShell code in a console, experimentation with that code was not possible because PowerShell does not include the commands passed as arguments to the console in the history. With this new release you can just use cursor up to get the last command and modify and re-run that command to experiment.

In addition to adding a new integrated Windows PowerShell console, we also updated the generated code to use the newer Get-CIMInstance cmdlet rather than the old Get-WMIObject.

The samples have also been updated with better generated sample code and the ability to run the sample code in the integrated console.

image

The “Run this” links behind each generated sample executes the code in the console right away. If you have a previous version of WMI Explorer installed you may not see these links until you rebuild the cache for that particular machine.

image

Please let us know what else we can add to make this tool even better. Build 2.2.51 is available right now, so go and get it.

 
[Google+] [Twitter] [Facebook] [LinkedIn] [StumbleUpon] [Digg] [Reddit] [Google Bookmark]

Why does this button close my form?

$
0
0

Have you ever copied a button and found that when a user presses it, the form closes immediately afterwards? We are here to answer:

Why does this button close my form?

The reason the form closes is that the Button control’s DialogResult property is set to a value other than None. This property tells the form to close after the user has clicked the button without you having to explicitly close the form in the button’s click event script block.

image

So next time you copy an OK or Cancel button, be sure to set the button’s DialogResult to None.

 

Please refer to the following article for more details on the button control and the DialogResult property:

https://www.sapien.com/blog/2011/06/07/primalforms-2011-spotlight-on-the-button-control/

 

 
[Google+] [Facebook] [LinkedIn] [StumbleUpon] [Digg] [Reddit] [Google Bookmark]

PowerShell Studio 2015: Enhancements for Debugging

$
0
0

In the last service release v4.2.86 we introduced some new enhancements to help improve your debugging experience.

 

New Variables Panel Context Menu

image

We added a new context menu to the Variables Panel that allows you to:

  • Add To Watch – Adds the selected variable to the Watch Panel.
  • Query in Debug Console – Runs the variable in the Debug Console, so that you can inspect the variable. If you select a property, then the variable’s property will be queried in the Debug Console.
  • Copy – Copies the cell contents to the clipboard.

New Watch Panel Context Menu

image

We also added a context menu to the Watch Panel that allows you to:

  • Copy – Copies the cell contents to the clipboard.
  • Select All– Selects all the watch variables.
  • Query in Debug Console – Runs the watch expression in the Debug Console.
  • Remove Watch Item – Removes the select expression from the Watch Panel.
  • Remove All – Removes all the expressions from the Watch Panel.

 

Adding Watch Expression via Editor

You can now use the editor’s context menu to add variables to the Watch Panel.

clip_image008

If you use the “Add To Watch” command on a property or method of a variable, it will include the whole statement.

clip_image010

You can also use the new “Run Selection in Debug Console” command via the editor’s context menu to run the selection in the Debug Console.

 

Debug Console

Submitted commands are now displayed in the output window of the Debug Console:

SNAGHTML51f45e

 

We hope that these enhancements will help improve your debugging experience.

If you have any suggestions or feature requests, please share them with us on our Wish List and Feature Requests forum.

 

 
[Google+] [Facebook] [LinkedIn] [StumbleUpon] [Digg] [Reddit] [Google Bookmark]
Viewing all 308 articles
Browse latest View live