Inject command line arguments into psake - powershell

I would like to inject command line parameters into my psake build script like:
.\build.ps1 Deploy environment="development"
But psake will treat every argument as a Task and will answer "task does not exists"
Is it possible to inject command line arguments in psake?
build.ps1 -->
Import-Module '.\psake.psm1'
Invoke-psake '.\tasks.ps1' $args
Remove-Module psake

The latest release of psake now supports passing parameters to Invoke-psake, e.g.
Invoke-psake .\parameters.ps1 -parameters #{"p1"="v1";"p2"="v2"}
This feature has just been added. :)

A global variable will solve my problem for now and with only one reference to $global:arg_environent it will be easy to change if i find a better way to inject the properties.
build.ps1
param(
[Parameter(Position=0,Mandatory=0)]
[string]$task,
[Parameter(Position=1,Mandatory=0)]
[string]$environment = 'dev'
)
clear
$global:arg_environent = $environment
Import-Module .\psake.psm1
Invoke-psake tasks.ps1 $task
Remove-Module psake
tasks.ps1
properties {
$environment = $global:arg_environent
}
task default -depends Deploy
task Deploy {
echo "Copy stuff to $environment"
}

I'm no expert, but I don't think it is possible to pass arguments to Invoke-Psake. Looking on the latest source for Psake the params for the Invoke-Psake function are:
param(
[Parameter(Position=0,Mandatory=0)]
[string]$buildFile = 'default.ps1',
[Parameter(Position=1,Mandatory=0)]
[string[]]$taskList = #(),
[Parameter(Position=2,Mandatory=0)]
[string]$framework = '3.5',
[Parameter(Position=3,Mandatory=0)]
[switch]$docs = $false
)
There are 4 parameters, your build file, a list of tasks, the .NET framework version, whether to output docs of your tasks. I'm new to powershell and psake and I'm trying to do the same thing, I am experimenting with doing something like this in my script to achieve the same thing:
properties {
$environment = "default"
}
task PublishForLive -precondition { $environment = "Live"; return $true; } -depends Publish {
}
task PublishForStaging -precondition { $environment = "Staging"; return $true; } -depends Publish {
}
task Publish {
Write-Host "Building and publishing for $environment environment"
#Publish the project...
}
Then calling psake with PublishForLive or PublishForStaging, whichever I need:
powershell -NoExit -ExecutionPolicy Unrestricted -Command "& {Import-Module .\tools\psake\psake.psm1; Invoke-psake .\psake-common.ps1 PublishForLive }"
But it doesn't seem to work for me! Setting the $environment variable in the task precondition seems to have no effect. Still trying to make this work...

Related

Powershell: Issue while calling a powershell script from another powershell script

I have a powershell script A.ps1 as below:
param([switch] $p1, [switch] $p2)
if ($p1.IsPresent)
{
$p1 = 2
& $B -onboardingId "" -p1 $p1.IsPresent $message = "Deployment In Progress" -connectionString $connectionString
}
elseif ($p2.IsPresent)
{
$p2 = 3
& $B -onboardingId "" -p2 $p2.IsPresent $message = "Deployment In Progress" -connectionString $connectionString
}
The script A.ps1 is calling B.ps1 from itself. Both the scripts are placed in the same path. But I am getting the error below when I try to call script:
The expression after '&' in a pipeline element produced an object that was not valid. It must result in a command name, a script block, or a CommandInfo object.
I tried -ArgumentList but it did not work out for me.
I tried to resolve the issue by referring online but I was not able to resolve it. Can I please get help on this?
Thank you.

Powershell Start-Process with Splatting

