$error.count does not work

I end my script via

if ($error.count -gt 0 ) 
{
something
}

On error this throws “This command cannot be executed because the interface is not supported”. HResult: -2146233079

What is wrong / missing?

Thanks - Michael

Are you sure that’s the code the error appears on? You may share the relevant part of your code - where the actual error happens and the complete error message (formatted as code as well please)

Thanks! The error is created within an function:

function install_application {
$batfile=$TMPPATH+"\"+$app_Applikation+"_install.bat"
$psexec=$env:_R_SPS+"\progs_common\PsExec64.exe"
$installpath=$TMPPATH+"\"+$app_Installationsquelle

try {
   Copy-Item -Path "$app_install_file" -Destination "$TMPPATH"
# "$env:_R_SPS\progs_common\PsExec64.exe -accepteula -s `"$installpath`" $app_Installationsparameter " | out-file -LiteralPath $batfile -Width 160 -Encoding ASCII -Force 
# start /wait "" "<program>" <parameter> (https://stackoverflow.com/questions/154075/using-the-start-command-with-parameters-passed-to-the-started-program)
   "start /wait `"`" $app_Installationsaufruf `"$installpath`" $app_Installationsparameter " | out-file -LiteralPath $batfile -Width 160 -Encoding ASCII -Force 
# & $psexec -accepteula -s "$batfile" | Out-Null
   Start-Process -FilePath $batfile -Wait -WindowStyle Hidden
   
   $INSTALLIERTE_VERSION = Ermittele_Version
   if ( [version]$INSTALLIERTE_VERSION -eq [version]$app_Version ) {
      $returncode= $INSTALLIERTE_VERSION
   } else {
      $returncode="0"
   }
Remove-Item $batfile
Remove-Item $installpath
}

catch {
   $returncode=0
}

return $returncode
}
#endfunction install_application

and the error-handling at the end of the script is:

# --- Ende main ---------------------------------------------------------------------------------

if ($error.count -gt 0 ) 
{
   " +++ Fehler: error.count -gt 0 : $error.count"
   " +++ Fehler: error.count -gt 0 : $error.count"                                                                  | out-file -LiteralPath $R_LOGFILE         -append -Width 160 -Encoding ASCII -Force
   " +++ Fehler: error.count -gt 0 : $error.count"                                                                  | out-file -LiteralPath $R_LOGFILE_DETAILS -append -Width 160 -Encoding ASCII -Force
   $error[0].Exception | format-list * -force
   $error[0].Exception | format-list * -force                                                                       | out-file -LiteralPath $R_LOGFILE -append -Width 160 -Encoding ASCII -Force
   $error.clear()
}

"$count1 Applikation[en] erfolgreich installiert"                                                                   | out-file -LiteralPath $R_LOGFILE -append -Width 160 -Encoding ASCII -Force

The errortext is:

Michael

Hmmm … Michael Michael Michael …

Migrating your batch fossils to current techology? :wink: :+1:t4: :love_you_gesture:t4:
Your code confuses me - first I wanted to say “a little bit” but it is actually - a lot. :man_shrugging:t4:

A general tip: You may do a step back and start with learning the very basics of PowerShell first. This will save you from a lot of wasted time and frustrations. Especially for beginners it is highly recommended ALWAYS to read the help for the cmdlets you’re about to use completely including the examples to learn how to use them.

And along with the syntax and common methods used for PowerShell you may change the style of your code a little bit. That would make your code a lot easier to read and to understand. And therefor easier to debug. Here you have some stuff to read about:

I will comment on your code from top to bottom without actually trying to find your issue. I could imagine that your issue will not be one anymore when your code is successfully migrated to proper PowerShell. :wink:

Function or cmdlet names should follow the naming standard of PowerShell in the form “Verb-Noun” and should only use approved (english) verbs. You can read more about here

Or you simply use Get-Verb to get a list of approved verbs.

While this works it would be easier to read when you add some spaces here and there. :wink: … like this:

$batfile = $TMPPATH + "\" + $app_Applikation + "_install.bat"

Regardless of that - where did you define $TMPPATH and $app_Applikation? Don’t answer - that’s actually a retorical question. :wink: It is best practice to use variables only in their own scope. Relying on variables from higher scopes can be error prone. Here you can read more about:

So instead of using variables from outside the function you should provide all necessary properties as parameters to the function. Here you can read more about:

In my experiences in an enterprise environment it usually unnecessary to use PsExec64.exe.

For a try-catch to work properly the cmdlets you want to catch errors from have to raise what’s called a terminating error. If they do not by default you have to force them with the common parameter -ErrorAction Stop.

In order to catch an error on a particular action you should enclode only this particular action into a try-catch block.

So to catch an error happening for the copy job you should use it like this:

try {
    Copy-Item -Path $app_install_file -Destination $TMPPATH -ErrorAction Stop
    }
 catch {
    'Copy-Job failed'
 }

This way you know exactly where the error happened. What I really liked though that you used the parameter names. Keep this habbit as it makes your code easier to read. :+1:t4:
And BTW: You should not use quotes for variables unless you have perticular use case. This can lead to weird errors.

If you have code you commented out anyway please remove it when you share it in a forum. This way it does not distract and - again - makes your code cleaner and easier to read. :wink:

Regardless of the fact that you start a CLI from inside another - actually more capable CLI - the executable for batch files is cmd.exe. So the correct way of calling a batch file would be

Start-Process -FilePath $Env:ComSpec -ArgumentList '/C', $batfile -Wait -WindowStyle Hidden

Anyway … instead of calling old batch files from PowerShell I’d recommend to migrate them properly to PowerShell.

Is Ermittele_Version a selfmade function? If yes - please see my previous comment on functions and naming conventions. :wink:

