Function

The best practice use the verb-noun combination when creating functions.

Verb: pick the verb from the standard list of powershelgl verbs to make your functions easier to remember.

To get the verb coverage, you can use Get-command and piping the results to the Group-Object cmdlet:

get-command -commandtype cmdlet | group-object -property Verb | sort-object -property count -Descending

To define a function, use syntax:

Function Function-Name

{

 #insert code here

}

Let’s have a review about the Parameters and Arguments first before we use them in a function:

The term parameter (sometimes called formal parameter) is often used to refer to the variable as found in the function definition, while argument (sometimes called actual parameter) refers to the actual input passed.

If the function has parameters, you can use three ways to path the parameter:

  1.  First is to use the name of the function and put the value inside parentheses.
  2.  use the hyphen and the parameter name
  3.  use positional arguments when passing a value. In this usage, you omit the name of the parameter entirely and simply place the value for the parameter following the call to the function.

E.g. create a function to get the lines, word and characters in a file. The complete text of the Get-TextStatistics function is shown here: Get-textStatistics Function

Function Get-TextStatistics($path)

{

Get-Content -path $path |

Measure-Object -line -character -word }

you can use either way bellow to call this function with a path ( Note that you must put quotations around the path )

Get-TextStatistics("C:\fso\mytext.txt")
Get-TextStatistics -p "C:\fso\mytext.txt"
Get-TextStatistics "C:\fso\mytext.txt"

To get local drive details:

 

$aryComputers = "loopback", "localhost"

Set-Variable -name intDriveType -value 3 -option constant

             foreach ($strComputer in $aryComputers)

{"Hard drives on: " + $strComputer

Get-WmiObject -class win32_logicaldisk -computername $strComputer|

                   Where {$_.drivetype -eq $intDriveType}}

intDriveType to 3 means always show the local drive, more about the drive type:

DriveType

Data type: uint32
Access type: Read-only
Qualifiers: MappingStrings (“Win32API|FileFunctions|GetDriveType”)

Numeric value that corresponds to the type of disk drive this logical disk represents.

Unknown (0)
No Root Directory (1)
Removable Disk (2)
Local Disk (3)
Network Drive (4)
Compact Disc (5)
RAM Disk (6)

 

Use the function

To get access to these functions, you will need to dot-source the containing script by placing a dot in front of the path to the script when you call it, and put the functions in a module or load them via the profile.

When pasting your functions into the function library script, pay attention to the comments at the end of the function. The comments at the closing curly bracket for each function not only point to the end of the script block, but also provide a nice visual indicator for the end of each function. This can be helpful when you need to troubleshoot a script. An example of such a function library is the ConversionFunctions.ps1 script, which is shown here:

 

ConversionFunctions.ps1

Function Script:ConvertToMeters($feet)

{

  "$feet feet equals $($feet*.31) meters"

} #end ConvertToMeters

Function Script:ConvertToFeet($meters)

{

 "$meters meters equals $($meters * 3.28) feet"

} #end ConvertToFeet

Function Script:ConvertToFahrenheit($celsius)

{

 "$celsius celsius equals $((1.8 * $celsius) + 32 ) fahrenheit"

} #end ConvertToFahrenheit

Function Script:ConvertTocelsius($fahrenheit)

{

 "$fahrenheit fahrenheit equals $( (($fahrenheit - 32)/9)*5 ) celsius"

} #end ConvertTocelsius
Using dot-sourced functions:

To dot- source the script, you use the dot-source operator (the period, or dot symbol), followed by a space, followed by the path to the script.

If the ConversionFunctions.ps1 is located at C:\scripts\ConversionFunctions.ps1, then use command .c:\scripts\ConversionFunctions.ps1 to load the functions in the ConversionFunctions.ps1.

Now you can call the script:

convertToMeters(10)

10 feet equals 3.1 meters

Verify:

Once you have included the functions in your current console, all the functions in the source script are added to the Function drive.

use dir function to verify the functions have been successfully imported.

