invoke-expression doesnot throw an error in powershell - powershell

I am creating custom forms and adding it to the printer server properties using forms.vbs and running it through cmd. The script is as follows
cscript 'C:\Tools\forms.vbs' -a -n "DD" -u inches -h 7.48 -w 7.48 -t 0 -e 0 -b 7.48 -r 7.48
This works fine when running in command prompt.
Now I invoked this code to the powershell as follows and it also works fine
$formname = "DD"
$cmd = "cscript 'C:\Tools\forms.vbs' -a -n " + '"' + $formname + '"' + " -u inches -h 7.48 -w 7.48 -t 0 -e 0 -b 7.48 -r 7.48 "
Invoke-Expression $cmd
The issue started when I thought of checking the error handling thing for the powershell invoke expression.
In cmd when we give the expression as
cscript 'C:\Tools\forms.vbs' -a -n "DD" -u inches -h 7.48 -w 7.48 -t 0 -e 0 -b 0 -r 0
This will definitely throw error as per the notes given in the form.vbs and it will not create a form.
So when I invoked the same error-thrown script to my powershell, the form is not creating as well as it is not throwing any errors. So I request me to guide in this regard. Thanks in advance.

Invoke-Expression only checks if it's possible to run the command at all. For example, if cscript.exe cannot be found, Invoke-Expression will throw an ObjectNotFound exception.
It doesn't check the exit code of the command or in any way parse its output. You should be able to see the output however.
Make sure you don't mix single and double quotes inside your expression:
$formname = "DD"
# Note double quotes around C:\Tools\forms.vbs
$cmd = 'cscript "C:\Tools\forms.vbs" -a -n ' + '"' + $formname + '"' `
+ ' -u inches -h 7.48 -w 7.48 -t 0 -e 0 -b 7.48 -r 7.48 '
Invoke-Expression $cmd
Output:
Microsoft (R) Windows Script Host Version 5.8
Copyright (C) Microsoft Corporation. All rights reserved.
Unable to add form DD, error code: 0x1A8. Object required
If you want your code to throw an exception, you need to parse the output manually, e.g.:
try {
$output = Invoke-Expression $cmd
if ($output -like "*error code*") { throw $output }
}
catch [System.Exception] {
$message = ($Error[0].Exception -split [System.Environment]::NewLine)[-1]
$message
}
Output:
Unable to add form DD, error code: 0x1A8. Object required

I have been using Start-Process to manage installs and uninstalls, and recently started using the same approach for arbitrary executables, which seems to be somewhat what you are trying to do, so...
$new.ExitCode > $null
$filepath = 'cscript.exe'
$argumentList = "C:\Forms.vbs"
$exitCode = (Start-Process -FilePath:$filePath -argumentList:$argumentList -wait -errorAction:Stop -PassThru).ExitCode
$exitCode
The VBS just throws up a messagebox and quits with a return code, like so.
MsgBox "Text"
WScript.Quit 4
After I close the message box I get that 4 back at the PowerShell console. With no Wscript.Quit, or no exit code provided, I get the expected 0 back.
Simple example, but maybe gets you close, assuming you can get the error code you need into a variable so you can return it from the VBS. Or maybe someone points out some nuance I am not aware of and we both learn something. ;)

Related

Passing piped commands via SSH

I'm using the Powershell module Posh-SSH to ssh into an Ubuntu server and run commands. I'm not having any difficulty passing simple lines such as:
$sshSession = New-SSHSession -ComputerName server001 -Credential $credential
$sshStream = New-SSHShellStream -Index $sshSession.sessionID
$sshStream.WriteLine("history")
$sshStream.Read()
The last line outputs exactly what it's supposed to. I want to run the following on the server:
for guest in `nova list --all-tenants --host serverName | grep Shutdown | awk '{ print $2 }'`; do nova start $guest; sleep 5; done"
Pasting this line right into $sshStream.WriteLine("") doesn't work at all as ` is an escape character in Powershell and $'s are used for variables already. I attempted to work around this by escaping some characters and putting it into a variable:
$block = "for guest in ``nova list --all-tenants --host server001 | grep Shutdown | awk '{ print `$2 }'`; do nova start `$guest; sleep 5; done"
$sshStream.WriteLine("$block")
$sshStream.WriteLine($block)
Both of my attempts above do not get read properly on the server. Any idea how I can work around this or if there's a better way to do this?
Thanks in advance
As TessellatingHeckler suggested, I used single-quotes and it worked:
$block = 'for guest in `nova list --all-tenants | grep Shutdown | awk ''{ print $2 }''`; do nova stop $guest; done'
$sshStream.WriteLine($block)
Try this
$block = #"
for guest in ``nova list --all-tenants --host server001 | grep Shutdown | awk '{ print `$2 }'`; do nova start `$guest; sleep 5; done
"#
$sshStream.WriteLine($block)
It will treat the "block" as a literal string (i.e. no escaping).