I want to call a "PS App Deployment Toolkit"-package (Link) from a PowerShell-Script with arguments.
The mentioned "PS App Deployment Toolkit"-package is a powershell-script, which I want to call with parameters. (Call a .ps1 from a .ps1)
I want to use splatting for the parameters.
I want to wait for the script to end.
I want to get the exit-code from the script.
Here is my code, which is not working:
$PSADToolKitInstallWrapper = "C:\Temp\MyPackage\PS-AppDeploy.ps1"
$PSADToolKitParameters = #{
"DeploymentType" = "Uninstall";
"DeployMode" = "Interactive";
"AllowRebootPassThru" = $True;
"TerminalServerMode" = $False;
"DisableLogging" = $False;
}
$InstallStatus = Start-Process -FilePath "PowerShell.exe" -ArgumentList $PSADToolKitInstallWrapper #PSADToolKitParameters -Wait -PassThru
Write-Host "Exit-Code: $( $InstallStatus.ExitCode )"
This Line would work fine, but I want to set the Parameters like in the example above:
$InstallStatus = Start-Process -FilePath "PowerShell.exe" -ArgumentList "$PSADToolKitInstallWrapper","-DeploymentType Install -DeployMode Silent -AllowRebootPassThru -TerminalServerMode" -Wait -PassThru
Could you please assist me to get this working?
Thank you!
I don't think you need to try so hard. Why run powershell.exe from inside a PowerShell script? You're already running PowerShell. Just run the command line you want:
$PSADToolKitParameters = #{
"DeploymentType" = "Uninstall"
"DeployMode" = "Interactive"
"AllowRebootPassThru" = $True
"TerminalServerMode" = $False
"DisableLogging" = $False
}
C:\Temp\MyPackage\PS-AppDeploy.ps1 #PSADToolKitParameters
If the path and/or filename to the script you want to run contains spaces, then call it with the invocation operator (&) and quote the filename; example:
& "C:\Temp\My Package\PS-AppDeploy.ps1" #PSADToolKitParameters
Checking the results of the script depends on what the script returns. If it returns an output object, then you can simply assign it:
$output = C:\Temp\MyPackage\PS-AppDeploy.ps1 ...
If the script runs an executable that sets an exit code, you check the value of the $LASTEXITCODE variable (this is analogous to the %ERRORLEVEL% dynamic variable in cmd.exe).

Passing arguments to job initialization script

I have multiple jobs and for every job I want to have the same initialization script that sets some things up. I'd like to pass some arguments to the initialization script, but unfortunately the arguments passed using -ArgumentList seem to be only accessible in the actual job script.
Here's an example that demonstrates the argument only being accessible in the actual script:
function StartJob([ScriptBlock] $script, [string] $name, [ScriptBlock] $initialization_script = $null, $argument = $null)
{
Start-Job -ScriptBlock $script -Name $name -InitializationScript $initialization_script -ArgumentList $argument | Out-Null
}
[ScriptBlock] $initialization_script =
{
# The argument given to StartJob should be accessible here
param($test)
echo "Test: $test"
}
[ScriptBlock] $actual_script =
{
param($test)
echo "Test: $test"
}
StartJob $actual_script "Test job" $initialization_script "Have this string in the `$initialization_script"
#(Get-Job).ForEach({
# Wait for the job to finish, remove it and output its results
Write-Host "$($_.Name) results:"
Receive-Job -Job $_ -Wait -AutoRemoveJob | Write-Host
})
How would I be able to be access the arguments passed in the $initialization_script?
AFAIK it's not possible to pass parameters to initialization scripts. Init scripts are designed to be reusable scripblocks to load known resources. If something can't be defined once, then it's unique to that job's scriptblock and doesn't belong in a init. script. You have a few alternatives:
If you have a module (.psm1 and maybe a .psd1), then place it in one of the module-folders (see $env:PSModulePath for paths) so you could simply write Import-Module MyImportantModule in your initialization script.
If you can't use the solution above, I would add a paramter to the actual script and pass in the path as a regular argument.
[ScriptBlock] $actual_script =
{
# The argument given to StartJob should be accessible here
param($test, $ModulePath)
#Import-Module $ModulePath
echo "Test: $test"
}
Start-Job -ScriptBlock $actual_script -Name "Test job" -ArgumentList "First argument", "c:\mymodule.ps1"
Or you could generate the initialization scriptblock in your script so it's dynamic:
$ModulePath = "c:\mymodule.ps1"
$init = #"
#Import-Module "$ModulePath"
#Something-Else
"#
$initsb = [scriptblock]::Create($init)

Cannot import module from Powershell started from Start-Process

