Showing posts with label batch. Show all posts
Showing posts with label batch. Show all posts

Sunday, November 4, 2012

Why I'm Still Not 100% on PowerShell

In the past, I have been somewhat critical of PowerShell.  Not because it is somehow technically inferior to alternatives, but because of environmental ramifications.  I was an early adopter actually, having joined up in the Monad testing program, and I was very excited about the potential it offered.  Today, I use PowerShell more than I ever have, but there are still many types of tasks that I don't use it for:

  • Deploying / Installing Software to Remote Computers
  • Maintaining Legacy Script Files
  • Heterogeneous Windows Versions and .NET versions
The main reason I don't use it for software deployments is the slower execution time.  Compared with basic Batch/CMD scripts, or even VBscript, it just takes longer to "spin-up" the .NET and PowerShell foundation goodies before it even parses the script code.  Multiply that by multiple installs per remote computer, and hundreds of remote computers, and the aggregate time difference can be significant.  This is especially true on older hardware and older operating systems, which brings up the point of "pervasiveness" of PowerShell in a mixed environment:  

Many environments I walk into (I'm a consultant after all) are not homogeneous when it comes to operating systems versions, or even "common applications".  It's not unusual to find multiple configurations of .NET, Java Runtime, DirectX, MSXML, Oracle client, and SQL Native Client installations.  One thing I rarely have to contend with is inconsistent support for Windows Scripting Host, let alone the ever-present CMD shell.  I can't say the same for PowerShell.  I wish it were as consistent and pervasive but it's just not.  I'm sure that it will be someday, but we all know how long it takes customers to upgrade to newer operating systems.

To be fair, the same was true for Windows Scripting Host back in the early days of Windows NT.  Microsoft cranked out several versions, until they finally stopped on 5.8 and let it sink in.  That had a nice impact on most shops since they were no longer worried that as soon as they deployed WSH they would have to follow up with another upgrade.  PowerShell is still evolving, so many IT managers aren't over-eager to deploy 3.0 when they seem to expect a 3.1 to come out any day.

I know it's not exactly logical to expect that PowerShell and .NET could be somehow combined and made to be more cohesive (for more streamlined deployment), it would help.  The size of such a deployment package would be excessive for many shops to deal with, and might be tough to deploy on legacy hardware when local disk storage is almost maxed out.  No, it seems Microsoft is betting on customers upgrading to Windows 8 and that would take care of everything as it pertains to achieving a ubiquitous PowerShell presence.  I don't think that's going to happen anytime soon however, for a variety of reasons.  So, for now, while I continue to expand my PowerShell scope, I am still dependent on VBScript and Batch scripts for many tasks.

I'm sure there are some of you out there that will shake your head in disbelief at all this, and that's fine.  I welcome constructive feedback.  So if you have some insights or ideas about how this can be managed more effectively, please let me know?

Tuesday, July 19, 2011

KixTart+VBscript+BAT+PowerShell=zzzzzzzz

Boredom is the sugar-daddy of invention.  Necessity may be the mother, but boredom is the Yang to that Yin.  For example, while sitting around pondering the endless string of bad decisions I've made in life, I decided to build a mouse trap of script code.

KiXtart calls VBscript calls BAT calls PowerShell

You can take this and do whatever you like or ignore it and roll your eyes.  I got the inspiration from a recent discussion with a long-time colleague about a former colleague from back in the 1980's who wrote some insanity for MIT that used LISP to write C code and compiled and ran it based on environment condition tests.  In other words: it wrote the code it needed to suit the environment at that moment.  I really miss working with LISP, eh, ughg, whatever... ok, so there you have it.  Oh, each of the scripts is named "hello.xxx" where "xxx" is the appropriate extension for the language (.kix, .vbs, .bat, .ps1)... fa la la la laaaaaaa...

[CODE]

rem hello.cmd
@echo off
kix32.exe "%~dp0hello.kix"

;; hello.kix
@break on
shell "cscript.exe /nologo hello.vbs"

' hello.vbs
Set objShell = CreateObject("Wscript.Shell")
result = objShell.Run("%comspec% /c hello.bat", 1, True)

rem hello.bat
@echo off
powershell -ExecutionPolicy Unrestricted -File "%~dp0hello.ps1"

## hello.ps1
$a = new-object -comobject wscript.shell
$b = $a.popup("Hello world!",5,"Wasting Time",1)

[/CODE]

Thursday, July 14, 2011

Scripting and Configuration Manager Packages

Config Manager admins (like Altiris, etc.) are often splitting their time between deploying MSI, EXE application installers as well as custom scripts.  Quite often, and for good reason, they use CMD or BAT scripts to wrap up a sequence of things that would otherwise take longer or require more effort to do within a re-packager like InstallShield.  The problem that I see quite often is forgetting to return a meaningful result code to the Config Manager agent.

For example (BEFORE):

@echo off
msiexec /I “%~dp0myinstaller.msi” /quiet /norestart
cacls “%programfiles%\myApps” /e /t /c /g users:c
reg add HKLM\software\myApps\Fubar /v “Tarfu” /t REG_SZ /d “ABC” /f

If you don’t bother to explicitly return the %errorlevel% value you could be in for a very unhappy surprise.   A little dose of error checking helps a lot.  Here’s (just) one example:

(AFTER):

@echo off
set log=%temp%\myapp.log
echo %DATE% %TIME% msiexec /I “%~dp0myinstaller.msi” /quiet /norestart >>%LOG%
msiexec /I “%~dp0myinstaller.msi” /quiet /norestart
echo %DATE% %TIME% exit code %errorlevel% >>%LOG%
if %errorlevel%==0 (
   goto Configure
) else (
   if %errorlevel%==3010 (
      echo %DATE% %TIME% reboot required (suppressed) >>%LOG%
      goto Configure
   ) else (
      goto Failure
   )
)
goto END

:Continue
echo %DATE% %TIME% doing custom configuration changes… >>%LOG%
cacls “%programfiles%\myApps” /e /t /c /g users:c
reg add HKLM\software\myApps\Fubar /v “Tarfu” /t REG_SZ /d “ABC” /f
echo %DATE% %TIME% installation complete >>%LOG%
goto END

:Failure
echo %DATE% %TIME% installation failed: exit code %errorlevel% >>%LOG%
exit %errorlevel%

:END
exit %errorlevel%

Wednesday, December 8, 2010

Useful CMD/BAT Path Expansion Variables

Save the following code into a .CMD or .BAT file and run it in a CMD shell console.  For some more see http://www.microsoft.com/resources/documentation/windows/xp/all/proddocs/en-us/percent.mspx?mfr=true  The lines in red are only applicable to 64-bit Windows installations.

@echo off
echo displaying various path alias values...
echo %~nx0
echo %comspec%
echo %~d0
echo %~dp0
echo %~dps0
echo %~dpp0
echo %~f0
echo --------------------------------
echo %systemdrive%
echo %systemroot%
echo %windir%
echo %programdata%
echo %programfiles%
echo %programfiles(x86)%
echo %userprofile%
echo %allusersprofile%
echo %temp%
echo %commonprogramfiles%
echo %commonprogramfiles(x86)%
echo %appdata%
echo %localappdata%
echo %public%

Monday, November 8, 2010

Chart of the Day: Raising CMD Script Errors

cmd

If I really need to explain this chart, then it means one of the following:

A) You have no idea what I'm talking about anyway

