Issue while executing powershell script through System.Diagnostics.Process or System.Management.Automation.Runspaces - powershell

Need your help in solving this following issue.
We have a powershell script like:
invoke-command -ScriptBlock { [cmdletbinding()]
param(
[parameter(mandatory=$True)]
[string] $ticktfilepath
)
$ticketdetails=get-content $ticktfilepath |%{if ( $_ -like '"AB*' ) {$_}}|%{echo "$($_.Split(',')[7].Split('"')[1])=$($_.Split(',')[3].Split(':')[0].Split(' ')[$_.Split(',')[3].Split(':')[0].Split(' ').length-1])=$($_.Split(',')[0].Split('"')[1]);"}
write-output $ticketdetails } -ArgumentList 'D:\file.csv'
This script reads a csv file and for those lines in the csv with “AB…” at the start, does some string parsing. The csv file passed has rows with the “AB…” and hence result are returned. This runs perfectly when executing through powershell console or ISE.
But as per our requirement, where we trying to execute the same script through:
1. System.Diagnostics.Process with process start info having file name as powershell.exe and the argument at the above script. It fails for –like. i.e at |%{if ( $_ -like '"AB*' ). It is always false for the condition even though it is expected to be true.
N.B. other powershell script works perfectly with this approach
2. Exactly Similar issue when executed through System.Management.Automation.Runspaces
So looks like some constraint using the “–like” operator.
We even with the System.Diagnostics.Process approach tried writing the script line by line leveraging the Process.StandardInput.WriteLine(line) but then powershell hangs.
Any pointer to address this will be highly appreciated.
While using System.Diagnostics.Process, I used something like:
ProcessStartInfo processStartInfo = new ProcessStartInfo();
processStartInfo.UseShellExecute = false;
processStartInfo.RedirectStandardError = true;
processStartInfo.RedirectStandardOutput = true;
processStartInfo.FileName = "powershell.exe";
processStartInfo.Arguments = <ScriptContent>;
Process powerShellProc = new Process();
powerShellProc.StartInfo = processStartInfo;
powerShellProc.Start();
string successMessage = powerShellProc.StandardOutput.ReadToEndAsync().Result;
string errorMessage = powerShellProc.StandardError.ReadToEndAsync().Result;
powerShellProc.WaitForExit();
where,
ScriptContent- is the above powershell script.
Instead of like, even tried with startswith but then also the same result. But with powershell console or iSE, it works perfectly.

It's probably too late to answer :)
You shouldn't call powerShellProc.StandardOutput.ReadToEndAsync().Result before process actually finished. You can use Invoke-Executable function from How to capture process output asynchronously in powershell?
The following order is working
$outTask = $oProcess.StandardOutput.ReadToEndAsync();
$errTask = $oProcess.StandardError.ReadToEndAsync();
$bRet=$oProcess.WaitForExit($TimeoutMilliseconds)
$outText = $outTask.Result;
$errText = $errTask.Result;

Related

PowerShell: How to clear cache of included files?

I include an external .ps1 into antother .ps1:
foo.ps1:
.("C:\test\bar.ps1");
$obj = [bar]::new();
$obj.out();
bar.ps1:
class bar{
$output;
bar(){
$this.output = 1;
}
[void] out(){
write-host $this.output;
}
}
The first time I execute foo.ps1 in the Windows PowerShell ISE the output is "1", as expected.
Then I go to bar.ps1 and change $this.output = 1; to $this.output = 2;. After executing foo.ps1 again the output is still "1". When I change something in foo.ps1, like simply appending a new line, and execute it once again, the output becomes "2". Changing back, like removing the new line, will make an output of "1" again.
For me it looks like an caching issue. Is it possible to clear or disable the caching?
Thanks in advance!

Pass an argument from a module

I need help understanding how to pass on an argument from an imported module.
The module contains some custom arguments such as -one, -two, -three
I am trying to make a GUI using the commands from the module.
eg. If "One" is selected from the drop down menu, pass through the -one command.
However when I do so (using the example below), I get the error: "A positional parameter cannot be found that accepts argument '-one'."
I can see that using the code below, it adds single quotations around the command which probably breaks it.
I know I can run an IF statement (eg if combobox.text = "one", do this), however I would prefer to use a variable instead of having to make multiple if statements or a loop. The use of a variable seems like a simpler option.
I'm learning this language as I go so I'm not quite there yet with the knowledge :)
Thanks for any help. Hope this made sense.
$variable = $comboboxNumbers.Text
#example One is selected from the dropdown
Custom-ADCommand -identity "username" $variable
Below is simple example method:
function Set-SwitchParams {
[CmdletBinding()]
param (
# Parameter help description
[Parameter(Mandatory = $false)]
[switch]
$SwitchA,
[Parameter(Mandatory = $false)]
[switch]
$SwitchB
)
begin {
}
process {
}
end {
if ($SwitchA){
Write-Host "SwitchA is activated"
}
if ($SwitchB){
Write-Host "SwitchB is activated"
}
}
}
Put the method in a PS1 file, e.g. SwitchPlayground.ps1. Then source the file in PowerShell via:
. .\SwitchPlayground.ps1
Afterward, you can play around with the command, e.g.:
Set-SwitchParmas -SwitchA
I'd suggest studying the following links:
about functions basic
about functions advanced
about function parameters
Hope that helps.
An If statement if probably much nicer, but its possible to create a string and then execute the string in powershell.
As a simple example take this string
$string = '#("test","hello","whats up")'
I can then execute it and use it to create an array
$array = invoke-expression $string
Which will create an array with "test", "hello" and "whats up" and store it in $array
PS C:\temp> $string = '#("test","hi","what")'
PS C:\temp> $array = Invoke-Expression $string
PS C:\temp> $array
test
hi
what

