Write realtime powershell output during TFS release execution - powershell

In our company we use TFS 2017 (update 1) for building and releasing our products. The release part is made up of several steps which include the execution of some Powershell scripts.
This is how I configure the PS step.
What I noticed is that the output of the powershell scripts is not written realtime while it is executing, but all together in the end of the PS task. This is very annoying in case of long running scripts as we are not able to see the live progress of the task, but we have to wait the task to finish to see the results.
I wrote some simple PS scripts to debug this problem but neither using write-host (this does not write nothing at all, even in the end of the task) nor using write-output nor with write-verbose -verbose allows me to write realtime output.
This is one example script I tried, without success.
Write-Output "Begin a lengthy process..."
$i = 0
while ($i -le 100)
{
Start-Sleep 1
Write-Output "Inner code executed"
$i += 10
}
Write-Output "Completed."
Did you ever found yourself in this situation?
Regards

I can reproduce this issue, based on my test realtime output is not supported for the PowerShell on Target Machines task.
Write-output or write-verbose -verbose just can output to console but it's not real-timed, the output only displays once the powershell script completely executed.
To display the real-time output you can use the Utility:PowerShell task instead of the Deploy:PowerShell on Target Machines task.
So, as a workaround you can deploy an agent on the target machine which you want to run the powershell script, then trigger the release using that agent running powershell script with Utility:PowerShell task.
UPDATE:
Well, find another workaround with Utility:PowerShell task:
1.Set up WinRM for target computers, refer to WinRM configuration
2.Copy the target PS script to the target machine (D:\TestShare\PStest.ps1 in below sample)
3.Create a PowerShell script to call the Powershell.exe to run the target powershell script on target machine, see below sample:
Param(
[string]$computerName = "ICTFS2015.test.com",
)
$Username = "domain\usename"
$Password = ConvertTo-SecureString "Possword" -AsPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential($Username,$password)
Invoke-Command -ComputerName $computerName -Credential $cred -ScriptBlock {Invoke-Expression -Command:"powershell.exe /c 'D:\TestShare\PStest.ps1'"}
4.Add a Utility:PowerShell task to run above PowerShell script. (You can check in or run Inline Script).

Related

override the PowerShell Cmdlet approach and have a PowerShell script manually process flags?

Is there away to override the PowerShell Cmdlet approach and have a PowerShell script manually process Script Arguments?
I Just want a simple example of a Powershell script that uses the classic C/perl approach of using "GetOptions" to process script argument flags manually. Instead of breaking everything up into "Command-lets", since in my case I don't care about integrating my script with the shell and returning objects for other command-let etc... Its just a one time use case where classic approach would be better than command-lets...
Here's an example:
File: script.ps1
param ($servername, $envname='Odyessy')
if ($servername -eq $null) {
$servername = read-host -Prompt "Please enter a servername"
}
write-host "If this script were really going to do something, it would do it on $servername in the $envname environment"
Example:
.\script.ps1 -servername HAL
.\script.ps1 -envname Discovery
Also See:
https://www.red-gate.com/simple-talk/sysadmin/powershell/how-to-use-parameters-in-powershell/

Trying to run an exe remotely on another server using Powershell and failing

