2 # Copyright (c) 2010 James Kovacs
3 # Permission is hereby granted, free of charge, to any person obtaining a copy
4 # of this software and associated documentation files (the "Software"), to deal
5 # in the Software without restriction, including without limitation the rights
6 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 # copies of the Software, and to permit persons to whom the Software is
8 # furnished to do so, subject to the following conditions:
10 # The above copyright notice and this permission notice shall be included in
11 # all copies or substantial portions of the Software.
13 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 #Requires -Version 2.0
23 #-- Private Module Variables (Listed here for quick reference)
24 [system.collections.stack]$script:context
26 #-- Public Module Variables -- The psake hashtable variable is initialized in the invoke-psake function
28 $script:psake.use_exit_on_error = $false # determines if psake uses the "exit()" function when an exception occurs
29 $script:psake.log_error = $false # determines if the exception details are written to a file
30 $script:psake.build_success = $false # indicates that the current build was successful
31 $script:psake.version = "4.00" # contains the current version of psake
32 $script:psake.build_script_file = $null # contains a System.IO.FileInfo for the current build file
33 $script:psake.framework_version = "" # contains the framework version # for the current build
34 $script:psake.default_build_file_name = 'default.ps1'
36 Export-ModuleMember -Variable "psake"
38 #-- Private Module Functions
41 param([string]$taskName)
43 Assert (![string]::IsNullOrEmpty($taskName)) "Task name should not be null or empty string"
45 $taskKey = $taskName.ToLower()
47 Assert ($script:context.Peek().tasks.Contains($taskKey)) "task [$taskName] does not exist"
49 if ($script:context.Peek().executedTasks.Contains($taskKey))
54 Assert (!$script:context.Peek().callStack.Contains($taskKey)) "Error: Circular reference found for task, $taskName"
56 $script:context.Peek().callStack.Push($taskKey)
58 $task = $script:context.Peek().tasks.$taskKey
60 $taskName = $task.Name
62 $precondition_is_valid = if ($task.Precondition -ne $null) {& $task.Precondition} else {$true}
64 if (!$precondition_is_valid)
66 "Precondition was false not executing $name"
70 if ($taskKey -ne 'default')
72 $stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
74 if ( ($task.PreAction -ne $null) -or ($task.PostAction -ne $null) )
76 Assert ($task.Action -ne $null) "Error: Action parameter must be specified when using PreAction or PostAction parameters"
79 if ($task.Action -ne $null)
83 foreach($childTask in $task.DependsOn)
85 ExecuteTask $childTask
88 $script:context.Peek().currentTaskName = $taskName
90 if ($script:context.Peek().taskSetupScriptBlock -ne $null)
92 & $script:context.Peek().taskSetupScriptBlock
95 if ($task.PreAction -ne $null)
100 $script:context.Peek().formatTaskNameString -f $taskName
103 if ($task.PostAction -ne $null)
108 if ($script:context.Peek().taskTearDownScriptBlock -ne $null)
110 & $script:context.Peek().taskTearDownScriptBlock
115 if ($task.ContinueOnError)
118 "Error in Task [$taskName] $_"
126 } # if ($task.Action -ne $null)
129 #no Action was specified but we still execute all the dependencies
130 foreach($childTask in $task.DependsOn)
132 ExecuteTask $childTask
136 $task.Duration = $stopwatch.Elapsed
137 } # if ($name.ToLower() -ne 'default')
140 foreach($childTask in $task.DependsOn)
142 ExecuteTask $childTask
146 if ($task.Postcondition -ne $null)
148 Assert (& $task.Postcondition) "Error: Postcondition failed for $taskName"
152 $poppedTaskKey = $script:context.Peek().callStack.Pop()
154 Assert ($poppedTaskKey -eq $taskKey) "Error: CallStack was corrupt. Expected $taskKey, but got $poppedTaskKey."
156 $script:context.Peek().executedTasks.Push($taskKey)
159 function Configure-BuildEnvironment
161 if ($framework.Length -ne 3 -and $framework.Length -ne 6) {
162 throw "Error: Invalid .NET Framework version, $framework, specified"
164 $versionPart = $framework.Substring(0,3)
165 $bitnessPart = $framework.Substring(3)
167 switch ($versionPart)
169 '1.0' { $versions = @('v1.0.3705') }
170 '1.1' { $versions = @('v1.1.4322') }
171 '2.0' { $versions = @('v2.0.50727') }
172 '3.0' { $versions = @('v2.0.50727') }
173 '3.5' { $versions = @('v3.5','v2.0.50727') }
174 '4.0' { $versions = @('v4.0.30319') }
175 default { throw "Error: Unknown .NET Framework version, $versionPart, specified in $framework" }
178 $bitness = 'Framework'
179 if($versionPart -ne '1.0' -and $versionPart -ne '1.1') {
180 switch ($bitnessPart)
182 'x86' { $bitness = 'Framework' }
183 'x64' { $bitness = 'Framework64' }
185 $ptrSize = [System.IntPtr]::Size
188 4 { $bitness = 'Framework' }
189 8 { $bitness = 'Framework64' }
190 default { throw "Error: Unknown pointer size ($ptrSize) returned from System.IntPtr." }
193 default { throw "Error: Unknown .NET Framework bitness, $bitnessPart, specified in $framework" }
196 $frameworkDirs = $versions | foreach { "$env:windir\Microsoft.NET\$bitness\$_\" }
198 $frameworkDirs | foreach { Assert (test-path $_) "Error: No .NET Framework installation directory found at $_" }
200 $env:path = [string]::Join(';', $frameworkDirs) + ";$env:path"
201 #if any error occurs in a PS function then "stop" processing immediately
202 # this does not effect any external programs that return a non-zero exit code
203 $global:ErrorActionPreference = "Stop"
206 function Cleanup-Environment
208 $env:path = $script:context.Peek().originalEnvPath
209 Set-Location $script:context.Peek().originalDirectory
210 $global:ErrorActionPreference = $script:context.Peek().originalErrorActionPreference
213 #borrowed from Jeffrey Snover http://blogs.msdn.com/powershell/archive/2006/12/07/resolve-error.aspx
214 function Resolve-Error($ErrorRecord=$Error[0])
217 $ErrorRecord | Format-List * -Force | Out-String -Stream | ? {$_}
219 "ErrorRecord.InvocationInfo"
220 $ErrorRecord.InvocationInfo | Format-List * | Out-String -Stream | ? {$_}
223 $Exception = $ErrorRecord.Exception
224 for ($i = 0; $Exception; $i++, ($Exception = $Exception.InnerException))
227 $Exception | Format-List * -Force | Out-String -Stream | ? {$_}
232 function Write-Documentation
234 $list = New-Object System.Collections.ArrayList
235 foreach($key in $script:context.Peek().tasks.Keys)
237 if($key -eq "default")
241 $task = $script:context.Peek().tasks.$key
242 $content = "" | Select-Object Name, Description
243 $content.Name = $task.Name
244 $content.Description = $task.Description
245 $index = $list.Add($content)
248 $list | Sort 'Name' | Format-Table -Auto
251 function Write-TaskTimeSummary
257 while ($script:context.Peek().executedTasks.Count -gt 0)
259 $taskKey = $script:context.Peek().executedTasks.Pop()
260 $task = $script:context.Peek().tasks.$taskKey
261 if($taskKey -eq "default")
265 $list += "" | Select-Object @{Name="Name";Expression={$task.Name}}, @{Name="Duration";Expression={$task.Duration}}
267 [Array]::Reverse($list)
268 $list += "" | Select-Object @{Name="Name";Expression={"Total:"}}, @{Name="Duration";Expression={$stopwatch.Elapsed}}
269 $list | Format-Table -Auto | Out-String -Stream | ? {$_} # using "Out-String -Stream" to filter out the blank line that Format-Table prepends
272 #-- Public Module Functions
277 Helper function for executing command-line programs.
280 This is a helper function that runs a scriptblock and checks the PS variable $lastexitcode to see if an error occcured.
281 If an error is detected then an exception is thrown. This function allows you to run command-line programs without
282 having to explicitly check fthe $lastexitcode variable.
285 The scriptblock to execute. This scriptblock will typically contain the command-line invocation.
288 .PARAMETER errorMessage
289 The error message used for the exception that is thrown.
293 exec { svn info $repository_trunk } "Error executing SVN. Please verify SVN command-line client is installed"
295 This example calls the svn command-line client.
308 SupportsShouldProcess=$False,
309 SupportsTransactions=$False,
310 ConfirmImpact="None",
311 DefaultParameterSetName="")]
314 [Parameter(Position=0,Mandatory=1)][scriptblock]$cmd,
315 [Parameter(Position=1,Mandatory=0)][string]$errorMessage = "Error executing command: " + $cmd
318 if ($lastexitcode -ne 0)
328 Helper function for "Design by Contract" assertion checking.
331 This is a helper function that makes the code less noisy by eliminating many of the "if" statements
332 that are normally required to verify assumptions in the code.
334 .PARAMETER conditionToCheck
335 The boolean condition to evaluate
338 .PARAMETER failureMessage
339 The error message used for the exception if the conditionToCheck parameter is false
343 Assert $false "This always throws an exception"
345 This example always throws an exception
348 Assert ( ($i % 2) -eq 0 ) "%i is not an even number"
350 This exmaple may throw an exception if $i is not an even number
362 It might be necessary to wrap the condition with paranthesis to force PS to evaluate the condition
363 so that a boolean value is calculated and passed into the 'conditionToCheck' parameter.
366 Assert 1 -eq 2 "1 doesn't equal 2"
368 PS will pass 1 into the condtionToCheck variable and PS will look for a parameter called "eq" and
369 throw an exception with the following message "A parameter cannot be found that matches parameter name 'eq'"
371 The solution is to wrap the condition in () so that PS will evaluate it first.
373 Assert (1 -eq 2) "1 doesn't equal 2"
376 SupportsShouldProcess=$False,
377 SupportsTransactions=$False,
378 ConfirmImpact="None",
379 DefaultParameterSetName="")]
382 [Parameter(Position=0,Mandatory=1)]$conditionToCheck,
383 [Parameter(Position=1,Mandatory=1)]$failureMessage
385 if (!$conditionToCheck) { throw $failureMessage }
392 Defines a build task to be executed by psake
395 This function creates a 'task' object that will be used by the psake engine to execute a build task.
396 Note: There must be at least one task called 'default' in the build script
403 A scriptblock containing the statements to execute
407 A scriptblock to be executed before the 'Action' scriptblock.
408 Note: This parameter is ignored if the 'Action' scriptblock is not defined.
411 .PARAMETER PostAction
412 A scriptblock to be executed after the 'Action' scriptblock.
413 Note: This parameter is ignored if the 'Action' scriptblock is not defined.
416 .PARAMETER Precondition
417 A scriptblock that is executed to determine if the task is executed or skipped.
418 This scriptblock should return $true or $false
421 .PARAMETER Postcondition
422 A scriptblock that is executed to determine if the task completed its job correctly.
423 An exception is thrown if the scriptblock returns $false.
426 .PARAMETER ContinueOnError
427 If this switch parameter is set then the task will not cause the build to fail when an exception is thrown
430 An array of tasks that this task depends on. They will be executed before the current task is executed.
432 .PARAMETER Description
433 A description of the task.
436 A sample build script is shown below:
438 task default -depends Test
440 task Test -depends Compile, Clean {
444 task Compile -depends Clean {
452 The 'default' task is required and should not contain an 'Action' parameter.
453 It uses the 'depends' parameter to specify that 'Test' is a dependency
455 The 'Test' task uses the 'depends' parameter to specify that 'Compile' and 'Clean' are dependencies
456 The 'Compile' task depends on the 'Clean' task.
459 The 'Action' parameter is defaulted to the script block following the 'Clean' task.
461 The equivalent 'Test' task is shown below:
463 task Test -depends Compile, Clean -Action {
467 The output for the above sample build script is shown below:
468 Executing task, Clean...
470 Executing task, Compile...
472 Executing task, Test...
477 ----------------------------------------------------------------------
479 ----------------------------------------------------------------------
482 Clean 00:00:00.0065614
483 Compile 00:00:00.0133268
484 Test 00:00:00.0225964
485 Total: 00:00:00.0782496
497 SupportsShouldProcess=$False,
498 SupportsTransactions=$False,
499 ConfirmImpact="None",
500 DefaultParameterSetName="")]
502 [Parameter(Position=0,Mandatory=1)]
503 [string]$name = $null,
504 [Parameter(Position=1,Mandatory=0)]
505 [scriptblock]$action = $null,
506 [Parameter(Position=2,Mandatory=0)]
507 [scriptblock]$preaction = $null,
508 [Parameter(Position=3,Mandatory=0)]
509 [scriptblock]$postaction = $null,
510 [Parameter(Position=4,Mandatory=0)]
511 [scriptblock]$precondition = $null,
512 [Parameter(Position=5,Mandatory=0)]
513 [scriptblock]$postcondition = $null,
514 [Parameter(Position=6,Mandatory=0)]
515 [switch]$continueOnError = $false,
516 [Parameter(Position=7,Mandatory=0)]
517 [string[]]$depends = @(),
518 [Parameter(Position=8,Mandatory=0)]
519 [string]$description = $null
522 if ($name.ToLower() -eq 'default')
524 Assert ($action -eq $null) "Error: 'default' task cannot specify an action"
530 PreAction = $preaction
532 PostAction = $postaction
533 Precondition = $precondition
534 Postcondition = $postcondition
535 ContinueOnError = $continueOnError
536 Description = $description
540 $taskKey = $name.ToLower()
542 Assert (!$script:context.Peek().tasks.ContainsKey($taskKey)) "Error: Task, $name, has already been defined."
544 $script:context.Peek().tasks.$taskKey = $newTask
551 Define a scriptblock that contains assignments to variables that will be available to all tasks in the build script
554 A build script may declare a "Properies" function which allows you to define
555 variables that will be available to all the "Task" functions in the build script.
557 .PARAMETER properties
558 The script block containing all the variable assignment statements
562 A sample build script is shown below:
565 $build_dir = "c:\build"
566 $connection_string = "datasource=localhost;initial catalog=northwind;integrated security=sspi"
569 Task default -depends Test
571 Task Test -depends Compile, Clean {
574 Task Compile -depends Clean {
590 You can have more than 1 "Properties" function defined in the script
593 SupportsShouldProcess=$False,
594 SupportsTransactions=$False,
595 ConfirmImpact="None",
596 DefaultParameterSetName="")]
598 [Parameter(Position=0,Mandatory=1)]
599 [scriptblock]$properties
601 $script:context.Peek().properties += $properties
608 Include the functions or code of another powershell script file into the current build script's scope
611 A build script may declare an "includes" function which allows you to define
612 a file containing powershell code to be included and added to the scope of
613 the currently running build script.
615 .PARAMETER fileNamePathToInclude
616 A string containing the path and name of the powershell file to include
620 A sample build script is shown below:
622 Include ".\build_utils.ps1"
624 Task default -depends Test
626 Task Test -depends Compile, Clean {
629 Task Compile -depends Clean {
646 You can have more than 1 "Include" function defined in the script
649 SupportsShouldProcess=$False,
650 SupportsTransactions=$False,
651 ConfirmImpact="None",
652 DefaultParameterSetName="")]
654 [Parameter(Position=0,Mandatory=1)]
655 [string]$fileNamePathToInclude
657 Assert (test-path $fileNamePathToInclude) "Error: Unable to include $fileNamePathToInclude. File not found."
658 $script:context.Peek().includes.Enqueue((Resolve-Path $fileNamePathToInclude));
661 function FormatTaskName
665 Allows you to define a format mask that will be used when psake displays
669 Allows you to define a format mask that will be used when psake displays
670 the task name. The default is "Executing task, {0}..."
673 A string containing the format mask to use, it should contain a placeholder ({0})
674 that will be used to substitute the task name.
678 A sample build script is shown below:
680 FormatTaskName "[Task: {0}]"
682 Task default -depends Test
684 Task Test -depends Compile, Clean {
687 Task Compile -depends Clean {
693 You should get the following output:
694 ------------------------------------
702 ----------------------------------------------------------------------
704 ----------------------------------------------------------------------
707 Clean 00:00:00.0043477
708 Compile 00:00:00.0102130
709 Test 00:00:00.0182858
710 Total: 00:00:00.0698071
722 SupportsShouldProcess=$False,
723 SupportsTransactions=$False,
724 ConfirmImpact="None",
725 DefaultParameterSetName="")]
727 [Parameter(Position=0,Mandatory=1)]
730 $script:context.Peek().formatTaskNameString = $format
737 Adds a scriptblock that will be executed before each task
740 This function will accept a scriptblock that will be executed before each
741 task in the build script.
744 A scriptblock to execute
748 A sample build script is shown below:
750 Task default -depends Test
752 Task Test -depends Compile, Clean {
755 Task Compile -depends Clean {
762 "Running 'TaskSetup' for task $script:context.Peek().currentTaskName"
765 You should get the following output:
766 ------------------------------------
768 Running 'TaskSetup' for task Clean
769 Executing task, Clean...
770 Running 'TaskSetup' for task Compile
771 Executing task, Compile...
772 Running 'TaskSetup' for task Test
773 Executing task, Test...
777 ----------------------------------------------------------------------
779 ----------------------------------------------------------------------
782 Clean 00:00:00.0054018
783 Compile 00:00:00.0123085
784 Test 00:00:00.0236915
785 Total: 00:00:00.0739437
797 SupportsShouldProcess=$False,
798 SupportsTransactions=$False,
799 ConfirmImpact="None",
800 DefaultParameterSetName="")]
802 [Parameter(Position=0,Mandatory=1)]
805 $script:context.Peek().taskSetupScriptBlock = $setup
808 function TaskTearDown
812 Adds a scriptblock that will be executed after each task
815 This function will accept a scriptblock that will be executed after each
816 task in the build script.
819 A scriptblock to execute
823 A sample build script is shown below:
825 Task default -depends Test
827 Task Test -depends Compile, Clean {
830 Task Compile -depends Clean {
837 "Running 'TaskTearDown' for task $script:context.Peek().currentTaskName"
840 You should get the following output:
841 ------------------------------------
843 Executing task, Clean...
844 Running 'TaskTearDown' for task Clean
845 Executing task, Compile...
846 Running 'TaskTearDown' for task Compile
847 Executing task, Test...
848 Running 'TaskTearDown' for task Test
852 ----------------------------------------------------------------------
854 ----------------------------------------------------------------------
857 Clean 00:00:00.0064555
858 Compile 00:00:00.0218902
859 Test 00:00:00.0309151
860 Total: 00:00:00.0858301
872 SupportsShouldProcess=$False,
873 SupportsTransactions=$False,
874 ConfirmImpact="None",
875 DefaultParameterSetName="")]
877 [Parameter(Position=0,Mandatory=1)]
878 [scriptblock]$teardown)
879 $script:context.Peek().taskTearDownScriptBlock = $teardown
882 function Invoke-psake
886 Runs a psake build script.
889 This function runs a psake build script
892 The psake build script to execute (default: default.ps1).
895 A comma-separated list of task names to execute
898 The version of the .NET framework you want to build. You can append x86 or x64 to force a specific framework. If not specified, x86 or x64 will be detected based on the bitness of the PowerShell process.
899 Possible values: '1.0', '1.1', '2.0', '2.0x86', '2.0x64', '3.0', '3.0x86', '3.0x64', '3.5', '3.5x86', '3.5x64', '4.0', '4.0x86', '4.0x64'
903 Prints a list of tasks and their descriptions
905 .PARAMETER Parameters
906 A hashtable containing parameters to be passed into the current build script. These parameters will be processed before the 'Properties' function of the script is processed. This means you can access parameters from within the 'Properties' function!
908 .PARAMETER Properties
909 A hashtable containing properties to be passed into the current build script. These properties will override matching properties that are found in the 'Properties' function of the script.
914 Runs the 'default' task in the 'default.ps1' build script in the current directory
917 Invoke-psake '.\build.ps1'
919 Runs the 'default' task in the '.build.ps1' build script
922 Invoke-psake '.\build.ps1' Tests,Package
924 Runs the 'Tests' and 'Package' tasks in the '.build.ps1' build script
929 If you have your Tasks in the .\default.ps1. This example will run the 'Tests' tasks in the 'default.ps1' build script.
932 Invoke-psake 'Tests, Package'
934 If you have your Tasks in the .\default.ps1. This example will run the 'Tests' and 'Package' tasks in the 'default.ps1' build script.
935 NOTE: the quotes around the list of tasks to execute.
938 Invoke-psake '.\build.ps1' -docs
940 Prints a report of all the tasks and their descriptions and exits
943 Invoke-psake .\parameters.ps1 -parameters @{"p1"="v1";"p2"="v2"}
945 Runs the build script called 'parameters.ps1' and passes in parameters 'p1' and 'p2' with values 'v1' and 'v2'
948 Invoke-psake .\properties.ps1 -properties @{"x"="1";"y"="2"}
950 Runs the build script called 'properties.ps1' and passes in parameters 'x' and 'y' with values '1' and '2'
953 If there is an exception and '$psake.use_exit_on_error' -eq $true
954 then runs exit(1) to set the DOS lastexitcode variable
955 otherwise set the '$psake.build_success variable' to $true or $false depending
956 on whether an exception was thrown
959 When the psake module is loaded a variabled called $psake is created it is a hashtable
960 containing some variables that can be used to configure psake:
962 $psake.use_exit_on_error = $false # determines if psake uses the "exit()" function when an exception occurs
963 $psake.log_error = $false # determines if the exception details are written to a file
964 $psake.build_success = $false # indicates that the current build was successful
965 $psake.version = "4.00" # contains the current version of psake
966 $psake.build_script_file = $null # contains a System.IO.FileInfo for the current build file
967 $psake.framework_version = "" # contains the framework version # for the current build
969 $psake.use_exit_on_error and $psake.log_error are boolean variables that can be set before you call Invoke-Psake.
971 You should see the following when you display the contents of the $psake variable right after importing psake
973 PS projects:\psake> Import-Module .\psake.psm1
974 PS projects:\psake> $psake
980 use_exit_on_error False
985 After a build is executed the following $psake values are updated (build_script_file, build_success, and framework_version)
987 PS projects:\psake> Invoke-psake .\examples\default.ps1
988 Executing task: Clean
990 Executing task: Compile
997 ----------------------------------------------------------------------
999 ----------------------------------------------------------------------
1002 Clean 00:00:00.0798486
1003 Compile 00:00:00.0869948
1004 Test 00:00:00.0958225
1005 Total: 00:00:00.2712414
1007 PS projects:\psake> $psake
1012 build_script_file C:\Users\Jorge\Documents\Projects\psake\examples\default.ps1
1013 use_exit_on_error False
1016 framework_version 3.5
1028 SupportsShouldProcess=$False,
1029 SupportsTransactions=$False,
1030 ConfirmImpact="None",
1031 DefaultParameterSetName="")]
1034 [Parameter(Position=0,Mandatory=0)]
1035 [string]$buildFile = $script:psake.default_build_file_name,
1036 [Parameter(Position=1,Mandatory=0)]
1037 [string[]]$taskList = @(),
1038 [Parameter(Position=2,Mandatory=0)]
1039 [string]$framework = '3.5',
1040 [Parameter(Position=3,Mandatory=0)]
1041 [switch]$docs = $false,
1042 [Parameter(Position=4,Mandatory=0)]
1043 [System.Collections.Hashtable]$parameters = @{},
1044 [Parameter(Position=5, Mandatory=0)]
1045 [System.Collections.Hashtable]$properties = @{}
1050 $script:psake.build_success = $false
1051 $script:psake.framework_version = $framework
1053 if ($script:context -eq $null)
1055 $script:context = New-Object System.Collections.Stack
1058 $script:context.push(@{
1059 "formatTaskNameString" = "Executing task: {0}";
1060 "taskSetupScriptBlock" = $null;
1061 "taskTearDownScriptBlock" = $null;
1062 "executedTasks" = New-Object System.Collections.Stack;
1063 "callStack" = New-Object System.Collections.Stack;
1064 "originalEnvPath" = $env:path;
1065 "originalDirectory" = Get-Location;
1066 "originalErrorActionPreference" = $global:ErrorActionPreference;
1069 "includes" = New-Object System.Collections.Queue;
1077 $stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
1080 If the default.ps1 file exists and the given "buildfile" isn't found assume that the given
1081 $buildFile is actually the target Tasks to execute in the default.ps1 script.
1083 if((Test-Path $script:psake.default_build_file_name ) -and !(test-path $buildFile)) {
1084 $list = New-Object System.Collections.ArrayList
1085 foreach($t in $buildFile.Split(',')) {
1087 if($t1 -ne $null -or $t1 -ne "") {
1091 $taskList = $list.ToArray()
1092 $buildFile = $script:psake.default_build_file_name
1095 # Execute the build file to set up the tasks and defaults
1096 Assert (test-path $buildFile) "Error: Could not find the build file, $buildFile."
1098 $script:psake.build_script_file = dir $buildFile
1099 set-location $script:psake.build_script_file.Directory
1100 . $script:psake.build_script_file.FullName
1109 Configure-BuildEnvironment
1111 # N.B. The initial dot (.) indicates that variables initialized/modified
1112 # in the propertyBlock are available in the parent scope.
1113 while ($script:context.Peek().includes.Count -gt 0)
1115 $includeBlock = $script:context.Peek().includes.Dequeue()
1119 foreach($key in $parameters.keys)
1121 if (test-path "variable:\$key")
1123 set-item -path "variable:\$key" -value $parameters.$key | out-null
1127 new-item -path "variable:\$key" -value $parameters.$key | out-null
1131 foreach($propertyBlock in $script:context.Peek().properties)
1136 foreach($key in $properties.keys)
1138 if (test-path "variable:\$key")
1140 set-item -path "variable:\$key" -value $properties.$key | out-null
1144 # Execute the list of tasks or the default task
1145 if($taskList.Length -ne 0)
1147 foreach($task in $taskList)
1152 elseif ($script:context.Peek().tasks.default -ne $null)
1158 throw 'Error: default task required'
1163 "`nBuild Succeeded!`n"
1165 Write-TaskTimeSummary
1167 $script:psake.build_success = $true
1171 #Append detailed exception and script variables to error log file
1172 if ($script:psake.log_error)
1174 $errorLogFile = "psake-error-log-{0}.log" -f ([DateTime]::Now.ToString("yyyyMMdd"))
1175 "-" * 70 >> $errorLogFile
1176 "{0}: An Error Occurred. See Error Details Below: " -f [DateTime]::Now >>$errorLogFile
1177 "-" * 70 >> $errorLogFile
1178 Resolve-Error $_ >> $errorLogFile
1179 "-" * 70 >> $errorLogFile
1180 "Script Variables" >> $errorLogFile
1181 "-" * 70 >> $errorLogFile
1182 Get-Variable -scope script >> $errorLogFile
1185 $buildFileName = Split-Path $buildFile -leaf
1186 if (test-path $buildFile) { $buildFileName = $script:psake.build_script_file.Name }
1187 Write-Host -foregroundcolor Red ($buildFileName + ":" + $_)
1189 if ($script:psake.use_exit_on_error)
1195 $script:psake.build_success = $false
1202 # Clear out any global variables
1204 [void]$script:context.Pop()
1208 Export-ModuleMember -Function "Invoke-psake","Task","Properties","Include","FormatTaskName","TaskSetup","TaskTearDown","Assert","Exec"