B) You don't care

C) You have no idea and don't care

D) Any of the above

Tuesday, November 2, 2010

Exit vs Exit /B

Geek moment: This seems like an extremely trivial issue, or decision, or difference, but it has a real impact.  I’m talking about BAT / CMD script coding here.  The “EXIT” statement terminates a script.  But the /B argument (or “parameter”) has a minor, yet noticable different impact:

Using /B instructs the shell processor to terminate the script, but not the shell process in which it runs.  When you launch a BAT or CMD script file, it launches an instance of CMD.exe in which to run.  CMD.exe is the shell processor for those kinds of scripts.  If you have BAT file “A” execute a CALL to run BAT file “B”, and within “B” you use EXIT %errorlevel%, it not only terminates “B” but “A” and the CMD shell instance.  If you use EXIT /B %errorlevel%, only “B” terminates and hands focus back to “A” to continue on.

Let’s test, shall we?

A.BAT
@echo off
echo this is script A.bat running...
CALL B.bat
echo after B.bat errorlevel is %errorlevel%
pause
  
B.BAT
@echo off
echo this is script B.bat running...
EXIT /B %errorlevel%

Copy each chunk of code into their respective files and save them with the appropriate names.  Then open a command console (cmd.exe) and run A.BAT and watch the output and the behavior.  (do NOT simply double-click on “A.BAT” to test this!  It is important you open CMD first and then run the script)

