Difference between revisions of "Windows PowerShell"

From HalfgeekKB
Jump to navigation Jump to search
 
(One intermediate revision by the same user not shown)
Line 1: Line 1:
==PowerShell prebuild and postbuild scripts for Visual Studio projects==
+
==PowerShell prebuild and postbuild script for Visual Studio projects==
  
 
Tested with VS2015.
 
Tested with VS2015.
Line 5: Line 5:
 
===How===
 
===How===
  
* Prepare (the macro list and) the ps1 boilerplate and event command line as directed below.
+
* Add a new file <code>buildevents.ps1</code> at the top level of the project.
** Alternatively, try (at your own risk) the examples already prepared from my own configuration.
+
* Copy the text below into the new file and save.
* Create <code>prebuild.ps1</code> and <code>postbuild.ps1</code> in the top level of the project and paste the ps1 boilerplate into each.
+
* In the project properties, change the Pre-build and Post-build commands to the commands suggested at the comments at the top of the file.
* Go to the ''Properties'' of the project and open the ''Build Events'' tab.
+
* Modify the script in the "TODO"-marked areas to add pre-build commands, post-build commands, and commands common to all runs.
** Click ''Edit Pre-build…'' and paste the pre-build event command line into the field. Replace <code>pxxbuild</code> with <code>prebuild</code>. Confirm.
+
 
** Click ''Edit Post-build…'' and paste the post-build event command line into the field. Replace <code>pxxbuild</code> with <code>postbuild</code>. Confirm.
+
====buildevents.ps1====
 +
 
 +
<syntaxhighlight lang=powershell>
 +
# For Prebuild command, use:
 +
#  powershell -ExecutionPolicy ByPass "&'$(ProjectDir)buildevents.ps1'" -Function Prebuild -ConfigurationName '$(ConfigurationName)' -OutDir '$(OutDir)' -DevEnvDir '$(DevEnvDir)' -PlatformName '$(PlatformName)' -ProjectDir '$(ProjectDir)' -ProjectPath '$(ProjectPath)' -ProjectName '$(ProjectName)' -ProjectFileName '$(ProjectFileName)' -ProjectExt '$(ProjectExt)' -SolutionDir '$(SolutionDir)' -SolutionPath '$(SolutionPath)' -SolutionName '$(SolutionName)' -SolutionFileName '$(SolutionFileName)' -SolutionExt '$(SolutionExt)' -TargetDir '$(TargetDir)' -TargetPath '$(TargetPath)' -TargetName '$(TargetName)' -TargetFileName '$(TargetFileName)' -TargetExt '$(TargetExt)'
 +
 
 +
# For Postbuild command, use:
 +
#  powershell -ExecutionPolicy ByPass "&'$(ProjectDir)buildevents.ps1'" -Function Postbuild -ConfigurationName '$(ConfigurationName)' -OutDir '$(OutDir)' -DevEnvDir '$(DevEnvDir)' -PlatformName '$(PlatformName)' -ProjectDir '$(ProjectDir)' -ProjectPath '$(ProjectPath)' -ProjectName '$(ProjectName)' -ProjectFileName '$(ProjectFileName)' -ProjectExt '$(ProjectExt)' -SolutionDir '$(SolutionDir)' -SolutionPath '$(SolutionPath)' -SolutionName '$(SolutionName)' -SolutionFileName '$(SolutionFileName)' -SolutionExt '$(SolutionExt)' -TargetDir '$(TargetDir)' -TargetPath '$(TargetPath)' -TargetName '$(TargetName)' -TargetFileName '$(TargetFileName)' -TargetExt '$(TargetExt)'
 +
 
 +
