【问题标题】:How should I use a batch script to create other scripts?我应该如何使用批处理脚本来创建其他脚本?
【发布时间】:2014-07-05 16:35:36
【问题描述】:

我正在创建一个我希望具有双重用途的脚本:

  1. 脚本将使用用户输入选项来执行命令以更改某些设置。这部分快完成了。

    • 该脚本通过SETLOCAL/ENDLOCALSET /P 将用户的选择收集到本地环境变量中,并稍后在脚本中调用这些变量以执行命令。

    • 收集用户选项后,有一个验证步骤会显示这些选项并在继续执行命令之前要求用户确认。

  2. 该脚本将为用户提供自动创建新脚本的选项,该选项内置了他们的选项,以方便日后使用。

这是我目前实现目标 2 的计划概念,虽然我不确定如何编写它:

  1. 构建可复制的模板脚本以开始创建自定义脚本。

    • 在模板脚本的最开始,SETLOCAL 将隔离由最终脚本创建的环境变量,以便在脚本完成运行后它们不会持续存在。

    • 紧跟在SETLOCAL 之后将是一个GOTO 命令,它指向脚本末尾的一个标签。标签将是已完成脚本中变量定义部分的开始。

    • GOTO 命令之后会是一个名为 STARTEXEC 的标签,在变量定义完成后将跳转到该标签。

    • 在变量部分标签之前将是一个带有一些命令的标签部分以退出脚本。

  2. 进入当前脚本:

    • 在验证步骤中添加CHOICE,询问用户是否愿意创建静态脚本。如果是,请通过SET /P 提示用户输入文件名,然后通过GOTO 在此脚本的执行流程中包含脚本构建命令。
  3. 使用一些类似的命令来构建静态脚本的变量部分:

    COPY ScriptTemplate.bat %UserFileName%.bat
    ECHO SET VAR1=%UserVar1% >> %UserFileName%.bat
    ECHO SET VAR2=%UserVar2% >> %UserFileName%.bat

  4. 再添加一行以确保静态脚本跳转到命令执行。

    ECHO GOTO STARTEXEC >> %UserFileName%.bat

我的问题在这里:

  1. 我的方法是否合理,或者是否有更好的方法来做到这一点,仍然通过批处理脚本?

  2. 在静态脚本返回到变量部分之前,我应该使用什么来退出它?我知道我需要ENDLOCALEXIT 会在这里工作,还是有其他更合适的方法?

【问题讨论】:

  • 您是否受限于批处理文件?
  • @Mechaflash 仅根据我目前的知识和经验水平,但是是的。此问题的范围仅限于批处理文件。
  • 我给出了答案,但是,我建议将来在 AutoIT 中寻找类似的项目。它很容易上手,而且您似乎足够熟练。
  • @Mechaflash 那里的答案不错,但在循环方面我还是有点迷茫。

标签: windows batch-file


【解决方案1】:

模板的想法似乎是一种简单的方法(不确定是否简短,但这可能是我接近它的方式。)根据原始模板创建一个单独的模板,删除所有 SET /P 命令。

编辑:

删除了旧答案。

在模板的最后,写:

GOTO:EOF

:User_Defined_Variables

在文件的开头,写:

CALL:User_Defined_Variables

在您的原始脚本中,在用户确认创建自定义脚本后,复制模板文件COPY /y template.bat userscript.bat 将所有用户变量发送给它。

(ECHO var1 = %uservar1% 
 ECHO var2 = %uservar2%
 Echo var3 = %uservar4%)>> userscript.bat
GOTO:EOF

所以当用户运行脚本时,CALL:User_Defined_Variables 将设置用户的脚本参数并继续执行脚本的其余部分。

【讨论】:

  • 好主意,但我对循环如何工作感到困惑。 (循环从来都不是我的强项。)特别是,它似乎只适用于指定数量的行。如果行数是可变的怎么办? (有些用户配置需要定义所有变量,有些则不需要。)这就是为什么我认为使用>> 将变量放在最后,使用GOTO 跳过生成的脚本可能更容易根据需要。
  • 给我一段代码(只是更新你的原始帖子),你要求用户输入,根据输入运行什么命令,我可以拼凑一个真实的例子。
  • 完全改变了我的答案。
【解决方案2】:

伊西,

我有一个与我的工作类似的功能...我们有一组不同的自定义变量,我们使用这些变量来启动我们处理的每个客户的其他功能。我已经用 Batch 编写了一个复杂的脚本,可以让我自己和同事实现这一点,但是我认为没有必要每次都创建一个单独的批处理文件。

我认为有 2 种方法可以实现您的目标:

  1. 您可以在开始时设置所有变量并从那里编辑它们

  2. 您可以每次都提示输入变量/编写新脚本

无论你写出一个批处理文件来写另一个批处理文件的任何一种方式都是愚蠢的,并且会在代码中留下各种潜在的错误。您不仅会在一个批处理脚本上进行错误检查,而且还会有另一个。

所以这里有一些你可以做的例子:

1.

@ECHO off
TITLE Install Script
COLOR 0A
SETLOCAL

REM ---------------------------
REM  *** EDIT VARIABLES BELOW ***
REM ---------------------------

:sharepath
set sharepath=\\SCIncapps\sharepath
REM SHAREPATH = The location of the files that will be copied to the client machine. List of files you will need in your SCIncIntViewer folder: 
REM vcredist_x86.exe, msxml6.msi,  Browser Access Client Controls.msi,  Automated Update Service.msi, bac.ico, dotnetfx35.exe, dotNetFx40_Full_x86_x64.exe,  Episys Client.msi
REM This Sharepath is where the Script needs to be located and has to be an already existing directory

:primaryStaging
set primaryStaging=SCIncweb
REM primaryStaging = The name of the back office server that handles AutoUpdate. This is usually the same as websrvr, except in distributed  environments

:webserver
set websrvr=SCIncweb
REM websrvr = The name of the Web Server; i.e. SCIncweb, SCInc14Doc1, 10.1.1.1, 192.168.1.20, etc.

:install_variables
set dotnet35=F
REM Defines the installation of .NET 3.5 SP 1 as True(T) or False(F)
set dotnet40=F
REM Defines the installation of .NET 4.0 as True(T) or False(F)
set regedit=F
REM Defines the creation of the Registry File to edit all IE settings as True(T) or False(F)
set SSL=F
REM Defines the use of SSL for the BAC URL; SSL is set as True(T) or False(F)
set org=0000
REM Defines the Organization for the BAC url shortcut that is created on the desktop for all users (enter the numeric org #)
set favorite=T
REM This will put the  Browser Access Client URL in their favorite folder and on their browser's quick link bar as True(T) or False(F)
set reboot=F
REM Defines whether or not the script will reboot the machine after it's complete as True(T) or False(F)
REM If using the PsExec.exe to push this script this will force the Domain Administrator to logoff the machine
set reloadAll=F
REM This defines if the _Installed_Files.txt will be overwritten to install all products again as True(T) or False(F)
REM NOTE This will copy down all items and install everything except .NET 3.5 SP1 and .NET 4.0

:creditUnion_Variables
set episys=F
REM Defines the installation of Episys Integration for  as True(T) or False(F)

:bank_Variables
set silver2020=F
REM Defines the installation of SCInc Integration for  as True(T) or False(F)
set coreDirector=F
REM Defines the use of Core Director for banks as True(T) or False(F)
set iseries=1.1.1.1
REM Defines the IP address of the iSeries if in-house Some Company, Inc Core, otherwise irrelevant
set dualinQuiry=F
REM Defines the deletion of the old SCInc Viewer if NOT using Dual Inquiry as True(T) or False(F)
set thinClient=F
REM Defines the /install and /execute flags on a Terminal Server as True(T) or False(F)
set vportsPath=%sharepath%
REM Defines the vports.xml file's location, this variable should be kept as the sharepath unless the client specifies otherwise

:Logs
set PCaudit=T
REM Defines whether or not you want just the PC name to be logged to a file as True(T) or False(F)
REM Creates a list of all the PC's that this script has been run on and puts it in the sharepath folder

REM ---------------------------
REM *** DO NOT EDIT BELOW ***
REM ---------------------------

IF /I '%scanStation%'=='T' goto:eof
REM If running the Scan Station Install tool only the variables are read and then the  Scan Station Install Tool.bat will resume
goto thinClient_inst

:thinClient_inst
IF /I '%thinClient%'=='F' goto date_time
change user /install

:date_time
FOR /F %%A IN ('TIME/T') DO SET time=%%A
REM Sets the time in a proper format for Error Logging
FOR /F "tokens=1-4 delims=/ " %%B IN ('DATE /t') DO SET date=%%C/%%D/%%E
REM Sets the date in a proper format for Error Logging

:errorLog
REM Logs the error messages for each product that the script attempts to install
IF exist %sharepath%\%org%_ _Installed_PCs_ErrorLog.txt goto PCaudit
echo.Microsoft Website for Errors:> %sharepath%\%org%_ _Installed_PCs_ErrorLog.txt
echo.http://msdn.microsoft.com/en-us/library/ms681381(VS.85).aspx>> %sharepath%\%org%_ _Installed_PCs_ErrorLog.txt
echo.(Popular Error: 9009, 1616 :: File does not exist in directory)>> %sharepath%\%org%_ _Installed_PCs_ErrorLog.txt
echo.--------------------------------------------------------------->> %sharepath%\%org%_ _Installed_PCs_ErrorLog.txt
set cleanInstall=0
REM Checks if the ErrorLog file already exists, if not it writes the fist 2 lines which contain the URL for determining the Errors from Microsoft
goto PCaudit

:PCaudit
REM Logs the Computer Name to the Installed_PC text file
REM This checks to make sure that the PC name doesn't already exist in that file and if it does it puts it into another file called %org%_ _Repeat_Installs_Log.txt
verify >nul
IF /I '%PCaudit%'=='f' set PCaudit=F
IF /I '%PCaudit%'=='F' goto start
IF /I '%PCaudit%'=='t' set PCaudit=T
set repeat=F
findstr /x "%computername%" %sharepath%\%org%_ _Installed_PCs_AuditList.txt 
IF '%ERRORLEVEL%'=='0' set repeat=T
IF /I '%repeat%'=='T' echo.%date% - %time% - %computername%>> %sharepath%\%org%_ _Repeat_Installs_Log.txt
IF /I '%repeat%'=='T' goto start
IF /I '%repeat%'=='F' echo.%computername%>> %sharepath%\%org%_ _Installed_PCs_AuditList.txt
goto start

:start
REM Changes all variables for True(T) and False(F) to capital letters since batch is case sensitive
set HKEY=HKEY_LOCAL_MACHINE
REM This script is meant to be run by a user with ADMIN privledges; 
REM " HKEY_LOCAL_MACHINE " registry items can only be edited by an admin

:_done
IF NOT exist "c:\SCInc\ \_done" md c:\SCInc\ \_done
IF NOT exist "c:\SCInc\ \_done\ _Installed_Files.txt" echo. Installed Files for %computername%: > c:\SCInc\ \_done\ _Installed_Files.txt
IF /I '%reloadAll%'=='T' echo. Installed Files: > c:\SCInc\ \_done\ _Installed_Files.txt
goto iviewerUrl
REM Creates the _done folder and the _Installed_Files.txt which will be local to the PC and will keep the products they install to prevent reinstallation
REM Delete this folder to reinstall all products or delete the line of text inside to reinstall a particular product

:iviewerUrl
set iviewerUrl=http://%websrvr%
IF /I '%SSL%'=='T' (set iviewerUrl=https://%websrvr%)
REM This sets the 'iviewerUrl' variable depeneding on if you have SSL enabled or not
set SCIncUrl=/bac/user/User_SO.asp?%OrgName=
REM This sets the rest of the URL for the browser shortcut (the '?' doesn't get a long with batch scripts)

:copy
REM Copies the files from the sharepath to the local machine
echo.
echo.Copying Necessary Files for Installation
echo.This could take a few minutes...
md C:\SCInc\ 
md C:\SCInc\Temp
REM Creates the ' \SCInc\ ' and ' \SCInc\Temp ' directories
goto 1

:1
verify >nul
findstr /x "copy_vcredist" "c:\SCInc\ \_done\ _Installed_Files.txt" 
IF '%ERRORLEVEL%'=='0' goto 2
echo.Copying vcredist_x86.exe
copy %sharepath%\vcredist_x86.exe c:\SCInc\temp
REM Copies the C++ Redistributable installer
IF '%ERRORLEVEL%'=='0' echo.copy_vcredist>> C:\SCInc\ \_done\ _Installed_Files.txt
IF NOT '%ERRORLEVEL%'=='0' echo.%date% - %time% - %computername% - There was an error copying vcredist_x86: Error Code %errorlevel%>> %sharepath%\%org%_ _Installed_PCs_ErrorLog.txt & set cleanInstall=1
goto 2
:2
verify >nul
findstr /x "copy_msxml6" "c:\SCInc\ \_done\ _Installed_Files.txt" 
IF '%ERRORLEVEL%'=='0' goto 3
echo.Copying msxml6.msi
copy %sharepath%\msxml6.msi c:\SCInc\temp
REM Copies MSXML 6.0 Parser installer
IF '%ERRORLEVEL%'=='0' echo.copy_msxml6>> C:\SCInc\ \_done\ _Installed_Files.txt
IF NOT '%ERRORLEVEL%'=='0' echo.%date% - %time% - %computername% - There was an error copying msxml6.msi: Error Code %errorlevel%>> %sharepath%\%org%_ _Installed_PCs_ErrorLog.txt & set cleanInstall=1
goto 3
:3
verify >nul
findstr /x "copy_BAC" "c:\SCInc\ \_done\ _Installed_Files.txt" 
IF '%ERRORLEVEL%'=='0' goto 4
echo.Copying  Browser Access Client Controls.msi
copy %sharepath%\" Browser Access Client Controls.msi" C:\SCInc\temp
REM Copies the  Browser Access Client Controls installer
IF '%ERRORLEVEL%'=='0' echo.copy_BAC>> C:\SCInc\ \_done\ _Installed_Files.txt
IF NOT '%ERRORLEVEL%'=='0' echo.%date% - %time% - %computername% - There was an error copying  Browser Access Client Controls.msi: Error Code %errorlevel%>> %sharepath%\%org%_ _Installed_PCs_ErrorLog.txt & set cleanInstall=1
goto 4
:4
verify >nul
findstr /x "copy_AutoUpdate" "c:\SCInc\ \_done\ _Installed_Files.txt" 
IF '%ERRORLEVEL%'=='0' goto 5
echo.Copying  Automated Update Service.msi
copy %sharepath%\" Automated Update Service.msi" C:\SCInc\temp
REM Copies the  Automated Update Service installer
IF '%ERRORLEVEL%'=='0' echo.copy_AutoUpdate>> C:\SCInc\ \_done\ _Installed_Files.txt
IF NOT '%ERRORLEVEL%'=='0' echo.%date% - %time% - %computername% - There was an error copying  Automated Update Service.msi: Error Code %errorlevel%>> %sharepath%\%org%_ _Installed_PCs_ErrorLog.txt & set cleanInstall=1
goto 5
:5
verify >nul
findstr /x "copy_icon" "c:\SCInc\ \_done\ _Installed_Files.txt" 
IF '%ERRORLEVEL%'=='0' goto copy_dotnet35
echo.Copying  BAC Icon
copy %sharepath%\bac.ico %windir%\System32
REM Copies the  Browser icon file to the System32 folder
IF '%ERRORLEVEL%'=='0' echo.copy_icon>> C:\SCInc\ \_done\ _Installed_Files.txt
IF NOT '%ERRORLEVEL%'=='0' echo.%date% - %time% - %computername% - There was an error copying bac.ico: Error Code %errorlevel%>> %sharepath%\%org%_ _Installed_PCs_ErrorLog.txt & set cleanInstall=1
echo.
echo.Created the following directories:
echo.-------------------------------------------------------
echo.
echo.C:\SCInc\ 
echo.C:\SCInc\Temp
echo.
echo.-------------------------------------------------------
goto copy_dotnet35

:copy_dotnet35
verify >nul
REM Copies .NET 3.5 Service Pack 1
reg query "HKLM\SOFTWARE\Microsoft\NET Framework Setup\NDP\v3.5"| findstr Install
REM Checks for .NET 3.5 and installs it if it doesn't find it
IF '%ERRORLEVEL%'=='0' set dotnet35=F
IF /I '%dotnet35%'=='F' goto copy_dotnet40
echo.Copying and installing .NET 3.5 Service Pack 1
echo.This will take a few minutes...
copy %sharepath%\dotnetfx35.exe C:\SCInc\Temp
IF NOT '%ERRORLEVEL%'=='0' echo.%date% - %time% - %computername% - There was an error copying .NET 3.5 SP1: Error Code %errorlevel%>> %sharepath%\%org%_ _Installed_PCs_ErrorLog.txt & set cleanInstall=1

:dotnet35
verify >nul
REM Installs .NET 3.5 Service Pack 1
echo.Installing .NET 3.5 Service Pack 1
echo.This could take a few minutes...
c:\SCInc\temp\dotnetfx35.exe /q /norestart
IF '%ERRORLEVEL%'=='0' echo.dotnet35>> C:\SCInc\ \_done\ _Installed_Files.txt & set net35=1
IF NOT '%ERRORLEVEL%'=='0' echo.%date% - %time% - %computername% - There was an error completing the installation of .NET 3.5 SP1: Error Code %errorlevel%>> %sharepath%\%org%_ _Installed_PCs_ErrorLog.txt & set cleanInstall=1
echo.
echo.-------------------------------------------------------
echo.
goto copy_dotnet40

:copy_dotnet40
verify >nul
REM Copies .NET 4.0
reg query "HKLM\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full"| findstr Install
REM Checks for the FULL (not client) version of .NET 4.0 and installs it if it doesn't find it
IF '%ERRORLEVEL%'=='0' set dotnet40=F
IF /I '%dotnet40%'=='F' goto msxml60
echo.Copying and installing .NET 4.0
echo.This could take a few minutes...
copy %sharepath%\dotNetFx40_Full_x86_x64.exe c:\SCInc\temp
IF NOT '%ERRORLEVEL%'=='0' echo.%date% - %time% - %computername% - There was an error copying .NET 4: Error Code %errorlevel%>> %sharepath%\%org%_ _Installed_PCs_ErrorLog.txt & set cleanInstall=1

:dotnet40
verify >nul
REM Installs .NET 4.0
echo.Installing .NET 4.0
echo.This could take a few minutes...
c:\SCInc\temp\dotNetFx40_Full_x86_x64.exe /q /norestart
IF '%ERRORLEVEL%'=='0' echo.dotnet40>> C:\SCInc\ \_done\ _Installed_Files.txt & set net40=1
IF NOT '%ERRORLEVEL%'=='0' echo.%date% - %time% - %computername% - There was an error completing the installation of .NET 4: Error Code %errorlevel%>> %sharepath%\%org%_ _Installed_PCs_ErrorLog.txt & set cleanInstall=1
goto msxml60

以上脚本是部分内容,已被编辑。

如您所见,我在文件开头设置了所有变量。这样,每次我需要更改某些内容时,我永远不会去代码中这样做,与我的同事一样。他们中的一些人能够改变它,而有些人不能,那些不容易理解要改变什么的人,因为everythign 都设置在文件的前 70 行中。 我认为这是最好的方法的原因是因为我可以灵活地随时改变事情。我有一些变量会触发我以后可能想要暂存的其他安装。使用创建另一个脚本的脚本,您可能会发现自己无法在不重新运行第一个批处理文件的情况下进行更改。

@echo off
> usermessage.vbs ECHO WScript.Echo InputBox( "What is the name of the Service you want to restart?", "Service:", "MspSvc" )
FOR /F "tokens=*" %%A IN ('CSCRIPT.EXE //NoLogo usermessage.vbs') DO SET Service=%%A
ECHO You will restart %Service%
DEL usermessage.vbs

net stop %Service%
net start %Service%

Pause

这是 Rob Vanderwoude 的作品。他可能是我所知道的最常用的批处理脚本命令网站。我已经修改了这部分以获取用户的输入并使用它来编写我的变量以重新启动服务。这可能适用于您想要编写一个编写另一个脚本的脚本..

如果是这种情况,那么您要做的是:

@ECHO off
TITLE Script Creator
COLOR 0A
SETLOCAL

> usermessage.vbs echo.WScript.Echo InputBox( "Pick something to test SETLOCAL/ENDLOCAL on?", "Variable:", "OUTSIDEVARIABLE" )
FOR /F "tokens=*" %%A IN ('CSCRIPT.EXE //NoLogo usermessage.vbs') DO SET outsideVar=%%A
echo.Your variable is %outsideVar%
DEL usermessage.vbs

echo.%outsideVar% is still set outside

echo.@echo off>c:\temp\newbatch.bat
echo.COLOR 1B>>c:\temp\newbatch.bat
echo.SETLOCAL>>c:\temp\newbatch.bat
echo.cls>>c:\temp\newbatch.bat
echo.set insideVar=%%outsideVar%% >>c:\temp\newbatch.bat
echo.^> usermessage.vbs echo.WScript.Echo InputBox( "Pick something to test SETLOCAL/ENDLOCAL on?", "Variable:", "INSIDEVARIABLE" ) >>c:\temp\newbatch.bat
echo.FOR /F "tokens=*" %%%%A IN ('CSCRIPT.EXE //NoLogo usermessage.vbs') DO SET insideVar=%%%%A >>c:\temp\newbatch.bat
echo.DEL usermessage.vbs >>c:\temp\newbatch.bat
echo.echo.Your variable is %%insideVar%% >>c:\temp\newbatch.bat
echo.echo.You have set the Second Variable: %%insideVar%% in this new batch file! >>c:\temp\newbatch.bat
echo.echo.%%insideVar%% is now Inside the new batch >>c:\temp\newbatch.bat
echo.Pause >>c:\temp\newbatch.bat
echo.ENDLOCAL >>c:\temp\newbatch.bat

echo.You are about to run the new batch file
pause
call c:\temp\newbatch.bat

cls
pause
echo.You created a batch file that set your outsideVar variable in it
echo.%outsideVar% is still set outside

ENDLOCAL
REM Install Batch Script
REM Created by Trevor G.

在这个脚本中,我们有一种独特的方式来确保每一行都将被写入新批处理脚本的末尾,但您还需要记住这里的关键内容......有时您需要使用^(克拉)和时间,您需要将 %% 加倍以确保您的两个变量都将被传递,并且在将其写入新命令之前,您不会触发脚本中的另一个命令。

【讨论】:

  • 您的脚本方式太长了。请将示例缩减为相关的子部分以显示您的答案。您不需要 整个 脚本。此外,请勿将 another 答案作为延续发布,这将被视为 noise,因此将被删除。如果你不能把它放在一个答案中,那么这很好地表明你说太多了。
  • 我们绝对希望您能提供帮助,但我们也希望每个人都渴望达到能够帮助每个人的质量水平;也就是说,答案并不是不好,而是可以变得更好,我们总是希望SO的用户让事情变得更好。看看你的答案,看看什么是真正需要的(而不是包含许多不相关位的代码转储)并将其精简到那个;你会发现它会得到很多更好的接受(以赞成票的形式)。
  • 另外,请注意,如here 所述,应将“希望对您有所帮助”和消息的签名部分进行编辑。
  • 您应该以不同的方式看待它。 SO 在发布问题和答案时定义了一些标准,我们希望每个人都遵守这些标准。如果你因为某种原因不这样做,我们会尽量指出哪里错了,应该怎么做,这样你以后就不会重蹈覆辙。 SO 与任何其他社区没有什么不同,无论是在互联网上,还是在现实生活中。社区有规则,他们希望每个人都遵守规则。不要气馁,您的大部分帖子都不错,但只需稍作调整即可。
  • 我非常感谢您的 cmets 并尊重您的所作所为,我已经做出了更改(在看到您指出的错误后的几分钟内),现在希望能够专注于我所做的工作确实提供了用户提出问题。我希望这里的下一个回复将重点放在实际问题上。
猜你喜欢
  • 1970-01-01
  • 2014-04-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-30
  • 2022-12-06
  • 2011-06-15
  • 2011-07-17
相关资源
最近更新 更多