Can't figure out how to properly execute exe with arguments

So I have been trying to write a script where I run an executable with arguments to return some information I need for our monitoring. Not long ago I have written a script that successfully managed to do that, using the following command:
$command = "-t vtl -p {1} -m {0} -s"
$check = Invoke-Expression -command ("$exemap\$exe $command" -f $server,$poort)
This worked perfectly. However I am in the process of writing a new script and the exact same thing does not seem to be working anymore. Here is a script I have to reproduce the problem:
$omgeving = "A"
$exemap = "\\cfc01.corp\rpa-{0}\Scripts\Check_actualiteit_RPA" -f $omgeving
#$exe = "echoargs.exe"
$exe = "stmmon.exe"
$exepath = "$exemap\"+"$exe"
$commando = "-t {0} -p {1} -m {2} -s"
$poort = "5062"
$berichttype = "VTL"
$server = "rpa-a-ap001"
$command = ($commando -f $berichttype,$poort,$server) -split " "
#$command = "-t VTL -p 5062 -m rpa-a-ap001 -s"
& $exepath $command
So I have negated some lines that are there for troubleshooting. I have tried using the Invoke-Expression command above and using the & operator. I have googled and tried a lot. I have tried using jobs and Invoke-Command. But all of them have the same result, an explanation from the exe telling me how to use it:
Usage: \\cfc01.corp\rpa-A\Scripts\Check_actualiteit_RPA\stmmon.exe [-v] [-h] -t <type> -p <port> -m <machine> -k <key> [-s]
This makes me believe that the executable is not really acknowleding any arguments. I tried using echoargs and the output from the script above is:
Arg 0 is <-t>
Arg 1 is <VTL>
Arg 2 is <-p>
Arg 3 is <5062>
Arg 4 is <-m>
Arg 5 is <rpa-a-ap001>
Arg 6 is <-s>
Or, if I dont use the -split " " in the $command variable, the echoargs is this:
Arg 0 is <-t VTL -p 5062 -m rpa-a-ap001 -s>
The script above may not be very dynamic, but the actual script im trying to make is going to be. The argumentlist should be configurable and dynamic, which is why im using the -f command on different occasions.
Can anyone see what I am doing wrong here and why the executable won't even acknowledge the existence of arguments?
Use the call operator (&) for running external commands. Use Join-Path for building paths. Use splatting for passing arguments to a program or function.
$omgeving = "A"
$exemap = "\\cfc01.corp\rpa-$omgeving\Scripts\Check_actualiteit_RPA" -f
$exe = "stmmon.exe"
$exepath = Join-Path $exemap $exe
$params = '-t', 'VTL',
'-p', 5062,
'-m', 'rpa-a-ap001',
'-s'
& $exepath #params
Also, judging from the help output, you seem to be missing a required parameter:
Usage: \\...\stmmon.exe [-v] [-h] -t <type> -p <port> -m <machine> -k <key> [-s]
If everything else fails, try this as a workaround:
$type = 'VTL'
$port = 5062
$server = 'rpa-a-ap001'
& cmd /c ('"{0}" -t {1} -p {2} -m {3} -s' -f $exepath, $type, $port, $server)
I am sorry to have wasted people's time here.
I have discovered the problem here. Apparently the 'type' arguments does not allow capital letters. I had not yet tried to change those, but it seems to have fixed the issue.

