cmd /c doesn’t like quotes

I was quite baffled at first.

This works:

cmd /c "C:\Program Files\7-Zip\7z.exe" C:\Temp\MyFile.7z

But this fails:

cmd /c "C:\Program Files\7-Zip\7z.exe" "C:\Temp\My Other File.7z"
'C:\Program' is not recognized as an internal or external command, operable program or batch file.

Turns out it’s an issue as old as Windows 2000.

The solution is to add another pair of quotes around the entire command:

cmd /c ""C:\Program Files\7-Zip\7z.exe" "C:\Temp\My Other File.7z""

Thank you, Microsoft.

ERROR: Value for ‘/TR’ option cannot be more than 261 character(s).

One would expect that, in the year of 2014, such errors would be a thing of the past…
But it’s true. You cannot create/update a scheduled tasks from command-line (using SCHTASKS) if the command line it runs is longer than 261 characters.
The funny thing is that you *can* create such a task using the GUI. So why the command-line limitation?

So, how to work around it?
option 1 – create a batch file to run the full command, and set the schedule tasks to execute that batch file. In most scenarios this is the easiest solution
option 2 – use a 3rd party utility for handling scheduled tasks (there are several, including jt.exe from Microsoft’s Windows 2000 SDK)

Get IPv4 and IPv6 using command line

This little batch file prints out either the machine’s IPv4 or IPv6 (based on the given argument – ‘4’ or ‘6’). It works on Windows 7 and 2008 (and probably later editions as well).

Update 25-Nov-2013: The IPv6 format was not correct in some cases. I’ve updated the script below with the fix

@echo off
 if "%1"=="" goto usage
 if %1==4 (
 set ip_address_string="IPv4 Address"
 for /f "usebackq tokens=2 delims=':'" %%f in (`ipconfig ^| findstr /c:"IPv4 Address"`) do echo %%f
 goto :eof
 ) else if %1==6 (
 for /f "usebackq tokens=5" %%i in (`netsh interface ipv6 show address ^| findstr /c:"Manual"`) do echo %%i
 goto :eof
 echo Usage: %0 ip_type
 echo Where ip_type is either 4 or 6

Task Scheduler – A Specified Logon Session Does Not Exist

The above error can appear when you try to create/modify a scheduled task to run as a specific user (schtasks /CHANGE /TN <task name> /RU <user> /RP <password>)

The cause of the error is a specific security policy on the machine.

It can be resolved via either the Local Group Policy Editor, or the Registry Editor (which is handy if you want to script it).

Continue reading

Preventing msi package from rebooting the system

When running msiexec to install, update or remove a certain product, you may want to prevent it from rebooting the system, or even prompt the user to reboot the system (e.g. if it’s a part of a larger installation or some other scripted operation).

Before Windows Installer 3.0, the only way to do it was setting the Windows Installer REBOOT property like this:

msiexec /i MyPackage.msi REBOOT=ReallySuppress

In Windows Installer 3.0, Microsoft added several command line switches which makes it more readable. So now the command looks like this:

msiexec /i MyPackage.msi /norestart

Much clearer, isn’t it?

Updating Windows Environment Variables

A well-known fact is that, in order to permanently set/modify an environment variable, one should update the Registry under:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment (System Variable)


HKEY_CURRENT_USER\Environment (User Variable)

However, this update does not go into effect until logging off and back on.

The solution is to broadcast a Windows Message to all running applications. The following C++ code provides the details:

SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0, (LPARAM) "Environment", SMTO_ABORTIFHUNG, 5000, &dwReturnValue);

In Perl, you can simply use the AdminMisc module to set environment variables. If you prefer to stick to standard modules (perl 5.8.9 and later), you can use the following code fragment:

use Win32::API;

	use constant HWND_BROADCAST => -1;
	use constant WM_SETTINGCHANGE => 0x1a;

	my $SendMessage = new Win32::API("user32", "SendMessage",
'NNNP', 'N')
    	or die "Couldn't create SendMessage: $!\n";
	my $RetVal =

Another alternative is to build the aforementioned C++ code into a small exe file, and use this utility anywhere you like.

In any case, note that the environment variable change will not be visible to the calling process. You’ll need to set it internally (for example, using $ENV in Perl) if you need it to be available inside the script.

References: Microsoft KB Article 104011, PerlMonks thread