---
title: "Automate Tasks with PowerShell PSake: A Walkthrough"
description: "Upgrade your automation skills with the open-source PowerShell Psake project and learn how to orchestrate tasks effectively."
canonical: "https://adamtheautomator.com/powershell-psake/"
---

# Automate Tasks with PowerShell PSake: A Walkthrough

> Upgrade your automation skills with the open-source PowerShell Psake project and learn how to orchestrate tasks effectively.

Source: https://adamtheautomator.com/powershell-psake/

---

ATA Learning

Tap to hide

[

ATA Learning

](/)

*   [Home](/)
*   [Tutorials](/tutorials/)
*   [Instructors](/author/)
*   [Advertising](/advertising/)
*   [Recommended Resources](/resources/)
*   [About Adam](/about-adam/)

Search for:  

*   [](https://twitter.com/adbertram)
*   [](https://github.com/Adam-the-Automator)
*   [](https://www.linkedin.com/company/adam-the-automator-llc)
*   [](/feed/)

![Automate Tasks with PowerShell PSake: A Walkthrough](https://adamtheautomator.com/wp-content/uploads/2020/12/Learn-Countless-Task-Automation-with-PSake-and-PowerShell.jpg)

# Automate Tasks with PowerShell PSake: A Walkthrough

[![](https://secure.gravatar.com/avatar/3d789c8b517f2dac6b170f741b31b0658bd8e9dc5f272cf683b8e7b3a31e4005?s=192&d=mm&r=g)Tsvika Nahir](https://adamtheautomator.com/author/tsvika/)23 December 202011 min. read

Categories: [IT Ops](/category/it-ops/)

Tags:[PowerShell](/tag/powershell/)

Table of Contents

*   [Prerequisites](#h-prerequisites)
*   [Setting Up the PSake Module](#h-setting-up-the-psake-module)
*   [Creating a Basic PowerShell PSake Script](#h-creating-a-basic-powershell-psake-script)
*   [Installing SQL with PSake](#h-installing-sql-with-psake)
*   [Designing the Building Blocks](#h-designing-the-building-blocks)
*   [Defining Task Execution Order](#h-defining-task-execution-order)
*   [Adding a PreCondition](#h-adding-a-precondition)
*   [Task Parameters](#h-task-parameters)
*   [Adding PreAction and PostCondition](#h-adding-preaction-and-postcondition)
*   [Running PSake Scripts in Pester Tests](#h-running-psake-scripts-in-pester-tests)
*   [Passing Parameters to Tasks](#h-passing-parameters-to-tasks)
*   [Using the Properties Parameter](#h-using-the-properties-parameter)
*   [PSake Task Modularization: Tasks as Files](#h-psake-task-modularization-tasks-as-files)
*   [Next Steps](#h-next-steps)

So you’ve learned how to automate tasks with a PowerShell script.  
That’s great! But now you’ve got a disorganized mess of scripts and modules with a hodgepodge of manual script executions, scheduled tasks, and more. It’s time to bring some order to the chaos and implement the automation orchestration engine known as PowerShell [_PSake_](https://github.com/psake/psake).

Not a reader? Watch this related video tutorial!

**_Not seeing the video? Make sure your ad blocker is disabled._**

PSake is an orchestration engine written as a PowerShell module that adds order to your scripts and gives you full control of what runs when and under what conditions. Though PSake is a build automation tool and its primary use case is in build scripts (usually executed by a build server in release automation scenarios), it is generally overlooked in everyday scripting scenarios. Let’s change that.

In this tutorial, you’re going to learn how PSake works along with some great examples for you to put into practice today!

## Prerequisites

This article will be a tutorial expecting you to follow along. If you’d like to follow along exactly as covered, be sure you have:

*   Windows PowerShell 3+. The tutorial uses Windows PowerShell v5.1
*   The PSake zip file from [_Github_](https://github.com/PSake/PSake). This tutorial uses v4.9.0.

## Setting Up the PSake Module

Assuming you have the PSake project from GitHub on your local machine, you’ll first need to run through a few steps to get it set up.

1.  Extract the PSake zip file downloaded from GitHub.
2.  Move the _src_ folder inside of the extracted ZIP file contents to a path under `_$env:PSModulePath_` to ensure PowerShell knows of the new module.
3.  Rename the _src_ folder to _PSake._
4.  Now run _`Get-Module PSake -ListAvailable`_ to confirm it shows up. If you don’t receive an error, you’re ready to proceed.

**_Related: [Understanding and Building PowerShell Modules](https://adamtheautomator.com/powershell-modules/#Interacting_with_Modules)_**

## Creating a Basic PowerShell PSake Script

To understand PSake, you need to build something. Let’s build a simple PSake script to see what it can do.

1.  Create a script named _psakefile.ps1_ with a single task. At a minimum, a task should have a name and an action block. The name _psakefile.ps1_ is not mandatory, but it is the default name expected by the engine.

> _A PSake task in its basic form is very similar to a [PowerShell function](https://adamtheautomator.com/powershell-functions/ "PowerShell function"):_  
> _a container for one or more commands that, when performed together, achieve a certain goal. These commands go into a script block that is passed to the `Action` parameter. A task has many advantages over a function. You will learn about these advantages as you read along._

Below is an example of a _psakefile.ps1_ with a somewhat simple task:

```powershell
task HelloWorld -Action {
    Write-Host '*** Hello World ***' -ForegroundColor Yellow
}
```

2\. Now that you’ve built the PSake file, you can call it from a PowerShell console with the _`Invoke-PSake`_ command and pass the task name as a value to the `_TaskList_` parameter.

> _`Invoke-PSake` is the execution engine for PSake. This command triggers tasks defined in psakefile.ps1. You pass a task name, or a list of comma-separated tasks to the `TaskList` parameter. If you’re executing multiple tasks, each task will execute in the order you have passed them to `TaskList` regardless of their location in psakefile.ps1._

Below is how you can trigger the _HelloWorld_ task:

```powershell
Invoke-PSake -BuildFile C:\Work\psakefile.ps1 -TaskList 'HelloWorld'
```

> _As long as you keep the name psakefile.ps1, and given that you set the console to the folder where it is located, you may omit the `BuildFile` parameter and its value._

3.  Running _`Invoke-PSake`_ will show PSake output to the console. When you execute the tasks in _psakefile.ps1_, you’ll see output similar to what you see below.

![Psake script output](https://adamtheautomator.com/wp-content/uploads/2020/12/image0.png)

_Psake script output_

The output consists of these components:

1.  The details about the PSake version.
2.  The name of each build task right before it runs (PSake considers every task as a _build_ task). In the example: _Executing HelloWorld_ in cyan.
3.  Any output the task had produced. In the example: _**Hello World**_ in yellow.
4.  Success/fail message. In the example: _psake succeeded…_ in green.
5.  Time summary (named _Build Time Report_) with the duration of each task, plus the total duration of the whole script.

## Installing SQL with PSake

In the previous section, you didn’t do much but invoke a dummy PSake script. Now build upon that knowledge and create a PSake script that installs SQL!

In this example, you’re going to create a PSake script that:

1.  Validates free disk space on a machine.
2.  Downloads a SQL ZIP file from a local repository.
3.  Extracts the ZIP file.
4.  Runs the installation on the C or D drive (whichever of the two exists).

Let’s see next how we can harness PSake for the job.

### Designing the Building Blocks

PSake is all about orchestrating tasks. Each task should have its own unique name and ideally should perform a single atomic operation like a PowerShell function. Using this concept, you can describe the steps below to build a task for each.

1.  ValidateDiskSpace
2.  DownloadSql
3.  ExtractSql
4.  InstallSqlDriveC
5.  InstallSqlDriveD

At this stage, you’re not actually building the code to do anything; you’re simply scaffolding out the tasks and creating the PSake file. You’ll notice the `Write-Host` references in the tasks below; you’ll be adding to the tasks later.

> _You should always use the `Description` parameter for each task. The `Description` parameter provides more information about each task both when executing the tasks and while reviewing the code._

```powershell
task ValidateDiskSpace -Description 'Validate Disk Free Space' -Action {
	
	Write-Host "`n   *** Checking disk free space ***`n" -ForegroundColor Yellow
	
}

task DownloadSql -Description 'Download SQL Setup' -Action {
	
	Write-Host "`n   *** Downloading SQL Setup from LAN ***`n" -ForegroundColor Yellow
	
}

task ExtractSql -Description 'Extract SQL Setup' -Action {
	
	Write-Host "`n   *** Extracting SQL Setup files ***`n" -ForegroundColor Yellow
	
}

task InstallSqlDriveC -Description 'Install SQL on C:' -Action {
	
	Write-Host "`n   *** Installing SQL Server on C drive ... please wait... ***`n" -ForegroundColor Yellow

}

task InstallSqlDriveD -Description 'Install SQL on D:' -Action {
	
	Write-Host "`n   *** Installing SQL Server on D drive ... please wait... ***`n" -ForegroundColor Yellow
	
}
```

### Defining Task Execution Order

You now have a PSake file that contains a set of tasks. At this point, you can run all of the tasks at once or choose to only execute some of them with the `_Invoke-PSake_` command.

You can call some (or all tasks) using `_Invoke-PSake_` and the `_TaskList_` parameter as you did earlier in the simple example. If you have more than one task to invoke, create an array, and define each task’s name as an item as shown below.

> _`Invoke-PSake` will run each task in the order defined in the array._

```powershell
$taskList = @()

$taskList += 'ValidateDiskSpace'
$taskList += 'DownloadSql'
$taskList += 'ExtractSql'
$taskList += 'InstallSqlDriveC'
$taskList += 'InstallSqlDriveD'

Invoke-PSake -TaskList $taskList
```

When you run the above code, you should get a result like the following:

![Psake script output](https://adamtheautomator.com/wp-content/uploads/2020/12/image2.png)

_PSake script output_

## Adding a PreCondition

Perhaps you need to perform some action _only if_ a certain condition is met. In this tutorial’s example SQL installation script, for example, maybe you need to test whether the volume where you store the installer is available before executing the task to invoke said installer.

You can use the `PreCondition` parameter to execute a piece of code that returns either a boolean True or False that dictates whether or not that task runs.

Notice in the example below the `_$installSqlOn_C_Drive_` and `_$installSqlOn_D_Drive_` variables. When `_Invoke-PSake_` invokes this script, these variables will contain a True or False value depending on if a C or D volume exists.

On each `task` line, you can then see that each task has a `_PreCondition_` scriptblock parameter which contains the value of those variables. At run time, either the `_InstallSqlDriveC_` or the `_InstallSqlDriveD_` task will run, depending on these variables.

```powershell
$installSqlOn_C_Drive = (Test-Path -Path 'C:') -and (-not (Test-Path -Path 'D:'))
$installSqlOn_D_Drive = (-not (Test-Path -Path 'C:')) -and (Test-Path -Path 'D:')

task InstallSqlDriveC -Description 'Install SQL on C:' -PreCondition { $installSqlOn_C_Drive } -Action {
	
	Write-Host "`n   *** Installing SQL Server on C drive ... please wait... ***`n" -ForegroundColor Yellow
	
}

task InstallSqlDriveD -Description 'Install SQL on D:' -PreCondition { $installSqlOn_D_Drive } -Action {
	
	Write-Host "`n   *** Installing SQL Server on D drive ... please wait... ***`n" -ForegroundColor Yellow
	
}
```

## Task Parameters

In addition to the `Action` and `Description` a task also support these parameters:

*   `PreCondition` – Script block that returns a boolean value. On False, the specific task is skipped. (A usage example is shown above).
*   `PostCondition` **–** Validation step. A script block that returns a boolean value. False means validation has failed to cause the whole script to stop.
*   `PreAction` – A script block to run prior to the task.
*   `PostAction` **–** A script block to run right after the task has completed with success.
*   `ContinueOnError` **–** Switch parameter. If used, any errors that may occur during the task runtime will not cause the whole script to break.
*   `Depends` **–** A name of a task (or a list of task names) that must run before the current task is executed. PSake will use this information to execute the task dependencies in the right order. E.g., if task A is dependent on task B, then PSake engine will run B before A.

> _At first the dependency mechanism sounds like a good idea. It helps to set tasks in a logical order. However, using the `Depends` parameter glues different tasks together, making it later difficult to test independently. But, since the user can explicitly set the order of tasks execution and pass this order when calling the PSake file → the use of the `Depends` parameter can be avoided altogether._

Let’s see next a usage example for some of these task parameters:

## Adding PreAction and PostCondition

Using the _InstallSqlDriveD_ task from the example above as a starting point, perhaps you have an additional request for the installation.

Maybe you need to record the times when the installation starts and ends. You need to record these times to two environment variables named _SqlSetupStartDate_ and _SqlSetupEndDate_. Second, after the installation completes, you need to verify that the _D:\\TempSqlFiles_ folder does not exist.

Luckily, the PSake task parameters _`PreAction`, `PostAction`_ and `_PostCondition_` (respectively) meet exactly these new requirements. Below is an example of how it can be done:

```powershell
task InstallSqlDriveD -Description 'Install SQL on D:' -PreAction {

     Write-Host '*** Writing SQL install start time to env. var. SqlSetupStartDate ***' -ForegroundColor Yellow
     $date = Get-Date -Format 'yyyy-MM-dd HH:mm:ss'
[Environment]::SetEnvironmentVariable('SqlSetupStartDate',$date,'Machine')

 } -PreCondition { 

     $installSqlOn_D_Drive

 } -Action {  
  
     Write-Host '*** Installing SQL Server on D drive... please wait... ***' -ForegroundColor Yellow 

} -PostAction {     

    Write-Host '*** Writing SQL install end time to env. var. SqlSetupEndDate ***' -ForegroundColor Yellow     
    $date = Get-Date -Format 'yyyy-MM-dd HH:mm:ss'
[Environment]::SetEnvironmentVariable('SqlSetupEndDate',$date,'Machine') 

} -PostCondition { 
    
Write-Host '*** Verifying temp files deleted ***' -ForegroundColor Yellow
     # in case if the folder exits this will return False, causing the whole script to stop
     (-not (Test-Path -Path 'D:\TempSqlFiles'))

 }
```

## Running PSake Scripts in Pester Tests

Wherever you can invoke a PowerShell script, you can invoke a PSake file. If you’re building infrastructure tests with Pester, you can invoke PSake within tests.

**_Related: [Writing Pester Tests for PowerShell](https://adamtheautomator.com/powershell-test/)_**

For example, maybe you have a Pester test to confirm the SQL setup ZIP file exists in a folder after you run the `_DownloadSql_` task. In that case, you build a simple Pester test and invoke the `_DownloadSql_` task within the test and check for the ZIP file right after it runs.

```powershell
Describe 'SQL install with PSake' {

    It 'Downloads Sql files' {

        $setup = 'C:\Downloads\SqlSetup.zip'

        if(Test-Path -Path $setup)
        {
            Remove-Item -Path $setup
        }

        # the single task under test here is DownloadSql
        Invoke-PSake -BuildFile C:\Work\psakefile.ps1 -TaskList DownloadSql
        
        $setup | Should -Exist
    }
}
```

## Passing Parameters to Tasks

Once you start using PSake you might want to parametrize some of the tasks. Typically, with PowerShell functions and scripts, you will pass various named parameters to the function/script; PSake is different.

To pass parameters to PSake files, you can use a `_Properties_` block that defines key/value pairs which PSake then makes available inside of each task in the file.

> _Be sure to define `Properties` block at the top of the PSake file. All PSake operations are read from the top down._

For example, to pass dynamic `_SqlYear_` and `_SqlVersion_` variables to each task in the PSake file, you can define them as shown below.

```powershell
Properties {
    $SqlYear = '2017'
    $SqlVersion = '14.0'
}

task -Name DownloadSql -Action {
    
    Write-Host "SQL version to install: SQL $SqlYear (version $SqlVersion)"

}
```

When you then invoke the PSake file with `_Invoke-PSake_`, you would then see the following output. Notice that the `_$SqlYear_` and `_$SqlVersion_` variables have been expanded with the values defined in the `_Properties_` block.

```powershell
psake version 4.9.1
Copyright (c) 2010-2018 James Kovacs & Contributors

Executing DownloadSql
SQL version to install: SQL 2017 (version 14.0)

psake succeeded executing C:\Work\PSakefile.ps1

--------------------------------------------------
Build Time Report
--------------------------------------------------

Name        Duration
----        --------
DownloadSql 00:00:00
------      --------
Total:      00:00:00
```

### Using the `Properties` Parameter

If you’d rather pass parameters to a task via a traditional parameter, PSake can help. You still need to keep the Properties block at the top of _psakefile.ps1_ as in the example above, but PSake lets you override the values.

To do so, define a hashtable with each of the key/value pairs you’d like to override. Then, pass the hashtable to the `_Properties_` parameter. PSake engine will use the values in the passed-in hashtable over those specified in the `_Properties_` block within the _psakefile.ps1_ script.

> _Note the differences in syntax between the `Properties` block and the `Properties` parameter. On the `Properties` block each line is a variable and thus prefixed with a dollar sign, whereas the `Properties` parameter is a hashtable, so each item is a key, and written without a leading $. Another difference is that the hashtable is preceded with @ character._

Below you can see an example of using the `Properties` parameter.

```powershell
$myNewProperties = @{
    SqlYear = '2019'
    SqlVersion = '15.0'
}

Invoke-PSake -TaskList DownloadSql -Properties $myNewProperties
```

## PSake Task Modularization: Tasks as Files

At some point, your PSake file will probably grow exponentially especially if you need to orchestrate large automation tasks. To ensure you can manage all of those tasks, you should focus on modularization or splitting tasks up to make things easier to manage.

**_Related: [How to Survive Refactoring a PowerShell Script from Hell](https://adamtheautomator.com/powershell-script/)_**

In this tutorial’s example, you were working with five tasks:

*   ValidateDiskSpace
*   DownloadSql
*   ExtractSql
*   InstallSqlDriveC
*   InstallSqlDriveD

Each of these tasks is defined inside of a single _pssakefile.ps1_ script. If you anticipate adding more many more tasks over time, you should split those tasks up into separate files with each task inside e.g. _ValidateDiskSpace.ps1_, _DownloadSql.ps1_, _InstallSqlDriveD.ps1_, _InstallSqlDriveD.ps1_, etc.

For example _InstallSqlDriveD.ps1_ will contain only this code:

```powershell
task InstallSqlDriveD -Description 'Install SQL on D:' -PreCondition { $installSqlOn_D_Drive } -Action {
	
	Write-Host "`n   *** Installing SQL Server on D drive ... please wait... ***`n" -ForegroundColor Yellow
	
}
```

Once the tasks are moved out, import the files into _psakefile.ps1_ using the `_Include_` function. Once this is done, the _psakefile.ps1_ content is reduced to this code:

```powershell
$installSqlOn_C_Drive = $true
$installSqlOn_D_Drive = $false

Include "$PSScriptRoot\ValidateDiskSpace.ps1"
Include "$PSScriptRoot\DownloadSql.ps1"
Include "$PSScriptRoot\ExtractSql.ps1"
Include "$PSScriptRoot\InstallSqlOnC.ps1"
Include "$PSScriptRoot\InstallSqlOnD.ps1"
```

> _When `Invoke-PSake` triggers the psakefile.ps1 script, `Invoke-PSake` does not know or care whether the tasks are within the psake file or were imported by the `Include` method._

## Next Steps

PSake is a powerful script orchestrator that can be used for many purposes: Software builds, CI/CD, package deployments, installers creations, and more. The only limit is your imagination. Getting used to building large scripts with PSake forces you to think in tasks (code building blocks). The concept of tasks is leveraging the PowerShell syntax, and by using tasks you enrich your existing command line knowledge.

The code you produce with PSake becomes more readable, maintainable, and easier to test. After some practice you will find that dividing your steps to different tasks makes them easier to script. The small amount of extra work it takes pays back big time in the medium and long terms.

Where do you see PSake fitting into your work projects?

Share this article

[Share on X](https://twitter.com/intent/tweet?url=https%3A%2F%2Fadamtheautomator.com%2Fpowershell-psake%2F&text=Automate%20Tasks%20with%20PowerShell%20PSake%3A%20A%20Walkthrough)[Share on Facebook](https://www.facebook.com/sharer/sharer.php?u=https%3A%2F%2Fadamtheautomator.com%2Fpowershell-psake%2F)[Share on LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fadamtheautomator.com%2Fpowershell-psake%2F)

## Related Posts

![](https://adamtheautomator.com/wp-content/uploads/2026/06/26995-troubleshoot-dns-issues-powershell-codex.webp)

### [Troubleshoot DNS Issues with PowerShell](/troubleshoot-dns-issues-powershell/)

Troubleshoot DNS issues with PowerShell by testing name resolution, DNS client settings, cache entries, and network connectivity in a repeatable workflow.

![](https://adamtheautomator.com/wp-content/uploads/2025/10/image_2025-10-24_095322075.png)

### [Migrating from PowerShell 6 to 7.5: Breaking Changes/New Features](/migrating-powershell-6-to-7-5/)

Migrate from PowerShell Core 6 to 7.5: breaking changes, features, and testing tips.

![](https://adamtheautomator.com/wp-content/uploads/2025/06/featured-image-6.png)

### [How to Add Timeouts to Pester Tests with PowerShell Runspaces](/pester-test-timeout-runspaces/)

Prevent Pester tests from hanging indefinitely using PowerShell runspaces. Learn to handle variable scoping, module loading, TestDrive access, and stream capture challenges with timeout protection.

## Categories

*   [IT Ops](/category/it-ops/)
*   [Cloud](/category/cloud/)
*   [DevOps](/category/devops/)
*   [Home Ops](/category/home-ops/)
*   [Information Security](/category/infosec/)
*   [Software Development](/category/software-development/)

## Site

*   [Home](/)
*   [Tutorials](/tutorials/)
*   [Instructors](/author/)
*   [Advertising](/advertising/)
*   [Recommended Resources](/resources/)
*   [About Adam](/about-adam/)

Copyright 2026© ATA Learning | [Privacy Policy](/privacy/)
