jump to navigation

It’s GUID To See You CMD er…. August 28, 2012

Posted by Micah Rowland in Uncategorized.
trackback

It’s been far too long as always. New projects, new pits, but every now and then you realize how much you take some things for granted have to improvise from scratch.

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)

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

{329674F9-97A7-CC6C-A0DA-DB21ED8EA0D3}

 

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?

Advertisements

Comments»

1. Sean Wheeler - October 4, 2012

@echo off
setlocal
set HEX=0123456789ABCDEF
set /a x=1
:top
set /a dec=16*%random%/32768
call :getX %%HEX:~^%dec%,1%%
set /a x+=1
if %x% EQU 32 goto :got32
goto :top
)
:got32
set GUID={%digits:~0,8%-%digits:~8,4%-%digits:~12,4%-%digits:~16,4%-%digits:~20,12%}
set GUID
:goto eof

:::::::::::::::::::::::::
:getX
set digits=%digits%%1
goto :eof


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: