I was tasked with modifying an old cmd script to add an event log entry at the beginning of the scripts run and an event log entry when it completed. To avoid cluttering the Application event log or one of the other default event logs that I lovingly refer to as event junk drawers, I created my own log with the New-EventLog cmdlet in PowerShell. After that, I added calls at the beginning and end of the cmd script that ran powershell.exe using the -Command argument and passed a short block of powershell commands.

What I did not forsee was the possibility of the cmd script running concurrently with an already running instance of the script, thus jumbling the logs and making it impossible to match a start log with its correct end log entry. I needed some way to uniquely identify each set of logs. That's when I came up with my guid idea! (get it? good idea = guid idea... forgive the pun, I promise it will be the last)

My "GUID" Idea: Step by Step
That's right, if I generated a guid in the cmd script and stamped that same guid in the start and end event log entries, I could match them up later. If this was a pure PowerShell script, I could simply call the [System.GUID]::NewGUID() .Net function and walk away. Unfortunately, cmd scripting leaves a little to be desired in terms of flexibility, so I broke out my old command scripting references, fired up Bing and went to work.

A GUID is a random string made up of 32 hexadecimal digits grouped in a {8-4-4-4-12} format. My first step was to get a random number in a cmd script. Enter the %random% variable. When evaluated by the command interpreter, %random% returns a (pseudo)random number between 0 and 32768. Applying a modular operator gave me my pseudo-random hexadecimal digit in decimal format.

set /a tempdec=16*%random%/32768
echo %tempdec%

Pass that decimal number through a set of cmd if statements and out pops a proper pseudo-random hexadecimal digit. I present the hex-o-matic pseudo-random number generator:

set /a tempdec=16*%random%/32768
if %tempdec% equ 0 (set digit=0)
if %tempdec% equ 1 (set digit=1)
if %tempdec% equ 2 (set digit=2)
if %tempdec% equ 3 (set digit=3)
if %tempdec% equ 4 (set digit=4)
if %tempdec% equ 5 (set digit=5)
if %tempdec% equ 6 (set digit=6)
if %tempdec% equ 7 (set digit=7)
if %tempdec% equ 8 (set digit=8)
if %tempdec% equ 9 (set digit=9)
if %tempdec% equ 10 (set digit=A)
if %tempdec% equ 11 (set digit=B)
if %tempdec% equ 12 (set digit=C)
if %tempdec% equ 13 (set digit=D)
if %tempdec% equ 14 (set digit=E)
if %tempdec% equ 15 (set digit=F)
echo %digit%

Now I just need 31 more. My first instinct was to drop my pseudo-random hex-o-matic code inside of the cmd script version of a iterative for loop

FOR /L %a (1,1,32) do ACTION

and call it a day. Unfortunately, that was too easy. %random% uses the current time as its seed, and when the FOR command is run, it gets the time at launch and provides that time value to the code in its care every time it is requested. That means that %random% uses the same time value and generates the same pseudo-random number every time it is called in the FOR command.

There was only one thing to be done, 32 successive hex-o-matic blocks stacked end to end, each adding one hexadecimal digit to the guid.

set /a tempdec=16*%random%/32768
if %tempdec% equ 0 (set guid=0)
if %tempdec% equ 1 (set guid=1)
if %tempdec% equ 2 (set guid=2)
if %tempdec% equ 3 (set guid=3)
if %tempdec% equ 4 (set guid=4)
if %tempdec% equ 5 (set guid=5)
if %tempdec% equ 6 (set guid=6)
if %tempdec% equ 7 (set guid=7)
if %tempdec% equ 8 (set guid=8)
if %tempdec% equ 9 (set guid=9)
if %tempdec% equ 10 (set guid=A)
if %tempdec% equ 11 (set guid=B)
if %tempdec% equ 12 (set guid=C)
if %tempdec% equ 13 (set guid=D)
if %tempdec% equ 14 (set guid=E)
if %tempdec% equ 15 (set guid=F)

set /a tempdec=16*%random%/32768
if %tempdec% equ 0 (set guid=%guid%0)
if %tempdec% equ 1 (set guid=%guid%1)
if %tempdec% equ 2 (set guid=%guid%2)
if %tempdec% equ 3 (set guid=%guid%3)
if %tempdec% equ 4 (set guid=%guid%4)
if %tempdec% equ 5 (set guid=%guid%5)
if %tempdec% equ 6 (set guid=%guid%6)
if %tempdec% equ 7 (set guid=%guid%7)
if %tempdec% equ 8 (set guid=%guid%8)
if %tempdec% equ 9 (set guid=%guid%9)
if %tempdec% equ 10 (set guid=%guid%A)
if %tempdec% equ 11 (set guid=%guid%B)
if %tempdec% equ 12 (set guid=%guid%C)
if %tempdec% equ 13 (set guid=%guid%D)
if %tempdec% equ 14 (set guid=%guid%E)
if %tempdec% equ 15 (set guid=%guid%F)

... (30 more of the above block)

Now I had a wonderful string of 32 hex digits in a row. Enter the cmd script substring syntax: %VARIABLE:~[STARTINDEX],[NUMBEROFCHARS]%

So we take our %GUID% string and...

set GUIDF={%GUID:~0,8%-%GUID:~8,4%-%GUID:~12,4%-%GUID:~16,4%-%GUID:~20,12%}

VOILA! Out pops


So the next time you whine about how PowerShell should include a Get-GUID cmdlet, just remember, it used to take 577 lines of cmd script to accomplish what $GUID = [System.GUID]::NewGUID() does in one. Ain't the future grand?

Topics: Technology, CMD script, Design & Development, GUID, PowerShell

Share this:

ABOUT Xtreme