Add help for functions
  • The  first step that needs to be done is to de ne a switched parameter named $help.
  • The second step involves creating and displaying the results of a here-string object that includes help information.
 Function Get-WmiClasses(
                 $class=($paramMissing=$true),
                 $ns="root\cimv2",
                 [switch]$help 
                  )
{
  If($help)
 
    {
     $helpstring = @"
     NAME
       Get-WmiClasses
     SYNOPSIS
       Displays a list of WMI Classes based upon a search criteria
     SYNTAX
       Get-WmiClasses [[-class] [string]] [[-ns] [string]] [-help]
     EXAMPLE
       Get-WmiClasses -class disk -ns root\cimv2"
       This command finds wmi classes that contain the word disk. The
       classes returned are from the root\cimv2 namespace.
 "@
     $helpString
       break #exits the function early
     }
   If($local:paramMissing)
     {
         throw "USAGE: getwmi2 -class <class type> -ns <wmi namespace>"
     } #$local:paramMissing
"`nClasses in $ns namespace ...." 
Get-WmiObject -namespace $ns -list | 
Where-Object {
              $_.name -match $class -and `
              $_.name -notlike 'cim*'
             }
 #
} #end get-wmiclasses

You can get the help text by command:

get-wmiclasses -help
Function with multiple parameters

To create a function that uses multiple input parameters, you use the Function keyword, specify the name of the function, use variables for each input parameter, and then define the script block within the curly brackets, or with param keyword inside the script.

1. Parameter in the curly brackets:

The pattern is shown here:

Function My-Function($Input1,$Input2)
{
 #Insert Code Here
}

Then you can call the function, type a space, type first parameter, second parameter, which are separated by space.

for example:

Function Get-TimesResult($a, $b)

{

$c=$a*$b

write-output "$a is $a, `$b is $b, the result is $c"

}

Get-timeResult 11 13

$a is 11, $b is 13, the result is 143

To constrain the type of parameter, you can add the type before the parameter, such as if you want the user only type a integer as zip code:

Function resolve-ZipCode ([int]$zip)

{.....}
2. Param statement

The syntax looks like:

      Function Function-Name
      {
        Param(
              [int]$Parameter1,

              [String]$Parameter2 = "DefaultValue",

              $Parameter3
             )

      #Function code goes here

      } #end Function-Name

Each parameter must be separated by a comma. All the parameters must be surrounded with a set of parentheses.

We use the example similar to the previous one:

Function Get-TimesResult()

{
param(
[int]$a,
[int]$b=15,
)

$c=$a*$b

write-output "$a is $a, `$b is $b, the result is $c"

}

Then call the function:

Get-timeResult -a 11 -b 13

$a is 11, $b is 13, the result is 143

The Param statement is the only way to gain access to advanced function features such as cmdlet binding, parameter attributes, and other powerful features of Windows PowerShell.

Use function for ease of Operation

If you want to display the IP information of a host named Frank-PC,  you may use a script.

The first line of code uses the Get-WmiObject cmdlet to retrieve the instances of the Win32_NetworkAdapterConfiguration WMI class that Internet Protocol (IP) enabled, and pass the result to the $IP variable. The IPAddress, IPSubNet, and DNSServerSearchOrder properties are all stored in an array.

$IP=Get-WmiObject -class Win32_NetworkAdapterConfiguration -Filter "IPEnabled = $true" -ComputerName "Frank-PC" 
" IP Address : "+$IP.IPAddress[0]
" Subnet mask : " + $IP.IPsubnet[0]
" Default Gateway: " + $IP.DefaultIPGateway
" DNS Server: " + $IP.DNSServerSearchOrder[0] 
" FQDN:" + $IP.DNSHostName + "." + $IP.DNSDomain

You can use a function to make the query easier:

function Get-IPInfo([string]$ComputerName)
{
$IP=Get-WmiObject -class Win32_NetworkAdapterConfiguration -Filter "IPEnabled = $true" -ComputerName $ComputerName
" IP Address : "+$IP.IPAddress[0]
" Subnet mask : " + $IP.IPsubnet[0]
" Default Gateway: " + $IP.DefaultIPGateway
" DNS Server: " + $IP.DNSServerSearchOrder[0] 
" FQDN:" + $IP.DNSHostName + "." + $IP.DNSDomain
}
Get-IPinfo("Frank-PC")

Note that if you query a info from a remote PC, you need to allow the WMI traffic through firewall.

Begin Process End

To make a structured powershell code, we can well organise it with begin, process, end statement.

  • The Begin section of the function is run once during the execution of the function. This block is used to provide optional one-time pre-processing for the function.
  • The Process section executes once for each item on the pipeline, this block is used to provide record-by-record processing for the function. This block might be used any number of times, or not at all, depending on the input to the function. For example, if the function is the first command in the pipeline, the process block will be used one time. If the function is not the first command in the pipeline, the Process block is used one time for every input that the function receives from the pipeline. If there is no pipeline input, the Process block is not used.
Function Get-IPObject([bool]$IPEnabled = $true)
{
 Get-WmiObject -class Win32_NetworkAdapterConfiguration -Filter "IPEnabled = $IPEnabled"
} #end Get-IPObject

Function Format-NonIPOutput($IP)
{
 Begin { "Index # `t Description" }
 Process {
 ForEach ($i in $ip)
     {
     Write-Host $i.Index `t $i.Description
     } #end ForEach
   } #end Process
} #end Format-NonIPOutPut

$ip = Get-IPObject -IPEnabled $False
Format-NonIPOutput($ip)
Filters

A filter is a special-purpose function. It is used to operate on each object in a pipeline.

The difference:

  • The Function need a loop function such as ForEach to go through the array; The filter does not require an ForEach Loop, because the loop function is already built in.

Filter version:

Filter AddOne
{
 "add one filter"
  $_ + 1
}

1..5 | addOne

Result:

Add One Filter
2
Add One Filter
3
Add One Filter
4
Add One Filter
5 
Add One Filter
6

 Function Version:

Function AddOne
{
  "Add One Function"
  While ($input.moveNext())
   {
     $input.current + 1
   } 
}

1..5 | addOne

Or you can use another way to loop:

Function AddOne
{
 "Add One Function"
 foreach($i in $input)
     {
     $i + 1
     } 
}

Both of them get same Result:

add one function
2
3
4
5
6

measure-command: used to measure the time it takes to run script blocks and cmdlets.

Here, you can use measure-command {1..50000 | addOne} to test the execution time of function and filter.

Obviously the Function will process faster.

Reference:

Win32_LogicalDisk: https://msdn.microsoft.com/en-us/library/aa394173(v=vs.85).aspx