1

I'm trying to run a query with a FOR loop and have each resulting variable line of the query output into it's own file.

I can't seem to get the delayed expansion variables to behave the way I want them to.

Basically I'm querying the printers installed on a print server and I want a .bat job containing certain text with the result output to multiple files containing the result name.

I think the problem is I'm not escaping some characters correctly, or I'm missing a % or ! on a variable, or some combination thereof.

@echo off
setlocal enabledelayedexpansion
FOR /F "tokens=1 delims=*" %%G IN ('wmic /node:PRINTSERVER printer get name') DO (

    SET printer=%%G
    SET printers=!printers: =!
    SET printers=!printers:Name=!
    ECHO ^(
        @ECHO OFF
        ECHO PLEASE WAIT WHILE YOUR PRINTER IS INSTALLED
        ECHO.
        ECHO ^"%windir%\system32\cscript %windir%\system32\prnmngr.vbs -ac -p \\PRINTSERVER\!printer!"^)>>!printer!.bat
)

endlocal

Expected results should be multiple files named PRINTERSHARENAME.bat

Each which contains:

@ECHO OFF
ECHO PLEASE WAIT WHILE YOUR PRINTER IS INSTALLED
ECHO.
%windir%\system32\cscript %windir%\system32\prnmngr.vbs -ac -p "\\PRINTSERVER\PRINTERSHARENAME"

EDIT

I will share more of my code. the wmic output contains spaces that had to be stripped, so this is why I used enabledelayedexpansion

EDIT2