param (
 +
    [string]$ConfigurationName, # The name of the current project configuration, for example, "Debug".
 +
    [string]$OutDir, # Path to the output file directory, relative to the project directory. This resolves to the value for the Output Directory property. It includes the trailing backslash '\'.
 +
    [string]$DevEnvDir, # The installation directory of Visual Studio (defined with drive and path); includes the trailing backslash '\'.
 +
    [string]$PlatformName, # The name of the currently targeted platform. For example, "AnyCPU".
 +
    [string]$ProjectDir, # The directory of the project (defined with drive and path); includes the trailing backslash '\'.
 +
    [string]$ProjectPath, # The absolute path name of the project (defined with drive, path, base name, and file extension).
 +
    [string]$ProjectName, # The base name of the project.
 +
    [string]$ProjectFileName, # The file name of the project (defined with base name and file extension).
 +
    [string]$ProjectExt, # The file extension of the project. It includes the '.' before the file extension.
 +
    [string]$SolutionDir, # The directory of the solution (defined with drive and path); includes the trailing backslash '\'.
 +
    [string]$SolutionPath, # The absolute path name of the solution (defined with drive, path, base name, and file extension).
 +
    [string]$SolutionName, # The base name of the solution.
 +
    [string]$SolutionFileName, # The file name of the solution (defined with base name and file extension).
 +
    [string]$SolutionExt, # The file extension of the solution. It includes the '.' before the file extension.
 +
    [string]$TargetDir, # The directory of the primary output file for the build (defined with drive and path). It includes the trailing backslash '\'.
 +
    [string]$TargetPath, # The absolute path name of the primary output file for the build (defined with drive, path, base name, and file extension).
 +
    [string]$TargetName, # The base name of the primary output file for the build.
 +
    [string]$TargetFileName, # The file name of the primary output file for the build (defined as base name and file extension).
 +
    [string]$TargetExt, # The file extension of the primary output file for the build. It includes the '.' before the file extension.
 +
 
 +
    [string]$Function # Name of the function to run
 +
)
 +
 
 +
# TODO Add common code here
 +
 
 +
function Prebuild ()
 +
{
 +
    # TODO Add code here
 +
}
 +
 
 +
function Postbuild ()
 +
{
 +
    # TODO Add code here
 +
}
 +
 
 +
# ------------------------------
 +
# AVOID EDITING BELOW THIS POINT
 +
# ------------------------------
 +
 
 +
function Run-BuildEventFunction($buildEventFunctionName)
 +
{
 +
    echo "--- Build event '$buildEventFunctionName' started ---"
 +
    Try
 +
    {
 +
        & $buildEventFunctionName
 +
        echo "--- Build event '$buildEventFunctionName' completed normally ---"
 +
    }
 +
    Catch
 +
    {
 +
        echo "--- Build event '$buildEventFunctionName' failed with exception ---"
 +
        throw
 +
    }
 +
}
 +
 
 +
# Call the event indicated by $Function
 +
Run-BuildEventFunction $Function
 +
</syntaxhighlight>
 +
 
 +
====Advanced: The script to generate buildevents.ps1====
 +
 
 +
<syntaxhighlight lang=powershell>
 +
 
 +
$scriptNameInProjectDir = "buildevents.ps1"
 +
 
 +
# This table is from https://msdn.microsoft.com/en-us/library/42x5kfw4%28v=vs.140%29.aspx
 +
# Copy table and paste into Excel, then copy from Excel into text editor.
 +
# (Copying straight from browser into the text editor doesn't give the tab-separated values needed here.)
 +
 
 +
$macroList = @'
 +
 
 +
$(ConfigurationName) The name of the current project configuration, for example, "Debug".
 +
$(OutDir) Path to the output file directory, relative to the project directory. This resolves to the value for the Output Directory property. It includes the trailing backslash '\'.
 +
$(DevEnvDir) The installation directory of Visual Studio (defined with drive and path); includes the trailing backslash '\'.
 +
$(PlatformName) The name of the currently targeted platform. For example, "AnyCPU".
 +
$(ProjectDir) The directory of the project (defined with drive and path); includes the trailing backslash '\'.
 +
$(ProjectPath) The absolute path name of the project (defined with drive, path, base name, and file extension).
 +
$(ProjectName) The base name of the project.
 +
$(ProjectFileName) The file name of the project (defined with base name and file extension).
 +
$(ProjectExt) The file extension of the project. It includes the '.' before the file extension.
 +
$(SolutionDir) The directory of the solution (defined with drive and path); includes the trailing backslash '\'.
 +
