Monday, December 19, 2005

WSJ: Beyond Google

IT industry searches
Research sources

Thursday, December 08, 2005

Continuous Integration

Avoiding Continuous Integration Build Breakage Patterns

Monday, December 05, 2005

Java vs C#/.NET

Well-authored, factual comparison.

Why Java hasn't lived up to expectations on the client. Java rules on the server but has faltered on the client. Presumably due to the runtime distribution issue.

Giga weighs in. A 2003 article but applicable. See "Rich Clients Stand-Alone".

XML Rich Client Technology Strengthens Java. Lines of code comparison in this article is misleading because much of the .Net code listed would be generated by the IDE automatically. Lines of code written would be comparable to that of the XML rich client (and a more interesting comparison). A good article nonetheless.

C and C++ give way to managed code

InfoWorld 2005 App Dev Survey

A slaughter of SWT (vs. Swing)

A COMPARISON OF MICROSOFT'S C# PROGRAMMING LANGUAGE TO SUN MICROSYSTEMS' JAVA PROGRAMMING LANGUAGE

Tuesday, November 01, 2005

Soft Dev Survey Says People, Not Tools, Matter Most

Development teams in the “best” category were
1. able to control requirements change
2. employed highly skilled people with good functional knowledge of the application domain
3. used tooling effectively
4. had project leadership.

My Favorite .Net Tools

Allocation Profiler
fxCop
TestDriven.Net
NUnit
JetBrains dotTrace Profiler (haven't used much but have heard good things...)
NDoc
NAnt

I want to...

Monday, October 31, 2005

Wednesday, October 19, 2005

What I'm reading...

A Whole New Mind
Freakonomics
China, Inc.
Awaken the Giant Within
The 8th Habit
The World is Flat
Polar Shift
State of Fear
Now, Discover your Strengths

Really more for me than anything. I need to remember what I've read now that I'm utilizing the library more often. Another phenomonym I've discovered is I read a lot faster now that I have a due date. Before, I'd just pick up whatever I was in the mood for. Now, I have a queue of books on hold which flow in lockstep; one after the other. The online reservation system at the library really feeds my reading appetite heartily!

Friday, September 23, 2005

CIO: What Will You Do When the Cyber-Levee Breaks?

What would you do in the event of the failure of the Internet?

I used to think about this kind of thing more often but maybe I've become too accepting of the distributed nature of the Internet as a safety measure. This article got me thinking about an EMP pulse or a small nuke knocking out a major portion of the Internet...say a few backbones in Chicago or something. Not having an Internet connection often brings my work to a complete halt...let alone operations at most businesses.

I'm growing weary of complete communication failures during traumatic homeland events: 9/11, Katrina, etc. Shouldn't local or state government contract with private industry to get satellite phones to major incidents within 4-6 hours? I mean, how hard can this be? C'mon. Or portable Wi-Fi / cellular towers. Whatever.

Technology aside, I think the bigger problem is lack of leadership. The average person lacks a sniff of a clue about what actions to take during a crisis situation. Politicians, who typically assume "control" during a crisis, are arguably the very worst folks to be in charge. They spend their careers assuaging constituents and trying to keep office rather than getting things done, organizing projects, and leading people.

I think we should train and maintain a network of "incident commanders" within our cities. These folks would know how to re-establish communications, would be aware of all their resources, would have ties to the federal government but would be based locally, and they would know how to lead people and solve problems. They wouldn't necessarily assume control but would work with local government to truly manage the crisis.

Rudy G. performed brilliantly during 9/11 but only because he had consciously put himself through leadership and contingency planning for years prior. We need more folks with leadership talents on the front lines during major incidents and we need to better utilize the smart folks and advanced technologies at our disposal.

Wednesday, August 31, 2005

My Home Network

Recently, I established a home network using the existing single-run CAT5e cabling running throughout my house. Fortunately, my builder had the foresight to use CAT5e to connect the phones. Ideally, I'd have future-proof bundled cables running through the house, but I didn't want to pull the cable through exisitng construction nor incur the expense. While carrying data and voice on separate twisted pairs within the same cable isn't CAT5e compliant, it worked well for this situation.

Planning
First, I visited many home networking sites and spoke with my networking-savy friends to understand materials needed and how to architect my network. Next, I created a matrix outlining all the drops in the house and what materials were necessary. Afterwards, I surfed the non-user-friendly ;-) Leviton site learning how their products worked together. Finally, I created a simple paper-based diagram detailing the wires and materials.

Materials
I bought all Leviton equipment. My choice stemed from various posts on networking sites and the availability of the materials. It was also reasonably priced and they had everything I needed. I purchased everything though SmartHomeUSA.com because they had the best prices and availability of all materials. They did a nice job except for some delays in drop-shipping my order from Leviton. All told, I spent about $325 to wire data and voice to 8 endpoints.

Shopping List
47603-PTE 1 LIN 12-Port Structured Media Panel $139.95 $139.95
47616-DSF 1 LIN DSL Filter Module $25.95 $25.95
47620-1W 6 CAT 5 Patch cord /1' $1.82 $10.92
40838-I 1 8-conductor CAT 5 Modular $4.17 $4.17
40859-BI 25 QP Blanks, Ivory Polybag $0.13 $3.25
40804-BI 10 QP 4 Port, Wallplate, Polybag $1.30 $13.00
40838-BI 15 8-conductor CAT 5 Jack, $3.65 $54.75
Belkin 2360-Joules Surge Protector $40
Misc. tools, wires, etc. from Home Depot $40

I already had the following from previous home networking:
RF114 Netgear Firewall Router
SBC DSL Modem (Siemens)

Preparation
Fortunately, my builder finished in a nice cabinet housing my electrical and security panels. All cable and CAT5e runs terminate to this cabinet. This is what that cabinet looked like before I started:

I screwed the wood panel on the right into the foundation and moved the alarm to this wood panel beforehand but forgot to take a picture. Due to the length of the CAT5e runs, you'll see the alarm panel move to the bottom to enable the CAT5e lines to reach the patch panel.

Implementation
First, I mounted the surge protector onto the wood panel.



