Sunday, September 11, 2011

My odd productivity scripts

I love to save time when working on my computer and as such I have written a number of time saving scripts over the years.

I have several things I do whenever I am setting up a new system that I will be using for a while.

I create a folder off the root of the system drive named Tools and I add it to the beginning of the system path.  In the Tools folder I copy my productivity scripts, and several folders:

  • docs - This contains my work, personal and technical documents
  • downloads - I set my browsers to download everything here
  • logs - Many of my productivity scripts log actions here
  • programs - I install my non portable development tools here when possible
  • scripts - Any helper \ productivity script not in the Tools folder itself goes here
  • utils - Any app or utility that is portable goes here
  • workshop - This contains sub-folders for any language I program in and each language sub-folder contains version folders and\or project folders

By having the Tools folder in the path and numerous batch scripts in the Tools folder I can launch any of the batch files from the Run prompt.  This allows me to skip several steps when launching apps or running processes.  Here is an example script that launches the portable version of 7-zip:

::: DOC: Runs 7-Zip
PUSHD %~dp0utils\7-Zip
SET Command=START 7-ZipPortable.exe
FOR /f "delims=" %%a in ('cscript.exe //Nologo %~dp0scripts\vbdate.vbs') do @Set strDate=%%a
FOR /f "delims=" %%a in ('cscript.exe //Nologo %~dp0scripts\vbtime.vbs') do @Set strTime=%%a
ECHO %0 - %strDate%-%strTime% - Command: %Command%  >> %~dp0logs\cmd.log

The first line @ECHO OFF tells the script not to echo the commands in the command prompt that is launched to run the batch file.  ECHO OFF sets the echo state to off for the rest of the batch file and the @ symbol sets the echo state to off for the ECHO OFF command.

The three colons (:::) operates as a remark statement in the batch file.  The batch "language" uses a single colon as a label and labels are not parsed at run time so using the three colons makes the script run a little quicker than it would if I used the REM statement.  Also I can parse the batch files for the DOC label and generate a list of what the scripts do if needed.

PUSHD sets the current working directory temporarily, the %~dp0 sets a variable that contains the path to the running script with a trailing backslash.

I SET a variable "Command" that contains the actual command used to launch the app or process.  This allows me to use the "Command" variable to both launch the app and to log the use of the command later in the script.

The vbdate.vbs and vbtime.vbs scripts are vbscripts that I use to get date\time stamps for logging or when I automate file renaming for backups.

The ECHO %0 etc.. sends the batch file name, the date-time and the Command to a log file.  The double greater than signs causes the information to be appended to the end of the target file.

The POPD command changes the current working directory back to where it was at the beginning of the script.

A number of these steps are not needed to actually launch the app or process but in different circumstances are useful to me for the way I work.  For example when running the batch file from the run dialog I don't need to POPD at the end of the script, but when running from a command line it would leave the directory set to what was set by the PUSHD command.

I also use AutoHotKey extensively for a number of tasks.  For example I keep a number of windows and applications open for days at a time but might only use them a few times a day (or week) so I use the Min2Tray script with AutoHotKey.  I have a keyboard command that will call a vbscript to tile all windows horizontally and one to tile all windows vertically.

#!H::RUN %maindrive%\Tools\scripts\tileh.vbs
#!V::RUN %maindrive%\Tools\scripts\tilev.vbs

That is WIN+ALT+H or +V causes AutoHotKey to call one of the following vbscripts:

Tile horizontally
dim objShell
set objShell = CreateObject("Shell.Application")
set objShell = nothing
Tile vertically
dim objShell
set objShell = CreateObject("Shell.Application")
set objShell = nothing

I have another AutoHotKey script that will stop my music from playing and lock all of my work systems when I hit #L (WIN+L).  Another script triggered by ^PrintScreen (CTRL+PrintScreen) that takes a screen shot and uses IrfanView (portable) to automatically save it as a png file.

