Use Cool PowerShell Tricks to Simplify Your Scripts

Doctor Scripto

Summary: Learn how to use a collection of cool Widows PowerShell tricks to simplify writing scripts.

 

Microsoft Scripting Guy Ed Wilson here. Today I am proud to announce that Microsoft’s  newest Windows PowerShell MVP  Bartek Bielawski returns to the Hey, Scripting Guy! Blog. Congratulations Bartek!

Photo of Bartek Bielawski

Bartek Bielawski has been working in IT more than 10 years for one company, PAREXEL, a global organization with headquarters in U.S.

In Bartek’s opinion, Windows PowerShell is the best product from Microsoft. Bartek can be found at his blog and as a moderator on the Scripting Guys Forum.

Here is Bartek!

 

My Favorite Windows PowerShell Tricks

Working interactively with Windows PowerShell can be more convenient and effective if you know and use some tricks that the Windows PowerShell team added here and there. I would like to mention a few that I like the most.


Using scriptblocks as values for parameters that take ValueFromPipelineByPropertyName

Very often people use Foreach constructs in places where that cmdlet is not needed. This trick helps to keep code brief and logical without losing flexibility that Foreach-Object would normally give us. The syntax, as you can see, is not very different from what you would use in Foreach-Object. This simple example shows what I mean:

ls *.ps1 | Rename-Item -NewName { $_.Name -replace ‘Untitled(\d)’, ‘$1_NoName’ }

Short, simple, and sweet.


Using New-Module –AsCustomObject to create more mature custom objects on-the-fly

Creating custom objects is something decent scripters usually can’t avoid. My favorite way is to use the Property parameter with a hash table. There is also a method that gives you two important (in some cases) elements that New-Object won’t give you: adding ScriptMethods and making object properties type-constrained. Sample code:

$Time = New-Module -AsCustomObject -ScriptBlock {

    [TimeSpan]$Span = 0

    function Since {

    param (

        [datetime]$Start

    )

        $Script:Span = New-TimeSpan -Start $Start

        $Span

    }

   

    function Till {

    param (

        [datetime]$End

    )

        $Script:Span = New-TimeSpan -End $End

        $Span

    }

    Export-ModuleMember -Function * -Variable *

}

 

Later, you can’t modify $Time.Span to be of type string; it will end up with exceptions (unless the string can be converted into TimeSpan).


Creating your own type accelerators.

Do you use any .NET Framework type very often? Wouldn’t you like to have it served in a similar way that some types are handled already, with friendly, short names? Well, there is a not-so-complicated way to get there. Joel Bennett (Jaykul) created a great module that I took the most important part of the code from with the Add-Accelerator function (and much, much more): 

$xlr8r = [type]::gettype(“System.Management.Automation.TypeAccelerators”)

$xlr8r::Add(‘Parser’,[System.Management.Automation.PSParser])

[Parser]::Tokenize(‘Write-Host Foo’,[ref]$null)
 

It may even work as a kind of “Using” substitute. If you create accelerators for all types in a given namespace, it will work as it would in C#. There is a command to do exactly that in Jaykul’s module.


Using descriptive errors for enums to get correct argument values

Making errors usually doesn’t help you get closer to solutions. Windows PowerShell is different, though, because many of errors you will see there will actually explain what you can do to fix them. There is one trick that requires making errors on purpose:

Set-ExecutionPolicy -ExecutionPolicy Some -Scope Any

# Error with possible ExecutionPolicy values.

Set-ExecutionPolicy -ExecutionPolicy Restricted -Scope Any

# Error with possible Scope values.

Set-ExecutionPolicy -ExecutionPolicy Restricted -Scope Process

# And now we are locked in the scriptless abyss.

Getting information about correct enumeration values in Windows PowerShell is pretty difficult when you try an “elegant” approach. Passing parameters that simply can’t work will get you there quicker. Error messages for wrong enum values used are descriptive enough to quickly find the right answer.


Using [scriptblock]::Create() to create executable code on the fly

Another issue you may walk into is how to use values passed by users to generate something you can later execute. Invoke-Expression was usually the first one to choose, but scriptblock’s static method Create gives you much more control over the code produced:

function Where-ObjectSimple {

param (

    [Parameter(Mandatory = $true)]

    [string]$Property,

    [Parameter(Mandatory = $true)]

    [string]$Operator,

    [Parameter(Mandatory = $true)]

    [string]$Pattern,

    [Parameter(ValueFromPipeline = $true,

        Mandatory = $true)]

    [PSObject]$InputObject

)

 

begin {

    $Where = @{

        FilterScript = [scriptblock]::Create(“`$_.$Property -$Operator ‘$Pattern'”)

       

    }

}

 

process {

    $InputObject | where @where

}

}

ls | Where-ObjectSimple Name like ‘*.ps1’

I prefer this solution over other options because it allows me to select which variables I would like to expand during creation of a script block and which should be used when a script block is used.

There are also other tiny tricks I like:

  • Using #<id><tab> and #<pattern from command><tab> to use history as a base for new commands.
  • Adding # at the start of an almost-complete command to keep it in history without actually running it (for example, to make sure we got all elements right).
  • Using Regex named/positional captures together with –match and –replace.


Conclusion

Working with Windows PowerShell is fun. It helps you get your job done without a huge amount of effort. With Windows PowerShell, you can be both entertained and surgically effective.

 

Wow! When I requested favorite Windows PowerShell tricks from the forum moderators, I was not expecting such coolness. Bartek, you rock!

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy

 

 

0 comments

Discussion is closed.

Feedback usabilla icon