Return output from Powershell script to UIPath using Invoke power shell

I am trying to get a value from an input box from a Powershell script back to a UI Path Sequence. I have created a simple sequence as an example. Yes, I know I could do this all in UI Path, I am just using an easy example as a way to try and test this for future use cases. Here is my sequence:
My text file from "Read text file" is:
$test = "Desktop/PassingArgs2of2.ps1 -Message foo"
Invoke-Expression -Command $test
The activity in UiPath looks like so:
The psCmd that I am running in the Invoke power shell activity looks like this:
Param(
[parameter(Mandatory=$true)]
[string]
$Message)
try{
$Global:fooVar = $null
function Test-InputBox(){
[void][Reflection.Assembly]::LoadWithPartialName('Microsoft.VisualBasic')
$msg = "fooMsg"
$title = "fooTitle"
$localtest = [Microsoft.VisualBasic.Interaction]::InputBox($msg, $title)
$Global:fooVar = $localtest.ToString()
}
Test-InputBox
}
catch{}
I tried setting fooVar equal to testLocal in the PowerShellVariables within Invoke power shell and then writing it, but that did not work.
Basically I want to get fooVar back into UI Path. Any help would be greatly appreciated. Thank you!
You're almost there. First, your Powershell script has to return a value. Take this for example:
[void][Reflection.Assembly]::LoadWithPartialName('Microsoft.VisualBasic')
$title = 'Your title goes here'
$msg = 'Your favorite color:'
$text = [Microsoft.VisualBasic.Interaction]::InputBox($msg, $title)
return $text
Here's the script in action (note that I called it twice and provided "red" the first time:
Then, just use this script directly in the Invoke Powershell activity. Note that the most important part here is the Output property - here, I decided to go for an array of strings. Naturally, as we only return a single value, you can just access the text provided by the user by accessing output(0).ToString().

Colon in Powershell

I try to run a script in PowerShell that starts a program with additional parameters.
$arrgs = "/sipuri:juerg.schuepbach#parl.admin.ch /multiplecalls:block"
& "BusyOnBusy.exe" $arrgs
It seems PowerShell don't get the argument block. I guess because of the :
I've tried the tings with {} but it's always the same error.
Powershell does not say it is an error. It's the program that says it is missing the block argument.
Thank for the help.
$psi = New-Object Diagnostics.ProcessStartInfo
$psi.Arguments = "/sipuri:juerg.schuepbach#parl.admin.ch /multiplecalls:block"
$psi.FileName = "X:\PathForProgram\BusyOnBusy.exe"
#$psi.UseShellExecute = $false
[void][Diagnostics.Process]::Start($psi)
The colon is the drive designation operator. If you want to pass the string liternally without the parser doing any interpretaion, just single-quote the string:
$arrgs = '/sipuri:juerg.schuepbach#parl.admin.ch /multiplecalls:block'
What if you try:
start-process BusyOnBusy.exe "/sipuri:juerg.schuepbach#parl.admin.ch","/multiplecalls:block"

Pass ProcessParameters runtime (MSBuildArguments) using Powershell to tfs 2010 build definitions

I am executing builds using powershell script. I need to pass the process parameters run time based on the commandline arguments passed to the script. I am using TFS 2010.
[void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.TeamFoundation.Client")
[void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.TeamFoundation.Build.Client")
$projectName = "test"
$buildName = "test.Build"
$tfsServer="xxx"
$tfsInstance = [Microsoft.TeamFoundation.Client.TeamFoundationServerFactory]::GetServer($tfsServer)
$buildService = $tfs.GetService([Microsoft.TeamFoundation.Build.Client.IBuildServer])
$buildDefinations = $buildService.QueryBuildDefinitions($projName)
Loop through all the builds to find the one we are looking for
foreach ($build in $buildDefinations)
{
Get the name of this build instance
$bNameInstance = $build.Name
$ClientName = "test1" #default set in the builddefination is "/p:xxx=test"
#Get the process parameters. I need to update the default value. How can we process the dictionary and update the value
$bMSBuildArguments = $build.ProcessParameters
#Once setting is done."/p:xxx=test1"
$build.ProcessParameters = $bMSBuildArguments
[Void]$buildService.QueueBuild($build)
}
I need help in updating the processparameters using the powershell code. I came across the C# (http://blogs.msdn.com/b/jpricket/archive/2010/03/25/tfs2010-queuing-a-build-from-code-with-custom-process-parameter-values.aspx)solution but not able convert that to Powershell
The answer is in the blog post provided. Try something like this:
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.TeamFoundation.Build.Workflow")
$request = $build.CreateBuildRequest()
$process = [Microsoft.TeamFoundation.Build.Workflow.WorkflowHelpers]::DeserializeProcessParameters($build.ProcessParameters)
#make changes to your process parameters in $process
$process.Item("asdf") = "new value"
$request.ProcessParameters = [Microsoft.TeamFoundation.Build.Workflow.WorkflowHelpers]::SerializeProcessParameters($process)
$buildService.QueueBuild($request)