My Technical Notes

Friday, 19 October 2012

Various Techniques for Powershell

Getting History

To get a history of all commands executed within your Powershell sessions do the following:


    Get-History | Select CommandLine > "C:\Temp\script1.ps1"
    

This is useful because it allows you to interactively build your code, and once you have finished you can use the above command to dump it into a file and then re-run later.

The default number of commands it keeps is 64, to change it, set the $MaximumHistoryCount to something larger.

Executing an anonymous block

Use the & operator followed by the code block and then by the argument:


    PS> & { param($name) Write-Host $name } 'Tahir'
    Tahir
    

Expression and Variable Expansion in Strings

Double Quoted Strings allow expansion but single quoted strings do not:


    PS> $name = 'Tahir Hassan';
    PS> 'My Name is $name'
    My Name is $name
    PS> "My Name is $name"
    My Name is Tahir Hassan
    

Therefore it is desirable to use single-quoted strings unless there is a need for expansion.

To expand a section of code, we wrap it in $() (useful for accessing properties):


    PS> $tahir = @{ 'Name' = 'Tahir'; 'BlogUrl' = 'tahirhassan.blogspot.co.uk' }
    PS> "My name is $( $tahir.Name ) and my blog can be found at $( $tahir.BlogUrl )"
    My name is Tahir and my blog can be found at tahirhassan.blogspot.co.uk
    PS> "test $( 'string' )"
    test string
    

Importing a DLL

Given a $dll_file_path, use the following command:


    Add-Type -Path $dll_file_path
    # OR
    Add-Type -AssemblyName "System.Web" # for .NET DLL's.
    

Instantiating an Object

Instantiating an existing class

Any object within the System namespace in mscorelib.dll can be instantiated without explicitly providing the "System" namespace before it:


        $date = New-Object DateTime(2009, 01, 01)
        

However, for any class outside of the System namespace, you have to provide the full namespace:


        $date = New-Object System.Text.StringBuilder(2009, 01, 01)
        # The first argument to New-Object is a string and the rest of the arguments don't have to be in brackets:
        # $date = New-Object "System.Text.StringBuilder" 2009, 01, 01
        

Since the first argument (the type) is a string, we can use store the namespace of the type in a string:


        $text_ns = "System.Text"
        # $date = New-Object "$text_ns.StringBuilder" 2009, 01, 01
        
Creating a Hashtable using @{} sytax

To create an hashtable you can use the @{} syntax:


        $tahir = @{ Name = 'Tahir'; BlogUrl = 'tahirhassan.blogspot.co.uk' }
        #OR 
        $tahir = @{ '"Name' = 'Tahir'; 'BlogUrl' = 'tahirhassan.blogspot.co.uk' } # quotes around the keys
        

Notice that we use a semi-colon and not a comma to separate the key-value pairs.

Creating a PSObject with a set of properties:

To do this we use the New-Object 'PSObject' –Property [HashTable]:


        $tahir = New-Object 'PSObject' -Property @{ 'Name' = 'Tahir'; 'BlogUrl' = 'tahirhassan.blogspot.co.uk' }
        

Creating an Array

To create a basic array, you can merely list the elements:


    $my_arr = 1, 2, 3, 4, 5
    

But using this syntax you cannot create an empty list. A better syntax is using the @(...):


    # same as above
    $my_arr = @(1, 2, 3, 4, 5) 
    # empty array
    $my_arr = @() 
    # concatenating two arrays using the + operator.
    $my_arr = @(1, 2, 3) + @(4, 5)
    

To access one of the elements you use the square bracket notation:


        $my_arr[3]
    

Creating an ArrayList

To create an arraylist, you can cast an array (as above) to an ArrayList:


    $arraylist = [System.Collections.ArrayList]$array
    

Calling Static Methods

To call a static method, you need to provide the full type name, which includes the namespace. (there is no way round this):


    [System.Int32]::MaxValue # can use [int] instead here.
    

Getting Help on commands

To get help on a command, say Get-Process, type the following:


    Get-Help Get-Process
    

Executing a Cmdlet

In PowerShell, merely typing the cmdlet name will execute it:


    Get-Process
    

Notice that in the above code, we do not use brackets after it e.g. Get-Process(), however the cmdlet is still being executed. When assigning the output notice that

In order to take the first element of this, we need to put brackets around Get-Process and use the square bracket notation:


    (Get-Process)[0]
    

Adding Intellisense through PowerTab

PowerTab is an extension of the PowerShell tab expansion feature. It can be found at CodePlex - PowerTab.

Viewing information using Out-GridView

Piping information to Out-GridView cmdlet will show the information in a GUI:


    dir | Out-GridView
    

Relational Operations

Inspired by Relational shell programming.

Sorting

To order or sort by, use the Sort-Object, aliased as sort:


        dir | Sort-Object name
        
Alternatively we can pass a function to sort (aka "selector"):

        dir | Sort-Object {$_.Name.SubString(0, 1)}
        
Selecting (aka "Projecting")
Naively Using Select-Object

When naively selecting using the Select-Object:


            dir | Select-Object 'Name', 'Mode'
            

What happens is that a PSCustomObject is created with the properties selected.

Using Select-Object with a Selector

Apparently, Select-Object is not designed to work with with a selector:


            PS> dir | Select-Object {$_.Name}
            
            $_.Name
            -------
            Folder1
            Folder2
            
            PS> (dir | Select-Object {$_.Name})[0].'$_.Name'
            Folder1
            

Basically, it returns PSCustomObject's with a $_.Name property. We instead wanted it to return the Name property only. To to this we can still call Select-Object but with the -ExpandProperty option:


            PS> dir | Select-Object -ExpandProperty 'Name'
            Folder1
            Folder2
            PS> (dir | Select-Object -ExpandProperty 'Name')[0]
            Folder1
            

However this still does not solve the problem of when we want to pass in a selector. For this, we use the Foreach-Object.

Using Foreach-Object for true Selection

To use Foreach-Object (or it's alias %) we pass in a selector:


            PS> dir | Foreach-Object { $_.Name }
            Folder1
            Folder2
            
Select Top N Elements

To get the first N elements using Powershell


        dir | Select-Object -First 3
        

We can also skip a certain number of elements:


        dir | Select-Object -Skip 2
        

Getting Current Path

Use Get-Location:


    Get-Location
    

Executing a string using Call Operator (&)

Use & as follows:


    & "C:\Program Files\Notepad++\notepad++.exe" "my_file.txt"
    

Customizing Prompt to only show last Directory Name

Stick the following into your $profile file (create it if it does not exist:


function prompt {
  $loc_path = (Get-Location).Path;
  $cur_dir = $loc_path.SubString($loc_path.LastIndexOf('\') + 1);
  $prompt_str = if ($cur_dir -eq "") { $loc_path } else { $cur_dir };
  return "PS: $prompt_str> ";
}
    

If it complains that it does not have the permissions to run the start up script then execute the following:


    Set-ExecutionPolicy Unrestricted -Force
    

Setting Up Alias's for Commonly used Apps

Use Set-Alias to do this:


    Set-Alias notepad++ "C:\Program Files\Notepad++\notepad++.exe"
    

No comments: