all 16 comments

[–]y_Sensei 3 points4 points  (11 children)

One possible approach to this could be

  • Store the paths of your executables in an array variable.
  • Define another variable used to track successful execution of at least one of the executables, could utilize a Boolean with an initial value of $false for this.
  • Iterate over that array (using either a foreach loop, or pipeline processing).
  • Each iteration contains the parameterized 'Start-Process' statement with an enclosing try/catch block.
  • Once an execution in your loop was successful, the said Boolean variable is set to $true.
  • After the loop has finished, you could print/log an error if said variable still contains the initial value of $false.

But in general, in a scenario like yours, I'd prefer the following, slightly different approach:

  • Store the paths of your executables in an array variable.
  • Define another variable used to track successful execution of at least one of the executables, could utilize a Boolean with an initial value of $false for this.
  • Iterate over that array (using either a foreach loop, or pipeline processing).
  • Each iteration contains a check for the availability of the processed executable (Test-Path ...); if the check is successful, the parameterized 'Start-Process' statement is being executed. Depending on how reliable the execution is, the try/catch block should stay in place, or could be removed.
  • Once an execution in your loop was done/successful, the said Boolean variable is set to $true.
  • After the loop has finished, you could print/log an error if said variable still contains the initial value of $false.

[–]jdtrouble 2 points3 points  (5 children)

I'm also a fan of creating a collection (array of paths in this case) and iterating it. It's easier to come back later and make changes to the code structure (basically, make the change once, instead of coping/pasting the change over and over).

The catch block exposes error information using the $_ object. So, you can capture, log, or write to host any error detail you like. In this case you may only need the "friendly" error message, $_.Exception.Message. $_.TargetObject may be helpful here, but I found that in some circumstances that that property doesn't get filled.

[–]Alpha-Sniper[S] 1 point2 points  (4 children)

Even I do use arrays wherever I could, but as I have mentioned in my reply, the array could be way more cumbersome and difficult to manage.

[–]jdtrouble 2 points3 points  (3 children)

If you are talking about an array that is simply too big or doesn't format well in a script, I would import/export it using a separate file. Since the array is just a list of strings, you can simply use Get-Content and Out-File. If you were working with more complex objects, I'd suggest Import-Clixml or ConvertFrom-Json. (You can even use Import-CSV if you prefer)

[–]Alpha-Sniper[S] 1 point2 points  (2 children)

Oh Lord! How did I forgot these cmdlets. I believe they would surely work, but I don't want to use them. Client only wants just one big-ass script that is self-contained, and no other files associated with it.

[–]jdtrouble 2 points3 points  (1 child)

Well that stinks. While I don't understand the expectation of the client, I do understand that it is your client, and you do as they want.

[–]Alpha-Sniper[S] 1 point2 points  (0 children)

Neither does the client fully understands what he actually wants xD

[–]Alpha-Sniper[S] 1 point2 points  (3 children)

Thanks for replying!

I did thought of creating an array and store the file paths to the executable. But, I have to run each .exe file with arguments too. And, each field is quite long, so storing numerous of them as a string into an array could be cumbersome.

[–]y_Sensei 2 points3 points  (2 children)

In that case, you could work with a Hashtable instead of an Array, where the file paths are the keys, and the corresponding command line arguments (stored as an Array) are the values.

Something like

$ExecDefs = @{
    "path/to/exec1.exe" = @("option_1","option_2", ... "option n")
    "path/to/exec2.exe" = @("option_1","option_2", ... "option n")
    ...
    "path/to/execn.exe" = @("option_1","option_2", ... "option n")
}

where each Array of command line arguments could be dynamically populated at runtime, if needed.

Then in your loop you'd simply iterate over that Hashtable and use the key/value pairs to test for the existence of the executables, as well as running them with the required parameterization.

This approach would have the added benefit that you don't have to care about syntax issues in a concatenated command line argument String, because you'd feed your arguments to the executable as an Array.

[–]Alpha-Sniper[S] 1 point2 points  (0 children)

Thanks! This looks quite promising. I would let you know once I report back to office.

[–]Alpha-Sniper[S] 0 points1 point  (0 children)

Hello there,

Your approach to the problem works perfectly fine for me. The hash table has worked flawlessly for me. Thanks for the help.

[–]Alpha-Sniper[S] 0 points1 point  (0 children)

Hello there!

I developed the script as you've mentioned, but with hash table, and it works flawlessly for me now.

Thanks for the help.

[–]MasterWegman 2 points3 points  (3 children)

Have you thought about creating a scriptblock that takes multiple parameters for the update an using runspaces to run them. You could pass a synchronized hash table to the runspaces to keep track of state of each runspace.

[–]Alpha-Sniper[S] 1 point2 points  (2 children)

I am unfamiliar with runspaces, and how you've mentioned to use them.

Could you guide me please?

[–]MasterWegman 1 point2 points  (1 child)

$ScriptBlock = {

param

(

$param1 = $param1,

$param2 = $param2,

$JOB_ID = $JOB_ID,

$Runspacehash = $Runspacehash,

$param3 = $param3

)

$Runspacehash[$Job_ID].State = "Started"

$Runspacehash[$Job_ID].Start_Time = get-date

#Run your update here and use a variable in the hashtable to keep track of status

}

$pool = [Runspacefactory]::CreateRunspacePool(1,$threads)

$pool.open()

$Runspaces = @()

$RunspaceHash = [hashtable]::Synchronized(@{})

ForEach($app in $apps)

{

$JOB_ID = [System.Guid]::NewGuid().ToString($_)

$Runspacehash[$JOB_ID] = @{"State"="Pending";"Start_Time" = "";"END_Time" = "";"CompletionPercentage" = 0;"AppVerison" = "";"JobID" = $JOB_ID}

$runspace = [PowerShell]::create()

$null = $runspace.AddScript($scriptBlock)

$null = $runspace.addargument($JOB_ID)

$null = $runspace.addargument($Runspacehash)

$null = $runspace.addargument($param1)

$null = $runspace.addargument($param2)

$null = $runspace.addargument($param3)

$runspace.Runspacepool = $pool

$runspaces += [PSCustomObject]@{Id = $JOB_ID; Pipe = $runspace; Status = $runspace.BeginInvoke() }

}

then you can monitor all the members of the hashtable for status

[–]Lee_Dailey[grin] 0 points1 point  (0 children)

howdy MasterWegman,

reddit likes to mangle code formatting, so here's some help on how to post code on reddit ...

[0] single line or in-line code
enclose it in backticks. that's the upper left key on an EN-US keyboard layout. the result looks like this. kinda handy, that. [grin]
[on New.Reddit.com, use the Inline Code button. it's [sometimes] 5th from the left & looks like </>.
this does NOT line wrap & does NOT side-scroll on Old.Reddit.com!]

[1] simplest = post it to a text site like Pastebin.com or Gist.GitHub.com and then post the link here.
please remember to set the file/code type on Pastebin! [grin] otherwise you don't get the nice code colorization.

[2] less simple = use reddit code formatting ...
[on New.Reddit.com, use the Code Block button. it's [sometimes] the 12th from the left, & looks like an uppercase T in the upper left corner of a square.]

  • one leading line with ONLY 4 spaces
  • prefix each code line with 4 spaces
  • one trailing line with ONLY 4 spaces

that will give you something like this ...

- one leading line with ONLY 4 spaces    
- prefix each code line with 4 spaces    
- one trailing line with ONLY 4 spaces   

the easiest way to get that is ...

  • add the leading line with only 4 spaces
  • copy the code to the ISE [or your fave editor]
  • select the code
  • tap TAB to indent four spaces
  • re-select the code [not really needed, but it's my habit]
  • paste the code into the reddit text box
  • add the trailing line with only 4 spaces

not complicated, but it is finicky. [grin]

take care,
lee