I'm trying to run a command line argument through VB.NET using the Shell() command.
I'm trying to use this piece of code:
FOR /R %I in (*.pdf) DO #pdf2swf.exe "%~fI" -o "%~dpI%~nI.swf" -f -T 9
-t -G
Using this:
Shell("FOR /R %I in (*.pdf) DO #pdf2swf.exe "%~fI" -o "%~dpI%~nI.swf" -f -T 9
-t -G ")
However, the interpreter is giving me this error:
Character is not valid. (BC30037)
For the %~ part.
I also tried created a string and passing the argument to the Shell() command by using Shell(StringName) but I still get the same error in the string.
How could I fix this issue?
This is not proper use of the Shell Method:
Public Shared Function Shell (PathName As String, [...]) As Integer
Parameters
PathName
Type: System.String
Required. String. Name of the program to execute, together with any required arguments and command-line switches. PathName can also include the drive and the directory path or folder.
The first parameter is supposed to be the name of a program to execute. FOR is not a program, it's a built-in feature of the cmd.exe command line interpreter.
As far as I can see, you have the following options:
Option 1: Explicitly call cmd.exe and pass the string that you want to execute with the /c parameter:
Shell("cmd.exe /c for /R %I ...")
Don't for get to duplicate quotation marks (") to escape them.
Option 2: Create a batch file and call the batch file using Shell.
Option 3: Don't use FOR to find the files you need, but use the methods of the System.IO namespace, e.g. Directory.EnumerateFiles, instead.
Escape your internal quote marks like this.
Shell("FOR /R %I in (*.pdf) DO #pdf2swf.exe ""%~fI"" -o ""%~dpI%~nI.swf"" -f -T 9 -t -G ")
As I recall, in VB.Net you escape double quote marks by doubling them.
EDIT:
It might help if you do the iteration outside of the Shell. (Certainly to debug)
Dim sourceFolder As String = "c:\Your call"
Dim sourceFiles As String[] = Directory.GetFiles(sourceFolder, "*.pdf")
ForEach file As String In sourceFiles
Dim justName As String = Path.GetFileNameWithoutExtension(file)
Dim shellCall As String = _
String.Format("pdf2swf.exe ""{0}"" -o ""{1}.swf"" -f -T 9 -t -G", _
file, justName)
Shell(shellCall)
EndFor
You could also cosider using System.Diagnostics.Process instead of Shell
Try escaping the quotes (2 quote marks - "" - in VB.NET, IIRC):
Shell("FOR /R %I in (*.pdf) DO #pdf2swf.exe ""%~fI"" -o ""%~dpI%~nI.swf"" -f -T 9 -t -G ")
If pdf2swf.exe is not in the same folder your program's executable is running from, that could be a reason you're getting the error.
Also, you'll have the same issue with the *.pdf files if they are in a different folder other than where your executable is. You can specify the drive and path to search:
Shell ("FOR /R C:\SomeFolder %I in (*.pdf) DO #pdf2swf.exe ""%~fI"" -o ""%~dpI%~nI.swf"" -f -T 9 -t -G ")
Related
I have looked at many SO questions/answers and though some seem similar to my issue they do not seem to be. The answers given fix issues the questions were asking about but will not solve my issue.
I have a batch file...
#ECHO ON
ECHO Disabling the following... >> C:\App\Debug.log
ECHO - V1 >> C:\Apps\Debug.log
FOR /F "tokens=* USEBACKQ" %%F IN (`sqlcmd -j -S DOMAIN\SQLSERVER -U username -P password -d DBNAME -Q "UPDATE [DBNAME].[dbo].[table1] SET ColOne='V1_OFF' WHERE ColOne='V1'"`) DO (
Echo %%F >> C:\Apps\Debug.log
)
EXIT /B
When I run this file at the command prompt it works perfectly fine. When I run it as a scheduled task it show me the echos but nothing for the for loop as expected.
Yes I have made sure the username (using whoami) is the same for the scheduled task set up as the manual run that I do.
Yes I know the user running the script has rights to everything (file access as well as DB access) because it works fine running it from the command prompt.
Scheduled task is set to run wither user is logged on or not.
Any ideas what might be wrong or what I can try for debugging purposes?
Thanks!
sqlcmd is perhaps not enough. cmd.exe in environment of scheduled task may fail to find the executable using local PATHEXT and local PATH environment variables. The executable should be specified with full qualified file name, i.e. drive + path + name + extension. Then the batch file does not anymore depend on the environment variables PATH and PATHEXT because of all files are referenced with full qualified file name.
for executes the specified command line with starting in background one more command process with %ComSpec% /c and the specified command line appended. This means executed is following with Windows installed on drive C::
C:\Windows\System32\cmd.exe /c sqlcmd -j -S DOMAIN\SQLSERVER -U username -P password -d DBNAME -Q "UPDATE [DBNAME].[dbo].[table1] SET ColOne='V1_OFF' WHERE ColOne='V1'"
for captures everything written to handle STDOUT of started command process. The lines of captured output are processed line by line by for after started cmd.exe terminated itself. Error messages output by started cmd.exe or the commands/executables executed by Windows command processor in background to handle STDERR are redirected to handle STDERR of command process processing the batch file and printed to console. But there is no console window on running a batch file as scheduled task. So error messages cannot be seen in this case.
The for command line can be modified easily here to get also error messages written into the C:\Apps\Debug.log.
FOR /F "tokens=* USEBACKQ" %%F IN (`sqlcmd -j -S DOMAIN\SQLSERVER -U username -P password -d DBNAME -Q "UPDATE [DBNAME].[dbo].[table1] SET ColOne='V1_OFF' WHERE ColOne='V1' 2^>^&1"`) DO (
The Microsoft article Using command redirection operators explains 2>&1. The two operators > and & must be escaped with ^ to be interpreted as literal characters on Windows command processor parsing the for command line before executing finally for which executes next %ComSpec% /c with the specified command line on which 2^>^&1 is changed already to 2>&1.
Does the log file C:\App\Debug.log contain with this modification following two lines?
'sqlcmd' is not recognized as an internal or external command,
operable program or batch file.
Yes, then no executable with file name sqlcmd is found by started cmd.exe. The best solution is referencing this executable with full qualified file name. See also: What is the reason for "X is not recognized as an internal or external command, operable program or batch file"?
Otherwise sqlcmd outputs perhaps an error message which should be now also in the log file C:\App\Debug.log.
It would be also possible to use following command line to let background cmd.exe write the error messages into a separate error log file C:\App\Error.log:
FOR /F "tokens=* USEBACKQ" %%F IN (`sqlcmd -j -S DOMAIN\SQLSERVER -U username -P password -d DBNAME -Q "UPDATE [DBNAME].[dbo].[table1] SET ColOne='V1_OFF' WHERE ColOne='V1'" 2^>C:\App\Error.log`) DO (
"tokens=* usebackq" results in first deleting all leading horizontal tabs and normal spaces on non-empty lines by for, then checking if the remaining line starts with ; in which case the line is also ignored and finally assigning the captured line not starting with ; and with leading tabs/spaces removed to loop variable F for further processing.
Better would be using the options usebackq^ delims^=^ eol^= not enclosed in double quotes which requires escaping the two spaces and the two equal signs with caret character ^ to be interpreted as literal characters by cmd.exe on parsing the command line before executing for. The line splitting behavior is disabled completed with delims= because of the definition of an empty list of delimiters. And no line except an empty line is ignored anymore because of end of line character modified from default ; to no character.
Finally a space on an echo line left to redirection operator >> is also output by echo and for that reason written as trailing space into the log file. Therefore no space should be used left to > or >> on printing a line with echo redirected into a file. But care must be taken on omitting the space character left to the redirection operator. The word left to redirection operator should not be 1, 2, ..., 9 as this would result in redirecting the output to these numbered handles into the specified file instead of the character 1, 2, etc. So if unknown text should be written into a file, it is better to specify first the redirection operator > or >> and the full qualified file name and next the echo command with the text to output. See also: Why does ECHO command print some extra trailing space into the file?
The three command lines with echo would be for this batch file:
ECHO Disabling the following...>> C:\App\Debug.log
ECHO - V1>> C:\Apps\Debug.log
>>C:\Apps\Debug.log ECHO %%F
following... is safe for being correct written into the file as also V1. %%F could be just 1 or a string ending with a space and a single digit and so it is better to specify the redirection first on the last echo command line to get finally executed by cmd.exe the command line ECHO %%F 1>>C:\Apps\Debug.log.
This question already has answers here:
CMake's execute_process and arbitrary shell scripts
(3 answers)
Closed 5 years ago.
I wanted to extract a string from a header in an execute_process.
But there is a bug with the command and I try a lot of things, always the same error.
execute_process(
COMMAND cat $(version_h) | grep -a "define myVersion " | cut -d " " -f3 | cut -d '"' -f2`
OUTPUT_VARIABLE _Version)
If I write the command in the console line, there is no problem.
The error says: "Parse error. Function missing ending ")". Instead found unterminated string with text "
"
execute_process() only deals with processes and their arguments, i.e. there is no shell involved.
So, you have two main options:
execute_process(COMMAND bash -c "..." OUTPUT_VARIABLE _Version)
execute_process(COMMAND cat ... COMMAND grep ... COMMAND cut ... COMMAND cut ... OUTPUT_VARIABLE _Version)
In the second version, the standard output and standard inputs of the commands chain together.
If you want to do anything more complex, you'll have to create a separate script and invoke it in a process-, not shell-, oriented way, i.e. option 1.
The problem was that I need to remove a quote character and I guess there is a confusion with Cmake and the bash command.
execute_process(COMMAND cat ... COMMAND grep ... COMMAND cut ... COMMAND cut -c2- COMMAND rev COMMAND cut -c2- COMMAND rev OUTPUT_VARIABLE _Version)
I am trying the following string in command prompt to execute some (test) remote commands on my server:
plink.exe -ssh -pw [PASSWD] [U/NAME]#[SERVER] -m cmds.bat -v
In my cmds.bat file I have some test commands:
sleep 3
#echo off
ls -la ~/
#echo on
sleep 1
I now want to beef this up to run a remote script while passing an argument. The argument will be handled and appended by my VBA code. This is the part I am stuck at. Please note the following VBA code is only a snippet; the part that calls Plink. The surrounding code, I am happy with:
If re.Test(Msg.Subject) Then
Set matchCol = re.Execute(Msg.Subject)
For Each match In matchCol
shellStr = "plink.exe -ssh [USERNAME]#[SERVER] -pw [P/WORD] -m cmds.bat " & match
Shell(shellStr, vbNormalFocus)
Next
End If
The offending line is:
shellStr = "plink.exe -ssh [USERNAME]#[SERVER] -pw [P/WORD] -m cmds.bat " & match
I do not know how to append the value held in variable match (captured by the Regexp) to the string to be executed in opening the shell.
The bat file will handle the command for actually running the script on the remote Unix server, where instead of ls -la ~/ in the above example I will use:
python ~/myscript.py [ARGUMENT FROM VBA VARIABLE "match"]
But how do I pass this match variable's value into this?
you cannot do this; plink just doesn't support this usage. your best bet is doing what you suggested in your comment: build the script on the fly. (and maybe don't call it .bat, that seems misleading a bit …)
Hi All I am Writing a Batch Script Which has to read a set of SQL Files which exists in a Folder then Execute Them Using SQLCMD utiliy.
When I am Trying to execute it does not create any output file. I am not sure where I am wrong and I am not sure how to debug the script. Can someone help me out with script?
#echo off
FOR %F IN (C:\SQLCMD*.SQL) DO sqlcmd -S LENOVO-C00 -U yam -P yam!# -i %F -o C:\SEL.txt -p -b
IF NOT [%ERRORLEVEL%] ==[0] goto get_Error
:Success echo Finished Succesffuly exit /B 0 goto end
:get_error echo step Failed exit /B 40
:end
If this is actually in a batch file (not being executed by hand at the command line), then the %F variables need to have the % characters doubled-up because of the way that cmd.exe executes the lines read from the batch file:
FOR %%F IN (C:\SQLCMD*.SQL) DO sqlcmd -S LENOVO-C00 -U yam -P yam!# -i %%F -o C:\SEL.txt -p -b
Though I would have thought you'd get a
F was unexpected at this time.
error if you only had one % character in front of the variable name.
Try to right click the Batch File and run as administrator.
Seems like the answer would be more like this:
FOR %%F "usebackq" IN (`dir.exe C:\SQLCMD*.SQL`) DO ...
I need a DOS command or a batch (.bat) file I can execute to run all the *.sql scripts in a directory and its subdirectories. What would the solution be?
The following will get you started
for /r %f in (*.sql) do echo %f
Run from the command line that will print the names of all the SQL files in the current directory and all sub directories.
Then substitute sqlcmd <connection args> -i%f for echo %f to execute the scripts.
Hope this helps.
Here you go. This batch file will execute all sql files in a directory and its subdirectories. It will also create an output.txt file with the results so you can see errors and whatnot. Some notes on batch file:
[YourDatabase] is the name of the database you want to execute the scripts against.
[YourPath] is the path of where you keep all the scripts.
[YourServerName\YourInstanceName] is the SQL server name and instance name, separated with a '\'
You'll want to replace the text after the '=' for each variable with whatever is appropriate for your server
Be sure NOT to put spaces around the '='
Do not put any quotes around [YourPath]
Make sure that [YourPath] has a '\' at the end
SET Database=[YourDatabase]
SET ScriptsPath=[YourPath]
SET ServerInstance=[YourServerName\YourInstanceName]
IF EXIST "%ScriptsPath%output.txt" del "%ScriptsPath%output.txt"
type NUL > "%ScriptsPath%output.txt"
FOR /R "%ScriptsPath%" %%G IN (*.sql) DO (
sqlcmd -d %Database% -S %ServerInstance% -i "%%G" -o "%%G.txt"
echo ..................................................................................... >> "%ScriptsPath%output.txt"
echo Executing: "%%G" >> "%ScriptsPath%output.txt"
echo ..................................................................................... >> "%ScriptsPath%output.txt"
copy "%ScriptsPath%output.txt"+"%%G.txt" "%ScriptsPath%output.txt"
del "%%G.txt"
)
for %f in ("c:\path\to\dir\*.sql") do sqlcmd -S [SERVER_NAME] -d [DATABASE_NAME] -i "%f" -b
Try a for loop. The options of this command have evolved and I'm not sure what version of DOS you are using, but assuming that DOS includes "cmd.exe from Windows XP", something like this could work:
for /r . %f in (*.sql) do #echo %f
Ok, this will only print the names of the files. I'm assuming you already have a program that you can run from the command line that will execute one SQL file, which you can use instead of echo.
For more information, try for /?.