How can I store the output of a command as a variable in PowerShell? - powershell

Say I execute the command:
git pshu
which will give me:
git: 'pshu' is not a git command. See 'git --help'.
Did you mean this?
push
If this was the last command I executed, I want retrieve the command and store its outputs in a variable for further use.
So far I have tried things like:
$var = echo (iex (h)[-1].CommandLine)
$var = iex (h)[-1].CommandLine | Out-String
etc.
How can I save such output to a variable?

Lets say you are running multiple commands, and you want to store store a run command based on its input.
Lets say you want to store non existing git commands, as git pshu. My proposal will be to store the command and search for the desired pattern on the output as "Did you mean...". In this case, you can follow as:
$output = git pshu *>&1
if ( "$output".indexOf("Did you mean") -ge 0 ) {
write-host "Command '$($(get-history)[$(get-history).count-1].CommandLine)' didnt exist"
where $(get-history)[$(get-history).count-1].CommandLine will contain the latest run command, in this example, `git pshu'

Related

Store output of command with error

I want to store the output of this command
git checkout master
the output of this command has two states.
success - the command outputs:
Switched to branch 'X'
failure - the command outputs
Your local changes to the following files would be overwritten by checkout <list files> : Please commit your changes or stash them before you switch branches. Aborting
I want to store the output and check if it succeeds by checking for the string abort.
This is what I've tried.
$output = git checkout master 2>&1
if ($output.Contains("Aborting")) {
Write-Host $output -BackgroundColor Red
} else {
Write-Host $output
}
but $output produces something like this, when in the second state:
It seems like the command completed, but it was the wrong syntax. How do I fix this? I would like to to ouput
Make sure that your command's stderr output is converted to regular strings:
$output = [string[]] (git checkout master 2>&1)
Without the [string[]] cast, stderr output lines are stored in $output as [System.Management.Automation.ErrorRecord] instances, and outputting such instances later somewhat misleadingly prints them as if they were PowerShell errors.
(Note that PowerShell Core no longer exhibits this behavior: while stderr lines are still captured as [System.Management.Automation.ErrorRecord] instances, they now print as regular strings.)

How to copy files in svn into a new directory that depends on a variable value?

I'm currently writing a script in PowerShell which calculates a new tag in the tag directory. I want to copy files from one SVN directory to another directory that depends on the new tag number I calculated.
Here are the lines from the script:
$tag = Write-Host "$($svnMavenTagPrefix)$($nextMavenTagVersion)"
svn copy http://tlvsvn1/svn/repos-bls/MassAnalytics/trunk/ http://tlvsvn1/svn/repos-bls/MassAnalytics/tags/${tag}
For some reason it doesn't work and I receive the following error:
svn: E205007: Could not use external editor to fetch log message; consider setting the $SVN_EDITOR environment variable or using the --message (-m) or --file (-F) options
svn: E205007: None of the environment variables SVN_EDITOR, VISUAL or EDITOR are set, and no 'editor-cmd' run-time configuration option was found
How can I copy the files to a new tag?
The Write-Host cmdlet prints the string you are passing as an argument but doesn't write anything to the output thus $tag is empty. I would recommend you to use a format string:
$tag = '{0}{1}' -f $svnMavenTagPrefix, $nextMavenTagVersion
$url = 'http://tlvsvn1/svn/repos-bls/MassAnalytics/tags/{0}' -f $tag
svn copy http://tlvsvn1/svn/repos-bls/MassAnalytics/trunk/ $url

How to get PowerShell to display the commands being called

I've got a simple PowerShell script that I'm calling from Jenkins:
function PerformRepoActions($localRepo)
{
$startDir = $pwd.path
cd $localRepo
hg recover
hg revert --all
hg pull -r $branch --rebase
hg update -r $branch
cd $startDir
}
$branch = $env:NAMEDBRANCH
PerformRepoActions $pwd.path
When I run this, it does not show any of the mercurial commands that I'm making. Here's what it shows in the Jenkins output:
no interrupted transaction available
pulling from [repo_location]
no changes found
0 files updated, 0 files merged, 0 files removed, 0 files unresolved
It's giving me the the output of the hg commands, but not showing the commands themselves.
So, I'm looking for something that will make those commands print out, equivalent to the cmd.exe "echo on".
A search tells me that the equivalent in PowerShell is "Set-PSDebug -Trace 1". So I add that to the beginning of the script, and it changes the output to:
DEBUG: 15+ >>>> $branch = $env:NAMEDBRANCH
DEBUG: 16+ >>>> PerformRepoActions $pwd.path
DEBUG: 5+ >>>> {
DEBUG: 6+ >>>> $startDir = $pwd.path
DEBUG: 7+ >>>> cd $localRepo
no interrupted transaction available
pulling from ssh://hg#mercurial.wilcoxassoc.com/PcDmis/QA
no changes found
0 files updated, 0 files merged, 0 files removed, 0 files unresolved
As you can see, while it does give me more output, but it doesn't actually show me the commands that I'm calling.
"Set-PSDebug -Trace 2" gives even more output, but still doesn't show what mercurial commands are being called.
The work-around that I've come up with is to create a function which echoes and the executes a string. It works, but it feels awful kludgey:
function execute($cmd)
{
echo $cmd
iex $cmd
}
function PerformRepoActions($localRepo)
{
$startDir = $pwd.path
execute "cd $localRepo"
execute "hg recover"
execute "hg revert --all"
execute "hg pull -r $branch --rebase"
execute "hg update -r $branch"
execute "cd $startDir"
}
$branch = $env:NAMEDBRANCH
PerformRepoActions $pwd.path
Is there some better way to do this?
It seems that there must be, but I've been surprised before.
edit: This is not a duplicate of PowerShell "echo on". Re-directing the output to a file, the answer to that question, isn't feasible. I need it to display in the Jenkins output, not a file.
there's a way that you can capture the contents of the current script that you're in, and with a little work you could probably marry that up with the relevant output. (whether that's a need I'm not sure)
As of Powershell v3 you have access to the abstract syntax trees (that's the only link I could find that said anything about it!)
Basically the Ast has access all properties of the current script (or any script you send to it) including its complete source.
running this script (I included notepad to show it running external exe)
Write-Host "before"
$MyInvocation.MyCommand.ScriptBlock.Ast
Write-Host "after"
notepad
Will produce this output
before
Attributes : {}
UsingStatements : {}
ParamBlock :
BeginBlock :
ProcessBlock :
EndBlock : Write-Host "before"
$MyInvocation.MyCommand.ScriptBlock.Ast
Write-Host "after"
notepad
DynamicParamBlock :
ScriptRequirements :
ImplementingAssembly :
Extent :
Write-Host "before"
$MyInvocation.MyCommand.ScriptBlock.Ast
Write-Host "after"
notepad
Parent :
after
I imagine if you play around with
$MyInvocation.MyCommand.ScriptBlock.Ast
You should be able to make it produce something like what you want.
edited to add
You could potentially take this a step further by using the Ast to select each Powershell cmdlet and attach a breakpoint to it, then you should have access to the cmdlet names (I don't think that would work with executables - and its only a theory at the moment!) You'd need to run the whole thing through an external script that managed the logging and continuing from the breakpoints. But I think it could work.

svnlook changed -t "$rev" "$repos" not getting executed

As in title I am calling from my post-commit hook script written in perl which has command
$msg = `$svnlook changed -t "$rev" "$repos"`;
which should execute and than I should send $msg to my service. But when I run
if ( length($msg) == 0 )
{
print STDERR "msg length is 0";
exit(1);
}
I get this error message on console, so why is this svnlook command not being executed?
I am using windows 7 and VisualSVN server.
On other note, I had other theory to run this command in hook itself like
#echo off
set repos=%1
set rev=%2
set changes=svnlook changed %repos% -r %rev%
C:\Perl64\bin\perl C:\repositories\myproject\hooks\myhook.pl %1 %2 changes
but I don't know how to pass this changes parameter, so if this could work, it could answer as well.
How to pass parameter from batch to perl script?
running svnlook changed help display the list of valid options to svnlook changed and their expected format:
$ svnlook help changed
changed: usage: svnlook changed REPOS_PATH
Print the paths that were changed.
Valid options:
-r [--revision] ARG : specify revision number ARG
-t [--transaction] ARG : specify transaction name ARG
--copy-info : show details for copies
Normally you would specify either a transaction number with -t or a revision number with -r. You appear to be passing a revision number with -t which will lead to unexpected results: either no results or results that are unrelated to the revision you wish to example.
I believe the correct usage in your case would be:
my $msg = `$svnlook changed -r "$rev" "$repos"`;
The above command is going to give you one long string that is delimited by newlines. You can get this is a more manageable array format by using the same command in list context:
my #changes = `$svnlook changed -r "$rev" "$repos"`;
additionally these lines will all have trailing newlines, you can eliminate them using the chomp() built-in:
my #changes;
chomp(#changes = `$svnlook changed -r "$rev" "$repos"`);
Alternatively, you could look at SVN::SVNLook which a Perl wrapper around the svnlook command.

Use console output of command-line tool in Powershell pipeline

In my PowerShell script, I'd like to use the output of a tool like git.
For example, the command line
git status
returns
# On branch master
nothing to commit (working directory clean)
Now I tried to use this output in the following pipeline command:
git status | $_.Contains("nothing to commit")
But I get the error
Expressions are only allowed as the first element of a pipeline.
What am I doing wrong?
$msg = [string](git status) | where { $_.Contains("nothing to commit") }
You can use select-string:
git status | select-string "nothing to commit"