Differences in calling CSVDE from Powershell vs Command Prompt

Can anyone explain why calling the CSVDE utility from an elevated Windows command prompt would differ than using the same string from an elevated Powershell console? The issue I have is that I can successfully export from Active Directory via the command prompt method, but Powershell returns an authentication error, "Simple bind returned 'Invalid Credentials'.
Here is the command used for both, edited for sensitive pieces:
c:\csvde.exe -s domain.company.org -f ExportFile.csv -l "givenName,sn,ipPhone,title,department,company,physicalDeliveryOfficeName,mail" -d "OU=ABC Group,OU=ABC Users,DC=DomainName,DC=org" -a UserDistinguishedName Password
Both sessions are running with Administrator privileges. I am a Powershell novice, and for the life of me, I can't figure this out.
Thanks!
I can see two potential issues. First thought is that it is taking your user name and password as separate arguments, or as Adi Inbar suggested: you've got some special characters that are causing issues. Either way I'd enclose things in single quotes so that arguments are passed as expected, and taken literally.
c:\csvde.exe -s 'domain.company.org' -f 'ExportFile.csv' -l 'givenName,sn,ipPhone,title,department,company,physicalDeliveryOfficeName,mail' -d 'OU=ABC Group,OU=ABC Users,DC=DomainName,DC=org' -a 'UserDistinguishedName' 'Password'
See if that doesn't resolve the issue. In my experience that is usually a safe way to run a executable from PowerShell. I suppose alternatively you can assign them to variables, and then pass those.
$Server = 'domain.company.org'
$OutFile = 'ExportFile.csv'
$Attributes = 'givenName,sn,ipPhone,title,department,company,physicalDeliveryOfficeName,mail'
$SearchRoot = 'OU=ABC Group,OU=ABC Users,DC=DomainName,DC=org'
$UserID = 'CN=TMTech,OU=Users,DC=Some,DC=Company,DC=org'
$Password = 'P#$$w0rd'
CSVDE.exe -s $Server -f $OutFile -l $Attributes -d $SearchRoot -a $UserID $Password

Start process with args which contains a path with blanks