$(SolutionPath) The absolute path name of the solution (defined with drive, path, base name, and file extension).
 +
$(SolutionName) The base name of the solution.
 +
$(SolutionFileName) The file name of the solution (defined with base name and file extension).
 +
$(SolutionExt) The file extension of the solution. It includes the '.' before the file extension.
 +
$(TargetDir) The directory of the primary output file for the build (defined with drive and path). It includes the trailing backslash '\'.
 +
$(TargetPath) The absolute path name of the primary output file for the build (defined with drive, path, base name, and file extension).
 +
$(TargetName) The base name of the primary output file for the build.
 +
$(TargetFileName) The file name of the primary output file for the build (defined as base name and file extension).
 +
$(TargetExt) The file extension of the primary output file for the build. It includes the '.' before the file extension.
 +
'@
  
Finally, add scripting after the boilerplate in <code>prebuild.ps1</code> and <code>postbuild.ps1</code> as necessary. This saves some serious acrobatics later on when some actual processing has to happen in the event.
 
  
===Prepare the macro list===
 
  
* Go to the ''Properties'' of the project and open the ''Build Events'' tab.
 
* Click ''Edit Pre-build…'' (which opens the pre-build event command line for editing).
 
* In a text editor (or spreadsheet), create a list of all of the names seen in the ''Macro'' column of the macro list in the dialog.
 
  
There appears to be no way to directly copy this table. For your sanity, I've included the list from my setup below.
+
function Get-BuildEventCommand ($buildEventFunctionName, $macroData)
 +
{
 +
    $commandStart = "powershell -ExecutionPolicy ByPass `"`&'`$(ProjectDir)$scriptNameInProjectDir'`""
 +
    $macroNames = $macroData | foreach-object { $_.Name }
 +
    $macrosAsArgs = $macroNames | foreach-object { "-$_ '`$($_)'" }
 +
    #$commandMacroArgs = [string]::Join(" ", $macrosAsArgs)
 +
    echo "$commandStart -Function $buildEventFunctionName $macrosAsArgs"
 +
}
  
===Prepare the ps1 boilerplate===
+
function Get-BuildEventCommandComment ($buildEventFunctionName, $macroData)
 +
{
 +
    echo "# For $buildEventFunctionName command, use:"
 +
    echo "#  $(Get-BuildEventCommand $buildEventFunctionName $macroData)"
 +
    echo ""
 +
}
  
The ps1 boilerplate is a <code>param</code> list that makes it possible to pass all macros to the script by name and enable the rest of the file to refer to the macro values as variables.
+
function Get-ParamList ($macroData)
 +
{
 +
    echo "param ("
 +
    foreach($macro in $macroData) {
 +
        echo "    [string]`$$($macro.Name), # $($macro.Description)"
 +
    }
 +
    echo ""
 +
    echo "    [string]`$Function # Name of the function to run"
 +
    echo ")"
 +
    echo ""
 +
}
  
Convert a copy of the macro name list into a ps1 boilerplate script by making the following changes:
+
function Get-FunctionTemplate ($buildEventFunctionName)
 +
{
 +
    echo "function $buildEventFunctionName ()"
 +
    echo "{"
 +
    echo "    # TODO Add code here"
 +
    echo "}"
 +
    echo ""
 +
}
  
* Prefix each line with <code>[string]$</code> and suffix each line <em>except the last</em> with <code>,</code>.
+
function Parse-MacroLine ($line)
** Using a spreadsheet: Create a blank spreadsheet. Paste the macro names in column A. In B1, enter the formula <code><nowiki>="[string]$" & A1 & ","</nowiki></code>, then fill down to the rest of column B. Select the generated column B values, copy, and paste them into a plain text editor. Manually delete the comma at the end of the last line.
+
{
** Using vim: Enter the command <code>:%s/\v(.*)/[string]$\1,/g</code>, then delete the comma at the end of the last line.
+
    $line = "$line"
* Enter the line <code>param (</code> above the list.
+
    if ($line -match "^\$\((.+?)\)\t(.*?)$") {
* Enter the line <code>)</code> below the list.
+
        $result = @{
* Indent as desired.
+
            Name = "$($matches[1])"
 +
            Description = "$($matches[2])"
 +
        }
 +
        $result
 +
    }
 +
    else {
 +
        $null
 +
    }
 +
}
  