I have a powershell script: MyPSScript.ps1:
function DoFoo() {
$Powershell = "C:\windows\System32\WindowsPowerShell\v1.0\Powershell.exe"
$Command = "& C:\Temp\myscript.ps1"
Start-Process $Powershell -ArgumentList ("-noexit", "-noprofile", "-Command", $Command)
}
In myscript.ps1 I have:
Import-Module "C:\Temp\myscript2.ps1"
DoSomething()
In myscript2.ps1 I have:
function DoSomething() {
Write-Output "Hello World"
}
The problem is that myscript.ps1 is correctly executed, but the module is not imported as nothing is printed. Also, since I open the new powershell window using -noexit, I can type in it and if I try to call DoSomething, Powershell complains because it cannot find the command.
The funny thing is that, if I try to type manually the same import directive, then it imports the file corrently...
Are there any issues in importing a module from a Powershell which has been called from another process as I am doing?
Beside the typo I fixed (missing "=") in your question, there are several problems in the script you provided. The first one (MyPSScript.ps1) defines a function DoFoo but never calls it. The second one (myscript.ps1) wrongly calls DoSometing() with parentheses. If you fix those two problems, you'll see your "Hello World".
MyPSScript.ps1:
function DoFoo() {
$Powershell = "C:\windows\System32\WindowsPowerShell\v1.0\Powershell.exe"
$Command = "& C:\Temp\myscript.ps1"
Start-Process $Powershell -ArgumentList ("-noexit", "-noprofile", "-Command", $Command)
}
DoFoo
myscript.ps1:
Import-Module "C:\Temp\myscript2.ps1"
DoSomething
Powershell modules have a .psm1 file extension.
Rename your file "myscript2.ps1" to "myscript2.psm1", then it should work.

Determine If Solution Compiles using MSBuild and PSake

I have put together a PSake (v2.0) build script, and the script is setting the $psake.build_success property as true even thought the call to MSBuild fails. Can anyone advise me on how to alter the script so that the $psake.build_success property will correctly return false when the MSBuild call fails?
My PSake build script is as follows:
properties {
$solutionFile = 'SOLUTION_FILE'
$buildSuccessfulMessage = 'Solution Successfully Built!'
$buildFailureMessage = 'Solution Failed to Build!'
$cleanMessage = 'Executed Clean!'
}
task default -depends BuildSolution
task BuildSolution
{
msbuild $solutionFile /t:Clean,Build
if ($psake.build_success)
{
$buildSuccessfulMessage
}
else
{
$buildFailureMessage
}
}
Is PowerShell's native $lastExitCode (i.e., WIn32 ExitCode) any use in the context? I'd be guessing that the built in one is only relevant when you're invoking a psake-related cmdlet.
i.e., replace the check with
if($lastexitcode -eq 0) {
Disclaimer: Only podcast level experience with psake :D
The issue seems to be that the call to MSBuild operation actually completes successfully, whilst the build operation it initiates fails. The way I was able to get around this was to pipe the output of the MSBuild call to a text file, and then parse the file for the string "Build Failed". If it contained the string, obviously the build failed.
My PSake build script is as follows:
properties {
$solutionFile = 'SOLUTION_FILE'
$buildSuccessfulMessage = 'Solution Successfully Built!'
$buildFailureMessage = 'Solution Failed to Build!'
$cleanMessage = 'Executed Clean!'
}
task default -depends Build
task Build -depends Clean {
msbuild $solutionFile /t:Build /p:Configuration=Release >"MSBuildOutput.txt"
}
task Clean {
msbuild $solutionFile /t:Clean
}
and in my calling script:
function Check-BuildSuccess()
{
return (! (Find-StringInTextFile -filePath .\MSBuildOutput.txt -searchTerm "Build Failed"))
}
function Is-StringInTextFile
(
[string]$filePath = $(Throw "File Path Required!"),
[string]$searchTerm = $(Throw "Search Term Required!")
)
{
$fileContent = Get-Content $filePath
return ($fileContent -match $searchTerm)
}
There is the psake Exec command that you can wrap msbuild with and a powershell error is thrown.
Exec {
msbuild $solutionFile "/p:Configuration=$buildConfiguration;Platform=$buildPlatform;OutDir=$tempOutputDirectory"
}
Neither $LastExitCode or $_ worked for me. This did however:
$buildArgs = "MySolution.sln", "/t:Build", "/p:Configuration=Debug"
$procExitCode = 0
$process = Start-Process -FilePath "msbuild" -ArgumentList $buildArgs -NoNewWindow -PassThru
Wait-Process -InputObject $process
$procExitCode = $process.ExitCode
#aha! msbuild sets the process exit code but powershell doesn't notice
if ($procExitCode -ne 0)
{
throw "msbuild failed with exit code $procExitCode."
}
P.S. If you use this in production I recommend adding -timeout handling to Wait-Process