We have Alteryx on several servers and want to be able to run jobs remotely from either command line or powershell, not through Alteryx API.
I have run alteryx flows locally from command line and powershell locally for years but now with multiple servers we have need to execute certain flows this way but to trigger from a react web app. We tried the API and it works but jobs often queue for too long and we need near realtime response and these jobs run in seconds. Our solution is to trigger outside the Alteryx API for immediate execution on a worker node with excess resources.
Our problem is that when testing the script which works well if run locally it runs all other commands fine except the execution of the alteryxenginecmd.exe program.
if I use Start-Process with passthru it generates a process but no output from the alteryx job and no errors detected.
If I use Call operator & if fails saying it can;t find the workflow, so the alteryxenginecmd.exe is firing but not reading or receiving the full path of the flow to run as the parameter. but it works fine locally.
I have used creds to force a sign on to clear any credential issue with no change in result.
I know Powershell has some oddities and maybe there is some tweak to how a command must be specified if the script is run from a remote server?
This is the script I want to run from remote server which does work fine in any of the 4 scenarios shown
$rundate = (Get-Date -format 'u') -replace "-","" -replace ":","" -replace " ","-"
$Pgm2Run = "\<somepath>\RunScriptRemote\RunRemoteTest2 - NoDB.yxmd"
$Bat2Run = "\\<somepath>\RunScriptRemote\RunRemoteTestJob.bat"
$JobLogFile = "\<somepath>\RunScriptRemote\LogsJob\JobTranscript $rundate.txt"
$ScriptLogFile = "\<somepath>\RunScriptRemote\LogsScript\RunJobTranscript $rundate.txt"
Start-Transcript -Path $ScriptLogFile
echo " "
echo "$rundate Start --> "
Echo "$rundate Before Start-Process"
#1 Start-Process -filepath "AlteryxEngineCmd.exe" -ArgumentList `"$Pgm2Run`" -RedirectStandardOutput $JobLogFile -Wait -PassThru
#2 Start-Process -filepath $Bat2Run -RedirectStandardOutput $JobLogFile -Wait -PassThru
#3 & AlteryxEngineCmd.exe "$Pgm2Run"
AlteryxEngineCmd.exe "$Pgm2Run"
echo "$rundate After Start-Process"
echo "$rundate End --> "
Stop-Transcript
This command run on Server1 to execute the script above on server2
Invoke-Command -ComputerName server2 -FilePath "\\<somepath>\RunScriptRemote\RunAlteryxAndLogIt.ps1"
And this is the result:
20200831-094309Z Before Start-Process
AlteryxEngineCmd.exe Version 2019.4.8.22007 © Alteryx, Inc. - All Rights Reserved.
Started running \\<somepath>\RunRemoteTest2 - NoDB.yxmd
Error - Alteryx Engine: Can't read the file "
Invoke-Command -ComputerName server2 -FilePath "\\<somepath>\RunScriptRemote\RunRemoteTest2 - NoDB.yxmd"
Finished in 0.020 seconds with 1 error
20200831-094309Z After Start-Process
I am not sure it is a powershell thing, it may well be an Alteryx thing because the issue seems to be executing that one exe properly. the script triggers properly from remote server and I tested other commands and all worked, I just can't seem to get the one executing this exe to work when run remotely though it works fine locally when same script is run locally. its like a barrier betweek a script running another script.
Any powershell experts familiar with running exe's remotely from another server?

Windows Task Scheduler Powershell get URL and download file

I am struggling with automating download of a file from website that opens a new tab when download is triggered and closes it right before the prompt to Save/Open/Close comes up in the main window. The script itself works just fine when launched manually until I try it in Task Scheduler. It runs great until it snags on the download. I've included a code to capture the URL of the file that needs to be downloaded and then pass it to Invoke-WebRequest which works fine out of PowerShell ISE but doesn't return any results when launched from Task Scheduler. I've included the counter and test file creation into the code to see if contents of do-while execute at all, and all 10 attempts were recorded. It's the part that searches through active URLs that's not returning results when launched via Task Scheduler.
# >> Keep trying to capture the CSV download link
$i = 1
Do {
$i | Add-Content -Path "C:\userfolder\try.txt"
$urls = (New-Object -ComObject Shell.Application).Windows() |
Where-Object {$_.LocationUrl -like "https://sitename.com/ReportViewer*"} |
Where-Object {$_.LocationUrl}
$reportURL = #($urls)[0].LocationURL
$i ++
}
While ($reportURL -eq $NULL -and $i -le 10)
# >> Send download link to web request and save to file
Invoke-WebRequest -Uri $reportURL -OutFile "C:\userfolder\ProfileList.csv"
I have tried the Wscript.Shell AppActivate and SendKeys('%S') before but the AppActivate wouldn't work probably because the PowerShell console window was hijakcing focus when launched via Task Scheduler. The task is set to execute powershell.exe with Arguments: C:\userfolder\CPdownload.ps1 -RunType $true, - and Start in: C:\userfolder. Run: only when user is logged in and with highest privileges; configured for Windows Server 2012 R2.
I've also tried launching the shell script through batch file from Task Scheduler with exactly the same result.
Thanks in advance for any pointers.
Probably your task needs to be run in interactive mode. By default scheduled tasks are run in Session 0. You can schedule task for interactive mode with /IT parameter. Check the following link for more info
https://msdn.microsoft.com/en-us/library/bb736357(VS.85).aspx
Old post however besides changing the script to interactive mode (this fixes it) you can change the Powershell execution policy to unrestricted (Set-ExecutionPolicy -ExecutionPolicy Unrestricted) if you wish to run the script outside of interactive mode. Just thought I'd post as recently come across this myself.