Now, modify the last line in B.BAT so it is EXIT %errorlevel% (remove /B from the line).  Then save the file and run A.BAT again.  See the difference?

But wait, that’s not all.

Let’s say you need to build a script to be packaged and advertised through something like Altiris (or whatever Symantec decides to name it today), or Microsoft System Center Configuration Manager 2007 (say that ten times in a single breath!  go ahead… I dare you!), what impact might this small “feature” have?

I’m glad you asked.  Because it’s not always possible (or desirable) to have one script “do everything” in the course of getting from A to Z (sorry to confuse the letters on you).  Maybe you have scripts that do very well-defined jobs and you simply want to “string” them together to accomplish a group of tasks without actually merging the script code.  This is not uncommon, so stop shaking your head, I’m watching you.  Maybe you have script InstallApp.bat followed by ConfigureOps.bat and RunInventory.bat.  I’m just picking names, indulge me for a minute…

If InstallApp.bat calls upon ConfigureOps.bat, which calls upon RunInventory.bat, and somewhere in RunInventory.bat or even ConfigureOps.bat there is a(n) EXIT statement without a /B parameter, then guess what happens to that entire house of cards running in memory?  That’s right, it implodes and the “parent” script in the process chain (in this case: InstallApp.bat) never finishes.  That is dangerous!

This hasn’t happened to me in production, but I did trip over it during testing, which is another reason why I can’t say it enough: test test test!

These are the O-rings in the Morton-Thiokol solid rocket boosters.  The low-grade concrete Halliburton purchased for the Deepwater Horizon project.  The tree limbs that knocked out a major Northeast power grid.  The little things that get overlooked but which can cause enormous problems later on.  Do you think these people were thinking about o-rings when this picture was taken?

Tuesday, October 26, 2010

Deploy Autodesk Design Review 2011 with SCCM 2007

Based upon: http://images.autodesk.com/adsk/files/adr2011_install_guide.htm  and embellished as you see below.  I’ve tested this and it works fine.  By the way, the .exe installation method using /q /v/qn that worked with ADR 2008 does not work with ADR 2011.  Just to let you know.  I tried multiple scenarios to see what works and what does not.  For example, trying to push the .MSI+.MST for ADR 2011 from an existing deployment tree for AutoCAD 2011, Civil 3D 2011 or Map 3D 2011 does not work.  Extracting the MSI from the download .EXE installer doesn’t work either.  You have to download the package from step 3 below.  In any case: enjoy!

Part 1 - Prep:

  1. Create root folder under a UNC share named “ADR2011”
  2. Create sub-folders “VCRedist\2005” and “VCRedist\2008”
  3. Download Design Review 2011 32-bit MSI installer
  4. Download MS Visual C++ 2005 SP1 Runtime
  5. Download MS Visual C++ 2008 Runtime
  • Folder tree should look something like this:
    • \server\software\ADR2011\...
      • SetupDesignReview2011.msi
      • Setup.bat
      • VCRedist\
        • 2005\
        • 2008\

Part 2 - Build:

  1. Extract VC++ 2005 .exe into %TEMP%
    • Creates VCRedist~3.EXE
  2. Extract the Extraction into “ADR2011\VCRedist\2005”
    • Creates vcredist.msi and vcredis1.cab
  3. Extract VC++ 2008 .exe into “ADR2011\VCRedist\2008”
    • Creates a bunch of files, including vc_red.msi
  4. Right-click the .MSI files, select “Properties”, and click the “Unblock” button (if it appears)
    • SetupDesignReview2011.msi
    • Vcredist.msi (2005)
    • Vc_red.msi (2008)
  5. Copy the script code (below) into a text editor and save it as “setup.bat” in the “ADR2011” root folder

Part 3 - Deploy via SCCM:

  1. Create a Collection for targeting clients with ADR 2011
  2. Create a Package:
    1. General (tab)
      1. Name: “Design Review”
      2. Version: “2011”
      3. Manufacturer: “Autodesk”
    2. Data Source (tab)
      1. Check “This package contains source files”
      2. Click “Set” and browse to the UNC folder
    3. Save and Close
  3. Create a Program for the Package:
    1. General (tab)
      1. Name: “Design Review 2011 32-bit Install”
      2. Command Line (Browse to select “setup.bat”)
    2. Environment (tab)
      1. Program can run: “Whether or not a user is logged on”
    3. Advanced (tab)
      1. Check “Suppress program notifications”
    4. Save and Close
  4. Add a Distribution Point:
    1. Select a DP server, save and close
  5. Create an Advertisement:
    1. General (tab)
      1. Name: “Autodesk Design Review 2011 32-bit Install”
      2. Comment: whatever you feel like entering
      3. Package: “Autodesk Design Review 2011 32-bit”
      4. Program: “Design Review 2011 32-bit Install”
      5. Collection: (your collection)
      6. Un-check “Include members of subcollections” (for now anyway)
    2. Schedule (tab)
      1. Click the asterisk “*” button next to “Mandatory assignments”
      2. Select “Assign immediately after this event: As soon as possible” (click OK)
      3. Check “Ignore maintenance windows when running program”
    3. Distribution Points (tab)
    4. Select: “Run program from distribution point”
      1. Select: “Download content from distribution point and run locally” (** you decide if this step works for you **)
    5. Save and Close
  6. Force SCCM machine policy refresh on target computer(s) to run advertisement sooner
  7. Eat something, Drink, Tell some bad jokes, Drink some more
  8. Check on the results
  9. Adjust as needed (and drink some more)
  10. Go to bed

SCRIPT CODE:

@echo off
rem ****************************************************************
rem Filename..: setup.bat
rem Author....: skatterbrainz.blogspot.com
rem Date......: 10/26/2010
rem Purpose...: install Autodesk Design Review 2011
rem ****************************************************************
CLS
SETLOCAL
SET LOG=%TMP%\adr2011_setup.log
SET DESC=DesignReview2011
rem -----------------------------------------------
echo %DATE% %TIME% initializing script [setup.bat] >%LOG%
echo %DATE% %TIME% source........ "%~dps0" >>%LOG%
echo %DATE% %TIME% target........ %computername% >>%LOG%
echo %DATE% %TIME% windir........ %windir% >>%LOG%
echo %DATE% %TIME% progfiles..... %programfiles% >>%LOG%
echo %DATE% %TIME% tmp........... %tmp% >>%LOG%
echo ---------------------------------------------- >>%LOG%
if not exist "c:\program files\common files\microsoft shared\vc\msdia80.dll" (
echo %DATE% %TIME% info: installing vcc 2005 32-bit runtime... >>%LOG%
echo %DATE% %TIME% command = msiexec /i "%~dps0VCRedist\2005\vcredist.msi" /quiet /norestart >>%LOG%
msiexec /i "%~dps0VCRedist\2005\vcredist.msi" /quiet /norestart
rem echo %DATE% %TIME% command = "%~dps0VCRedist\2005\vcredist_x86.exe" /q:a /c:"msiexec /i vcredist.msi /qn /l*v %temp%\vcredist_x86.log" >>%LOG%
rem start /wait "%~dps0VCRedist\2005\vcredist_x86.exe" /q:a /c:"msiexec /i vcredist.msi /qn /l*v %temp%\vcredist_x86.log"
echo %DATE% %TIME% info: result code = %errorlevel% >>%LOG%
) else (
echo %DATE% %TIME% info: vcc 2005 32-bit runtime already installed >>%LOG%
)
echo ---------------------------------------------- >>%LOG%
if not exist "c:\program files\common files\microsoft shared\vc\msdia90.dll" (
echo %DATE% %TIME% info: installing vcc 2008 32-bit runtime... >>%LOG%
echo %DATE% %TIME% command = msiexec /i "%~dps0VCRedist\2008\x86\vc_red.msi" /quiet /norestart >>%LOG%
msiexec /i "%~dps0VCRedist\2008\x86\vc_red.msi" /quiet /norestart
echo %DATE% %TIME% info: result code = %errorlevel% >>%LOG%
) else (
echo %DATE% %TIME% info: vcc 2008 32-bit runtime already installed >>%LOG%
)
echo ---------------------------------------------- >>%LOG%
echo %DATE% %TIME% info: downloading installer package... >>%LOG%
copy "%~dps0SetupDesignReview2011.msi" "%tmp%" /Y
echo %DATE% %TIME% info: installing %DESC%... >>%LOG%
echo %DATE% %TIME% command = msiexec /i "%tmp%\SetupDesignReview2011.msi" /quiet /norestart >>%LOG%
msiexec /i "%tmp%\SetupDesignReview2011.msi" /quiet /norestart
echo %DATE% %TIME% info: result code = %errorlevel% >>%LOG%
echo ---------------------------------------------- >>%LOG%
echo %DATE% %TIME% info: installation complete! >>%LOG%
ENDLOCAL
exit %errorlevel%


Important: Be careful of word-wrapping when copying the code above.  Each line that begins with “echo” should end with “>>%LOG” on the same line.  Do not let it wrap to the next line!

Friday, October 8, 2010

Teaching Pigs to Sing (and scripts to make pretty logs)

Today is Friday, and OMFG the weather is increditastical here in sunny Virginia Beach, Virginia!  Going outside feels like having someone rub your scalp and sing pretty songs in your ear.  Yeah, I can’t concentrate on anything else, but… I must.

I had a walk-up request to package MapInfo Pro 10.0 today.  But not just by itself (because that would’ve been too easy, and you can’t have “easy” on a Friday), it had to include another application called “ADAM” and then copy down a whole folder tree of content files and make a shortcut to one of them on the “All Users” Start Menu as well.  It turns out the whole bundle is aimed at installing the “ADAM” software bundle for MapInfo by Deccan International.

The vendor (Pitney-Bowes, and don’t even ask why the **** Pitney-Bowes bought MapInfo.  It makes as much sense as eBay buying Skype, but oh well, onward…) provides a setup.exe, a setup.msi, and a data1.cab file.  They also provide a nice installation guide with tips on running the setup.exe unattended by feeding in arguments using the ancient InstallShield method (you know: setup.exe /v”a bunch of crap here”), but the problem with those is that they’re ill-behaved when strung together in a sequence because they often don’t wait to finish before releasing their “mutex” (go look that one up.  It’s ok.  I’ll wait…).  Are you back?  Ok, so the better option, in most cases, is using the .MSI file and making a transform (.MST) to stuff in the arguments more efficiently.

So, I fired up Wise Package Studio, consumed a coffee, ate a trail mix bar, and made a transform for the installation that inputs the “USERNAME”, “COMPANYNAME”, “PIDKEY” (serial number) and “ACCD” (activation code).  No problem.

You can use Orca instead of Wise Package Studio, or InstallShield, if you prefer.  As long as you can make and edit the .MST it doesn’t matter.

Time to setup the deployment folder structure.  I placed it on a server share named “Packages”, under a root folder named “Deccan”, then copied the MapInfo Pro 10.0 “Disk 1” files into a sub-folder called “MI_PRO\Disk1”.  Then I copied the ADAM installation files under a sub-folder under “Deccan” named “ADAM” and another folder created for “CADAnalyst” under “Deccan”.  The structure looks like this…

\Server\Packages\Deccan\…
-MI_PRO\Disk1
-ADAM
-CADAnalyst

I placed the .MST file into the “Disk1” sub-folder, next to the .MSI file it relates to.

I then created two script files:  setup.bat, and makeshortcut.vbs

Setup.bat simply runs the .MSI with the .MST transform in “quiet” mode.  Then it runs the ADAM .MSI installation, and downloads the data files and makes a shortcut using a call to the makeshortcut.vbs (vbscript) file.  But I also wanted this to generate a self-describing log file so I could backtrace any problems or check on progress, etc.  The “echo” command is simple enough, and I add %DATE% and %TIME% to make a standard “timestamped” log entry output.

However, VBScript uses a completely different format for showing a full date, so I had to beat that into shape with a hammer (see the makeshortcut.vbs script at the end).  I needed the output from both to merge into one log file and look consistent.  That’s just me.  Maybe you don’t care that much, which is fine.  I care about a lot of stupid things.

@echo off
01. rem ****************************************************************
02. rem Filename..: setup.bat
03. rem Author....: Guess Who? (skatterbrainz.blogspot.com)
04. rem Date......: 10/08/2010
05. rem Purpose...: install MapInfo 10 + ADAM + CAD Analyst files
06. rem ****************************************************************
07. CLS
08. SETLOCAL
09. SET LOG=%TMP%\mapinfo10_setup.log
10. echo %DATE% %TIME% initializing script [test_setup] >%LOG%
11. echo %DATE% %TIME% source = "%~dps0" >>%LOG%
12. echo %DATE% %TIME% target = %computername% >>%LOG%
13. echo %DATE% %TIME% tmp = %tmp% >>%LOG%
14. echo ---------------------------------------------- >>%LOG%
15. echo %DATE% %TIME% installing MapInfo Pro 10... >>%LOG%
16. msiexec /i "%~dps0MI_PRO\Disk1\MapInfo Professional 10.0.msi" TRANSFORMS="%~dps0MI_PRO\Disk1\MapInfoPro10_1.mst" /quiet /norestart
17. echo %DATE% %TIME% completed / result code = %errorlevel% >>%LOG%
18. rem ----------------------------------------------
19. if exist "c:\Program Files\Deccan International\ADAM.mbx" (
20. echo %DATE% %TIME% ADAM has already been installed >>%LOG%
21. ) else (
22. echo %DATE% %TIME% installing HPC ADAM ... >>%LOG%
23. msiexec /i "%~dps0ADAM\ADAMsetup.msi" /quiet /norestart
24. echo %DATE% %TIME% completed / result code = %errorlevel% >>%LOG%
25. )
26. rem ----------------------------------------------
27. if exist "c:\Program Files\Deccan International" (
28. if exist "c:\Program Files\Deccan International\CADAnalyst" (
29. echo %DATE% %TIME% the CADAnalyst folder was already created >>%LOG%
30. ) else (
31. echo %DATE% %TIME% downloading data files for CAD Analyst... >>%LOG%
32. xcopy "%~dps0CADAnalyst\*.*" "c:\Program Files\Deccan International\CADAnalyst\*.*" /s /y
33. echo %DATE% %TIME% download complete... >>%LOG%
34. )
35. ) else (
36. echo %DATE% %TIME% error / target folder Deccan International not found! >>%LOG%
37. exit /b 1
38. )
39. rem ----------------------------------------------
40. if exist "%allusersprofile%\Start Menu\Programs\CAD Analyst.lnk" (
41. echo %DATE% %TIME% shortcut already exists >>%LOG%
42. ) else (
43. echo %DATE% %TIME% creating a start menu shortcut for cad analyst .mbx file... >>%LOG%
44. cscript /nologo %~dps0makeshortcut.vbs "N=CAD Analyst" "T=c:\Program Files\Deccan International\CADAnalyst\CAD Analyst.MBX" "L=2" "W=c:\Program Files\Deccan International\CADAnalyst" "D=CAD Analyst" >>%LOG%
45. )
46. echo %DATE% %TIME% installation complete! >>%LOG%
47. ENDLOCAL
48. exit /b %errorlevel%


The %errorlevel% variable is used to capture and display the result code of the last-run command, which is “msiexec” in each case.  Then I force a script “exit” using the /b option and a return code that is non-zero if an error occurs.  If all proceeds along fine and finishes properly, the %errorlevel% result code at the very end should be zero (0).  Most deployment tools see zero as “good” or “no errors occurred”.



Then comes the makeshortcut.vbs script, for making the shortcut.  I could have downloaded some utility .exe to call instead, but I prefer making my own stuff so I know who to blame when it explodes or implodes.



'****************************************************************
' Filename..: makeShortcut.vbs
' Author....: Guess Who? (skatterbrainz.blogspot.com)
' Date......: 10/08/2010
' Purpose...: create a shortcut
'****************************************************************
Dim objArgs, fso, oShell, i, arg, scName, scTarget
Dim scFolder, scCaption, scLoc

Echo "info: makeShortcut.vbs --> processing inputs..."
Set objArgs = WScript.Arguments
If objArgs.Count = 0 Then
Echo "error: incorrect number of arguments supplied"
Echo "-- example..."
Echo "-- makeShortcut.vbs ""N=name"" ""T=target"" ""W=folder"" ""D=description"" ""L=loc"""
wscript.Quit(1)
Else
Echo "info: " & objArgs.Count & " arguments were provided"
Set fso = CreateObject("Scripting.FileSystemObject")
Set oShell = CreateObject("Wscript.Shell")
For i = 0 to objArgs.Count - 1
arg = objArgs(i)
Select Case Ucase(Left(arg,2))
Case "N=":
scName = Mid(arg,3)
Case "L=":
Select Case Right(arg,1)
Case "1":
' all-users desktop
scLoc = oShell.ExpandEnvironmentStrings("%allusersprofile%") & "\Desktop"
Case "2":
' all-users start menu / programs
If fso.FolderExists("C:\ProgramData\Microsoft\Windows\Start Menu\Programs") Then
' check for windows 7 client first
scLoc = "C:\ProgramData\Microsoft\Windows\Start Menu\Programs"
Else
' default to assuming windows xp client
scLoc = oShell.ExpandEnvironmentStrings("%allusersprofile%") & "\Start Menu\Programs"
End If
Case "3":
' current user desktop
scLoc = oShell.ExpandEnvironmentStrings("%userprofile%") & "\Desktop"
Case "4":
scLoc = Mid(arg,3)
End Select
Case "T=":
scTarget = Mid(arg,3)
If fso.FileExists(scTarget) Then
Echo "info: shortcut target has been verified"
Else
Echo "error: shortcut target could not be found!"
wscript.Quit(2)
End If
Case "W=":
scFolder = Mid(arg,3)
If fso.FolderExists(scFolder) Then
Echo "info: shortcut working folder verified"
Else
Echo "error: shortcut working folder could not be found"
wscript.Quit(3)
End If
Case "D=":
scCaption = Mid(arg,3)
End Select
Next
If scFolder = "" or scTarget = "" or scName = "" or scLoc = "" Then
Echo "error: insufficient arguments provided"
wscript.Quit(4)
Else
Echo "validating shortcut parameters..."
Echo "-- name = " & scName
Echo "-- target = " & scTarget
Echo "-- path = " & scFolder
Echo "-- location = " & scLoc
Echo "-- caption = " & scCaption
On Error Resume Next
Set oShortcut = oShell.CreateShortcut(scLoc & "\" & scName & ".lnk")
If err.Number = 0 Then
Echo "info: creating shortcut..."
oShortcut.TargetPath = scTarget
oShortcut.WorkingDirectory = scFolder
oShortcut.IconLocation = scTarget & ",0"
oShortcut.WindowStyle = 1
oShortcut.Description = scCaption
oShortcut.Save
If fso.FileExists(scLoc & "\" & scName & ".lnk") Then
Echo "-- shortcut has been created"
Else
Echo "-- failed to create shortcut!"
End If
Else
Echo "-- access denied to the specified location!"
End If
End If
End If

'----------------------------------------------------------------
' comment: echo runtime progress
'----------------------------------------------------------------

Sub Echo(s)
wscript.Echo DosDate() & " " & s
End Sub

'----------------------------------------------------------------
' comment: format date stamp to match DOS %DATE% %TIME% format
'----------------------------------------------------------------

Function DosDate()
dn = Left(WeekDayName(WeekDay(Now)),3)
mo = PadLeft(Month(Now), "0", 2)
dd = PadLeft(Day(Now), "0", 2)
yr = Year(Now)
x = mo & "/" & dd & "/" & yr
DosDate = dn & " " & x & " " & FormatDateTime(Now, vbShortTime) & ".00.00"
End Function

'----------------------------------------------------------------
' comment: pad string on left side with char to requested length
'----------------------------------------------------------------

Function PadLeft(sVal, ch, max)
Dim tmp
tmp = Trim(sVal)
Do Until Len(tmp) = max
tmp = ch & tmp
Loop
PadLeft = tmp
End Function


Together, these run the installations, copy the files, make the shortcut, create a nice log, save the girl, kill the bad guy, and free the hostages, with rolling credits at the end and sweet theme music.



Now I can check the “mapinfo10_setup.log” under the %TEMP% folder path to see what’s going on.  Note that when you deploy this as a SCCM package, it runs as the local account “NT_AUTHORITY\SYSTEM” (aka “SYSTEM”), so the %TMP% and %TEMP% paths are C:\WINDOWS\TEMP (or %WINDIR%\TEMP).



I’m done.  Beer time folks.  It’s a tough job, but someone’s gotta do it.

Monday, July 7, 2008

Stupid Scripting Tip 109: IF EXIST (FOLDER)

The CMD shell allows you to write some nifty script code. Not as crazy as VBscript or Kixtart or PowerShell obviously, but still, very useful. Sometimes a BAT/CMD script is the best solution. Actually more often than you'd think.

So, the IF EXIST statement is a very common tool, but you can only test for FILE objects with it, not FOLDER objects. However, thanks to the inherent NUL object, you can! Simply append \NUL on the end of a folder path to test for it using IF EXIST.

IF EXIST C:\FOLDERNAME\NUL GOTO WHATEVER

Works great.