Usually a return code of 0 stands for “No Error”. In PowerShell the 0 evaulates to $false and everything else to $true. So this would be a little bit confusing for me. You may use the [Boolean] $false instead of the a little bit missleading 0. And BTW - again - you should not use quotes becauise it turns the type from [INT] to [STING].

Why all this white space? To make your code easier to read you should try to keep the lines short. You can add a line break after each pipe symbol to achieve this. More about style in the style guide I linked above.
And it is a quite repetitive. I’d have assigned the string to a variable once and use it as often as needed.

But anyway … it will not work as you may think. :wink: Inside strings you have to use the subexpression operator to properly expand object properties. … like this:

  " +++ Fehler: error.count -gt 0 : $($error.count)"

Here you can read more about:

And I’d recommend to use -Encoding UTF8 instead of ANSI. That’s more universal when there are special characters like German Umlaute. :wink: :de:

And last but not least:

Please don’t post images of code or error messages or console output. Instead post the plain text and format it as code. And if there are German texts you should translate them if it’s necessary to understand the error.

Have a nice Weekend. :love_you_gesture:t4:

Many thanks for exhausting feedback and helpful links.

Please allow for two general remarks:

  1. There ist an optimal und a real world. In the real world I am unable to migrate from my wll-proofen and hardenend batch fossils (260 MB of code) in one step to Powershell. So I decided to do it step by step as time allows and funrionality implies.
  2. Most of my code snippets I got from Google contributions and a a PS beginner it is difficult to decide if they are “well” progammed. Insted I was glad they were working.

Naming conventions: Read, understood and done
Spaces in text concatenations : Read, understood and done
Scope of global variables: I am used to use global variables. In my case I forogt to declare them as such. Do not use in PS?
No need of psexec: I agree in the meantime
Terminating error / -ErrorAction Stop: Read, understood and done
try-catch block only for particular action: Read, understood and done
Calling batch file: Read, understood and done
Retrncode “0”: I used it bacause the respective function should return either a string or a value showing negative result: Better use a string like “false”?
All this white space: Makesr reading the code (for me) easier as f.e. all out.-file-statements are in the same position.
Inside strings you have to use the subexpression operator to properly expand object properties: Read, understood and done
I do use ASCII (not ANSI) for better compartibility between PS and batch - Switch to UTF?
Posting images: Quite clear but unfortunately I had no example of output except printout available.

Next (:slight_smile:) question on error-handling: In which cases (every catch-section?) should I use error.clear()?

Thanks again - Michael

1 Like

A general remark from me: You don’t have to justify yourself here at all. Of course you are allowed to have your own opinion and your own style and use whatever part of my suggestions you like. … or nothing at all … it’s up to you and I’m fine with that as well. They are suggestions - not lawful orders. :wink:

Actually - if this code does its job it does not make sense to migrate at all unless you have to change it anyway. :man_shrugging:t4:

There is a lot of crappy code out there - I know that. But shouldn’t I point out if there is room for improvement? :thinking: :smirk: :slight_smile:

:+1:t4: :+1:t4: :love_you_gesture:t4: :smiling_face_with_three_hearts:

If you know what you’re doing it’s fine. Sometime there’s no easy way around it - I know. :man_shrugging:t4: But in general I’d try to avoid them. It usually makes your code more easily re-usable. Especially when you write functions you should avoid to use external variables inside functions. The better approach would be to provide all necessary properties as parameters and output all properties created or modified by the function as return values.

That’s actually a matter of personal style or company or team rules if there are some. I just wanted to point out that it could be confusing depending on your expectation how things should work.

If you want to return a true or false don’t do it as a [STRING] - do it as a proper [BOOLEAN] with $true or $false. You may enrich the return object with additional properties. You could return the final status $true or $false AND the return code from the setup exectuable for example. :wink:

That’s - again - of course your own decission. But using that large amount of white space and long lines makes your code at least here in the forum very hard to read. And - especially when it comes to repetitive code there are usually better options like loops or functions.

If you need extensive logging you may take a look at some frameworks like

There you have a lot of already built in options you can choose from. Like log files, event log, data bases or whatever …

I’d suggest that because since you are obviously from Germany there may be some Umlaute from time to time and it just looks ugly if they appear as square brackets or small rectangles. :man_shrugging:t4:

I actually don’t have an opinion on that at all. If you benefit from it or if it has any advantages for you - do it. If not - leave it. :man_shrugging:t4:

Cheers

Thanks!

How to " return the final status $true or $false AND the return code from the setup exectuable"?

Michael

function Get-ResultObject {
    [PSCustomObject]@{
        InstallExitCode = 1603
        InstallExitText = 'A fatal error occurred during installation.'
        InstallStatus   = $false
    }
}

If you run the function you get this

InstallExitCode InstallExitText                             InstallStatus
--------------- ---------------                             -------------
           1603 A fatal error occurred during installation.         False

But you could assign theresult to a variable:

$Result = Get-ResultObject

And use the object later on … like this:

'The installation returned the exit code: {0}' -f $Result.InstallExitCode

Or you could check the status in an if statement for example:

if ($Result.InstallStatus) {
    'cool'
}Else{
    'uncool'
}

Thanks! But: I need the resultcode in batch and thus my only chances seem to be:

  • “0” |
  • resultfile
    In the best world (only PS) this problem will not exist.
    Michael

True. :man_shrugging:t4:

And my comment …

was actually only about the “PowerShell world”.

How do you do in batch? I’d assume you use this one return code you created and evaluate it, right? So for now you’d need to use this one return code you need for batch as exit code for the PowerShell script. But that does not mean you have to limit the new functions you create in your new PowerShell scripts to this one return code. That’s what I meant.

I totally understand and agree. Now it’s time to learn (f.e. from the links you sent to me).

Michael