Use Powershellscript to start remote Powershellscrhipt with Parameters

I have a Powershell Script (PS1), which gets Events from a Remote Computer.
When there is a special Event, it (PS1) should start a Powershell Script (PS2) which is on the remote Computer. The 2nd Script gets 2 Parameter from the first and the first should not wait for the 2nd (it will copy some files with robocopy and this will need some time)
PS1:
icm -ComputerName $Computer {param ($source, $location)
'G:\RoboCopyScript_271113.ps1'} -ArgumentList $source, $location
-Credential $credWinLog
PS2: param ( [Parameter(Position=0)]$source,
[Parameter(Position=1)]$location )
Someone knows how i make the PS2... something like a Child Process?
and where my Errors ware with the Parameters, i tried so much :/

Running a set function name in multiple Powershell scripts

I am building a testing framework for my current development team. One thing that I'd like to let them do is create a Powershell script to run their tests. The system is a database deploy system, so to test it they will need to potentially run some set-up code, then the deploy will be kicked off, then they will run some check code at the end.
Since the deploy takes awhile I'd like to have the framework handle that once for all of the tests. So, the basic flow is:
Run test #1 set-up
Run test #2 set-up
Run test #3 set-up
Run the deploy process
Run the code to confirm that test #1 passed
Run the code to confirm that test #2 passed
Run the code to confirm that test #3 passed
I figured that I would have the framework always call a function called "setup" (or something similar) in all of the Powershell scripts in a particular directory. If no "setup" function exists that's ok and it shouldn't error out. Then I would run the deploy and then run the other functions in the Powershell scripts.
Given a directory listing, how could I cycle through each Powershell script and run these functions?
Thanks for any guidance!
this will recurse through the given folder and execute all the setup.ps1 scripts it finds.
Get-ChildItem D:\test -Recurse | where { $_.name -eq "setup.ps1" }| foreach {
"Executing $($_.Fullname)"
Invoke-Expression "$($_.Fullname) -setup -Verbose"
}
It doesn't accept parameters though....
If you just wanted to go one folder deep this will do the job:
Get-ChildItem D:\test | where{$_.psiscontainer}|foreach {
Get-ChildItem $_.fullname | where { $_.name -eq "setup.ps1" }| foreach {
"Executing $($_.Fullname)"
Invoke-Expression "$($_.Fullname) -setup -Verbose"
}
}
It's irritated me a little that the parameters didn't work - I wonder if using the Invoke-Command could work for that. I haven't got time to try now, unless anyone else figures it out I'll have a look later.
Here's the script i used for setup.ps1
[cmdletbinding()]
Param()
function setup() {
Write-Verbose "In setup 1"
Write-Output "Done setup 1"
}
setup
HTH
Thanks to Matt's ideas I was able to come across Invoke-Expression. Ideally I would have liked to use Invoke-Command with the -filepath parameter, which supposedly defaults to running locally. However, there is a bug that requires using the -ComputerName parameter even when running locally. If you use that parameter then it requires remoting to be turned on, even when running on the local computer.
Here's the code that I used in my script:
# Run the setup functions from all of the Powershell test scripts
foreach ($testPSScript in Get-ChildItem "$testScriptDir\*.ps1") {
Invoke-Expression "$testPSScript -Setup"
}
# Do some other stuff
# Run the tests in the Powershell test scripts
foreach ($testPSScript in Get-ChildItem "$testScriptDir\*.ps1") {
Invoke-Expression "$testPSScript"
}
My test script then looked like this:
param([switch]$Setup = $false)
if ($Setup) {write-host "Setting things up"; return}
Write-Host "Running the tests"