Here is the output of my wmic command (Note that there are trailing spaces I've stripped out in the above code and the word 'Name' and a blank line at the end of the command):

C:\Users\bleepbloop>wmic /node:PRNTSVR printer get name
Name
PRINTER1                          
PRINTER2                              
OFFICEPRINTER                        

EDIT3

OK, I'm getting close. Here is code to reproduce, using an answer below:

(
echo Here is my first line
echo Here is my second line
echo Here is my third line
)>"textfile.txt"

FOR /F "delims=" %%G IN ('TYPE textfile.txt') DO (
    (
        ECHO @ECHO OFF
        ECHO ECHO PLEASE WAIT WHILE YOUR PRINTER IS INSTALLED
        ECHO ECHO.
        ECHO "%%windir%%\system32\cscript" "%%windir%%\system32\prnmngr.vbs" -ac -p \\PRINTSERVER\%%G
    )>%%G.bat
)

This works as expected and gives me 3 files named

Here is my first line.bat
Here is my second line.bat
Here is my third line.bat

however now I want to strip out all spaces from the variables output by textfile.txt, and for that I think I need to use delayed expansion?

So I want:

Hereismyfirstline.bat
Hereismysecondline.bat
Hereismythirdline.bat

I think I need to do this by using enabledelayedexpansion and inserting the following in the FOR loop:

SET variable=%%G
SET variable=!variable: =!

and then I have to insert the variable back into the loop properly. Still not sure how.

I want the file

Hereismyfirstline.bat

to contain

@ECHO OFF
ECHO PLEASE WAIT WHILE YOUR PRINTER IS INSTALLED
ECHO.
"%windir%\system32\cscript" "%windir%\system32\prnmngr.vbs" -ac -p \\PRINTSERVER\Hereismyfirstline

and the next file

Hereismysecondline.bat

to contain:

@ECHO OFF
ECHO PLEASE WAIT WHILE YOUR PRINTER IS INSTALLED
ECHO.
"%windir%\system32\cscript" "%windir%\system32\prnmngr.vbs" -ac -p \\PRINTSERVER\Hereismysecondline
bleepbloop
  • 41
  • 1
  • 6

2 Answers2

1

I suggest this batch code for this task:

@echo off
setlocal EnableExtensions DisableDelayedExpansion
for /F "skip=1 eol=| tokens=*" %%I in ('%SystemRoot%\System32\wbem\wmic.exe /node:PRINTSERVER printer get name 2^>nul') do (
    for /F "eol=| delims=   " %%J in ("%%I") do (
        set Printer=%%~nxJ
        if defined Printer (
            echo @echo off
            echo echo PLEASE WAIT WHILE YOUR PRINTER IS INSTALLED
            echo echo/
            echo "%%SystemRoot%%\system32\cscript.exe" "%%SystemRoot%%\system32\prnmngr.vbs" -ac -p "\\PRINTSERVER\%%~nxJ"
        )>"%%~nxJ.bat"
    )
)
endlocal

Note: After delims= on second for command line must be a horizontal tab character and not one or more spaces as displayed by the web browsers according to HTML standard for the tab character.

Processing output of wmic is problematic because of this application outputs data always Unicode encoded using UTF-16 Little Endian encoding and for has a quirks on processing this Unicode output correct. For more details see for example How to correct variable overwriting misbehavior when parsing output?

The outer for processes the output of wmic with skipping first line containing heading Name. For all other non-empty lines all leading normal spaces and horizontal tabs are removed before assigning the rest of the line to specified loop variable I even on starting very unusual with a semicolon. | is not allowed in a printer name, but ; would be allowed although having never seen a printer name starting with ;.

The inner for with horizontal tab character as delimiter processes the printer name which can contain one or more spaces, but not a tab character. The printer name with all trailing horizontal tabs removed is assigned to specified loop variable J.

The remaining string is the printer name with trailing normal spaces. Windows prevents usually the creation of a file with trailing spaces. For that reason is assigned to environment variable Printer with using %%~nxJ just the printer name without trailing spaces. But spaces inside the printer name are kept by this command.

A single carriage return caused by the for quirks on processing of output of wmic results in getting environment variable Printer deleted instead of being defined with the carriage return.

So if the environment variable Printer is really defined with a printer name containing no, one or even more spaces, but no leading spaces/tabs and no trailing spaces/tabs, the batch file can be created with using printer name as assigned to loop variable J in batch file and in batch file name using %%~nxJ.

So there is no delayed environment variable expansion needed which makes this batch file working also for a printer name containing an exclamation mark.

See also DosTips forum topic ECHO. FAILS to give text or blank line - Instead use ECHO/ for the reason writing into the created batch files echo/ instead of echo..

This batch code uses delayed expansion inside the inner loop to remove all spaces from printer name for the batch file name.

@echo off
setlocal EnableExtensions DisableDelayedExpansion
for /F "skip=1 eol=| tokens=*" %%I in ('%SystemRoot%\System32\wbem\wmic.exe /node:PRINTSERVER printer get name 2^>nul') do (
    for /F "eol=| delims=   " %%J in ("%%I") do (
        set "Printer=%%~nxJ"
        if defined Printer (
            setlocal EnableDelayedExpansion
            set "BatchFileName=!Printer: =!"
            (
                echo @echo off
                echo echo PLEASE WAIT WHILE YOUR PRINTER IS INSTALLED
                echo echo/
                echo "%%SystemRoot%%\system32\cscript.exe" "%%SystemRoot%%\system32\prnmngr.vbs" -ac -p "\\PRINTSERVER\!Printer!"
            )>"!BatchFileName!.bat"
            endlocal
        )
    )
)
endlocal

It is absolutely no problem to run a batch file with one or more spaces in file name on enclosing entire batch file name in double quotes like any other file/folder name containing a space or one of these characters &()[]{}^=;!'+,`~. But this second batch file code demonstrates that it is possible to create the batch files with no spaces in file name while exclamation marks in printer name are nevertheless processed correct.

This code is slower than first code because of usage of setlocal and endlocal inside the loop. Read this answer for details about the commands setlocal and endlocal and what happens on every usage of these two commands in background making the second variant slower than the first variant.

Note: The printer name inside the batch file is with spaces. Just the batch file name is without spaces. But that can be easily changed if needed.

Mofi
  • 46,139
  • 17
  • 80
  • 143
  • This batch file doesn't do anything for me, and doesn't output any files, but you've been very helpful and I did learn some things. I also tried removing the wmic command and used 'type textfile.txt' in that space where textfile.txt contains 3 lines of text with spaces, and the second 2 lines were output as .bat files and the first line was not. I suspect that you are on the right track with the wmic encoding causing an issue as I've gotten other errors while trying to process wmic output that I have not gotten on normal text files. Thx for your help, ill find names another way. – bleepbloop Aug 08 '19 at 19:38
0

Parenthesis can group commands, but not split arguments. So, instead of ECHO (..., do:

    SET printer=%%G
    (
        ECHO @ECHO OFF
        ECHO ECHO PLEASE WAIT WHILE YOUR PRINTER IS INSTALLED
        ECHO ECHO.
        ECHO ^"%windir%\system32\cscript %windir%\system32\prnmngr.vbs -ac -p \\PRINTSERVER\!printer!"
    )>!printer!.bat

Replaced >> with > which will create new files for each printer, instead of appending more commands to existing files.

Noticed also you don't need delayed expansion, and probably "delims=" is more adequate. Overall, your code may be rewritten as:

FOR /F "delims=" %%G IN ('wmic /node:PRINTSERVER printer get name') DO (
    (
        ECHO @ECHO OFF
        ECHO ECHO PLEASE WAIT WHILE YOUR PRINTER IS INSTALLED
        ECHO ECHO.
        ECHO "%%windir%%\system32\cscript" "%%windir%%\system32\prnmngr.vbs" -ac -p \\PRINTSERVER\%%G
    )>%%G.bat
)
LS_ᴅᴇᴠ
  • 10,823
  • 1
  • 23
  • 46
  • This code works with 'type filename.txt' however not with the wmic command because there are spaces that have to be stripped from the output. That's why i think I need enabledelayedexpansion is to strip the spaces. Please see my question edits and I've clarified a lot. Thanks for sharing this, it's helped me get farther, but not quite there yet. – bleepbloop Aug 08 '19 at 18:30