Next, I mounted the patch panel, router, and DSL modem.



Finally, I wired everything up (this is the finished product).



The individual panels within the patch panel / board are (from left to right)
-Telephone Line Distribution Panel
-DSL Filter
-CAT5e Voice and Data Board
-2nd Telephone Line Distribution Panel

I wanted to keep the Telephone Line Distribution Panels together but the CAT5e runs were a little short and I had to get one panel closer to the cable ends.

Another item of interest here is the non-standard punchdowns. Since I use the blue, white/blue twisted pair for voice and the remaining pairs (3) for data, my CAT5e cable is split between two plugs on my panel. I have the data pairs as tight (the standard calls for <= 1cm from the cable shielding) to the data plug/port as possible with the telephone pair traveling the extra distance. I figured the phone pair would be more forgiving than the data pair.

DSL Filter

One particularly interesting feature I implemented involves the DSL filter. Recently, I switched to SBC DSL using their $14.95/month offer. As a downside, one must install a small dongle-like device on all phone jacks to filter out the DSL signal. Leviton makes a slick device that I installed on my board to filter out the DSL before it is distributed to the individual CAT5e runs. Here's a close-up of the DSL module (look for the solid blue CAT5e cable entering from the top):



The blue twisted pair (blue and white/blue) line running from demarcation (source phone line running in from the street) is first run through the in/out pairs on the DSL filter. Instead of cutting the wires, one just cuts through the outter shielding exposing around a 2-3mm piece of copper wire. After creating two of these exposures (one for in and one for out), I simply punched the wires down.

Security Override
My house has a built in security system wired into my phone line which will contact an outside monitoring service in the event of an alarm. This feature should have the ability to override the entire system to make the outbound call to the monitoring service. To enable this, the Leviton board sports a security override terminal. Looking at the photo above, just to the right of the DSL filter terminal, there is a second terminal for the security override. I followed the stripping procedure above and punched down the blue and white/blue wires.

To the right of the security override terminal, you can see the RJ45 plug. This plug connects to the alarm itself. Finally, I terminate the demarcation blue and white/blue twisted pair into the terminal marked "FROM DEMARCATION".

Jacks
On the jack side, I simply punched down the data and phone pairs to separate plugs/ports. I tried to remain consistent with the data plug placement on the jack (lower left in the block of four) but I could have labeled it.


Conclusion
When I finished this project, my wife inquired, "Now why did we need this?" I had to laugh and answer honestly that we didn't really need an internal network but that it did simplify management for me, it's convenient to be able to plug in anywhere in the house, and it was a lot of fun! (except punching down all those tiny wires with the cheap plastic tool...I have big hands) Ok, so it was a geek exercise but I learned a lot and it enables me to expand my network easily. Next, I'm adding a Linux box in the basement with 2 RAID1 mirrored drives to serve as my network storage/backup utility...but that's another write-up!

Tuesday, August 23, 2005

HOWTO: Secure your wireless network

Usually, WiFi vendors will provide browser-based interfaces to secure a wireless access point. However, sometimes those interfaces aren't the most intuitive so it helps to understand the issues and gain additional background. These are the best articles I've found:

Securing Your Wireless Network
Configuring Windows XP IEEE 802.11 Wireless Networks for the Home and Small Business

In summary, the most important steps to securing your wireless access point:
-Read vendor documentation throughly
-Use 128-bit encryption
-Change your SSID
-Update the access point firmware
-Enable the firewall (if built-in)

Happy hacking.

HOWTO: Remove the My Way Search Assistant

I abhor spyware. Recently, I was chagrinned to discover the "My Way Search Assistant" element within my Windows XP Add/Remove Programs on my new Dell Inspiron 6000. At first, I though I'd accidentally picked it up installing other software. After a Google search, I realized Dell factory installs the utility. Dell denies My Way is spyware but mysteriously prohibit its removal. (As you can tell, I love a conspiracy theory!)

So, here's how I removed the My Way Search Assistant:

1. Open the registry using a command line prompt regedit
2. Search for the string "My Way Search Assistant"
3. Once found, examine the other nodes within the same parent registry key. There should be one referencing an .msi file.
4. Browse to the directory of the .msi file.
5. Right-mouse on the .msi file selecting uninstall.

Happy hacking.

Tuesday, June 14, 2005

Recovering from Windows XP virus annihilation

Recently, several members of the family have had their computers "owned" by viruses or spyware. At my house, I'm more focused on prevention but if all else fails, here's a great write up of using Windows XP Recovery features to repair your down and out home computer.

Also, a correspondence with one of my pals (a conversation I've had many times with lots of folks):

---------------------------------------------------------------------

Nope. I think you're on the right path. Good write-up:

Afterwards, I would recommend the following:

1. Set only 1 person within the household as an Administrator...I've found the Mom is usually best. Disable the ability to install software for all other users (i.e. they only belong to Users group)
2. Install virus scanning software; set to update nightly, scan nightly
3. Update Windows with all patches from www.windowsupdate.com. Set Windows to update automatically. Make sure you install SP2
4. Enable the Windows firewall from SP2
5. Download and install the latest Zone Alarm firewall
6. Run a hardware router with a built-in firewall in front of your cable/DSL modem
7. Install and set to run regularly a spyware checker such as Ad-aware
8. If you/they are using a wireless network, use 128-bit WEP encryption with a 13-bit passcode.
9. Enable the pop-up blocker within IE6, Windows SP2
10. Don't use Outlook Express but rather a standard browser for email
11. Don't use file sharing programs
12. Don't use chat programs like AIM or Yahoo messenger without a scanner

Also, from my blog:
http://effectivethoughts.blogspot.com
http://effectivethoughts.blogspot.com/2005/01/preventing-spyware.html
http://effectivethoughts.blogspot.com/2005/03/security-guide-for-smb.html
http://effectivethoughts.blogspot.com/2005/06/avoiding-phishing-attacks.html
http://effectivethoughts.blogspot.com/2005/04/michael-howard-keeping-home-computer.html

Jeff...

On 6/14/05, wrote:

no luck...won't even boot up in Safe Mode...just loops through and says Windows could not start, please choose a mode to boot up in...any option you choose loops back around to same screen. couldn't find his rescue CD to boot from, so I need to order one from HP today. Any other advice? (besides using it as a boat anchor)



-----Original Message-----
From: Jeff Hunsaker [mailto:]
Sent: Tuesday, June 14, 2005 9:19 AM
To:
Subject: WinXP repairs

How did you fare?

--
Jeff Hunsaker

Top Ten Data Crunching Tips and Tricks

Top Ten Data Crunching Tips and Tricks

Free E-Learning and Skills Assessments for VS 2005/SQL Server 2005

David Boschman highlights free Microsoft online training...good through 11/1.

Monday, June 13, 2005

Avoiding Phishing Attacks

Good write-up on avoiding the latest Internet exploit-phishing. Basically, don't trust links embedded into emails-always browse to sites involving personal or credit card data by typing the address directly into a browser.

Friday, June 10, 2005

Custom Exception Handling in C#

Rule of thumb is to avoid throwing System.Exception or System.ApplicationException. I created a custom exception (below) which inherits from Exception.

Implement standard exception constructors

Types should not extend certain base types

[Serializable]
public class MyCustomException : System.Exception
{
public MyCustomException(){}

public MyCustomException (string message) : base (message) {}

public MyCustomException (string message, Exception innerException) :
base(message, innerException){}

protected ProcessorException(SerializationInfo info, StreamingContext context) :
base (info, context) {}

}

Wednesday, June 08, 2005

Friday, May 27, 2005

Inno installation script: VB6, MSDE, MDAC

An Inno installation script I wrote to install a VB6 application and optionally, MSDE and MDAC. It also executes several database scripts as well as prompts the user to install MSDE or choose an existing SQL Server database.


; MyApp Install Script
; Author: Jeff Hunsaker
; Version: 1.0.0.0


#define AppName "MyApp"
#define AppNameLong "My App"
#define AppPublisher "My Firm, Inc."
#define Ver1 "1"
#define Ver2 "0"
#define Ver3 "0"
#define Ver4 "0"
#define MinVersion "4.1.1998,4.0.1381sp5"
#define DBInstance "DBInstance" ;when MSDE installed locally/new
#define DBDatabase "DBDatabase"
#define DBDefaultSaPassword "sapassword"
#define DBDefaultSaAccount "sa"
#define DBAppUserName "AppUser"
#define DBAppPassword "password"
#define DBDefaultServer "(LOCAL)"
#define DBDSN "MyApp"
#define DBDSNDescription = "My App"

[Setup]
MinVersion={#MinVersion}
OnlyBelowVersion=0,0
AppCopyright=© 2005 {#AppPublisher}
AppName={#AppNameLong}
AppVerName={#AppNameLong} {#Ver1}.{#Ver2}.{#Ver3}.{#Ver4}
PrivilegesRequired=admin
AllowRootDirectory=true
AllowUNCPath=false
ShowLanguageDialog=no
WizardImageFile=logos\some.bmp
WizardImageStretch=no
AppID={{42F4A6D5-72BF-4C3E-AFE9-A345C13C842D}
AppMutex={#AppName}
DefaultDirName={pf}\{#AppName}
EnableDirDoesntExistWarning=true
AlwaysShowComponentsList=false
DisableReadyPage=no
LanguageDetectionMethod=none
AppPublisher={#AppPublisher}
AppPublisherURL=http://www.myfirm.com/
AppVersion={#Ver1}.{#Ver2}
UninstallDisplayName={#AppNameLong} {#Ver1}.{#Ver2}.{#Ver3}.{#Ver4}
UserInfoPage=yes
UsePreviousUserInfo=yes
DefaultGroupName={#AppName}
DisableProgramGroupPage=yes

[_ISTool]
LogFile=cwinstall.log
LogFileAppEND=true

[Icons]
Name: {group}\{#AppName}; Filename: {app}\{#AppName}.exe; WorkingDir: {app}
Name: {group}\{cm:UninstallProgram, {#AppName}}; Filename: {uninstallexe}

[Files]
;************************************************************************************************
; VB system files
;************************************************************************************************
; see also
; http://support.microsoft.com/default.aspx?scid=kb;en-us;830761
;************************************************************************************************
Source: vbfiles\stdole2.tlb; DestDir: {sys}; Flags: restartreplace uninsneveruninstall sharedfile regtypelib
Source: vbfiles\msvbvm60.dll; DestDir: {sys}; Flags: restartreplace uninsneveruninstall sharedfile regserver
Source: vbfiles\oleaut32.dll; DestDir: {sys}; Flags: restartreplace uninsneveruninstall sharedfile regserver
Source: vbfiles\olepro32.dll; DestDir: {sys}; Flags: restartreplace uninsneveruninstall sharedfile regserver
Source: vbfiles\asycfilt.dll; DestDir: {sys}; Flags: restartreplace uninsneveruninstall sharedfile
Source: vbfiles\comcat.dll; DestDir: {sys}; Flags: restartreplace uninsneveruninstall sharedfile regserver


;************************************************************************************************
; 3rd party DLL files
;************************************************************************************************
Source: projectfiles\somedll.DLL; DestDir: {app}; Flags: restartreplace sharedfile uninsnosharedfileprompt


;************************************************************************************************
; MS DLL files
;************************************************************************************************
Source: system32\msstdfmt.dll; DestDir: {sys}; Flags: restartreplace sharedfile regserver
Source: system32\msbind.dll; DestDir: {sys}; Flags: restartreplace sharedfile regserver
Source: misc\dao360.dll; DestDir: {dao}; Flags: restartreplace sharedfile regserver
Source: misc\sqlns.rll; DestDir: {pf}\Microsoft SQL Server\80\Tools\Binn\Resources\1033; Flags: restartreplace sharedfile


;************************************************************************************************
; VB OCX files
;************************************************************************************************
Source: msocxs\COMCT332.ocx; DestDir: {sys}; Flags: restartreplace sharedfile regserver uninsneveruninstall
Source: msocxs\MSCOMCT2.ocx; DestDir: {sys}; Flags: restartreplace sharedfile regserver uninsneveruninstall
Source: msocxs\MSCOMCTL.ocx; DestDir: {sys}; Flags: restartreplace sharedfile regserver uninsneveruninstall
Source: msocxs\TABCTL32.ocx; DestDir: {sys}; Flags: restartreplace sharedfile regserver uninsneveruninstall
Source: msocxs\MSMASK32.ocx; DestDir: {sys}; Flags: restartreplace sharedfile regserver uninsneveruninstall
Source: msocxs\MSDATGRD.ocx; DestDir: {sys}; Flags: restartreplace sharedfile regserver uninsneveruninstall
Source: msocxs\COMDLG32.ocx; DestDir: {sys}; Flags: restartreplace sharedfile regserver uninsneveruninstall
Source: msocxs\MSADODC.ocx; DestDir: {sys}; Flags: restartreplace sharedfile regserver uninsneveruninstall



;************************************************************************************************
; 3rd party OCX files
;************************************************************************************************
Source: system32\someocx.ocx; DestDir: {sys}; Flags: restartreplace sharedfile regserver uninsnosharedfileprompt



;************************************************************************************************
; project files
;************************************************************************************************
Source: projectfiles\{#AppName}.exe; DestDir: {app}; Flags: replacesameversion uninsnosharedfileprompt



;************************************************************************************************
; MDAC
;************************************************************************************************
Source: MDAC\mdac_typ.exe; DestDir: {tmp}\mdac; MinVersion: {#MinVersion}; Flags: ignoreversion; Check: GetNotInstallMSDEFlag


;************************************************************************************************
; MSDE 2000 SP3a
;************************************************************************************************
Source: msde\*.*; DestDir: {tmp}\msde; MinVersion: {#MinVersion}; Flags: ignoreversion; Check: GetInstallMSDEFlag
Source: msde\msi\*.*; DestDir: {tmp}\msde\msi; MinVersion: {#MinVersion}; Flags: ignoreversion; Check: GetInstallMSDEFlag
Source: msde\msm\*.*; DestDir: {tmp}\msde\msm; MinVersion: {#MinVersion}; Flags: ignoreversion; Check: GetInstallMSDEFlag
Source: msde\msm\1033\*.*; DestDir: {tmp}\msde\msm\1033; MinVersion: {#MinVersion}; Flags: ignoreversion; Check: GetInstallMSDEFlag
Source: msde\setup\*.*; DestDir: {tmp}\msde\setup; MinVersion: {#MinVersion}; Flags: ignoreversion; Check: GetInstallMSDEFlag



;************************************************************************************************
; SQL scripts
;************************************************************************************************
Source: scripts\osql.exe; DestDir: {tmp}\scripts
Source: scripts\buildobjects.sql; DestDir: {tmp}\scripts
Source: scripts\createdatabase.sql; DestDir: {tmp}\scripts
Source: scripts\populatedata.sql; DestDir: {tmp}\scripts


[Run]
;************************************************************************************************
; MSDE 2000 SP3a:
;************************************************************************************************
; see also:
; http: //msdn.microsoft.com/library/default.asp?url=/library/en-us/distsql/distsql_84xl.asp
;************************************************************************************************
Filename: {tmp}\msde\Setup.exe; Parameters: SECURITYMODE=SQL INSTANCENAME={#DBInstance} SAPWD={#DBDefaultSaPassword}; WorkingDir: {tmp}\msde; MinVersion: {#MinVersion}; StatusMsg: Installing Microsoft Data Engine (MSDE); Check: GetInstallMSDEFlag
Filename: {pf}\Microsoft SQL Server\80\Tools\Binn\scm.exe; Parameters: -Action 1 -Pwd {code:GetDbPassword} -Service MSSQL${#DBInstance} -Silent 1; WorkingDir: {pf}\Microsoft SQL Server\80\Tools\Binn; MinVersion: {#MinVersion}; StatusMsg: Starting Microsoft Data Engine (MSDE); Check: GetInstallMSDEFlag


;************************************************************************************************
; MDAC 2.7 SP1 Refresh (WinXP)
;************************************************************************************************
; see also:
; http://msdn.microsoft.com/library/default.asp?url=/library/en-us/mdacsdk/htm/wphistory_redistributemdac.asp
; http://support.microsoft.com/default.aspx?scid=kb;EN-US;842262
;************************************************************************************************
Filename: {tmp}\mdac\mdac_typ.exe; Parameters: "/Q:A /C:""dasetup /Q:D /N"""; WorkingDir: {tmp}\mdac; MinVersion: {#MinVersion}; StatusMsg: Installing Microsoft Data Access Components (MDAC); Check: GetNotInstallMSDEFlag


;************************************************************************************************
; SQL scripts
;************************************************************************************************
; execute base SQL for new installations
Filename: {tmp}\scripts\osql.exe; Parameters: -U{code:GetDbLogin} -P{code:GetDbPassword} -S{code:GetDbServer} -dmaster -ocreatedatabase.log -r -e -i{tmp}\scripts\createdatabase.sql; WorkingDir: {tmp}\scripts; Flags: runhidden; Check: GetDatabaseNotExistsFlag; StatusMsg: Executing database scripts: create database
Filename: {tmp}\scripts\osql.exe; Parameters: "-U{code:GetDbLogin} -P{code:GetDbPassword} -S{code:GetDbServer} -dmaster -oaddlogin.log -r -e -Q""if not exists(SELECT * FROM master..syslogins WHERE name='{#DBAppUserName}') exec sp_addlogin '{#DBAppUserName}', '{#DBAppPassword}', '{#DBDatabase}';"""; WorkingDir: {tmp}\scripts; Flags: runhidden; StatusMsg: Executing database scripts: create application account
Filename: {tmp}\scripts\osql.exe; Parameters: "-U{code:GetDbLogin} -P{code:GetDbPassword} -S{code:GetDbServer} -d{#DBDatabase} -ograntdbaccess.log -r -e -Q""if not exists(SELECT * FROM sysusers WHERE name='{#DBAppUserName}') exec sp_grantdbaccess @loginame='{#DBAppUserName}';"""; WorkingDir: {tmp}\scripts; Flags: runhidden; StatusMsg: Executing database scripts: create application account
Filename: {tmp}\scripts\osql.exe; Parameters: "-U{code:GetDbLogin} -P{code:GetDbPassword} -S{code:GetDbServer} -d{#DBDatabase} -oaddrole.log -r -e -Q""exec sp_addrolemember @rolename='db_owner', @membername='{#DBAppUserName}';"""; WorkingDir: {tmp}\scripts; Flags: runhidden; StatusMsg: Executing database scripts: create application account
Filename: {tmp}\scripts\osql.exe; Parameters: -U{code:GetDbLogin} -P{code:GetDbPassword} -S{code:GetDbServer} -d{#DBDatabase} -obuildobjects.log -r -e -i{tmp}\scripts\buildobjects.sql; WorkingDir: {tmp}\scripts; Flags: runhidden; Check: GetDatabaseNotExistsFlag; StatusMsg: Executing database scripts: create objects
Filename: {tmp}\scripts\osql.exe; Parameters: -U{code:GetDbLogin} -P{code:GetDbPassword} -S{code:GetDbServer} -d{#DBDatabase} -opopulatedata.log -r -e -i{tmp}\scripts\populatedata.sql; WorkingDir: {tmp}\scripts; Flags: runhidden; Check: GetDatabaseNotExistsFlag; StatusMsg: Executing database scripts: populate data

; TODO: execute update SQL for this version

; update database version value
Filename: {tmp}\scripts\osql.exe; Parameters: "-U{code:GetDbLogin} -P{code:GetDbPassword} -S{code:GetDbServer} -d{#DBDatabase} -odel_DatabaseVersion.log -r -e -Q""DELETE FROM {#DBDatabase}..DatabaseVersion"""; WorkingDir: {tmp}\scripts; Flags: runhidden; StatusMsg: Executing database scripts: update version
Filename: {tmp}\scripts\osql.exe; Parameters: "-U{code:GetDbLogin} -P{code:GetDbPassword} -S{code:GetDbServer} -d{#DBDatabase} -oins_DatabaseVersion.log -r -e -Q""INSERT INTO {#DBDatabase}..DatabaseVersion (DatabaseVersionID, CurrentVersion) VALUES (1, '{#Ver1}.{#Ver2}.{#Ver3}.{#Ver4}')"""; WorkingDir: {tmp}\scripts; Flags: runhidden; StatusMsg: Executing database scripts: update version



[Registry]
Root: HKLM; SubKey: Software\ODBC\ODBC.INI\ODBC Data Sources; Flags: createvalueifdoesntexist uninsdeletevalue deletevalue; ValueName: {#DBDSN}; ValueType: string; ValueData: SQL Server
Root: HKLM; SubKey: Software\ODBC\ODBC.INI\{#DBDSN}; Flags: createvalueifdoesntexist uninsdeletevalue deletevalue; ValueName: Driver; ValueType: string; ValueData: {sys}\SQLSRV32.dll
Root: HKLM; SubKey: Software\ODBC\ODBC.INI\{#DBDSN}; Flags: createvalueifdoesntexist uninsdeletevalue deletevalue; ValueName: Server; ValueType: string; ValueData: {code:GetDbServer}
Root: HKLM; SubKey: Software\ODBC\ODBC.INI\{#DBDSN}; Flags: createvalueifdoesntexist uninsdeletevalue deletevalue; ValueName: Database; ValueType: string; ValueData: {#DBDatabase}
Root: HKLM; SubKey: Software\ODBC\ODBC.INI\{#DBDSN}; Flags: createvalueifdoesntexist uninsdeletevalue deletevalue; ValueName: Description; ValueType: string; ValueData: {#DBDSNDescription}

[INI]


[CustomMessages]
databaseInfoCaption=Database information
databaseInfoDescription=Please indicate the database information

[Code]
var
Label1: TLabel;
Label2: TLabel;
Label3: TLabel;
txtServer: TEdit;
rbInstallMSDE: TRadioButton;
rbUseExisting: TRadioButton;
txtLogin: TEdit;
txtPassword: TEdit;
_installMSDE: boolean; // installing MSDE locally or using existing SQL instance
dbExists: boolean; // installing to new or existing database
dbServer: String; // use existing SQL Server server name
dbLogin: String; // use existing SQL Server login
dbPassword: String; // use existing SQL Server password

//************************************************************************************************
// EVENT HANDLERS
//************************************************************************************************
procedure databaseInfo_Activate(Page: TWizardPage);
begin
end;

procedure databaseInfo_CancelButtonClick(Page: TWizardPage; var Cancel, Confirm: Boolean);
begin
end;

procedure rbUseExisting_Click(Sender: TObject);
begin
// enable entry fields
txtServer.Enabled := True;
txtServer.ReadOnly := False;
txtLogin.Enabled := True;
txtLogin.ReadOnly := False;
txtPassword.Enabled := True;
txtPassword.ReadOnly := False;
end;

procedure rbInstallMSDE_Click(Sender: TObject);
begin
// disable entry fields
txtServer.Enabled := False
txtServer.ReadOnly := True;
txtLogin.Enabled := False;
txtLogin.ReadOnly := True;
txtPassword.Enabled := False;
txtPassword.ReadOnly := True;
end;

//************************************************************************************************
// FUNCTIONS
//************************************************************************************************
function InitializeSetup(): Boolean;
begin
// extract OSQL.exe file...needed in databaseInfo_NextButtonClick()
ExtractTemporaryFile('osql.exe');
Result := True;
end;

procedure DeInitializeSetup();
begin
end;

function GetInstallMSDEFlag: Boolean;
begin
Result := _installMSDE;
end;

function GetNotInstallMSDEFlag: Boolean;
begin
Result := not _installMSDE; // coded this way to accommodate the Check values
end;

function GetDatabaseExistsFlag: Boolean;
begin
Result := dbExists;
end;

function GetDatabaseNotExistsFlag: Boolean;
begin
Result := not dbExists; // coded this way to accommodate the Check values
end;

function GetDbServer(Default:String): String;
begin
Result := dbServer;
end;

function GetDbLogin(Default:String): String;
begin
Result := dbLogin;
end;

function GetDbPassword(Default:String): String;
begin
Result := dbPassword;
end;

function GetDbInstallType(Default:String): String;
begin
if (_installMSDE) then
Result := 'Local'
else
Result := 'Remote';
end;

// returns a string given a boolean and 2 representative return strings
function BoolToStr(b:boolean; TrueValue:string; FalseValue:string) : String;
begin
if b then
Result:=TrueValue
else
Result:=FalseValue;
end;

// output pre-installation stats
function UpdateReadyMemo(Space, NewLine, MemoUserInfoInfo, MemoDirInfo, MemoTypeInfo, MemoComponentsInfo, MemoGroupInfo, MemoTasksInfo: String): String;
var
cTemp: String;
DatabaseInfo: String;
begin

// create database information
DatabaseInfo := 'Database information:' + NewLine;
if (_installMSDE) then
begin
DatabaseInfo := DatabaseInfo + CHR(9) + 'Install MSDE locally' + NewLine;
DatabaseInfo := DatabaseInfo + CHR(9) + 'Server: ' + dbServer + NewLine;
DatabaseInfo := DatabaseInfo + CHR(9) + 'Login: ' + dbLogin + NewLine;
// DatabaseInfo := DatabaseInfo + CHR(9) + 'Password: *****' + NewLine;
DatabaseInfo := DatabaseInfo + CHR(9) + 'Password: ' + dbPassword + NewLine;
end
else
begin
DatabaseInfo := DatabaseInfo + CHR(9) + 'Use existing SQL Server' + NewLine;
DatabaseInfo := DatabaseInfo + CHR(9) + 'Server: ' + dbServer + NewLine;
DatabaseInfo := DatabaseInfo + CHR(9) + 'Login: ' + dbLogin + NewLine;
// DatabaseInfo := DatabaseInfo + CHR(9) + 'Password: *****' + NewLine;
DatabaseInfo := DatabaseInfo + CHR(9) + 'Password: ' + dbPassword + NewLine;
end;

cTemp := MemoUserInfoInfo + NewLine + NewLine;
cTemp := cTemp + MemoDirInfo + NewLine + NewLine;
cTemp := cTemp + DatabaseInfo + NewLine + NewLine;

Result := cTemp;
end;


function databaseInfo_ShouldSkipPage(Page: TWizardPage): Boolean;
begin
Result := False;
end;

function databaseInfo_BackButtonClick(Page: TWizardPage): Boolean;
begin
Result := True;
end;

// executes upon clicking Next within database info dialog
function databaseInfo_NextButtonClick(Page: TWizardPage): Boolean;

var
ResultCode: Integer;
output: String;
begin

// initialize
_installMSDE := False;
dbExists := False;

// install MSDE ok
if (rbInstallMSDE.Checked) then
begin
_installMSDE := True; // MAY be overriden in the logic below
dbServer := '{#DBDefaultServer}\{#DBInstance}';
dbLogin := '{#DBDefaultSaAccount}';
dbPassword := '{#DBDefaultSaPassword}';
Result := True;
end
else
begin
// ensure all fields provided if use existing selected
if ((rbUseExisting.Checked) and
((txtServer.Text = '') or
(txtLogin.Text = '') or
(txtPassword.Text = ''))) then
begin
MsgBox('You must provide server, login, and password for an existing installation.', mberror, MB_OK);
Result := False;
end
else
begin
// persist entered values
dbServer := txtServer.Text;
dbLogin := txtLogin.Text;
dbPassword := txtPassword.Text;
_installMSDE := False;
Result := True;
end
end;

// output check for existing database message
MsgBox ('Setup will now determine if the database exists. This may take up to 30 seconds.', mbInformation, MB_OK);

// determine if instance/database exist
if Exec(ExpandConstant('{tmp}\osql.exe'), '-U' + dbLogin + ' -P' + dbPassword + ' -S' + dbServer + ' -l10 -odatabaseexists.log -Q"EXIT(SELECT COUNT(*) FROM master..sysdatabases WHERE name=''{#DBDatabase}'')"', '', SW_HIDE, ewWaitUntilTerminated, ResultCode) then
begin
// read in the OSQL output file 0 if not exists, 1 if exists --> MUST LOOK FOR '0' FIRST because file returns 1 record(s) affected
if LoadStringFromFile(ExpandConstant('{tmp}\databaseexists.log'), output) then
begin
if Pos(ExpandConstant(IntToStr(0)), output)>0 then
begin
if (_installMSDE) then
begin

// Delete any stragler crgp .mdf and .ldf files but leave the directory itself
DelTree(ExpandConstant('{pf}\Microsoft SQL Server\MSSQL${#DBInstance}\Data\{#DBDatabase}*'), False, True, True);
DelTree(ExpandConstant('{pf}\Microsoft SQL Server\MSSQL${#DBInstance}\Data\' + Lowercase(ExpandConstant('{#DBDatabase}')) + '*'), False, True, True);

// database does not exist but instance does; user indicated install MSDE; else user indicated use existing SQL Server
MsgBox ('The database does not yet exist and will be created during installation. Original system account and password is assumed. Click back and choose existing SQL Server if this is incorrect.', mbInformation, MB_OK);

_installMSDE := False;
end
else
MsgBox ('The database does not yet exist and will be created during installation using the credentials supplied.', mbInformation, MB_OK);
end
else
begin
if Pos(ExpandConstant(IntToStr(1)), output)>0 then
begin
if (_installMSDE) then
begin
// database and instance exist; user indicated install MSDE; else user indicated use existing SQL Server
// should never hit this but coded it anyway just in case
MsgBox ('The database exists and will undergo an upgrade during installation. Original system account and password is assumed. Click back and choose existing SQL Server if this is incorrect.', mbInformation, MB_OK);
_installMSDE := False;
end
else
MsgBox ('The database exists and will undergo an upgrade during installation using the credentials supplied.', mbInformation, MB_OK);
dbExists := True;
_installMSDE := False;
end
else
begin
if Pos('Login failed for user', output)>0 then
begin
// credentials incorrect
MsgBox ('Incorrect login credentials.', mbInformation, MB_OK);
Result := False;
end
else
begin
if Pos('SQL Server does not exist', output)>0 then
begin
// server does not exist
if not _installMSDE then
begin
MsgBox ('SQL Server does not exist. Try re-entering the information.', mbInformation, MB_OK);
Result := False;
end
else
begin

// Delete any stragler crgp .mdf and .ldf files but leave the directory itself
DelTree(ExpandConstant('{pf}\Microsoft SQL Server\MSSQL${#DBInstance}\Data\{#DBDatabase}*'), False, True, True);
DelTree(ExpandConstant('{pf}\Microsoft SQL Server\MSSQL${#DBInstance}\Data\' + Lowercase(ExpandConstant('{#DBDatabase}')) + '*'), False, True, True);

MsgBox ('MSDE will be installed locally. Afterward, a reboot may be required (select yes if prompted).', mbInformation, MB_OK);

Result := True;
_installMSDE := True;
end
end
end
end
end
end
end;
end;

function databaseInfo_CreatePage(PreviousPageId: Integer): Integer;
var
Page: TWizardPage;
begin
Page := CreateCustomPage(
PreviousPageId,
ExpandConstant('{cm:databaseInfoCaption}'),
ExpandConstant('{cm:databaseInfoDescription}')
);

{ Label1 }
Label1 := TLabel.Create(Page);
with Label1 do
begin
Parent := Page.Surface;
Left := ScaleX(16);
Top := ScaleY(56);
Width := ScaleX(58);
Height := ScaleY(13);
Caption := 'SQL Server:';
end;

{ Label2 }
Label2 := TLabel.Create(Page);
with Label2 do
begin
Parent := Page.Surface;
Left := ScaleX(16);
Top := ScaleY(104);
Width := ScaleX(58);
Height := ScaleY(13);
Caption := 'Login name:';
end;

{ Label3 }
Label3 := TLabel.Create(Page);
with Label3 do
begin
Parent := Page.Surface;
Left := ScaleX(16);
Top := ScaleY(152);
Width := ScaleX(50);
Height := ScaleY(13);
Caption := 'Password:';
end;

{ rbInstallMSDE }
rbInstallMSDE := TRadioButton.Create(Page);
with rbInstallMSDE do
begin
Parent := Page.Surface;
Left := ScaleX(0);
Top := ScaleY(8);
Width := ScaleX(361);
Height := ScaleY(17);
Caption := 'Install Microsoft SQL Server Database Engine (MSDE) locally';
TabOrder := 1;
Checked := True;
ONCLICK := @rbInstallMSDE_Click;
end;

{ rbUseExisting }
rbUseExisting := TRadioButton.Create(Page);
with rbUseExisting do
begin
Parent := Page.Surface;
Left := ScaleX(0);
Top := ScaleY(32);
Width := ScaleX(401);
Height := ScaleY(17);
Caption := 'Use existing SQL Server installation. Account must have administrative rights.';
TabOrder := 2;
TabStop := True;
ONCLICK := @rbUseExisting_Click;
end;

{ txtServer }
txtServer := TEdit.Create(Page);
with txtServer do
begin
Parent := Page.Surface;
Left := ScaleX(16);
Top := ScaleY(72);
Width := ScaleX(257);
Height := ScaleY(21);
Enabled := False;
ReadOnly := True;
TabOrder := 3;
end;

{ txtLogin }
txtLogin := TEdit.Create(Page);
with txtLogin do
begin
Parent := Page.Surface;
Left := ScaleX(16);
Top := ScaleY(120);
Width := ScaleX(257);
Height := ScaleY(21);
Enabled := False;
ReadOnly := True;
TabOrder := 4;
end;

{ txtPassword }
txtPassword := TEdit.Create(Page);
with txtPassword do
begin
Parent := Page.Surface;
Left := ScaleX(16);
Top := ScaleY(168);
Width := ScaleX(257);
Height := ScaleY(21);
Enabled := False;
ReadOnly := True;
TabOrder := 5;
end;


with Page do
begin
OnActivate := @databaseInfo_Activate;
OnShouldSkipPage := @databaseInfo_ShouldSkipPage;
OnBackButtonClick := @databaseInfo_BackButtonClick;
OnNextButtonClick := @databaseInfo_NextButtonClick;
OnCancelButtonClick := @databaseInfo_CancelButtonClick;
end;

Result := Page.ID;
end;

//************************************************************************************************
// PROCEDURES
//************************************************************************************************
procedure InitializeWizard();
begin
// display custom database page after selecting directory
databaseInfo_CreatePage(wpSelectDir);
end;

Tuesday, May 24, 2005

Google Hack: overriding word breaks

Recently, while working on an Inno installer project, I grew frustrated at Google for returning many "...in no..." results while searching for the string "inno". The solution to override word breaks in Google is to add a preceeding "+" (e.g. +Inno). Not sure why but I thought it was cool I actually received a response from Google:

--------------------------------------------------------------------------------

Re: [#26513876] inno search
1 message

--------------------------------------------------------------------------------
help@google.com Mon, May 23, 2005 at 8:02 PM
To: jeff.com
Hi Jeff,

Thank you for your note. To help "force" a particular search term, you can include a + symbol in front of the word or words you're searching for. For example, a search for [ +inno ] returns the following search results:

http://www.google.com/search?hl=en&lr=&safe=off&c2coff=1&q=%2Binno&btnG=Search

For additional tips, please see http://www.google.com/help/refinesearch.html or check out http://www.google.com/help/operators.html. If you'd like a little guidance, try searching from our Advanced Search page: http://www.google.com/advanced_search

Regards,
The Google Team

Original Message Follows:
------------------------
From: jeff.com
Subject: inno search
Date: Wed, 18 May 2005 18:12:35 -0000

Hi, I'm trying to search on the word inno but it returns results 'in no'.
Enclosing in quotes doesn't seem to help. Suggestions?

Thanks.

Jeff...


Language: en
WebUserLocale: en
IssueType: find_specific

Monday, May 23, 2005

Virtual PC for MSDN Windows 98

I had the darnest time establishing a MS Virtual PC instance using the MSDN copy of Windows 98 SE. The Windows XP and 2000 bootable CDs prompted me during installation while Windows 98, living in a subdirectory and not bootable, just kept throwing errors. Finally, I came up with the following:

1. Obtain a Window 98 boot disk (I ended up using Bootdisk.com). (A little scary from a security aspect, but I needed to get this done)
2. Boot from this disk normally until arriving at a command prompt
3. fdisk the virtual C: drive
4. format the virtual C: drive
5. copy the Windows 98 installation directory and files from the CD onto the virtual C:
6. execute setup.exe from the directory where you just copied the files

BTW, it would be an improvement if Virtual PC MSDN would include vanilla installations for all the MS operating systems. Windows XP and 2000 are straightforward but Windows 98 is tricky and they all consume quite a bit of time to establish. A fat DVD containing vanilla instances would be tight.

Wednesday, May 04, 2005

Regular Expression Resource Sites

Regular Expression Library
Regex Coach
Extreme Regex Foo

Great discussion implementation: Scotts.com

I think Scott's lawn care site does an outstanding job providing very helpful information in a discussion format. The branding matches the root web site dead on, it looks very professional yet fresh and appealing, and real live experts (e.g. "Scotts WebLawn Guy") monitor the site providing resolution to otherwise elusive problems. Accounts are integrated with the scotts.com site but one doesn't need to log in to view discussion postings. The technology is Fuse Talk available in Cold Fusion and ASP.Net. Basic edition is $129.

Finally, this vehicle creates a huge marketing win for Scott's. For example, check out this softball thread. Scotts WebLawn Guy knocks one out of the park when asking "If Scotts could make (product idea) that would (blank), I would definitely buy it." and receiving 21 posts!

SMB: Backup Options

Small Business Backup Comparisons

Wednesday, April 27, 2005

FxCop .Net code analyzer

http://www.gotdotnet.com/team/fxcop/

FxCop is a code analysis tool that checks .NET managed code assemblies for conformance to the Microsoft .NET Framework Design Guidelines. It uses reflection, MSIL parsing, and callgraph analysis to inspect assemblies for more than 200 defects in the following areas:
Library design
Localization
Naming conventions
Performance
Security
FxCop includes both GUI and command line versions of the tool, as well as an SDK to create custom rules.

LINKS: Sharepoint Portal Development

Good book for developers
Good book for administration
Not released yet but this book looks intreguing
All Sharepoint books
Good Sharepoint BLOG
Sharepoint Admin Guide
Sharepoing Server Help
Sharepoint FAQ
Sharepoint Community

HOWTO: *nix Primer

http://wks.uts.ohio-state.edu/basic_unix_guide/unix_guide.html

HOWTO: Search from CmdLine using FINDSTR

findstr /M /S "PROFILE_PRIBUSINESS" *.* >> PROFILE_PRIBUSINESS.txt

HOWTO: Deploy ASP.Net in a Secure Fashion

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/secmod/html/secmod98.asp
http://www.microsoft.com/technet/security/tools/mbsahome.mspx

HOWTO: Control browsers with JavaScript

http://developer.irt.org/script/window.htm

HOWTO: SQL Server: Reporting on performance

Some resources to draw info on SQL Server memory usage, locks, fragmentation, etc. This is my favorite SQL Server tuning site: http://www.sql-server-performance.com/

SQL Server Perf Mon

SQLServer: Access Methods - Page Splits/sec: Number of page splits occurring as the result of index pages overflowing.
SQLServer: Databases - Data File Size (KB)
SQLServer: Databases - Log File Size (KB)
SQLServer: Databases - Log File Used Size (KB)
SQLServer: General Statistics - User Connections: Number of users connected to the system.
SQLServer: Locks - Average Wait Time (ms): The average amount of wait time (milliseconds) for each lock request that resulted in a wait.
SQLServer: Locks - Number of Deadlocks/sec: Number of lock requests that resulted in a deadlock.
SQLServer: Memory Manager - Total Server Memory (KB): Total amount of dynamic memory the server is currently consuming
Many, many others…

Queries

View Blocks
SELECT spid, blocked, waittype, getdate() AS 'Time'
FROM master..sysprocesses (nolock)
WHERE blocked <> 0

View a whole lot of info on processes
SELECT *
FROM master..sysprocesses (nolock)

View process info sorted by memory usage
SELECT *
FROM master..sysprocesses (nolock)
ORDER BY memusage DESC

How to monitor SQL Server 2000 blocking


Stored Procedures (system)
Sp_lock
Sp_who
Sp_who2
Sp_monitor
sp_spaceused

HOWTO: Clean out SQL Server Index Wizard hypothetical indexes

SELECT 'DROP INDEX ' + object_name(id) + '.' + name AS Hypothetical FROM sysindexes
WHERE indexproperty(id, name, 'IsHypothetical') = 1

HOWTO: Self sign SSL Certificates in IIS 6.0

SelfSSL

HOWTO: Redirect http to https under IIS

http://www.isapirewrite.com/

HOWTO: Restore a differential database backup

ALTER DATABASE DB_Restore_To SET SINGLE_USER
GO

RESTORE DATABASE DB_Restore_To FROM DISK = 'C:\MSSQL\DB_Restore_From_Full.BAK' WITH NORECOVERY
GO

RESTORE DATABASE DB_Restore_To FROM DISK = 'C:\MSSQL\DB_Restore_From_Diff.BAK' WITH NORECOVERY
GO

RESTORE LOG DB_Restore_To FROM DISK = 'C:\MSSQL\DB_Restore_From_Tran.TRN'
GO

ALTER DATABASE DB_Restore_To SET MULTI_USER
GO

Article comparing VB.NET and C# languages

http://www.codeproject.com/dotnet/vbnet_c__difference.asp

Tuesday, March 08, 2005

Security Guide for SMB

Good 10 step guide to implementing security for the small business. Includes 10 step guide to securing wireless networks too.

http://techrepublic.com.com/5139-6240-5591138.html