Working with Functions in Windows PowerShell

  • 11/11/2015

Using functions to encapsulate business logic

There are two kinds of logic with which script writers need to be concerned. The first is program logic, and the second is business logic. Program logic includes the way the script works, the order in which things need to be done, and the requirements of code used in the script. An example of program logic is the requirement to open a connection to a database before querying the database.

Business logic is something that is a requirement of the business, but not necessarily a requirement of the program or script. The script can often operate just fine regardless of the particulars of the business rule. If the script is designed properly, it should operate perfectly fine no matter what gets supplied for the business rules.

In the BusinessLogicDemo.ps1 script, a function called Get-Discount is used to calculate the discount to be granted to the total amount. One good thing about encapsulating the business rules for the discount into a function is that as long as the contract between the function and the calling code does not change, you can drop any kind of convoluted discount schedule that the business decides to come up with into the script block of the Get-Discount function—including database calls to determine on-hand inventory, time of day, day of week, total sales volume for the month, the buyer’s loyalty level, and the square root of some random number that is used to determine an instant discount rate.

So, what is the contract with the function? The contract with the Get-Discount function says, “If you give me a rate number as a type of system.double and a total as an integer, I will return to you a number that represents the total discount to be applied to the sale.” As long as you adhere to that contract, you never need to modify the code.

The Get-Discount function begins with the Function keyword and is followed by the name of the function and the definition for two input parameters. The first input parameter is the $rate parameter, which is constrained to be of type system.double (which will permit you to supply decimal numbers). The second input parameter is the $total parameter, which is constrained to be of type system.integer, and therefore will not allow decimal numbers. In the script block, the value of the -total parameter is multiplied by the value of the -rate parameter. The result of this calculation is returned to the pipeline.

The Get-Discount function is shown here.

Function Get-Discount([double]$rate,[int]$total)
{
  $rate * $total
} #end Get-Discount

The entry point to the script assigns values to both the $total and $rate variables, as shown here.

$rate = .05
$total = 100

The variable $discount is used to hold the result of the calculation from the Get-Discount function. When calling the function, it is a best practice to use the full parameter names. It makes the code easier to read and will help make it immune to unintended problems if the function signature ever changes.

$discount = Get-Discount -rate $rate -total $total

The remainder of the script produces output for the screen. The results of running the script are shown here.

Total: 100
Discount: 5
Your Total: 95

The complete text of the BusinessLogicDemo.ps1 script is shown here.

BusinessLogicDemo.ps1

Function Get-Discount([double]$rate,[int]$total)
{
 $rate * $total
} #end Get-Discount


$rate = .05
$total = 100
$discount = Get-Discount -rate $rate -total $total
"Total: $total"
"Discount: $discount"
"Your Total: $($total-$discount)"

Business logic does not have to be related to business purposes. Business logic is anything that is arbitrary that does not affect the running of the code. In the FindLargeDocs.ps1 script, there are two functions. The first function, Get-Doc, is used to find document files (files with an extension of .doc, .docx, or .dot) in a folder that is passed to the function when it is called. The -Recurse switch parameter, when used with the Get-ChildItem cmdlet, causes the function to look in the present folder, and within child folders. This function is a stand-alone function and has no dependency on any other functions.

The LargeFiles piece of code is a filter. A filter is a kind of special-purpose function that uses the Filter keyword rather than the Function keyword when it is created. (For more information on filters, see the “Understanding filters” section later in this chapter.) The FindLargeDocs.ps1 script is shown here.

FindLargeDocs.ps1

Function Get-Doc($path)
{
 Get-ChildItem -Path $path -include *.doc,*.docx,*.dot -recurse
} #end Get-Doc

Filter LargeFiles($size)
{
  $_ |
  Where-Object { $_.length -ge $size }
} #end LargeFiles

Get-Doc("C:\FSO") |  LargeFiles 1000