All in all I currently have about 150 batch files, about 50 AutoHotKey scripts\commands\hotstrings, around 20 vbscripts and probably 10 - 15 Python programs that I have written to save me time and make tasks easier.  These scripts save me minutes to hours throughout the week.

Thursday, June 30, 2011

This is pretty cool

Open Source Ecology is a movement dedicated to the collaborative development of tools for replicable, open source, modern off-grid "resilient communities."

Tuesday, June 28, 2011

Shared DLLs

How Shared DLLs work ( a work in progress )

Files that are directed to do so in an MSI database will place a value name in the Registry here

In the MSI Packaging world the common understanding of "Shared DLLs" that I have come across is:
  1. They are dlls that have been listed in the SharedDLLs key in the registry
  2. They are listed because they may be used by more than one MSI installed application
  3. The regsitry key is created as a DWORD and it is incremented each time an application is installed with the file
  4. They are decremented each time one of these applications are uninstalled
  5. This keeps the shared dll installed until the final application using the noted dll is uninstalled.

Much of this is true but some correction, and further explanation is needed:
  1. Actually the "Shared Dll" is an MSI's Component's file Key Path so it could be any file type really
  2. This is correct
  3. Correct, the value name is set to the file key path and the value data is initially set to 1
  4. Correct
  5. It leaves behind more than the referenced file, in actuality it causes the whole component to stay installed.

In the Component table the Attributes can be set to 8 (the bit flag name is msidbComponentAttributesSharedDllRefCount) to let Windows Installer know to increment the reference count in the Shared DLL registry of the components key file. If the key file already exists in the registry the reference count will be incremented whether this bit is set or not. This can cause orphaned files if the value exists but the package that installed it is no longer installed, this would cause the value data to be one greater than the actual number of installed applications sharing the files.

So I tried a few experiments:
I created a couple of MSI's that installed the same text files to the same directories, and had the same key path for that
componentbut in all other ways they were different.

App 1 component with same keypath but not set as shared dll
App 2 component with same keypath but set as shared dll

When I installed then in this order everything behaved as I expected:
Install App 2 - SharedDLLs value data set to 1 then
Install App 1 - SharedDLLs value data set to 2

When I installed them in the reverse order something strange happened
I expected:
Install App 1 - SharedDLLs value data does not exist then
Install App 2 - SharedDLLs value data set to 1

What I saw was:
Install App 1 - SharedDLLs value data does not exist then
Install App 2 - SharedDLLs value data set to 2
Uninstall App 1 - SharedDLLs value data still set to 2
Uninstall App 2 - SharedDLLs value data still set to 1 and the component files remain

I tried it again this way:
Install App 1 - SharedDLLs value data does not exist then
Install App 2 - SharedDLLs value data set to 2
Uninstall App 2 - SharedDLLs value data set to 1
Uninstall App 1 - SharedDLLs value data still set to 1 and the component files remain

More later, I am too tired to continue with this now.

Oh, and here is a tool that can check the size of the SharedDll Registry Key.

My Top Ten Favorite Tools I Keep On My Thumb Drive

Most of these tools are completely portable, the ones that are not usually have a very small footprint.  Many of these tools are open source as well.

In alphabetical order

Monday, February 28, 2011

RIP Frank Buckles

The last veteran of World War I passed away yesterday, Sunday Feb 27, 2011.

In Flanders Fields

In Flanders fields the poppies blow
Between the crosses, row on row,
That mark our place; and in the sky
The larks, still bravely singing, fly
Scarce heard amid the guns below.

We are the Dead. Short days ago
We lived, felt dawn, saw sunset glow,
Loved and were loved, and now we lie,
In Flanders fields.

Take up our quarrel with the foe:
To you from failing hands we throw
The torch; be yours to hold it high.
If ye break faith with us who die
We shall not sleep, though poppies grow
In Flanders fields.

He served his country. He is the last of that war, and his passing should be remembered, should be honored. I would like to see the flags at half mast this week, all week.