I need to start a process from a powershell script and pass such params :
-a -s f1d:\some directory\with blanks in a path\file.iss
to do that, I write the folowing code :
$process = [System.Diagnostics.Process]::Start("$setupFilePath", '-a -s -f1"d:\some directory\with blanks in a path\fileVCCS.iss"')
$process.WaitForExit()
as a result the process starts but the last argument : -f1d:\some directory\with blanks in a path\file.iss
is not passing correctly. Help, please
I think you can use Start-Process:
Start-Process -FilePath $setupFilePath -ArgumentList '-a','-s','-f1"d:\some directory\with blanks in a path\fileVCCS.iss"' |
Wait-Process
I understand your question to be:
How to pass multiple arguments to start a process where one of the arguments has spaces?
I'm assuming the equivalent in a Windows batch file would be something like:
"%setupFilePath%" -a -s -f1"d:\some directory\with blanks in a path\fileVCCS.iss"
where the double quotes allow the receiving process (setupFilePath in this case) to receive three arguments:
-a
-s
-f1"d:\some directory\with blanks in a path\fileVCCS.iss"
To accomplish this with the code snippet in your question I would use back ticks (to the left of the 1 and below the escape key, not to be confused with a single quote; aka Grave-accent) to escape the inner double quotes like this:
$process = [System.Diagnostics.Process]::Start("$setupFilePath", "-a -s -f1`"d:\some directory\with blanks in a path\fileVCCS.iss`"")
$process.WaitForExit()
Note that in addition to using back ticks I also changed the single quotes around your argument list to double quotes. This was necessary because single quotes do not allow the escapes we need here (http://ss64.com/ps/syntax-esc.html).
Aaron's answer should work just fine. If it doesn't then I would guess that setupFilePath is not interpretting -f1"d:\space here\file.ext" as you expect it to.
OPINION ALERT The only thing I would add to his answer is to suggest using double quotes and back ticks in order to allow using a variable within the path for argument -f1:
Start-Process -FilePath $setupFilePath -ArgumentList '-a','-s',"-f1`"$pathToVCCS`"" |
Wait-Process
This way you won't have a hard-coded, absolute path in the middle of a long line.
On PowerShell v3, this works:
& $setupFilePath -a -s -f1:"d:\some directory\with blanks in a path\fileVCCS.iss"
Using the PSCX echoargs command shows this:
25> echoargs.exe -a -s -f1"d:\some directory\with blanks in a path\fileVCCS.iss"
Arg 0 is <-a>
Arg 1 is <-s>
Arg 2 is <-f1d:\some directory\with blanks in a path\fileVCCS.iss>
Command line:
"C:\Program Files (x86)\PowerShell Community Extensions\Pscx3\Pscx\Apps\EchoArgs.exe" -a -s "-f1d:\some directory\with blanks in a path\fileVCCS.iss"
On V2 use - note the addition of a backtick on the last double quote:
PS> echoargs.exe -a -s -f1"d:\some directory\with blanks in a path\fileVCCS.iss`"
Arg 0 is <-a>
Arg 1 is <-s>
Arg 2 is <-f1d:\some directory\with blanks in a path\fileVCCS.iss>
Command line:
"C:\Program Files (x86)\PowerShell Community Extensions\Pscx3\Pscx\Apps\EchoArgs.exe" -a -s -f1"d:\some directory\with blanks in a path\fileVCCS.iss"

Perl Syntax Error: bareword found where operator expected

This is my perl script code. in this i'm getting error like "bareword found where operator expected at $cmd"
my $path = $folder."/".$host."_".$database_name.".bak";
$cmd .= "-U $user_name -P $password -S $host -d master -Q "BACKUP DATABASE [$database_name] TO DISK = N'$path'" ";
any one help me?
When a string has double quotes within it, you need to escape them with \.
$cmd .= "-U $user_name -P $password -S $host -d master -Q \"BACKUP DATABASE [$database_name] TO DISK = N'$path'\" ";
Also, Perl lets you use other characters for quote delimiters. qq followed by almost any character is the same as double quotes. So you could do things like this to avoid the need of backslashes:
$cmd .= qq(-U $user_name -P $password -S $host -d master -Q "BACKUP DATABASE [$database_name] TO DISK = N'$path'" );
$cmd .= qq|-U $user_name -P $password -S $host -d master -Q "BACKUP DATABASE [$database_name] TO DISK = N'$path'" |;
And so on...
Update: How to execute a system command in Perl. There are three basic ways:
system($cmd); #Goes through the shell if shell metacharacters are detected.
system(#command_and_args); #first element is the command, the rest are arguments
system executes a command and waits for it to return. The return value is the exit status of the program.
my #results = `$cmd`; #Always goes through shell.
Backticks execute a command and return its output. You should only use this if you actually need the output; otherwise, it is better to go with system.
exec $cmd;
exec #command_and_args;
exec is exactly like system, except that it never returns. It effectively ends your program by calling another program.
Use the one that is most appropriate to your situation. Or in this case, since you are executing SQL, consider using the DBI module. It's definitely a better approach for anything more than a couple of simple commands.
Looks like you have your " characters in the wrong place. I'm not sure where they should be.
In your second line, the string literal:
"-U $user_name -P $password -S $host -d master -Q "
is immediately followed by the bareword
BACKUP