Showing posts with label installation. Show all posts
Showing posts with label installation. Show all posts

Monday, January 27, 2014

Dastardly Dissections: PowerShell and Software Deployment Dabbling

I was turned onto PowerShell several years ago, but like most music that I've held onto, it took awhile to grow on me.  Until I had one of those "a-HA!" moments, which was just this past week.  I have to give a double-extra "thank you!" to folks like Jeffery Hicks and Don Jones (among many others), as well as all the folks who patiently help others on sites like StackOverflow and Microsoft TechNet.  If I had that much patience I'd be a therapist.


The Meat and Potatoes

I wanted to find a balance between efficiency and reusable code structures.  Ever since I was forged in the fires of LISP programming by an incredible guru named Brad Hamilton, I've sought to make my code as refactoringly refined and reusable as possible.  It should work like a Lego block, as he once mentioned to me.  Another word he used was "organic".  It should work and feel like it grew out of nature, not like a 7-legged cat trying to climb an ice mountain.

Much of what you will see below (and soon-after stab your own eyes out with a plastic fork, out of the sheer horror of it all) is my own personal seasoning.  I like to put a nerdy block-style heading at the top, followed by a group of related custom variable assignments, and then start to work destroying any sense of productivity soon after.

In a nutshell: I define some variables to identify the product, the installer file, the source path, the target path that the installer creates on a typical client, and then move on.

The next part checks if the file is already present, indicating a previous installation was already completed and then exit if that's the case.  If not found, go ahead and run the installation and return the exit code.

(Updated 1/28/2014: line in red below replaces the line just above it.  Ensures script calls installer from the same location / path)

[powershell-begin-ugly-code]

#------------------------------------------------------------
# filename...: install-orca.ps1
# author.....: David M. Stein
# date.......: 01/27/2014
# purpose....: install Microsoft Orca using PowerShell 3
#------------------------------------------------------------

# comment: define variables and assignments

$appName = "Microsoft Orca"
$msifile = "orca.msi"
# $srcPath = "\\appserver3\utils\microsoft"
$srcPath = Split-Path -Parent $PSCommandPath
$path32  = "C:\Program Files (x86)\Orca\orca.exe"
$path64  = ""

$f1 = get-location

write-host "info: searching for existing installation of $appName..."
if (test-path -Path $path32) {
  write-host "info: $appName is already installed (aborting install)"
  $retval = 5000
} else {
  write-host "info: installing $msiFile....."
  set-location $srcPath
  write-host "info: working path is $srcPath"

# comment: the following line may wrap incorrectly in a browser...
  $retval = (start-process msiexec.exe -ArgumentList "/i $msifile /qn" -Wait -PassThru).ExitCode

  switch ($retval) { 
    0    {write-host "info: success"} 
    3010 {write-host "info: success (reboot pending)"} 
    1603 {write-host "fail: I hate 1603. A useless error code!"}
    1605 {write-host "skip: target application was not found (uninstall abort)"} 
    default {write-host "fail: uh-oh? exit code is $retval"}
  }
 
  set-location $f1
  write-host "info: installation complete."
}
exit $retval

[powershell-end-ugly-code]


Why exit with code number 5000?  Good question. I wanted to be able to filter in on that via System Center Configuration Manager, especially through direct T-SQL queries and BI reporting.  I tend to "live" in the SQL Server environment more than anywhere else for some reason.  It feels like wandering around a big-volume hardware store on a quiet night.

If I treated an existing install as a "failure" or exception, I would have to assign a non-zero result code.  I could consider it a "success" and return 0 (zero) as well, but then I wouldn't be able to query for unnecessary attempts in my production environments.  Artificial flavoring has its uses.

To invoke this from an non-Powershell state, I fire off the command string as follows...

powershell -File install-orca.ps1

Then I can fetch the result implicitly via the command pipeline or explicitly by interrogating %errorlevel% via the CMD shell interface.

Ripping It Out Again

So, what about the Uninstall flip-side of this?  Let's try this out...

[powershell-begin-stupid-code]

#------------------------------------------------------------
# filename...: uninstall-orca.ps1
# author.....: David M. Stein
# date.......: 01/27/2014
# purpose....: uninstall Microsoft Orca using PowerShell 3
#------------------------------------------------------------

# comment: define variables and assignments

$appName = "Microsoft Orca"
$guid    = "{85F4CBCB-9BBC-4B50-A7D8-E1106771498D}"
$path32  = "C:\Program Files (x86)\Orca\orca.exe"
$path64  = ""

$f1 = get-location

if (test-path -Path $path32) {
  write-host "info: $appName is installed.  Uninstall it now..."

  # comment: the following line may wrap incorrectly in a browser also...

  $retval = (start-process msiexec.exe -ArgumentList "/x ""$guid"" /qn" -Wait -PassThru).ExitCode

  switch ($retval) { 
    0 {
        write-host "info: uninstallation was successful."
        write-host "info: removing leftover files and folders..."
        Remove-Item $path32 -Recurse
      }
   3010 {write-host "info: success (reboot pending)"} 
   1605 {write-host "info: target application was not found (uninstall abort)"} 
        default {write-host "fail: exit code is $retval"}
  }
 
} else {
  $retval = 0
  write-host "info: $appName was not found on this computer (abort uninstall)"
}
write-host "info: completed"
exit $retval

[powershell-end-stupid-code]