===Prepare the event command line===
 
  
The event command line is the command called by Visual Studio for the pre- and post-build commands. This generated command line in particular passes the values of all of the macros as named parameters.
 
  
Convert a copy of the macro name list into the event command line by making the following changes:
+
$macroLines = $([Regex]::Split($macroList,"\r\n|\r|\n")) | where { $_ -ne $null -and $_.Trim() -ne "" }
  
* Replace each line <code><var>NAME</var></code> with <code>-<var>NAME</var> $(&#39;<var>NAME</var>&#39;)</code>.
+
$macroData = $macroLines | foreach-object { Parse-MacroLine $_ } | where { $_ -ne $null }
** Using a spreadsheet: Create a blank spreadsheet. Paste the macro names in column A. In B1, enter the formula <code><nowiki>="-" & A1 & " $('" & A1 & "')"</nowiki></code>, then fill down to the rest of column B. Select the generated column B values, copy, and paste them into a plain text editor.
 
** Using vim: Enter the command <code><nowiki>:%s/\v(.*)/-\1 $('\1')/g</nowiki></code>.
 
* Enter the line <code>powershell -ExecutionPolicy ByPass "&'$(ProjectDir)pxxbuild.ps1'"</code> above the list.
 
* Replace all newlines with a single space.
 
** Using a spreadsheet and Notepad: Create a blank spreadsheet. Paste the lines into column A (if the lines were copied from another spreadsheet, use Paste Values Only to avoid copying formulas). Re-copy the lines from A, then paste the transpose (usually under Paste Special) at B1. Select the cells that have been populated (B1, C1, etc.) and copy into Notepad. In the text that has just been pasted, select a tab character and copy it. Using the ''Replace…'' function, paste the tab character into ''Find what:'' and type a space in ''Replace with:''. Run ''Replace All''.
 
** Using Windows-native gvim: Enter the command <code>:%s/\n/ /g</code>
 
** Using Visual Studio text editor: Create a new text file in Visual Studio. (This is temporary and should not be associated with the project or solution.) Paste the lines. Open Quick Replace for the current document. Use <code>\r\n</code> for the search term and <code> </code> for the replacement term, and make sure ''Use Regular Expressions'' is selected. Replace all instances.
 
  
===For my configuration===
+
$buildEventFunctionNames = "Prebuild", "Postbuild"
  
====Macro list====
+
foreach($buildEventFunctionName in $buildEventFunctionNames) {
 +
    Get-BuildEventCommandComment $buildEventFunctionName $macroData
 +
}
  
<nowiki>
+
Get-ParamList $macroData
ConfigurationName
 
DevEnvDir
 
OutDir
 
PlatformName
 
ProjectDir
 
ProjectExt
 
ProjectFileName
 
ProjectName
 
ProjectPath
 
SolutionDir
 
SolutionExt
 
SolutionFileName
 
SolutionName
 
SolutionPath
 
TargetDir
 
TargetExt
 
TargetFileName
 
TargetName</nowiki>
 
  
====Event command line====
+
echo "# TODO Add common code here"
 +
echo ""
  
Substitute <code>pre</code> or <code>post</code> for <code>pxx</code>.
+
foreach($buildEventFunctionName in $buildEventFunctionNames) {
 +
    Get-FunctionTemplate $buildEventFunctionName
 +
}
  
  powershell -ExecutionPolicy ByPass "&'$(ProjectDir)pxxbuild.ps1'" -ConfigurationName '$(ConfigurationName)'  -DevEnvDir '$(DevEnvDir)'  -OutDir '$(OutDir)'  -PlatformName '$(PlatformName)'  -ProjectDir '$(ProjectDir)'  -ProjectExt '$(ProjectExt)'  -ProjectFileName '$(ProjectFileName)'  -ProjectName '$(ProjectName)'  -ProjectPath '$(ProjectPath)'  -SolutionDir '$(SolutionDir)'  -SolutionExt '$(SolutionExt)'  -SolutionFileName '$(SolutionFileName)'  -SolutionName '$(SolutionName)'  -SolutionPath '$(SolutionPath)'  -TargetDir '$(TargetDir)'  -TargetExt '$(TargetExt)'  -TargetFileName '$(TargetFileName)'  -TargetName '$(TargetName)'
+
echo @'
 +
# ------------------------------
 +
# AVOID EDITING BELOW THIS POINT
 +
# ------------------------------
  
====ps1 Boilerplate====
+
function Run-BuildEventFunction($buildEventFunctionName)
 +
{
 +
    echo "--- Build event '$buildEventFunctionName' started ---"
 +
    Try
 +
    {
 +
        & $buildEventFunctionName
 +
        echo "--- Build event '$buildEventFunctionName' completed normally ---"
 +
    }
 +
    Catch
 +
    {
 +
        echo "--- Build event '$buildEventFunctionName' failed with exception ---"
 +
        throw
 +
    }
 +
}
  
<syntaxhighlight lang=powershell>
+
# Call the event indicated by $Function
param (
+
Run-BuildEventFunction $Function
[string]$ConfigurationName,
+
'@
[string]$DevEnvDir,
 
[string]$OutDir,
 
[string]$PlatformName,
 
[string]$ProjectDir,
 
[string]$ProjectExt,
 
[string]$ProjectFileName,
 
[string]$ProjectName,
 
[string]$ProjectPath,
 
[string]$SolutionDir,
 
[string]$SolutionExt,
 
[string]$SolutionFileName,
 
[string]$SolutionName,
 
[string]$SolutionPath,
 
[string]$TargetDir,
 
[string]$TargetExt,
 
[string]$TargetFileName,
 
[string]$TargetName
 
)
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  

Latest revision as of 13:09, 11 February 2016

PowerShell prebuild and postbuild script for Visual Studio projects

Tested with VS2015.

How

  • Add a new file buildevents.ps1 at the top level of the project.
  • Copy the text below into the new file and save.
  • In the project properties, change the Pre-build and Post-build commands to the commands suggested at the comments at the top of the file.
  • Modify the script in the "TODO"-marked areas to add pre-build commands, post-build commands, and commands common to all runs.

buildevents.ps1

# For Prebuild command, use:
#   powershell -ExecutionPolicy ByPass "&'$(ProjectDir)buildevents.ps1'" -Function Prebuild -ConfigurationName '$(ConfigurationName)' -OutDir '$(OutDir)' -DevEnvDir '$(DevEnvDir)' -PlatformName '$(PlatformName)' -ProjectDir '$(ProjectDir)' -ProjectPath '$(ProjectPath)' -ProjectName '$(ProjectName)' -ProjectFileName '$(ProjectFileName)' -ProjectExt '$(ProjectExt)' -SolutionDir '$(SolutionDir)' -SolutionPath '$(SolutionPath)' -SolutionName '$(SolutionName)' -SolutionFileName '$(SolutionFileName)' -SolutionExt '$(SolutionExt)' -TargetDir '$(TargetDir)' -TargetPath '$(TargetPath)' -TargetName '$(TargetName)' -TargetFileName '$(TargetFileName)' -TargetExt '$(TargetExt)'

# For Postbuild command, use:
#   powershell -ExecutionPolicy ByPass "&'$(ProjectDir)buildevents.ps1'" -Function Postbuild -ConfigurationName '$(ConfigurationName)' -OutDir '$(OutDir)' -DevEnvDir '$(DevEnvDir)' -PlatformName '$(PlatformName)' -ProjectDir '$(ProjectDir)' -ProjectPath '$(ProjectPath)' -ProjectName '$(ProjectName)' -ProjectFileName '$(ProjectFileName)' -ProjectExt '$(ProjectExt)' -SolutionDir '$(SolutionDir)' -SolutionPath '$(SolutionPath)' -SolutionName '$(SolutionName)' -SolutionFileName '$(SolutionFileName)' -SolutionExt '$(SolutionExt)' -TargetDir '$(TargetDir)' -TargetPath '$(TargetPath)' -TargetName '$(TargetName)' -TargetFileName '$(TargetFileName)' -TargetExt '$(TargetExt)'

param (
    [string]$ConfigurationName, # The name of the current project configuration, for example, "Debug".
    [string]$OutDir, # Path to the output file directory, relative to the project directory. This resolves to the value for the Output Directory property. It includes the trailing backslash '\'.
    [string]$DevEnvDir, # The installation directory of Visual Studio (defined with drive and path); includes the trailing backslash '\'.
    [string]$PlatformName, # The name of the currently targeted platform. For example, "AnyCPU".
    [string]$ProjectDir, # The directory of the project (defined with drive and path); includes the trailing backslash '\'.
    [string]$ProjectPath, # The absolute path name of the project (defined with drive, path, base name, and file extension).
    [string]$ProjectName, # The base name of the project.
    [string]$ProjectFileName, # The file name of the project (defined with base name and file extension).
    [string]$ProjectExt, # The file extension of the project. It includes the '.' before the file extension.
    [string]$SolutionDir, # The directory of the solution (defined with drive and path); includes the trailing backslash '\'.
    [string]$SolutionPath, # The absolute path name of the solution (defined with drive, path, base name, and file extension).
    [string]$SolutionName, # The base name of the solution.
    [string]$SolutionFileName, # The file name of the solution (defined with base name and file extension).
    [string]$SolutionExt, # The file extension of the solution. It includes the '.' before the file extension.
    [string]$TargetDir, # The directory of the primary output file for the build (defined with drive and path). It includes the trailing backslash '\'.
    [string]$TargetPath, # The absolute path name of the primary output file for the build (defined with drive, path, base name, and file extension).
    [string]$TargetName, # The base name of the primary output file for the build.
    [string]$TargetFileName, # The file name of the primary output file for the build (defined as base name and file extension).
    [string]$TargetExt, # The file extension of the primary output file for the build. It includes the '.' before the file extension.

    [string]$Function # Name of the function to run
)

# TODO Add common code here

function Prebuild ()
{
    # TODO Add code here
}

function Postbuild ()
{
    # TODO Add code here
}

# ------------------------------
# AVOID EDITING BELOW THIS POINT
# ------------------------------

function Run-BuildEventFunction($buildEventFunctionName)
{
    echo "--- Build event '$buildEventFunctionName' started ---"
    Try
    {
        & $buildEventFunctionName
        echo "--- Build event '$buildEventFunctionName' completed normally ---"
    }
    Catch
    {
        echo "--- Build event '$buildEventFunctionName' failed with exception ---"
        throw
    }
}

# Call the event indicated by $Function
Run-BuildEventFunction $Function

Advanced: The script to generate buildevents.ps1

$scriptNameInProjectDir = "buildevents.ps1"

# This table is from https://msdn.microsoft.com/en-us/library/42x5kfw4%28v=vs.140%29.aspx
# Copy table and paste into Excel, then copy from Excel into text editor.
# (Copying straight from browser into the text editor doesn't give the tab-separated values needed here.)

$macroList = @'

$(ConfigurationName)	The name of the current project configuration, for example, "Debug".
$(OutDir)	Path to the output file directory, relative to the project directory. This resolves to the value for the Output Directory property. It includes the trailing backslash '\'.
$(DevEnvDir)	The installation directory of Visual Studio (defined with drive and path); includes the trailing backslash '\'.
$(PlatformName)	The name of the currently targeted platform. For example, "AnyCPU".
$(ProjectDir)	The directory of the project (defined with drive and path); includes the trailing backslash '\'.
$(ProjectPath)	The absolute path name of the project (defined with drive, path, base name, and file extension).
$(ProjectName)	The base name of the project.
$(ProjectFileName)	The file name of the project (defined with base name and file extension).
$(ProjectExt)	The file extension of the project. It includes the '.' before the file extension.
$(SolutionDir)	The directory of the solution (defined with drive and path); includes the trailing backslash '\'.
$(SolutionPath)	The absolute path name of the solution (defined with drive, path, base name, and file extension).
$(SolutionName)	The base name of the solution.
$(SolutionFileName)	The file name of the solution (defined with base name and file extension).
$(SolutionExt)	The file extension of the solution. It includes the '.' before the file extension.
$(TargetDir)	The directory of the primary output file for the build (defined with drive and path). It includes the trailing backslash '\'.
$(TargetPath)	The absolute path name of the primary output file for the build (defined with drive, path, base name, and file extension).
$(TargetName)	The base name of the primary output file for the build.
$(TargetFileName)	The file name of the primary output file for the build (defined as base name and file extension).
$(TargetExt)	The file extension of the primary output file for the build. It includes the '.' before the file extension.
'@




function Get-BuildEventCommand ($buildEventFunctionName, $macroData)
{
    $commandStart = "powershell -ExecutionPolicy ByPass `"`&'`$(ProjectDir)$scriptNameInProjectDir'`""
    $macroNames = $macroData | foreach-object { $_.Name }
    $macrosAsArgs = $macroNames | foreach-object { "-$_ '`$($_)'" }
    #$commandMacroArgs = [string]::Join(" ", $macrosAsArgs)
    echo "$commandStart -Function $buildEventFunctionName $macrosAsArgs"
}

function Get-BuildEventCommandComment ($buildEventFunctionName, $macroData)
{
    echo "# For $buildEventFunctionName command, use:"
    echo "#   $(Get-BuildEventCommand $buildEventFunctionName $macroData)"
    echo ""
}

function Get-ParamList ($macroData)
{
    echo "param ("
    foreach($macro in $macroData) {
        echo "    [string]`$$($macro.Name), # $($macro.Description)"
    }
    echo ""
    echo "    [string]`$Function # Name of the function to run"
    echo ")"
    echo ""
}

function Get-FunctionTemplate ($buildEventFunctionName)
{
    echo "function $buildEventFunctionName ()"
    echo "{"
    echo "    # TODO Add code here"
    echo "}"
    echo ""
}

function Parse-MacroLine ($line)
{
    $line = "$line"
    if ($line -match "^\$\((.+?)\)\t(.*?)$") {
        $result = @{
            Name = "$($matches[1])"
            Description = "$($matches[2])"
        }
        $result
    }
    else {
        $null
    }
}



$macroLines = $([Regex]::Split($macroList,"\r\n|\r|\n")) | where { $_ -ne $null -and $_.Trim() -ne "" }

$macroData = $macroLines | foreach-object { Parse-MacroLine $_ } | where { $_ -ne $null }

$buildEventFunctionNames = "Prebuild", "Postbuild"

foreach($buildEventFunctionName in $buildEventFunctionNames) {
    Get-BuildEventCommandComment $buildEventFunctionName $macroData
}

Get-ParamList $macroData

echo "# TODO Add common code here"
echo ""

foreach($buildEventFunctionName in $buildEventFunctionNames) {
    Get-FunctionTemplate $buildEventFunctionName
}

echo @'
# ------------------------------
# AVOID EDITING BELOW THIS POINT
# ------------------------------

function Run-BuildEventFunction($buildEventFunctionName)
{
    echo "--- Build event '$buildEventFunctionName' started ---"
    Try
    {
        & $buildEventFunctionName
        echo "--- Build event '$buildEventFunctionName' completed normally ---"
    }
    Catch
    {
        echo "--- Build event '$buildEventFunctionName' failed with exception ---"
        throw
    }
}

# Call the event indicated by $Function
Run-BuildEventFunction $Function
'@

PSModulePath

PowerShell's search path for the Import-Module command is in the PSModulePath env var:

echo $env:PSModulePath

By default on one system it seems to be

  • a user modules dir at My Documents\WindowsPowerShell\Modules
  • a global modules dir at system32\WindowsPowerShell\v1.0\Modules\

PowerShell Community Extensions (pscx)

Get it from http://pscx.codeplex.com/. The directory structure in the ZIP file needs to be such that the path to Pscx.psm1 is

Modules/Pscx/Pscx.psm1

where Modules is one of the directories in $env:PSModulePath.

(end)