Rob van der Woude's Scripting Pages

Unattended & Silent Installations

On this page I'll collect (links to) sample scripts and commands for unattended and silent software installations (and migrations).
My definition of an unattended installation is any installation that does not require user input but may display dialogs or progress bars etc. Silent installations are installations without any visible interface elements.

The main focus will on installing software, drivers, etcetera in Windows (NT 4 and later, not 9*/ME), not on installing Windows itself, though some links will be provided.

I won't restrict myself to a single script language, the goal is getting the job done.

The installation commands or scripts are roughly categorized:



BE CAREFUL: This machine has no brain, use your own

Preparing harddisks for a new operating system is tricky, because it can be done only when you boot from another medium like a floppy disk, CD-ROM or bootable USB stick -- or another harddisk.

• Probably the most well-known tool to (re)partition harddisks is FDISK.
FDISK is a native DOS command, so if you created a bootable DOS diskette you probably have a copy of FDISK.EXE or FDISK.COM available.
From my own experience, however, I would advise against using FDISK on modern computers.
FDISK has been known to miscalculate partition sizes and create overlapping partitions. In most cases you wouldn't notice this until a partition is almost completely filled with data, which will then be lost.

• If you still own a copy of an old Norton/Symantec Ghost version, you can use GDISK to (re)partition harddisks.
Copy GDISK.EXE to your bootable medium (floppy disk, CD-ROM, USB stick).
GDISK.EXE is for 16-bits DOS; if you boot with a 32-bits OS, like BartPE, use GDISK32.EXE instead.
Boot from that medium and issue the command GDISK without any command line arguments to list all harddisks with their numbers. This is especially important if you boot from a USB medium, as this may often be recognized as harddisk 1, and the internal harddisk as harddisk 2 (depending on the computer's BIOS and the type of USB medium). And we wouldn't want to accidentally repartition our bootable USB stick or external harddisk, now would we?

Let's suppose our USB stick is listed as harddisk 1, then we can repartition the "real" harddisk (2) with the following commands:


GDISK 2 /DEL /ALL will erase all existing partitions on harddisk 2.
GDISK 2 /MBR will recreate a standard MBR on harddisk 2, important if the harddisk was somehow encrypted, like (IBM) laptops with their BIOS password set.
GDISK 2 /CRE /PRI /SZ:4096 /FOR /Q /V:SYSTEM will create a new 4GB primary partition labeled "SYSTEM" and quick-format it.
GDISK 2 /CRE /EXT will create an extended partition on the rest of the disk.
GDISK 2 /CRE /LOG /FOR /Q /V:DATA will create a logical drive using the entire extended partition, label it "DATA" and quick-format it.

Read Symantec's detailed explanation of all GDISK command line switches.

Caution: As always, test these commands thoroughly on the type of computer you intend to use them for.
Kids, don't try this at home!


By default, Windows is installed with DHCP enabled for all network adapters.
However, you probably want to use static IP addresses on servers.

This is where NETSH is put to good use.
NETSH is available on Windows XP and later versions.

I won't describe all NETSH's command line parameters, as there are enough to write a book on it.
Start by typing NETSH /? on a command prompt and explore from there, if you have some time to spare.

What I will describe is how to create your own NETSH scripts.
As an example we'll use NETSH to set a static IP address for a network adapter, instead of DHCP.

First check the current settings using the command:


For a single network adapter you'll probably see something like this:

Windows IP Configuration

		Host Name . . . . . . . . . . . . : mypc
		Primary Dns Suffix  . . . . . . . :
		Node Type . . . . . . . . . . . . : Unknown
		IP Routing Enabled. . . . . . . . : No
		WINS Proxy Enabled. . . . . . . . : No
		DNS Suffix Search List. . . . . . : lan

Ethernet adapter Local Area Connection:

		Connection-specific DNS Suffix  . : lan
		Description . . . . . . . . . . . : Realtek RTL8139/810x Family Fast Ethernet NIC
		Physical Address. . . . . . . . . : 00-11-22-33-AA-BB
		Dhcp Enabled. . . . . . . . . . . : Yes
		Autoconfiguration Enabled . . . . : No
		IP Address. . . . . . . . . . . . :
		Subnet Mask . . . . . . . . . . . :
		Default Gateway . . . . . . . . . :
		DHCP Server . . . . . . . . . . . :
		DNS Servers . . . . . . . . . . . :
		Lease Obtained. . . . . . . . . . : Sunday, March 26, 2017 12:07:04
		Lease Expires . . . . . . . . . . : Monday, March 27, 2017 12:07:04
Note: On the computer used in this example, Autoconfiguration (or APIPA) has been disabled.
This is not the default setting, by default it will be enabled.
My APIPA.bat and/or APIPA.vbs scripts can help you change or restore APIPA settings.

Before we change any network setting, we'll first save the current settings to a file:

	NETSH interface dump ip > netsh.dhcp.script

If we ever want to restore the current DHCP setting, all we need to do is issue the following command:

	NETSH -f netsh.dhcp.script

Now we'll change the network adapter's IP settings manually.
Open the Network Connections properties, next open the network adapter's properties, and than the TCP/IP properties.
Click "Use the following IP address" and fill in all required IP addresses.
When finished, click "OK" and close the dialogs.

Type IPCONFIG /ALL again to check the new settings:

Windows IP Configuration

		Host Name . . . . . . . . . . . . : mypc
		Primary Dns Suffix  . . . . . . . :
		Node Type . . . . . . . . . . . . : Unknown
		IP Routing Enabled. . . . . . . . : No
		WINS Proxy Enabled. . . . . . . . : No

Ethernet adapter Local Area Connection:

		Connection-specific DNS Suffix  . :
		Description . . . . . . . . . . . : Realtek RTL8139/810x Family Fast Ethernet NIC
		Physical Address. . . . . . . . . : 00-11-22-33-AA-BB
		Dhcp Enabled. . . . . . . . . . . : No
		IP Address. . . . . . . . . . . . :
		Subnet Mask . . . . . . . . . . . :
		Default Gateway . . . . . . . . . :
		DNS Servers . . . . . . . . . . . :

If the settings are OK we'll save these new settings to another file:

	NETSH interface dump ip > netsh.staticip.template

This section was written for Windows XP and TCP/IP v4.
It is kept here in case you might still need it.
For Windows 7 and later, skip this section. You can click the button on the right to hide this section semi-permanently (for 1 month if cookies are enabled).

Open this file netsh.staticip.template in any text editor and look for the following lines:

set address name="Local Area Connection" source=static addr= mask=
set address name="Local Area Connection" gateway= gwmetric=0
set dns name="Local Area Connection" source=static addr= register=PRIMARY
set wins name="Local Area Connection" source=static addr=none

# End of interface IP configuration

We could copy the template to a separate script for each server, and adapt the addresses manually.
Or we can remove these last lines shown above from the template and create a batch file that will add them on the fly:

	:: This batch files requires 1 parameter: the last octet for the new static IP address
	IF "%~1"=="" EXIT 1
	:: Check if the parameter is a number between 0 and 255
	SET /A 1 * %1 2>NUL | FIND "%~1" >NUL || EXIT 1
	IF %1 LSS   0 EXIT 1
	IF %1 GTR 255 EXIT 1
	:: Copy the template to the script for the new static IP address
	COPY /Y netsh.staticip.template netsh.staticip%1.script
	:: Append the missing lines, filling in the last octet
	>> netsh.staticip%1.script ECHO set address name="Local Area Connection" source=static addr=10.0.0.%1 mask=
	>> netsh.staticip%1.script ECHO set address name="Local Area Connection" gateway= gwmetric=0
	>> netsh.staticip%1.script ECHO set dns name="Local Area Connection" source=static addr= register=PRIMARY
	>> netsh.staticip%1.script ECHO set wins name="Local Area Connection" source=static addr=none
	>> netsh.staticip%1.script ECHO.
	>> netsh.staticip%1.script ECHO.
	>> netsh.staticip%1.script ECHO popd
	>> netsh.staticip%1.script ECHO # End of interface IP configuration
	NETSH -f netsh.staticip%1.script

To set static IP address on another server, run the batch file above with 156 as its only command line argument.

Notes: 1 The lines added by the batch file are the lines we removed from the template.
The batch file shown here is meant as an example only.
If the lines you removed from your template file were different from the lines shown here, modify your batch code accordingly.
  2 Though the pure batch approach described above will work fine, a more elegant approach would be to use my SFaR (Simple Find and Replace) or RFaR (Regex Find and Replace) scripts:

CSCRIPT //NoLogo RFaR.vbs /F:netsh.staticip.template /O:netsh.staticip33.script /P:"(set address name=.Local Area Connection. source=[a-z]+ addr=[0-9]+\.[0-9]+\.[0-9]+)\.[0-9]+( mask=[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)" /R:"$1.33$2" /RC

(this should be a single command line; note the use of dots instead of escaped doublequotes, due to command line restrictions).
This command modifies one line in the file netsh.staticip.template and saves the result as netsh.staticip33.script.
The /RC switch tells the script to return the number of matches as the return code, so IF %ErrorLevel% EQU 1 can be used to test for successful replacement.

The following line will perform a similar find and replace, but requires some extra attention to the template file, to make sure that only one line matches (preferably the right one):

CSCRIPT //NoLogo SFaR.vbs /I:netsh.staticip.template /O:netsh.staticip33.script /F:" source=static addr= mask=" /R:" source=static addr= mask="
  3 The example above stems from ancient times - the Windows XP and IPv4-only era.
Though the technique discussed still applies, the number of lines that would have to be added to the batch file would make it impractical.

Now use a tool like WinMerge to compare the 2 scripts:

WinMerge screenshot

The result (difference) will look like this:

# ----------------------------------
# IPv4 Configuration
# ----------------------------------
pushd interface ipv4

set global icmpredirects=enabled
add route prefix= interface="Local Area Connection" nexthop= publish=Yes
add address name="Local Area Connection" address= mask=

# End of IPv4 configuration

The part above (both black and red) is exactly the part that we can now save as a NETSH script (let's name it netsh.staticip.10_0_0_135.script)

As can be seen in the left WinMerge pane, the code to restore the settings for this particular network connection is:

# ----------------------------------
# IPv4 Configuration
# ----------------------------------
pushd interface ipv4

set global icmpredirects=enabled

# End of IPv4 configuration

You may want to save it as netsh.restore.dhcp.script

This isn't that much code to create on the fly.
The following batch file dynamically creates and executes a temporary script to set a static IP address.
The only command line parameter required is the last octet of the new IP address:

IF "%~1"=="" (
	ECHO Usage: %~n0 octet
	ECHO Where: "lastoctet" is the last octet of the new static IP address
	EXIT /B 1
>  netsh.static.temp.script ECHO pushd interface ipv4
>> netsh.static.temp.script ECHO.
>> netsh.static.temp.script ECHO reset
>> netsh.static.temp.script ECHO set global icmpredirects=enabled
>> netsh.static.temp.script ECHO add route prefix= interface="Local Area Connection" nexthop= publish=Yes
>> netsh.static.temp.script ECHO add address name="Local Area Connection" address=10.0.0.%1 mask=
>> netsh.static.temp.script ECHO.
>> netsh.static.temp.script ECHO.
>> netsh.static.temp.script ECHO popd
NETSH -f netsh.static.temp.script
IF NOT ERRORLEVEL 1 DEL netsh.static.temp.script
Notes: 1: The batch code above is meant as an example only.
Your NETSH scripts will most likely be different, and so will the required batch file!
  2: In the batch code above, the temporary script netsh.static.temp.script will be deleted after being executed, unless NETSH returns an ErrorLevel higher than 0.


Admin's Guide to Server Core Commands.
Includes commands to rename a computer, join a domain, and many more...

Microsoft's Remote Installation Services (RIS)

Customizing Unattended Setup

Unattended Windows, the definitive how-to guide

Unattended, A Windows deployment system at

Computer Accounts

Microsoft's NETDOM command line tool can be used to:

User Accounts & Groups

As we are discussing software installations, we will focus on local users and groups.
However, since we'll be using the NET command, it won't be that hard to translate the commands to domain users and groups.

	NET USER new_account new_password

creates a new user account and sets its password.
The following command will add the new command to the local Administrators group:

	NET LOCALGROUP Administrators new_account /ADD

To create a new domain administrator account, use the following commands:

	NET USER new_account new_password /DOMAIN
	NET GROUP "Domain Admins" new_account /ADD /DOMAIN

This works for Active Directory too, the new account will be added to the "Users" container.
In Active Directory, the DS Tools are the preferred tools to manage user accounts, groups, computer accounts and OUs.

Many commands on my Useful Commands for Windows Administrators page can be useful for unattended installations too.


Permissions on files and folders can be set using CACLS or its Resource Kits counterparts XCACLS or SUBINACL.
SUBINACL can even be used to find and replace permissions.

To change ownership a third party tools like SUBINACL is required.

Registry permissions have always been a pain...

Or wait a minute, is this true...?

Enter SeCEdit & MMC!

Using MMC to create custom security templates, you can use SeCEdit to apply them unattendedly.
This way you can set permissions, inheritance and/or ownership on files, folders, services and registry keys.
Read more on my SeCEdit page.

Or download and use Microsoft's SUBINACL.EXE, which allows a little more "detailed" permissions configuration.


For registry changes, REGEDIT is the tool to use.
It may not be as simple to use as REG.EXE, but at least its command line usage has remained unchanged since Windows NT 4. If you plan on using REG.EXE, on the other hand, you'll need to check its version and modify the command line(s) accordingly.

The command you are likely to use most often is the import (or merge) command:


REGEDIT.EXE regfile.REG imports (or merges) regfile.REG into the registry.
/S makes this a silent import (by default the user is prompted for confirmation, and the import is confirmed afterwards).
START /WAIT makes the batch file wait for REGEDIT to finish the import.

Note: It is possible to use SeCEdit to manipulate registry values, but it is not as simple to use as REGEDIT.
If you also need to set permissions in the registry, do have a look at my SeCEdit page.
If you don't need to change anything but permissions in the registry, you may want to check out Microsoft's SUBINACL.EXE.


• Use RUNDLL32 PRINTUI.DLL,PrintUIEntry to install and configure printers.
RUNDLL32.EXE and PRINTUI.DLL are both native in Windows 2000 and later (as a matter of fact, RUNDLL32.EXE has been around a lot longer, as you might guess after taking a look at my RUNDLL page).

With PRINTUI.DLL you can add, configure and delete printers and printer drivers, both local and remote.
The command line switches can be supplied on the command line or read from a file.

• If you prefer VBScript (or actually WSH, including VBScript and JScript), PRNADMIN.DLL is the tool for you.
PRNADMIN.DLL is part of the Windows Server 2003 Resource Kit, which can be downloaded for free.
Though PRNADMIN.DLL was available in the Windows 2000 Server Resource Kit too, it is not available in the free Windows 2000 Resource Kit Tools for administrative tasks download.

Unlike PRINTUI.DLL, PRNADMIN.DLL can be used to create printer ports too!

• If you need to migrate a single printer, use my ExpPrnDr.bat (Export Printer Driver) instead.
It uses Microsoft's DEVCON.EXE to list all files belonging to a specific printer driver, and PRINTUI.DLL to install that printer driver on any computer.
Tested only on Windows XP, may work on Windows 2000.

• With Microsoft's PrintMig tool you can create backups of your complete set of printers, ports, drivers, print processors and print monitors.
Unfortunately there is no way to selectively backup nor restore, so you may want to backup a clean test system with just the printers and components you need to migrate.
I successfully used it on Windows Server 2000 and 2003, with some manual tweaking afterwards for the latter.

• For Windows Server 2008, Windows Vista and Windows 7, PrintMig should no longer be used.
Instead, use the Printer Migration Wizard, or the PRINTBRM.EXE command-line tool located in the %windir%\System32\spool\tools folder.
To backup, use:

	%windir%\System32\Spool\Tools\PRINTBRM.EXE -S \\server -B -F d:\location\server.printerExport

To restore, use:

	%windir%\System32\Spool\Tools\PRINTBRM.EXE -S \\server -R -F d:\location\server.printerExport

• An often overlooked way to add a network printer connection to a Windows computer is the following one-liner:

	START \\servername\printername

or, if the printer name contains spaces:

	START "Printer" "\\servername\printer name"

Granted, this isn't a completely unattended installation, as it will still ask for confirmation from the user. But, hey, it's simple!

Scheduled Tasks

There are several ways to install or migrate Scheduled Tasks.

• For Windows NT 4 use the AT command to list all tasks, and reschedule them again with that same AT command.
As I doubt this will be used very often nowadays, I won't go over the details.

• For Windows 2000 and XP, you can use JT from the Resource Kits. List all jobs with the JT /SE command, then list all properties of each job using the JT /PJ job command:

	FOR /F "skip=1 tokens=*" %%A IN ('JT /SE') DO (
		>> job_properties.txt ECHO.%%~A
		JT /PJ "%%~A" >> job_properties.txt
		>> job_properties.txt ECHO.
		>> job_properties.txt ECHO.


	FOR %%A IN (%windir%\Tasks\*.job) DO (
		>> job_properties.txt ECHO.%%~nA
		JT /PJ "%%~nA" >> job_properties.txt
		>> job_properties.txt ECHO.
		>> job_properties.txt ECHO.

Analyze the results and use JT to rebuild the tasks.

A Quick-and-Dirty shortcut way to migrate scheduled tasks is to copy all *.job files from the %windir%\Tasks folder on a "template computer" to the %windir%\Tasks folder on a remote computer and use:

	JT /LJ "\\remote_pc\remote_windir\Tasks\task_we_just_copied.job" /SC domain\user password

to set the credentials on the target computer.

A batch file to do that might look like this:

	SET RemotePC=%~1
	SET User=%~2
	SET Password=%~3
	IF NOT DEFINED RemotePC (SET /P RemotePC=Enter remote computer name: )
	IF NOT DEFINED User     (SET /P User=Enter user name in domain\user format: )
	IF NOT DEFINED Password (SET /P Password=Enter password for %User%: & CLS)
	FOR /F "skip=2 tokens=2*" %%A IN ('REG Query "\\%RemotePC%\HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion" /v PathName') DO SET RemoteWinDir=%%~B
	FOR %%A IN ('DIR /A-D /B %windir%\Tasks\*.job') DO (
		COPY /Y "%windir%\Tasks\%%~nxA" \\%RemotePC%\%RemoteWinDir::=$%\Tasks\*.*
		JT /LJ "\\%RemotePC%\%RemoteWinDir::=$%\Tasks\%%~nxA" /SC %User% %Password%

• For Windows XP and later, SCHTASKS is the preferred command.
The procedure is the same as described for JT, but with different command line arguments.

Automating the migration (inventory) may be more of a challenge, because of SCHTASKS' more verbose screen output.


In Windows 7 (and maybe Vista too?) an extra challenge will be the dispersal of scheduled tasks over several locations.

You may want to use JT for the inventory, and SCHTASKS for creating the new jobs.

Note: It goes without saying that to migrate scheduled tasks, you first need to migrate the programs executed by these tasks.

Devices and drivers

• Many hardware drivers come as .MSI files, in which case you can (un)install them like any other .MSI package.

• If a driver comes as a set of (uncompressed) files including a .INF file, use:

	RUNDLL32.EXE AdvPack.dll,LaunchINFSection filename.inf,,3


	RUNDLL32.EXE SetupAPI.dll,InstallHinfSection DefaultInstall 128 filename.inf

The number 128 in the second RUNDLL32.EXE command means no reboot:

0 System provided INF
128 Set the default path of the installation to the location of the INF (typical setting)
+0 Never reboot the computer
+1 Reboot the computer in all cases
+2 Always ask the users if they want to reboot
+3 Reboot the computer if necessary without asking user for permission
+4 If a reboot of the computer is necessary, ask the user for permission before rebooting

If the path or file name of the .INF file contains spaces, use the short file name notation. Never use quoted long file names!

A sample using AdvPack.dll, to remove Windows Media Player (9):

	RUNDLL32.EXE AdvPack.dll,LaunchINFSection %windir%\INF\wmp.inf,Uninstall

• Another way to install drivers that come with .INF files is using DEVCON:

	DEVCON.EXE [-r] install filename.inf hwid
-r reboot automatically if needed
filename.inf .INF to use to install the device
hwid hardware ID to apply to the device

• Another use for DEVCON is to remove existing devices, even when still physically connected, install new drivers and then rescan for "new" hardware to reinstall the devices with the new drivers:

	:: Remove all existing smartcard readers (modify
	:: the FIND command to remove only specific devices)
	FOR /F "tokens=1 delims=: " %%A IN ('DEVCON FindAll ˆ=SmartCardReader ˆ| FIND ":"') DO (
		DEVCON Remove "@%%~A"
	:: Uninstall the old driver and install the new driver(s)
	:: Scan for new hardware
	DEVCON Rescan


To use encryption we will need keys and certificates.

CERTREQ and CERTUTIL from the Windows Server 2003 Support Tools can be used to query and manage (CA) certificates without user interaction.

In Windows 2000 and later, CRYPTEXT.DLL can be used with RUNDLL32.EXE:

Note: This list was generated by running the following command in Windows XP SP2:
  CSCRIPT.EXE //NoLogo GetRunDL.vbs | FIND.EXE /I "cryptext.dll"

CryptExtAddCER will open the wizard to add a certificate with a .CER extension, CryptExtOpenCER will display a .CER certificate's properties dialog.

You can use KiXtart's or VBScript's SetFocus( ) and SendKeys( ) functions to "click" through the wizards' dialogs.
If you use this method in automated installations, make sure a user is logged in and understands that he/she should not touch the mouse or keyboard until the installation is finished. Otherwise, if the wizard's dialog looses focus the installation will fail.

Microsoft's CAPICOM in conjunction with KiXtart, VBScript or (Object) Rexx can also be used to manage certificates.

Or use WinHttpCertCfg or CertMgr, both from Microsoft too.

.MSI Files

Use Windows Installer (executable name: MSIEXEC.EXE) to install .MSI files.

The general command syntax for unattended installations of .MSI files (with verbose logging, without reboot) is:

	MSIEXEC.EXE /I myfile.MSI /QN /L*V myfile.LOG /norestart REBOOT=ReallySuppress

The general uninstall command syntax (with verbose logging and without reboot) is:

	MSIEXEC.EXE /X myfile.MSI /QN /L*V myfile.LOG /norestart REBOOT=ReallySuppress


	MSIEXEC.EXE /X {unique_identifier} /QN /L*V myfile.LOG /norestart REBOOT=ReallySuppress

The latter does not require the original .MSI file. The unique identifier can be found in the registry under HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall, it is the name of the subkey.
You may also want to take a look at the UninstallString values under each subkey.

My own GetUnins.vbs uses this technique.

More details and links are available on my MSIEXEC.EXE page.

Portable Apps

Instead of devising your own silent installation routines for each application, you may want to consider using portable applications instead.
A portable application is an application that does not need to be installed, and can be run from a removable, local or mapped network drive. Just copy the files to their new location and run the application.
Though originally intended for use on USB sticks, these portable applications are perfect for quick deployment to local disk drives.

A great source for preconfigured portable applications is

page last uploaded: 2016-09-19, 14:57