A few notes on the example above:

  1. First, you may notice the additional code to remove leftover files and folders.  That's because it's not uncommon to find leftover files and folders after a "successful" uninstall.  The reasons are many, but in short: just clean them up if needed.  
  2. Second, if the installation was not found, I force a 0 return value here.  I could have also forced something like 5001 or 6000 or 227001 or whatever (as long as it's not in conflict with known result codes used by other apps or processes).  I chose 0 because I'm tired and sitting in a realllllllly comfortable chair right now.  Too lazy to use a longer value.
  3. I could have used Test-Path to find the Registry Key instead of a folder and file.  That would work as well, and the example would look instead something like the following...

Test-Path "HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\{85F4CBCB-9BBC-4B50-A7D8-E1106771498D}"

(note that I had to wrap the path in matching double quotes; otherwise it tries to evaluate the { and } as code).

If you're not familiar with Windows Installer methods (e.g. msiexec syntax), that's okay.  That means you're probably "normal".  I'm not.  You can invoke an uninstall using "/x" and provide a specific .msi package file, or you can locate the associated application GUID from the Registry (see HKLM\Software\Microsoft\Windows\CurrentVersion\Uninstall, or for 32-bit apps on a 64-bit client, like Orca, refer to HKLM\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall) and use that as well.  Below is a screen capture of REGEDIT showing the key and value on my cheap laptop...


Find the "UninstallString" value and grab a copy to inspect.  The irony is the "/I" prefix, which denotes "Install", but you can ignore that.  Almost every product entry will have an "UninstallString" value and it will almost always contain "Msiexec /I{blahblahblah}".  For an uninstall operation, you replace "/I" with "/X" (upper or lower case, doesn't matter), and move on.  It's the rest of that string that matters.  That's the GUID, and it is usually pretty reliable for use with msiexec to uninstall a known product entry.

More Mindless Notes:
  • You may encounter cases where you do NOT want to delete leftover files and folders (I didn't even mention leftover Registry keys and value, did I?).  Just comment that line and you're good to go.
  • You may need to stop services in order to perform some tasks.  You can use the Get-Service cmdlet or Stop-Service.  To remove a service, you can use the ancient SC.EXE command (under \Windows\System32) to invoke the Delete method.  Just don't forget that it may require a reboot.
  • Be careful to validate every exit code before assuming anything other than 0 (zero) is "bad".  3010 for example is good.  In some contexts (is that proper English?), the exit code 1605 could be considered "good" as well.
  • I'm NOT a PowerShell expert.  I'm still learning and very possibly farther behind on this stuff than you (in which case you're probably not reading sentence because you already left this page to find what you are really looking for).  I hope I'm not the smartest guy in the room.  That's a boring proposition to consider.  I'd rather be learning.
Namaste.

Sunday, September 8, 2013

Exam 2013-0824 - Software Packaging, Repackaging and Deployment

The following exam consists of 5 questions pertaining to the field of "software repackaging and deployment" within a Microsoft Windows environment.  Each question may have one or more answers (multiple choice).  You have 15 minutes to complete it.  Good luck!


1. You've been assigned a request ticket to repackage and deploy a product to several computers within your network environment.  The ticket states that there are no binaries from which to build the package, and you must contact the vendor to continue.  You call the vendor and state your objectives.  The vendor replies that you cannot have a copy of their binaries because they don't trust anyone to handle them without pirating them, and that only they can perform installations for each computer.

Which of the following should be your first choice of action?

A. Reach through the phone and bitch-slap the representative with both hands.
B. Laugh hysterically and tell them to "never mind", because you already downloaded a copy from Pirate Bay.
C. Hang up. Close the ticket with a comment stating the vendor is on cheap drugs.
D. All the above.

2. You deployed a bootstrap package to execute a "per-user" installation of a product which was originally packaged as a "Click-Once" installer, onto a group of Windows 7 computers.  You are now told to remove that application and install a different application.  You discover that many of the target computers were shared among multiple users, who each launched the installer and have used it extensively.

Which should you do first?

A. Hire a hitman to kill the vendor.
B. Hire two hitmen and a hitwoman to kill the vendor.
C. Start smoking heavily.  If you already smoke, then smoke more heavily.
D. Look for a job outside of the IT world.

3. Your manager makes a comment during a staff meeting to the effect that "all MSI package installation deployments are the same, and simple as dirt!".  You should...

A. Remain motionless while thinking of your family, starving and crying at home around the bare dinner table, because you reacted properly and choked that person out, instead of ignoring it.
B. Ask the person, "so, when are you taking that job on by yourself?"
C. Yawn and continue working on your Fantasy Football roster from your mobile phone.
D. All of the above, in any order you desire.

4. A different manager insists that virtualization is the cure-all for deploying and managing client applications.

A. You raise your eyebrows.
B. You raise your eyebrows.
C. You raise your eyebrows again.
D. All of the above.

5. Which of the following command syntax examples will install the "fubar2014.msi" package, apply a transform named "tarfu.mst" during the installation, capture the log output into the user's "temp" data folder, do all of this silently, and keep your coffee warm throughout:

A. msiexec /i fubar2014.msi /qn TRANSFORMS=tarfu.mst /l* %temp%\fubar2014.log
B. msiexec /i fubar2014.msi /qb! TRANSFORMS=tarfu.mst /l* %appdata%\fubar.log
C. msiexec /install fubar2014 /quiet /norestart TRANSFORMS=tarfu.mst /lvao %appdata%\fubar.log
D. None of the above.


Be honest, did you scroll down here first and cheat?  Seriously? I hope not.  That would be even worse than failing it without cheating.


answers:

1. D
2. C
3. D
4. D
5. D

Friday, February 8, 2013

The Next Book

I have given up on the book-topic survey, as far as relying on the votes as a means for determining which course to pursue. The votes are just too scattered, with no clear "winner". (I said "scattered".. heh heh. Ok, too easy an not clever enough).
(do e-ebooks require e-glasses too?)

Anyhow, I decided to go with the book sales numbers to point me in the direction to go. Based on two months of numbers (December 2012 - February 2013), the topics appear to fall in place as follows (from most to least popular):


  1. Software packaging and deployment
  2. Visual LISP Programming
  3. AutoCAD Network Administration and Packaging/Deployment
  4. IT Project Management

Shoving this through a secondary logic-filter (somewhat like processing beer through a Randall), hopefully this arrives at a clear direction.  Here goes...


  1. The responses from my recent blog post about Software Packaging were unexpectedly good.
  2. Visual LISP is a dying language, unfortunately.  It was fun while it reigned supreme, and more fun when I actually worked with it.
  3. I'm caught  up on 2013 network deployments for Autodesk products
  4. I pretty much covered what I wanted to in IT Project Management
So 1 + 1 = 1, errr, uhhh, what I mean is that I think I will follow up "Grinding Gears" with a newer/better-tasting/less-filling/no-wait-I-meant-MORE-filling version, focusing on Software Repackaging and Testing.  I think that makes sense.  If you strongly disagree, share your thoughts (and if you own a copy of any of my books, and you haven't posted a rating or feedback on Amazon yet, please do so?  I really depend on that to help me focus on what you want me to write about and what needs more work).




Wednesday, February 6, 2013

The Not-So Fine Art of Software Re-Packaging and Deployment


New and Improved / Amended Version!

Note: Thanks to Mikko Järvinen for reminding me about "Uninstall Testing", also known as "Package Removal Testing" or "PRT".  I added the changes below in blue (just FYI).

I had to prepare the following for an internal FAQ document to help our "customers" better understand the ramifications, and pontifications, with respect to processing a request to have software packaged (re-packaged) for deployment to their computers.  It's a work in progress, but this is where it stands right now...


Overview

Software can be installed in a variety of ways, but when it comes to installing software on a large number of computers in the shortest time, AND with the highest level of consistency and reliability, it requires a little more work.

Unfortunately, software vendors do not follow a common playbook when it comes to packaging their products for installation. Some products are packaged in a way that makes it easy to install them using automation tools. Most are not. When software is not packaged in a way that lends itself to being installed easily, it often requires "repackaging".

Packaging vs. Re-packaging

Packaging is the process whereby a software product is compiled into an original installation package. This is often a single ".exe" or "msi" file, but in many cases it results in a collection of many folders and files. An installer that comes as a single ".exe" file is referred to as an "Executable installer". An installer that comes as a single ".msi" file is referred to as a "Windows installer package".

Executable installer packages are the most common.  These are the familiar .exe packages (e.g. setup.exe). They often provide a built-in mechanism for launching them along with a list of options or settings to pre-configure the installation without having to step through a series of dialog input forms. In many cases, this includes the option for running it in "silent" mode. "Silent" mode allows the installation to run without displaying any forms or prompting for user input. This is essential for mass deployment using automation tools such as Microsoft Configuration Manager or Group Policy.

Repackaging is the process of taking the smelly crap that some vendors hand you, and mooshing it up into a new, less-smelly ball of goodness that can be installed "silently" and pre-configured, just the way your precious customers are begging for.  There are no limits to what qualifies as "repackaging".  It can be wrapping the installation parameters within a script file (pick your script language, it really doesn't matter that much), or it can be squeezing it through the meat-grinder of something like InstallShield, or AdminStudio, to make a whole new installation binary (i.e. a new .EXE, or a Windows Installer .MSI file, etc.).  I won't even bother with discussing .ZAP files because I just ate.

Did I just say that it doesn't really matter what scripting language you use? Well, that's sort of true.  I don't recommend you just pick a scripting language without considering how it will fit into what the rest of your organization uses.  Even more important, you need to consider what the environment will support (if you do everything in one language, you might find out some of the target devices don't support it).

Complications and Time Factor

One of the most commonly asked questions about packaging and re-packaging is "How long does it take?" The answer is always "It depends.". No two software installations work exactly the same. Because of this, it is impossible to predict how long it will take to get a workable unattended installation package prepared and tested. Some of the variables that play a critical role in determining the time it takes to re-package an installation include:
  • The original installation package format and integrity
  • Vendor licensing and activation requirements
  • Removal or Upgrade of older versions
  • Checking for, and resolving prerequisites
  • Per-machine vs Per-user configuration settings
  • Operating System dependencies
  • Business-specific configuration settings
  • Vendor compliance with Microsoft's recommended guidelines
  • Client/Server dependencies
This is not an exhaustive list, and each of these can greatly impact the difficulty with re-packaging the installation. In some cases, it can render the re-packaging process ineffective, requiring manual installation and configuration; something we try to avoid at all costs.

Other factors that should be factored in:
  • The relative chemical stimulant consumption rate of the under-paid coders hired by the vendor (on contract, of course).
  • The address of the mobile trailer they call an "office"
  • Whether they include "Grateful Dead Reunion Tour" dates as paid holidays
  • When you say "InstallShield" and they respond with "What's that?"
  • When you really have to explain to the vendor what a "silent install" is
  • When you call their "support line" and reach the owner/president/senior architect/coder guy every time.
I'm sure I could add more, but I'm too tired right now.  Let's move on...

Testing and Validation

Once an installation package has been developed, the next step in the process is to test it. In most cases, this is done by using "test" computers whereby a designated user will "remote" into the test computer from their own location and test the software installation. This eliminates the need for customers to travel around to physically sit down at the test computer and allows greater flexibility with scheduling.

In most cases, a virtual machine "test computer" will suffice just fine.  It doesn't matter what you prefer to work with (VMware, VirtualPC, VirtualBox, etc.) as long as it works and users can remote into it and do what they do (crash and break things, usually).

In some cases, usually when special hardware devices are required to be used with the software, it may be necessary for the customer to physically sit down at the test computer and log on, so they can use the hardware devices properly.

The process whereby customers test the software prior to it being deployed into production, is referred to as "User Acceptance Testing", or UAT.  But be careful, as UAT is *NOT* the entire testing process.  It's just one piece of it.

The most basic testing process goes something like this:

  1. Install the application using the normal means, on an isolated test computer.  This helps the repackager get familiar with how the application "normally" installs, and what options and settings it provides along the way to completion.  This is sometimes called "Installation Analysis Testing" or IAT.  It's also equally important to use this step for documenting the "footprint" an application installation leaves on a computer.  Having a complete list of changes it makes to the Registry, File System, Services and security environment, are all crucial pieces of information. This is required for making sure that you build an uninstall package that does a thorough job of cleaning up when the application is removed.
  2. After repacking, use the new repackaged package (a mouthful, sorry), to do the install to verify that it (A) installs properly, even silently, and (B) launches and functions properly after installation. This is sometimes called "Initial Package Testing" or IPT.  After running the IPT, it is vital that you confirm that the installed application functions properly. This also adds a new dimension to the "footprint" by virtue of launching and using the application, which often initiates a chain of post-installation configuration processes that modify additional things in the Registry, File System, Services, and so forth.  This is where a wrench often comes flying in from left field during the uninstall testing (IRT), so be prepared to make some adjustments to your uninstall package.
  3. After the repackaged package has passed IPT, it's time to load it up into your deployment/distribution system (i.e. Microsoft System Center Configuration Manager) - (and you thought I couldn't string a bunch of words together into a longer name than that, pffft!).  Once loaded into your deployment system, the next step is to target a test computer to verify that the deployment system delivers the installation package, and installs it successfully.  This is sometimes called "Package Deployment Testing" or PDT.
  4. After PDT, it's time to go to User Acceptance Testing, or UAT.  In most situations, you can use the same targeted test computer from the PDT without have to do another deployment, but the choice is yours (and varies by individual circumstances).
  5. Once UAT is complete, you should be ready to remove the safety lock and fire with both barrels.  In other words, you should be ready to go to Production Deployment.
Some important notes pertaining to the above gibberish:
  • Steps 2, 3 and 4 should be performed on a test computer for each type of target configuration.  In other words, if you will be expected to deploy this to Windows XP, Vista, Windows 7 and Windows 8 computers, you should definitely perform each test on an appropriate test computer.  And don't forget that 32-bit and 64-bit configurations add another layer of complexity (and testing).
  • If your target user base does not (generally) have local Administrative permissions on their computer device, make sure you package and test with that expectation.  And more importantly: Be sure to have a user account logon and launch the application the FIRST TIME after being deployed, so that it will behave as it would on the other 99.99% of the target clients (unless you expect to walk around, or remote into, every computer after the deployment - which would probably suck).
  • Useful tools in your arsenal for developing installation packages are InstallShield and AdminStudio.  But in addition to their primary capabilities, another useful aspect of AdminStudio is to use the Repackager "snapshot" feature to help compare "before" and "after" system states when doing your Uninstall development and testing.  For example, you can take a "before" snapshot, install and run the application, and then take an "after" snapshot.  The results of comparing both snapshots will reveal what aggregate changes were made to the system, thereby helping to shine some light on how to develop an effective package for removing the application completely and cleaning up behind it.
The level of testing you employ will depend upon the nature of your environment obviously.  The smaller and less complex an environment is, the less likely you will need to perform as many phases of testing. But it never hurts to test more than you think you should.  It usually saves you from yourself later on (if your poorly-tested, bad packaging output lands on 10,000 devices over a weekend, your Monday will very likely suck ass indeed).

Deployment

Once a software installation package has been tested and approved by the customer, the IT department can then begin to deploy it to the requested devices. The method we use is an automated deployment tool named Microsoft System Center Configuration Manager.

Final Thoughts

Software Packaging and Repackaging (two distinct processes) are a combination of science and art. While based upon technology (science), there is a lot of human intuition (art) involved as well.  If you expect to master these things using one or the other alone, you will be in for a tough time.  Also, be prepared to consume additional quantities of caffeine.

Sunday, April 29, 2012

Project Taphouse

There's not really a Project called "Taphouse", at least not that I'm working on.  But I'm calling it that because I can't really discuss what it's really for or for whom it is being built.  However, it has been (and still is) an interesting project.  It's forced me to drill into Google for lots of command goodies I knew about, but hadn't used in a long time.  Many I hadn't had to use in the way I'm using them now either.  So I thought I'd share some of this in case it's helpful to others.

Here's the basis of the requirement:

The Requirements

"Mobile tablets or laptops will be used to collect inventory data from remote locations using a wireless handheld barcode scanner device.  The remote locations will not always have accessible WiFi, nor a reliable 3G or 4G signal.  Further, testing at locations that have 4G LTE coverage indicates excessive battery drain when using active LTE communication.  Requesting a client-based inventory collection tool that can download configuration updates, as well as upload inventory data, but only when attached to the base network.  Material costs must be kept to absolute minimum."

This led to five minutes of head-scratching, a little Google searching, and finally an "a-ha!" moment:

A local web app using a local database.  The web app will offer the means for capturing inventory scan data, manual entry (when needed), and provide upload/download capability when connectivity allows.

The Ingredients
  1. Windows 7 tablet or laptop
  2. Local IIS instance and virtual directory configuration (windows authentication, disable anonymous authentication, to allow tracking of entries by logged on user)
  3. ASP or ASP.NET web app
  4. SQL Server 2008 R2 Express
  5. Coffee
  6. Sugar snacks
  7. Bad music
(Note: steps 2, 3, 4 can be done in any order, but it helps to move step 5 to step 1 sometimes)

The Deliverable
  1. A packaged installation that can be easily deployed to laptops or tablets, either manually, or via Configuration Manager advertisement, to enable user to begin capturing inventory data at remote locations in the field.
The Chunks
  • Step 1 is easy enough.  
  • Step 2 was interesting.  First I used the DISM command to install and configure IIS, the necessary component features, and Windows Authentication.
  • Step 3 involves creating the virtual directory target folder, copying in the web app content files, and then using APPCMD to create and configure the web site and virtual folder settings
  • Step 4 involves creating a configuration (response) file for installing SQL Express 2008 R2 to allow for silent installation on other computers.
Install and Configure IIS features

dism /Online /Enable-Feature /FeatureName:IIS-WebServerRole
dism /OnLine /Enable-Feature /FeatureName:IIS-WebServer
dism /OnLine /Enable-Feature /FeatureName:IIS-ApplicationDevelopment
dism /OnLine /Enable-Feature /FeatureName:IIS-ISAPIExtensions
dism /OnLine /Enable-Feature /FeatureName:IIS-ASP
dism /OnLine /Enable-Feature /FeatureName:IIS-WebServerManagementTools
dism /OnLine /Enable-Feature /FeatureName:IIS-Security
dism /OnLine /Enable-Feature /FeatureName:IIS-WindowsAuthentication

Create Virtual Folder


I created the folder "inventory" beneath "c:\inetpub\wwwroot", but you could put it anywhere really.  The main thing is to poing the "/PhysicalPath:" parameter to the appropriate location.  The APPCMD command is easy to use for creating and configuring the virtual directory.  For this project, I'm building the virtual directory under the Default web site.

appcmd add vdir /app.name:"Default Web Site/" /path:/inventory /physicalPath:c:\inetpub\wwwroot\inventory

appcmd set config "Default Web Site" /section:windowsAuthentication /enabled:true /commit:apphost

appcmd set config "Default Web Site" /section:anonymousAuthentication /enabled:false /commit:apphost

Install SQL Server 2008 R2 Express

Actually, the first step is to launch the installer (.exe) from a CMD console using /Action=Install /UIMode=Normal  - This enables the "Ready to Install" step in the left-hand vertical list of steps shown in the installation dialog.  For whatever reason, if I simply double-click the .exe and run the installation "normally" it doesn't show this feature.  You need the "Ready to Install" feature because it's the only place the shows the path to the "ConfigurationFile.ini" response file it creates, and allows you to abort a "real" installation at the final step and keep the .INI file.

Once you have the .INI, the CMD syntax for using it is pretty simple, but you still need to make some very minor modifications to the .INI first.

INI modifications

Add:  IACCEPTSQLSERVERLICENSETERMS=1
Change:  QUIETSIMPLE to "True"
Change:  SECURITYMODE to "SQL"  (you don't have to do this, but I prefer to)
Add:  SAPWD=[enter a strong password here]
Change:  TCPENABLED to "1"
Change   NPENABLED to "1"

You could set QUIET="True" for no dialog display, but I like to see some progress since it's pretty slow and pauses a few times along the way.

The installation syntax (assumes both files are in the same folder):

SQLEXPRWT_x86_ENU.exe /ConfigurationFile=ConfigurationFile.ini


But wait - There's more!


After installing the database, I still need to automate the setup of the database schema, create tables, users and grant permissions.  I created some T-SQL scripts and saved them in a folder.  Then I use the SQLCMD command to execute them using the default "sa" user account (note that I've replaced the actual password with "**" below, but you have to specify the actual password)


cd "\Program Files\Microsoft SQL Server\100\Tools\Binn"
sqlcmd -U sa -P ** -S %ComputerName%\INVENTORY -i 1_create_database.sql -o "%temp%\1_sql.log"
sqlcmd -U sa -P ** -S %ComputerName%\INVENTORY -i 2_create_login.sql -o "%temp%\2_sql.log"
sqlcmd -U sa -P ** -S %ComputerName%\INVENTORY -i 3_create_user.sql -o "%temp%\3_sql.log"
sqlcmd -U sa -P ** -S %ComputerName%\INVENTORY -i 4_create_table.sql -o "%temp%\4_sql.log"
sqlcmd -U sa -P ** -S %ComputerName%\INVENTORY -i 5_grant_user_privs.sql -o "%temp%\5_sql.log"
sqlcmd -U sa -P ** -S %ComputerName%\INVENTORY -i 6_sample_data.sql -o "%temp%\6_sql.log"

As an example of the T-SQL script, this is "1_create_database.sql" taken from the project at build 3...

( NAME = N'Inventory', FILENAME = N'c:\Program Files\Microsoft SQL Server\MSSQL10_50.INVENTORY\MSSQL\DATA\Inventory.mdf' , SIZE = 2048KB , FILEGROWTH = 1024KB )
 LOG ON
( NAME = N'Inventory_log', FILENAME = N'c:\Program Files\Microsoft SQL Server\MSSQL10_50.INVENTORY\MSSQL\DATA\Inventory_log.ldf' , SIZE = 1024KB , FILEGROWTH = 10%)
GO
ALTER DATABASE [Inventory] SET COMPATIBILITY_LEVEL = 100
GO
ALTER DATABASE [Inventory] SET ANSI_NULL_DEFAULT OFF
GO
ALTER DATABASE [Inventory] SET ANSI_NULLS OFF
GO
ALTER DATABASE [Inventory] SET ANSI_PADDING OFF
GO
ALTER DATABASE [Inventory] SET ANSI_WARNINGS OFF
GO
ALTER DATABASE [Inventory] SET ARITHABORT OFF
GO
ALTER DATABASE [Inventory] SET AUTO_CLOSE OFF
GO
ALTER DATABASE [Inventory] SET AUTO_CREATE_STATISTICS ON
GO
ALTER DATABASE [Inventory] SET AUTO_SHRINK OFF
GO
ALTER DATABASE [Inventory] SET AUTO_UPDATE_STATISTICS ON
GO
ALTER DATABASE [Inventory] SET CURSOR_CLOSE_ON_COMMIT OFF
GO
ALTER DATABASE [Inventory] SET CURSOR_DEFAULT  GLOBAL
GO
ALTER DATABASE [Inventory] SET CONCAT_NULL_YIELDS_NULL OFF
GO
ALTER DATABASE [Inventory] SET NUMERIC_ROUNDABORT OFF
GO
ALTER DATABASE [Inventory] SET QUOTED_IDENTIFIER OFF
GO
ALTER DATABASE [Inventory] SET RECURSIVE_TRIGGERS OFF
GO
ALTER DATABASE [Inventory] SET  DISABLE_BROKER
GO
ALTER DATABASE [Inventory] SET AUTO_UPDATE_STATISTICS_ASYNC OFF
GO
ALTER DATABASE [Inventory] SET DATE_CORRELATION_OPTIMIZATION OFF
GO
ALTER DATABASE [Inventory] SET PARAMETERIZATION SIMPLE
GO
ALTER DATABASE [Inventory] SET  READ_WRITE
GO
ALTER DATABASE [Inventory] SET RECOVERY SIMPLE
GO
ALTER DATABASE [Inventory] SET  MULTI_USER
GO
ALTER DATABASE [Inventory] SET PAGE_VERIFY CHECKSUM 
GO
USE [Inventory]
GO
IF NOT EXISTS (SELECT name FROM sys.filegroups WHERE is_default=1 AND name = N'PRIMARY') ALTER DATABASE [Inventory] MODIFY FILEGROUP [PRIMARY] DEFAULT
GO

And, here' an example of the T-SQL script, "5_grant_user_privs.sql" taken from the project at the same build...

use [Inventory]
GO
GRANT DELETE ON [dbo].[AuditInventory] TO [InvUser]
GO
use [Inventory]
GO
GRANT INSERT ON [dbo].[AuditInventory] TO [InvUser]
GO
use [Inventory]
GO
GRANT SELECT ON [dbo].[AuditInventory] TO [InvUser]
GO
use [Inventory]
GO
GRANT UPDATE ON [dbo].[AuditInventory] TO [InvUser]
GO
use [Inventory]
GO
GRANT DELETE ON [dbo].[Collections] TO [InvUser]
GO
use [Inventory]
GO
GRANT INSERT ON [dbo].[Collections] TO [InvUser]
GO
use [Inventory]
GO
GRANT SELECT ON [dbo].[Collections] TO [InvUser]
GO
use [Inventory]
GO
GRANT UPDATE ON [dbo].[Collections] TO [InvUser]
GO

Conclusion

I haven't described the download and upload aspects yet, but I will in the near future.  Those features are interesting in and of themselves.  But for now, hopefully this will keep you entertained (or put you fast asleep).

As I've said many times before: Microsoft gives you tons of goodies to help automate almost any task.  The combination of silent installation capabilities, scripts, commands like DISM, APPCMD, SQLCMD, and the ability to string it all together in a simple BAT script, opens the door to unlimited possibilities.  You can wrap all this in a nice .MSI using InstallShield as well, but I wanted to show that it's possible to do all this with absolutely ZERO cash spent on software product licensing (besides Windows itself).  One final note, if you wrap all this in a script, be sure to run the script using "Run as Administrator".

Cheers!


Friday, April 13, 2012

Packaging Exam: Part 3

The stupidity continues on...

You've installed a 32-bit application on a 64-bit Windows 7 Enterprise computer.  You want to track down all the places you might likely find this "footprint".  Which locations would you select?

A. %ProgramFiles%
B. %ProgramFiles(x86)%
C. %CommontFiles%
D. %CommonFiles(x86)%
E. %ProgramData%
F. %WINDIR%\System32
G. Registry: HKLM\SOFTWARE
H. Registry: HKLM\SOFTWARE\WOW6432node
I. Registry: HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall
J. Registry: HKLM\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall
K. Registry: HKEY_CLASSES_ROOT


Answer:

(I'm not telling)  moo-ha-ha-haaaa!  Post your answers below...

Wednesday, April 11, 2012

Why Logging Matters

Nobody likes dealing with log files.  Nerds like to invoke a shock of disbelief by claiming they do, but let's face it, if they saw a naked attractive person or a glass of cold beer, they'd rather tackle one of those before tackling a big log file.

But if you are writing software, or making anything that uses software technology to "do" something, you really need to take some time to at least make it possible to generate a log output.  A log file is like the black box on an aircraft. It's your chance to create a trail of crumbs to lead you back to where things go wrong at the worst possible times.  Whether you save your status output to a "file", a database, a cardboard box or whatever, doesn't really matter.  Well, it does matter, but the most important aspect is that you bother to make some output to be captured somewhere while your bundle of technological joy is doing something.

What to do?

So, how do you know what to log?  In simplest terms: EVERYTHING.  Log as much as you possibly can.  You can get fancy and split your verbosity into "normal" and "heavy-duty" if you want.  It really depends on your assessment of how complex the processing you're performing really is.  Regardless of verbosity, the most simple and direct advice I can offer you is to do your logging output as follows:

A) Before you execute the next task
B) During the task execution (redirected log output)
C) After the task completes (result or exit code)

I've seen people who only use option (A), which isn't bad really, except that the output you'd see at (C) might impact the very next task to be executed (or another later in the sequence).  Option (C) alone makes it tough to track a complicated (lengthy) sequence, since you won't be able to find where it crashed.  At the very least, use options (A) and (C) together.  Even without (B) that will help enormously.  One project I worked with would include a routine in (C) that essentially captured the output from (B) which happened to be an out-of-band process, and merge it back into the same log as (A), and then continued piping into the same log with (C) and onward.  That's really not as complicated as it wounds.

Time-stamping is very important as well.  I prefer to prefix each and every line of status output with a (short-format) DATE and (long-format) TIME, followed by a category tag (e.g. "info", "fail", "warn", etc.) and then the detailed verbage.  As an example from a CMD script:

echo %DATE% %TIME% info: adjusting target folder permissions... >>%LOG%
cacls %TARGETPATH% /e /t /c /g users:C
echo %DATE% %TIME% info: exit code is %errorlevel% >>%LOG%

From VBscript, you could do it something like this as well:

wscript.echo Now & " info: getting ready to copy files to " & targetPath
retval = objShell.Run("cmd /c robocopy " & sourcePath & " " & targetPath & options, 7, True)
wscript.echo Now & " info: exit code is " & retval

The language doesn't really matter.  You can do this with PowerShell, KiXtart, Perl, or anything that is still often used in 2012.  The above examples are just for demonstration.  There are many ways, some better than others, to create status output for logging.  Just do it.


Conclusion

Logging really is your friend.  It's your black box recorder, waiting to shine a crucial light on exactly which little bolt failed and caused the entire jumbo jet to crash into a mountain side on a clear day.  Best of all, it's ENTIRELY under your control (if you're the one enabling status output from your program code or software package, or script). You can make it do whatever you want.  But be careful to use it wisely and be consistent.

Packaging Exam: Part 1

I'm going to start posting questions from my "packaging exam" which I use for screening job applicants for one of our larger customers.  Being that I also work on the packaging and deployment team, I've compiled these questions from past experience as well as past interviews.  The questions are continuously updated, and I can't post all of them, so I'm planning to post just a sampling of them over a few days span.

Scenario:  You've performed an uninstall of a software application which was originally installed from an MSI package.  Afterwards, you've discovered that the product installation folder as well as several files within it and in sub-folders beneath it were left behind.

Question: What is/are the most likely reasons these items were left behind?

A. The files were added or modified after the initial installation
B. The files were "in use" by another process at the time of the uninstall
C. The files were marked as "hidden" or "system"
D. You ran the uninstall without Administrator level permissions.

Correct Answers:  A, B

Explanation:

A. An MSI installation (Windows Installer) uses a manifest-oriented approach to mapping uninstall processing with the original installation changes.  If objects are added after the installation, they are not considered part of the original installation and are left alone.  Being that they are left alone, the folders in which they reside cannot be safely deleted.

B. Files which are marked as being "in use" by a process (or service, also a process), are locked from deletion.  In order to delete the files, you must stop any services which use the files, and/or terminate processes which are using them.

Comments:

A common approach to performing "clean" uninstalls is to include TASKKILL or (Sysinternals') PSKILL requests to terminate processes, as well as SC or PSSERVICE (Sysinternals) to stop running services, prior to beginning the main uninstall.  This helps to ensure files are not in use while the uninstall is being executed.  Even though many installers will include robust handling of services and processes, many more do not bother.

For removing leftover folders and files, the old "RD" command will usually suffice.  For leftover Registry keys, the REG command is usually sufficient as well.

Sunday, November 20, 2011


It is now available on Amazon.com!

Download a free sample or buy it for only $7.99

Available for US, UK, Germany, and France Kindle shoppers.

Don't have a Kindle?  No problem.  You can download FREE Kindle Reader Apps for Windows, WP7, OSX, iOS (iPod, iPhone, iPad), Blackberry and Android

Still not satisfied?  You can use the Kindle Cloud Reader to read books in your web browser too.

Saturday, November 19, 2011

Book Announcement: Packager's Pocket Reference, 2nd Edition




The 2nd Edition is out!  Chocked full of new examples, reference information and new chapters on lab setups, methods and approaches to making packages through a variety of means.  Scripting, packaging and all that stuff.  Still in a compact "reference" format and size, makes it easy to navigate and find what you need fast.

Available soon* on Amazon Kindle and Kindle Reader apps (Windows, OSX, Android, Blackberry, iPad) for only... $7.99 (USD)



* submitted to Amazon 11/19/2011 and should be available for purchase within a few days afterwards.

Thursday, October 6, 2011

When Applications Take a Dump

How many times have you uninstalled a software product only to find out later that it left traces of its existence all over your poor computer?  Part of the work of a software packager (or rather: repackager) is to perform forensic analysis of the footprint of an application at the time of installation, after being used, and after being uninstalled.  The goal is always to get the computer back to a state as if the application had never been installed, but without causing issues with the operating system or other applications.  Rather than try to split this over XP, Vista and Windows 7, I'm only talking about 7 here.  I don't give a crap about XP or Vista anymore, sorry.  If the %name% stuff confuses you, just open a CMD window, type in SET and press Enter to see what I'm talking about.

The Obvious

  • %ProgramFiles%
  • %WinDir%\System32
  • %CommonProgramFiles%
  • %AllUsersProfile% (note: This is a Symbolic Link to %ProgramData%, same place)
  • %ProgramData%
  • %Temp%
  • HKLM\SOFTWARE\<vendor-or-product>
  • HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall

The Not-So-Obvious

  • 64-bit Systems
    • %ProgramFiles(x86)%
    • %CommonProgramFiles(x86)%
    • HKLM\Software\Wow6432Node\...
  • %LocalAppData%
  • %SystemDrive%\Users\Default (note: "Default User" is a JUNCTION to "Default", same place)
  • Services
  • DCOM configuration settings
  • WMI / CIM namespaces
  • HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Run (and RunOnce)
  • HKLM\SOFTWARE\Microsoft\Active Setup\...
  • HKLM\SOFTWARE\ODBC\...
  • HKEY_CLASSES_ROOT\...
  • HKLM\SYSTEM\CurrentControlSet\...
  • HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment
  • %ProgramData%\Microsoft\Windows\Start Menu\Programs\Startup

This is not a complete list.  Some applications crap in more places than these.  But hopefully this gives you a rough idea of places to look when something gets left behind and things are just not quite right as a result.

Tools

Some of the tools that can come in handy to help investigate what an application does to a computer are as follows:

  • Virtualization: VMware Player, VMware Workstation, Virtual Box, Hyper-V
  • Sysinternals:  Process Explorer, AutoRuns, Process Monitor
  • CMD:  DIR /AH /AS
  • InstallShield Repackager (snapshot results)

clean_up_after_yourself

Software Development's Biggest Mistakes

The most common and most detrimental mistakes that seem to occur again and again.  I'm not saying you need to "master" all of these, but you should be familiar enough with all of these aspects to be able to explain them to your grandmother.  Hopefully you strive to apply these in your daily work.

Basics_Hero

  • Not Understanding Programming Basics
    • Decision Branching (If / Then / Else / Select /Switch / Cond / ElseIf, etc.)
    • Boolean Logic (And, Not, Or, etc.)
    • Functions, Sub-Routines, Lambda Expressions
    • Iteration and Recursion (While, Do, For, Apply, Mapcar, etc.)
    • Variable Scopes (local, private, global, public, etc.)
    • Not understanding all of the Data Types for a given language
    • Not understanding String Behaviors (for given language)
    • Not understanding File Streams
    • Ignoring ERROR/EXCEPTION HANDLING (Gaa!!!!  GD IT!!!)
    • Not Documenting source code (it ain't just for others, it helps you as well, especially when you go back to fix something a year later)
    • Modularity / Code Reuse
  • Not Understanding Databases
    • Ignorant of Table Structures and Data Types
    • Ignorant of Constraints
    • Normalization !!!!!!!!!  God damn it!  Normalize your fucking tables!!!
    • Views and Stored Procedures
    • Using MS-Access to build applications (GD IT!!!!!!!  teeth gnashing)
    • Excel is NOT a database!
  • Not Understanding User Context
    • Assuming users have administrator rights (kill the developer on sight!)
    • Not understanding Multi-user / Shared computer environments
    • Not understanding Terminal Services / Server Shared environments
    • Not understanding Service / Proxy accounts
  • Not Understanding the Installation (and Uninstall) Process
    • Not following the documented guidelines (TechNet, MSDN)
    • Not providing a Silent/Unattended installation option
    • Not providing a Silent/Unattended Uninstallation option
    • Not using MSI-based installers (Windows only) - a setup bootstrap is ok, but building your own installer is just stupid as shit.  And stop with the no-name bullshit setup packagers, just buy Wise or InstallShield and do it right, mmmkay?
  • Ignoring Cohesion and Consistency
    • Installation scatters crap all over the place, rather than keeping it collocated logically
    • Application stores state data in too many locations (registry and files, and ...)
    • Forgetting to REFACTOR your code (using the rollback method, where you revisit project "A" after finishing product "C" to apply what you learned since)
    • Ignoring common naming conventions.  Name your code files, functions, variables, registry keys, event entries, database names, tables, views, procedures, services and everything CONSISTENTLY!  If you don't care enough to make your code look like it works as an integral army of awesomeness, what else don't you care about?  Making it work properly?!
  • Becoming Locked into One Language
    • Learning and Using ONE language is like eating with only a fork.  No spoon or knife?  It's like trying to rebuild a car engine with only a screw driver.  Languages are tools.  The more you learn and apply, the broader your skills, understanding and wisdom about methods, approaches, and quality.
    • Never assume an "old" language has nothing to offer.  There are still plenty of situations where an "old" BAT script will work more efficiently than VBscript or PowerShell.  Where an INI file will work more efficiently than an XML file or a database table query.
    • Arguing in defense of ONE language above all others.   Within the context of a particular project or contract, this is acceptable.  However, in the global scope of programming, this is the sign of a complete idiot.
    • Buying books on one language before reading books on general programming practices and theory is just stupid.  This is like reading a book on 1001 ways to use a fork to eat.  Why not read up on eating, then learn about the tools, that way you understand why you're using the fork, and not just how to use it.

What can you do about it?

  • Read Books on Programming topics (not just an "Unleashed" book on your favorite language)
  • Read some useful Blogs about programming
  • Go to School (a university, not a for-profit tech school)
  • Join MSDN or TechNet or something similar (and use it!)
  • Meet with other programmers - ESPECIALLY programmers that work with other languages, database engineers and administrators, network engineers, etc.

Friday, September 23, 2011

A Friday Mini Braindump

This is a bit rambling, but hopefully worth your while...

I've been in training all week learning AdminStudio and InstallShield.  During that same time, work has not stopped or hibernated, and house chores haven't let up (my wife is hundreds of miles away visiting family right now), so my brain is a bit frazzled and woozy.

DirectX + AutoCAD 2012 + Configuration Manager = who cares?

During this same week I received several emails relating to my blog posts regarding the repackaging of DirectX for deploying AutoCAD 2012 via Configuration Manager.  That sentence is a ****ing mouthful.

I have already posted several articles dealing with this subject, and even included it in my book.  The recent inquiries have been about how to repackage the components for silent installation using something other than Wise Package Studio.  I ran through a few tests using InstallShield 2011 and it works as well (albeit using a somewhat more verbose process), and even toyed with merging the results back into the AutoCAD 2012 network deployment by way of editing the .INI file to point the [DIRECTX] sequence to use the new .MSI. (WARNING: this practice is completely unsupported by Autodesk, so if you pursue that, you're on your own.  Don't call me).

Then it dawned on me: I just don't give a shit about this topic anymore.  Maybe I'm getting older?  I'm just tired of making the same Band-Aid for the same mess; a mess I didn't create.

Wise Package Studio vs. InstallShield / AdminStudio

On a side note: I received some rather interesting responses about my comments regarding Wise being dumped by Symantec and why I feel InstallShield is a "better way to go".

Here's why:

  1. Upgrades to Wise Package Studio, since 6.x, have been minimal.  It's hard for even (former Wise/Altiris/Symantec) engineers to argue that 8.0 is nothing more than 7.0 SP4.  Even the community forums are rife with comments that indicate the future is gloomy for that product line.
  2. http://www.symantec.com/connect/forums/wps-80-vs-adminstudio
  3. My discussions with several Symantec employees at TechEd 2011 made it clear to me that even they do not know whether WPS has any future.
  4. Compare this http://www.flexerasoftware.com/products/installshield/top-reasons.htm with navigating the Symantec web site and trying to find a CLEAR link to WPS anymore.  They have been steadily burying it as time passes.  Don't believe me?  Check this out: http://www.symantec.com/business/products/allproducts.jsp  (press CTRL+F and enter "wise" and see how many matches it finds)

Wise is dead.  It just doesn't know it yet.  What a shame too.  It was once such a cool product.

Sometimes Reality Hurts

The painful reality of working in the IT field is this:

Everything you accomplish in the line of your IT work, and I mean EVERYTHING, will be gone and forgotten in ten to twenty years.

Your ancestors made furniture, built houses, roads and bridges, constructed buildings, and railroads.  We move bits around.  We can still find their furniture, their houses, drive on their roads and bridges, visit their buildings and ride their railroads.  You don't think your network, servers and software will vanish?  Ask the folks who built Windows 3.1 and the folks who worked at Sun Microsystems in the 1990's.

The reality is that no matter how important we think we are, none of our accomplishments will last as long as that hand-carved wooden rocking chair.  Those stone-laid Roman highways are a bitch, aren't they?

Feeling happier now?  :)

Sometimes Reality Feels Good

My son is 12.  He's been playing guitar for several years, only one of which did he take lessons.  The rest of his learning has been self-driven and via Google and various tab sites.  He averages roughly one new song per week.  He just picks something that catches his ear and he dives into learning how to play it.  It's amazing.  I can listen to him play for hours.

When I was 12 I had a bicycle and a TV with 3 local channels of 1960's re-runs and news.  Compared to today, that was like living in the Australian outback, but that was in Virginia in the 1970's.  For all the new inventions and distractions and the loss of naiveté of our modern world, seeing kids push themselves to do cool things gives me a good feeling that there's still hope.

Battery Life

During the power outage after Hurricane Irene last month, I started thinking about how long my various gadgets last when they're just sitting idle and not being used.  I decided to do my own experiment:

Google Chromebook CR-48 = 1.5 days

iPod Touch v1 = 2 days

Blackberry Tour 9630 = 2.5 days

Kindle Wi-Fi 3.0 = 7.5 days

The main difference, besides the construction and capacity of each battery, is really in how the firmware and software are devised to maximize (or not) the battery life.  Clearly we have not progressed very far with commercial battery technology in a long, long time.  We're just getting better at optimizing utilization of the technology we've had for so long.

I'm fried - enjoy your Friday (and your weekend!) - Dave

Saturday, September 3, 2011

Awesometarded?

Read this first...

http://usa.autodesk.com/adsk/servlet/ps/dl/item?siteID=123112&id=17687583&linkID=9242018&CMP=OTC-RSSSUP01

Now.  Think about how this might impact network environments where the IT department, as a policy, packages and deploys such updates using their own tools (i.e. Microsoft System Center Configuration Manager, Symantec Altiris, etc.).  Ok.  So, if I follow their "Solution" I should wrap this turd in a perfume-scented script that runs it once, checks if exit code 1402 was returned, and then runs it again?!  I'm still sniffing this perfume scented turd, and it ain't smelling any better folks.  I'm sorry, but this is not a "solution".  I seriously hope someone inside Autodesk is working on a "Service Pack 1a"

Thursday, September 1, 2011

Patching Civil 3D 2011 - Part 3, The Final Chapter

I sort of promised a "part 3" and here it is. I was toying around with using a .CMD script, but decided to go with a VBscript solution instead.  Dovetailing with my Package Scripting 101 blog post somewhat, this should provide a brief example of just one rationale for choosing an approach to a problem constraint.  In this case, the constraint was how "best" to detect if the (a) base product is installed, and (b) the updates are already installed.

The best criteria for my needs is/was to check for a specific Registry key/value.  My preference is to go with using the RegRead() method of the Wscript.Shell object, rather than the clunky REG Query test and fetching the %errorlevel% result, so I chose VBscript.

[code]
'**************************************************************** ' Filename..: install_updates.vbs ' Author....: skatterbrainz ' Date......: 09/01/2011 ' Purpose...: install updates 1 and 2 for AutoCAD Civil 3D 2011 '**************************************************************** appName = "AutoCAD_Civil3D_2011_Update2" Set objShell = CreateObject("Wscript.Shell") Set objFSO = CreateObject("Scripting.FileSystemObject") strTemp = Env("TEMP") progFiles = Env("PROGRAMFILES") scriptPath = Replace(wscript.ScriptFullName, "\" & wscript.ScriptName, "") strLog = strTemp & "\CVB_" & appName & "_install.log" Set objLogFile = objFSO.CreateTextFile(strLog, True) '---------------------------------------------------------------- echo "installing... " & appName echo "source....... " & scriptPath echo "target....... " & Env("COMPUTERNAME") echo "windir....... " & Env("WINDIR") echo "progfiles.... " & progFiles echo "temp......... " & strTemp echo "logfile...... " & strLog echo "-----------------------------------------------" echo "info: searching for civil 3d 2011 installation..."
appPath = progFiles & "\Autodesk\AutoCAD Civil 3D 2011\acad.exe"
If objFSO.FileExists(appPath) Then echo "info: checking for installed updates... " key = "HKLM\Software\Microsoft\Windows\CurrentVersion" & _
"\Uninstall\AutoCAD Civil 3D 2011 Version 3\DisplayName" On Error Resume Next result = objShell.RegRead(key) If err.Number = 0 Then echo "info: updates are already installed (abort)" wscript.quit(0) Else update1 = scriptPath & "\c3d2011_win32_sp1.msp" update2 = scriptPath & "\c3d2011_win32_sp2.msp" command1 = "msiexec /p " & chr(34) & update1 & chr(34) & " /quiet /norestart" command2 = "msiexec /p " & chr(34) & update2 & chr(34) & " /quiet /norestart" result = 0 echo "info: updates not installed. installing now..." echo "info: command = " & command1 result = objShell.Run(command1, 7, True) echo "info: exit code is " & result echo "info: command = " & command2 result = objShell.Run(command2, 7, True) echo "info: exit code is " & result If result = 0 Then echo "info: restarting computer in 30 seconds" x = objShell.Run("shutdown /r /f /t 30", 7, True) End If End If Else echo "info: civil 3d 2011 installation not found." End If echo "-----------------------------------------------" echo "completed / exit code: " & result objLogFile.Close wscript.quit(result) Sub echo (strMsg) Dim ln ln = FormatDateTime(Now, vbShortDate) & " " & _ FormatDateTime(Now, vbLongTime) & " " & strMsg objLogFile.WriteLine(ln) End Sub Function Env(varName) Env = objShell.ExpandEnvironmentStrings("%" & varName & "%") End Function [/code]

Log output...

[code]
9/1/2011 1:42:07 PM installing... AutoCAD_Civil3D_2011_Update2 9/1/2011 1:42:07 PM source....... \\Server1\source$\Apps\Adsk\C3D2011_Updates 9/1/2011 1:42:07 PM target....... Computer1234 9/1/2011 1:42:07 PM windir....... C:\WINDOWS 9/1/2011 1:42:07 PM progfiles.... C:\Program Files 9/1/2011 1:42:07 PM temp......... C:\DOCUME~1\dstein\LOCALS~1\Temp 9/1/2011 1:42:07 PM logfile...... C:\DOCUME~1\dstein\LOCALS~1\Temp\ACAD_Civil3D_2011_Update2_install.log 9/1/2011 1:42:07 PM ----------------------------------------------- 9/1/2011 1:42:07 PM info: searching for civil 3d 2011 installation... 9/1/2011 1:42:07 PM info: checking for installed updates... 9/1/2011 1:42:07 PM info: updates not installed. installing now... 9/1/2011 1:42:07 PM info: command = msiexec /p "\\server1\source$\Apps\Adsk\C3D2011_Updates\c3d2011_win32_sp1.msp" /quiet /norestart 9/1/2011 1:46:40 PM info: exit code is 0 9/1/2011 1:46:40 PM info: command = msiexec /p "\\server1\source$\Apps\Adsk\C3D2011_Updates\c3d2011_win32_sp2.msp" /quiet /norestart 9/1/2011 1:48:40 PM info: exit code is 0 9/1/2011 1:48:40 PM info: restarting computer in 30 seconds 9/1/2011 1:48:40 PM ----------------------------------------------- 9/1/2011 1:48:40 PM completed / exit code: 0
[/code] 

Conclusion

As I always say: This is not the only solution.  This is simply ONE possible approach that works for me, and may work for you.  Maybe not.  If this helps you, great.  If not, eh.

If you're in the same situation I'm in: Existing installations needing to be patched - you should also make sure to patch your administrative deployment share (aka "Network Deployment").  I would download both .exe files, extract the .msp files from them, and import them into the Deployment utility to add them into the deployment image.  That way your future installations will have the updates included.

Sunday, August 21, 2011

Autodesk Scripts: TKO

Maybe I'm drinking the wrong Kool Aid.  Maybe I'm just being paranoid?  Maybe I'm giving myself waaaaaaaay too much credit.  But it seems that lately when I post some script code for doing something with respect to deployment (or "un-deployment", one of my favorite words to chuckle over), Autodesk publishes their own version and trumps me soundly.  I dunno. 

Whatever the case, my focus has always been on making it possible to run "unattended" for massive scale environments (read: Microsoft System Center Configuration Manager, or Altiris, or whatever), while Autodesk is focused on making a thorough script (or KB/support article) that is designed to work interactively (someone runs it, not via an automated agent or scheduled task).  Case in point: KB Article TS45252.

Rather than try to "compete", or engage in some sort of "race", I'm bowing out.  Autodesk wins.  They have battalions of younger code monkeys with infinite more time to accomplish more in less time.  They have the means to do a better job than do I.  My resources, time and enthusiasm are much lower.  Call it "Low-T" or whatever, but as I approach 50 I'm starting to rethink my priorities.

As a tip for anyone still interested in (more-or-less) "porting" Autodesk deployment and removal scripts for use in an unattended scenario:

  • Look for MSIEXEC statements that use /qb! and replace with /quiet /norestart
  • Look for instances of "WindowsInstaller.Installer" that use the ConfigureProduct method, and modify the UILevel property from msiUILevelBasic to msiUILevelSilent (note that msiUILevelBasic = 3, and msiUILevelSilent = 2)
  • Look for MsgBox() statements and replace them with Wscript.Echo
  • If the MsgBox() statement is used in the Function form (returns a value) force the return value by hard assignment (e.g. intChoice = MsgBox("Continue?", vbYesNo, "Caption"), just set intChoice = vbYes)
  • Add error checking throughout and make sure to "raise" errors using Wscript.Quit(err.Number).  If you are running the .VBS from a .BAT or .CMD script, be sure to raise the error again from there user the DOS "EXIT %errorlevel%" statement.
  • It helps to add secondary condition checking and raise forced errors if needed. This is helpful for things like making sure folders are deleted, registry keys are removed, and so on.
  • Follow the MSIEXEC error code advice I posted a few days ago here.

Finally, I'm not saying that I won't ever post relevant code here again.  I'm just saying that unless it's something truly unique and provides added value, I'll let it go by the wayside.  I should have learned my lesson when AutoLISP was left out in the cold to starve and die slowly.  I guess I've been too nostalgic and sentimental about it all.  Time to grow up.

Thursday, August 4, 2011

Scripts Calling Scripts, and So On...

I tried to come up with a clever title, but I just finished a grueling bike ride in the heat and humidity, followed by cold beer and pizza, so my brain is not on the clever channel right now.  But here goes...

I recently got a few e-mails about my recent post about running script packages from Configuration Manager and how to handle return exit codes.  Rather than dive into the syntactical minutae, I think a conceptual overview is in order.

Basically, when one thing calls another thing, and that second thing calls yet another thing, there are a variety of issues that come into play when it comes to the calling thing getting a "result" from the thing it calls.

When you create a Package and Program in Configuration Manager (or Altiris, Tivoli, wtf), which runs a .MSI installation file, it automatically invokes msiexec to do the heavy lifting on the client.  When msiexec runs the .msi (and/or .msp, or .msi + .mst, etc.), msiexec handles the return value by evaluating the execution process as it progresses.  If it bombs out, you get back an exit code that is "non zero" (remember: in most cases, a zero value indicates "success").

When your package/program executes an .EXE, the CMD/explorer shell process handles the resulting exit code.

In both msiexec and .exe situations, the handlers (msiexec and cmd/explorer) pass the result exit code back to whatever called them (i.e. Configuration Manager agent).

When you call a script, it introduces a "sort of" proxy situation.  The script handler (cmd for .bat or .cmd scripts, kix32.exe for .kix or .kx scripts, powershell for .ps1 scripts, or wscript.exe or cscript.exe for .vbs or .js scripts, and so on...) does not automatically "raise" the exit code from a scripted task up to the calling process (Config Manager agent).  Instead, the handler will return an exit code based on whether or not the script itself completed or not.  If, within the script code, you forcibly raise an exit code, it will respect that and pass that value up the stack to the calling process.

So, let's give an example:

  1. You make a Config Manager Package and Program that calls a .CMD script
  2. Inside the .CMD script you execute a msiexec /I <filename.msi> /quiet /norestart
  3. The .msi installation fails with exit code 1604
  4. The .cmd script returns 0 to the Configuration Manager agent (e.g. "success")

Why?  Because the .cmd completed successfully even though the msiexec task failed.

What to do?

The specifics of how to "raise" an exit code depend on the scripting language being used.  For .cmd and .bat script, use the EXIT statement followed by the value you wish to raise to the calling stack.  You can give an explicit value, such as 33, or you can pass the %errorlevel% value, which will temporarily hold the value of the last error.  If you check for the %errorlevel% immediately after the msiexec execution, you can capture the value, and then raise it accordingly.

Here's a short example:

@echo off
msiexec /I "%~dp0fubar.msi" /quiet /norestart
if %errorlevel%==0 (
   echo installation successful >>%logfile%
) else (
   if %errorlevel%==3010 (
      echo installation successful [reboot pending] >>%logfile%
   ) else (
      echo installation failed [exit code: %errorlevel%] >>%logfile%
      exit %errorlevel%
   )
)

The 10th line is where the exit code is raised to whatever is calling this script.  So if the msiexec process fails with error 1619, it saves that value in the CMD %errorlevel% variable.  Then in the script, we pass %errorlevel% up using the exit command.  When it fails, and the script passes the value back to the Configuration Manager agent, it reports back to the site server that it failed with error 1619.  All is well in the Universe.

What happens when a vendor's wonderful setup.exe doesn't properly return an expected exit code when it fails?  What?!!!! (insert 1980's vinyl album scratch sound here)

Did I just say that vendors might actually have produced less-than-perfect installation packages?  Is this even possible?  OH NO HE DIDN'T!!  OH SHIZNIT!  OH SNAP-STICK!  What now?

Yes.  Unfortunately, the ugly, brutal truth is that there are many, many, many such pieces of fecal matter labeled as "installation" files or packages.  Some come from widely-known, huge, corporate vendors, while a larger number come from smaller shops where they feed chained wild monkeys bags of Skittles and Kegs of Mountain Dew and whip them with Chinese egg noodles until they produce installer files.

What to do?

You have to get creative and wrap their crap in some script to perform additional checks and double-checks, and raise your own custom errors.  I call this a "crap wrap", because it wraps crap.

FWIW: I have my own definition of "crap installer" >>> Any installer that is not a 100% pure MSI file is crap.  Period.  I f-ing hate setup.exe, and setup.exe bootstrap installers.  NullSoft is crap also (silent installations are ok, but silent uninstalls are horrifically f**ked).  And anyone who sells you a .zap file should be shot on site (I'm not including those of you that have to make your own .zap files, we share the same pain). 

I make one exception to this rule: self-contained applications.  Things like Sysinternals' PSTools, where you don't really "install" anything, you simply copy/download the .exe and it's ready to go.  I wish more apps were that well-packaged actually.  Imagine if Autodesk provided Inventor 2012 as a self-contained application that required NO installation process.  OMG.  I would need a Kleenex.  (don't even try to suggest App-V or ThinApp as being in this category, they are not).

In any case, back to the subject:

When one thing calls another, you need to examine what each down-level process returns up the stack, as it were.  Using a virtual machine environment is great for this, as is using the good-ole CMD shell to perform command line diagnostics along the way.

I'd go on longer, but I'm out of brain power right now... I need more pizza.

Thursday, April 28, 2011

Setting up Windows Web Admin on IIS7

I should have posted this much sooner, but here goes.  This is a quick how-to procedure for installing and configuring the IIS side of things.  I'm using Windows Server 2008 R2 and IIS7, but this is pretty similar for Windows Server 2008 as well.

IIS Configuration Procedure

1. Download the wwa.zip file and extract it to a folder on your IIS host server

2. Open IIS Manager

3. Expand the Server object

4. Right-click Application Pools, select Add Application Pool…

SNAGHTML7d638f3

5. Enter a Name for the new pool (leave other defaults alone), click OK

SNAGHTML7d4f9a2

6. Right-click on the new Application Pool, click Advanced Settings

SNAGHTML7d887ae

7. Select the ellipses (…) next to the Identity setting…

image

8. Select "Custom account", and click the "Set" button

9. Enter an account (with sufficient account management rights), and the password…

image

10. Click OK, click OK again and again to return to IIS Manager.

11. Expand Sites, right-click "Default Web Site" and select "Add Application"

SNAGHTML7dd5eac

12. Enter the Alias, and select the Physical Path, and click OK

image

13. Double-click Authentication

image

14. Disable "Anonymous Authentication" and enable "Windows Authentication"

image

15. Right-click on the web application object (e.g. "wwa") in the left-hand panel, and select "Manage Application" / "Advanced Settings…"

image

16. Change the Application Pool setting to "WindowsWebAdmin" and click OK

image

17. Click OK and close IIS Manager

You should be good to go.  To test, open your browser and navigate to the appropriate URL.  Once opened, click the "About" link at the bottom of the home page.  Under the "Web Server" section, verify that Authentication Mode is "CONTROLLED" and that your domain account is shown for the REMOTE_USER value.

Wednesday, April 27, 2011

Imaging Computers with MDT 2010 and AutoCAD 2012

Microsoft Deployment Toolkit (MDT) 2010 is a FREE product that is aimed at helping System Administrators prepare and deploy custom operating system installations (images).  I’m not going to explain MDT, WAIK or WDS here.  There are too many other sites, books, and videos that do a great job of that. I don’t need to add any more noise there.

 

If you have network license AutoCAD clients and a network deployment share, you already know how that can save time doing repeated installations.  You may also know how much it helps when pushing installations via SCCM 2007 (or similar products).  Maybe you’ve tried bundling AutoCAD into your operating system image process but are using Ghost or some other snapshot process and find it less than ideal.  Well, MDT not only provides an easier option, it eliminates much of the headache incurred with push installations.

 

For starters, MDT uses a sequential process to perform tasks (hence “task sequences”).  Rather than running entirely under an unattended SYSTEM context with no UI, it runs under a user context (typically), so most of the prerequisite tasks of the deployment work just fine (unlike trying to push with SCCM, where the .NET Framework 4, and DirectX component steps fail).  So you can run the default installation and simply add the "/W" parameter to use it with MDT 2010.

Caveats:

 

You may have better luck than I’ve had with using a “thin” image process and trying to install .NET Framework 4 as a task sequence package instead of going with a “thick” or “hybrid” client build*.  In my experience, the .NET 4 installation via MDT task sequence never works.   But you may be blessed.  My approach is to include .NET components in the base image via a reference capture.  It is crucial to have .NET 4 installed before attempting to install AutoCAD 2012 via an automated/unattended process or it will fail.

I only use network license deployments of AutoCAD when installing via SCCM or MDT.  I do not ever recommend installing standalone/individual licenses

 

Steps:

  1. Build your AutoCAD 2012 deployment share ON the server where the MDT package will refer clients to (this works much better than building it elsewhere and then moving it and editing the deployment configuration INI files)
  2. Configure permissions on the deployment share to suit the user context of the MDT installation (if needed)
  3. Right-click the AutoCAD 2012 installation shortcut in the UNC folder (e.g. Acad2012.lnk), select Properties
    1. Copy the “Target” string contents
    2. Click Cancel to close the properties dialog form
  4. Open the MDT Workbench, expand the Deployment share, select Applications
    1. Add a new Application to the MDT workbench deployment group
    2. Option:  Application without source files or elsewhere on the network
    3. Properties:
      • Publisher: Autodesk
      • Application Name: AutoCAD
      • Version: 2012
      • Language: (leave blank unless you really want to enter it)
    4. Details:
      • Command Line: “setup.exe” (for now)
      • Working Directory: Browse to the UNC share path (do NOT choose from drive letter!) make sure to specify the AdminImage sub-folder in the path (e.g. “\\ ServerName\Acad2012\AdminImage”)
      • After created, click Finish
    5. Double-click the AutoCAD 2012 entry in MDT
      • Click the “Details” tab
      • Replace the “Quiet install command” text with the string copied in step 3/a (example below).  Be sure to replace <uncpath> with your actual UNC path.
        • Example: <uncpath>\AdminImage\setup.exe /W /qb /I <uncpath>\AdminImage\<deployment>.ini
      • Click OK
    6. Right-click the Deployment Share in MDT Workbench and select “Update Deployment Share”

Assuming the rest of your MDT deployment share is configured, and you've already generated a suitable Boot WIM and Boot ISO file set, you should now be ready to start deploying AutoCAD 2012 with your images.

 Notes:

1.       If you discover (like I have) that you also need to install the DirectX components ahead of the AutoCAD deployment installation, you can add the Acad2012DX.msi package I’ve posted and set a Dependency within the AutoCAD 2012 application entry so it runs the DirectX installer first.  If you do this, click “Hide this application in the Deployment Wizard” from within the MDT application properties for the Acad2012DX application item.

2.       A return code of 259 from the AutoCAD installation can be ignored.  I have not seen, heard or experienced any detrimental effects after that has occurred.

3.       Because there is NO OPTION to disable desktop shortcuts for Design Review 2012 or Inventor Fusion 2012 via the Deployment Wizard configuration, you will have to resort to some trickery if you are required to keep shortcuts OFF of the standard desktop.  My trickery is to add DEL commands to a script that wraps the main installation.

4.       If you choose to enable the network log option, keep these points in mind:

a.       The UNC path to the logs needs to have appropriate ACL and Share permissions granted to allow the remote installation context to make updates to the folder contents (log file)

b.      It tracks the entire deployment bundle, but won’t be updated on the network share until the end of the installation process.

c.  If the connection fails before the installation completes, the only trace of a partial installation will be in the client logs.

d.  The network log is cummulative.  It grows with each client installation.  You may want to back it up, rename or delete it occassionally to recover space.

5.       Why does Design Review 2012 get a “Autodesk” prefix, while Inventor Fusion 2012 does not?  Consistency is important.

 

*terms borrowed from Johan Arwidmark and Mikael Nystrom of TrueSec (www.truesec.com)  - geniuses on the topic of Windows deployment automation

Assumptions:

·         MDT 2010 Update 1 with WAIK 7

·         32-bit Windows 7 client Deployment Image with .NET 4 included (sysprep’d from ref computer)

·         New install (not a refresh, upgrade or replacement)

Script Code:

Paste the following code into Notepad…

 

@echo off

TITLE Installing AutoCAD 2012

CLS

echo installing AutoCAD 2012...

SETLOCAL

SET XLOG=%TMP%\Adsk2012_Setup.log

echo %DATE% %TIME% installing autocad 2012 from network deployment >%XLOG%

rem ------------------------------------------------------

rem beware of word-wrapping below.  should be on one line...

rem ------------------------------------------------------

\\SERVERNAME\Acad2012\AdminImage\setup.exe /W /qb /I \\SERVERNAME\Acad2012\AdminImage\ACAD2012.ini /language en-us

rem ------------------------------------------------------

echo %DATE% %TIME% cleaning up desktop shortcuts... >>%XLOG%

del "%public%\Desktop\Autodesk Design Review 2012.lnk" /f /q

del "%public%\Desktop\Inventor Fusion 2012.lnk" /f /q

echo %DATE% %TIME% desktop shortcuts removed >>%XLOG%

ENDLOCAL

 

Edit the code to replace SERVERNAME and other info to suit your needs.  Save the Notepad file as setup.cmd somewhere on the MDT server (e.g. E:\Apps\Scripts\Acad2012\setup.cmd)

 

Import into MDT 2010 deployment share:

Right-click Applications, select New Application

Select type: “Application with source files”

Specify the properties (publisher, product, version)

Select the setup.cmd file (click Browse)

Confirm, import and click Finish

 

Open the Application properties, copy the “Application GUID” value to the clipboard

 

Open Deployment Properties, click Rules tab

 

Add to [Default] section…

 

; autocad 2012 custom deployment

Applications001={paste the application GUID here}

If you already have other ApplicationsXXX entries, just insert it after the highest number and assign the next sequential number (e.g. Applications011={guid} )

Useful Links on MDT 2010: