Wednesday, June 18, 2008

SQL Server 2008 Launch

Attended Microsoft's 2008 launch event - Heroes Happen Here - in Sacramento two weeks ago. At the Sacramento Convention Center on J St.

In the morning, I was in the SQL Server session, collateral at (http://sqlserver2008jumpstart.microsofttraining.com/content/info.asp?CcpSubsiteID=69&infoid=27) Most of it was fairly DBA-side heavy. The first session was on Infrastructural improvements, it wasn't very demo-friendly, a lot of security features, basically expanded on 2005 in areas such as encryption and securing functions. A new feature called 'Transparent Data Encryption', allowed the whole database to be encrypted, and, as the title describes, the developer does not need to change any of their code to work with it... Similar impact on the developer as using EFS to encrypt the file system, but there seems to be minimal performance hit and less overhead, plus the keys can be centrally managed, backed up, etc. where EFS this is difficult / impossible? Other interesting factoids that were sort of mentioned as asides, I need to research them a bit more, was the ability to expose the file system, and XML files or sources as data objects, and concept called 'Sync Services' (which may have been around in 2005, but less prominent)

The second presentation introduced an really helpful feature for multi-server management called Declarative Management Framework (DMF) for policy-based management. Basically, most settings, or rule you could manually apply to one server, could easily be applied to many servers. (Much further than the 'Master Server' concept in SQL 2000-2005 that applied scripts to multiple servers by kicking off SQL Server Agent on each target) I saw it as basically three dimensions:
  • How to enforce the policy (log it only, force the change (possibly 'breaking' the other server?)
  • When to enforce it (on demand, scheduled, when changes occurred)
  • On what servers (By version, by server OS, etc. - similar pattern as group policy, a variety of custom filters could be built up to apply the change to only certain dbs, or servers) For that matter, servers could be grouped in some custom manner too.

In some of the environments, I've worked in with a large amount of MSDE or SQL Express instances, this is a {deity}-send. I'm not completely sure how it works against occassionally-connected boxes, on demand would not to be an option, but scheduled or on change would, assuming the result of applying the policy placed some logic on each remote server... but if only SQL 2008 contains the logic (it was mentioned that past version of SQL are supported, but as remote servers... similar to how SQL 2000 boxes can be administered with SSMS)

Anywhom, using the 'log-only' feature, with the data captured, my idea was to create some model of a 'compliance score' off it, for example, a 'grade' each server would get for compliancy with some standard. Some policies could be weighted differently, i.e. setting backup options may be higher weight than stored proc naming conventions... Will have to get a SQL 2008 box set up to take a look.

The last session of the SQL Server morning was new features of Analysis Services. The features were largely incremental, since I haven't spent much time in this tool yet, I quickly surmised that I needed to work with it from the ground up, vs. learning what changed in 2008 vs. 2005. A brief demo of some changes in SSRS showed a tool called 'Report Designer'. It was definitely new, but it seemed to fill the same space as 'Report Builder', and unless I misheard, it was explicitly mentioned that both existed.

The afternoon session was on Visual Studio. I don't have as many notes on that, probably a creature of zoning out in the afternoon, and most of the features were very incremental (and I actually recall seeing a very similar demo on VSTO last year)

Christopher Schipper demo'd various ASP.net features -nested master pages, more CSS design and 'debugging', javascript debugging, LINQ to XML. A couple of features that stood out for me was a Sync feature. To the project, simply clicking 'Add->Local Database Cache' allowed the creation of an offline copy of a data source to be shipped with the app. 1 line of code - cacheRefTablesSyncAgent.cache could be called to update the cache. 1 way synchronization is easy. 2-way is possible, but requires more code to handle events related to conflict management.

There was a demo of VSTO, creating a form that would be part of Outlook, could be used to consume/respond to an email.

Saturday, June 14, 2008

Project Management Professional (PMP)

In May 2008, I became a certified Project Management Professional (PMP), a credential through PMI. I've been interested almost 3 years, joining PMI when I still lived in San Diego, but about a year or so of serious study and work towards it.

The PMP is the flagship certification of PMI, attesting to my experience, education, and knowledge managing projects. In my case, experience includes 13 projects over 7 years for 8 seperate companies. All relevant experience had to be within the last 8 years and cover at least 4500 hours of project work (this applied as I have a Bachelor's degree, w/o the experience requirement is larger) A goal of PMI is to have the PMP recognized around the world as the standard, approaching the status of a CPA to accounting, or 'passing the bar' for an attorney. PMP's work in a variety of industries, construction, and manufacturing notably, and more and more in Information Technology (IT).

Obviously, my specialty is IT projects, though most of my project are really business project with a technology component. I plan to continue along my current career path, working with the State of California - Department of Corrections & Rehabilitation. I really believe that applying basic levels of project management to the smaller efforts I see will improve results. Basic definitions of scope, and schedule would prevent many of our smaller efforts seem to trail off endlessly. There is also a huge opportunity to parametric-ize smaller IT projects. Projects where the planning, documentation, and other 'overhead', might on paper seem to overwhelm the actual effort to produce a little benefit, but the resulting process (report, database, document, etc.) might be used 10, 100, 1000 times over.

Learning the PMI material even in the last year has allowed me to manage projects to more success. The PMP has just given me more 'tools in the toolbox' from which to manage projects, especially communications planning, and human resource mgmt. I can't say I've completely rethought my approach to scope, time and cost aspects. They were challenging when not having really any formal guide as to how to manage them, and they are challenging with such. Really the challenge on all of the areas is managing customer expectations, and learning the PMBOK gives me new ways to get those expectations out on the table.

Exam Prep


There's already a lot of mindshare out there on strategies to pass the exam, but I'll just add, more than any exam I've ever taken, it's not one you can 'cram' for. You have to just know the material and live it and breathe it, for at least some portion of you full-time activities, even if applying the PMBOK to a small or even personal project seems superfluous. That being said, I did find it advantageous to keep the PMI material at the 'top of my head' for the weeks up to the exam. This might not be your learning style, but it helped me more to hand-write, or type, tables of processes, study sheets, lists o' things, etc. than to read a pre-prepared one. Also, taking advice from an instructor with IIL, D.W. Nesper, reading PM network magazine and some of the journals, helped me to think in a reflexively PM-oriented manner about some of the questions. I did put together a quick Access database that helped me organize my thinking about the PM processes, if I get a chance to empty it out, I'll post it here as well.

Thursday, June 5, 2008

Scripting - Create a desktop shortcut to a URL (Updated for IE7)

This article discusses a script that creates a desktop shortcut to a particular URL, with a given custom icon. I know, pretty routine stuff, but when the requirement of a project is to deploy a 'desktop shortcut' to affected customers, I often find that deploying such a script on a web site, such that it can be accessed on demand, or pushing out via a login script or other type of automated technology meets the requirement.

The script:


  1. Copies a custom icon from a network share to the local computer (so the icon shows up, even if the user is offline)

  2. Creates a shortcut on the desktop, references the custom icon

  3. Prompts the user if they wish to launch the site immediately



I developed this script a number of years ago, and recently had the opportunity to re-use it for another app. Unfortunately, upon initial run, it worked except for the custom icon, it was using the default browser icon instead. Thought maybe I broke something because I had also modified the target location of the custom icon to support Vista (as well as 9x-XP). I then tested versions of it I had written in the past that were still in production, those had the same issue.

Turns out the issue was on computers with Internet Explorer 7. Internet Explorer 6 computers were fine. The IE7 computer had a slightly different format in the *.url files placed on the desktop. Didn't discover this until I opened up the .url file in notepad to compare one the script created, to one that was manually created.

In IE6, the url's were basically this format:



[InternetShortcut]
URL=http://intranet/MyApp
IconIndex=0
IconFile=C:\Documents and Settings\TestUser\Application Data\MyApp.ico

While it is in ini file format (note the section 'InternetShortcut' in square brackets), there was only one section, so we were able to get away with simply appending the property=value lines to the file, as in the following snippent



Dim fso
Set fso = WScript.createobject("Scripting.FileSystemObject")

Dim f
Set f = fso.getfile(sURLLinkFile)

Dim contents
contents = ""

Dim line

Dim ots
Set ots = f.openastextstream(1)

'read in contents of the file, except for any existin icon settings
do while not ots.atEndofstream
line = ots.readline
if instr(1,line,"IconIndex",1) = 0 and instr(1,line,"IconFile",1) = 0 then
contents = contents & line & vbcrlf
end if
loop
ots.close

'add the lines for iconindex and file
if not (isnull(iIconIndex) or isnull(IconLocation)) then
if not (isempty(iIconIndex) or isempty(IconLocation)) then
contents=contents &"IconIndex=" & cstr(iIconIndex) & vbcrlf
contents=contents & "IconFile=" & IconLocation
end if
end if

set ots = f.openastextstream(2)
ots.write contents
ots.close

set ots = nothing
set f = nothing
set fso = nothing

The IE7 version has added a section (notice the GUID in square brackets on the 4th line) and a few more properties


So, absent any change in the script, the .URL files were coming out as:



[InternetShortcut]
URL=http://intranet/MyApp
IDList=
HotKey=0
[{000214A0-0000-0000-C000-000000000046}]
Prop3=19,2
IconIndex=0
IconFile=C:\Documents and Settings\TestUser\Application Data\MyApp.ico

With the Icon reference essentially in the 'wrong' section, no .url appears with the standard browser icon. This appeared to be true regardless of default browser (i.e. FireFox, etc.) just having IE7 vs. IE6. (Computers that had created shortcuts while on IE6, then upgrading to IE7, appeared OK.)


To resolve, grabbed some INI read-write functions from http://www.motobit.com, which, after including the functions, cleaned up the core code quite a bit anyway:



WriteINIString "InternetShortcut", "IconIndex", iIconIndex, sURLLinkFile
WriteINIString "InternetShortcut", "IconFile", IconLocation, sURLLinkFile

So we end up with:



[InternetShortcut]
URL=http://intranet/MyApp
IDList=
HotKey=0
IconIndex=0
IconFile=C:\Documents and Settings\TestUser\Application Data\MyApp.ico
[{000214A0-0000-0000-C000-000000000046}]
Prop3=19,2

Excellent stuff, right? So here's the full code:



'-------------------------------------------------------------------------------
'Creates a desktop 'shortcut', or 'icon' to a given URL
'Runs with limited-rights user, so you can give users the ability to create a
'shortcut on-demand, or roll out with a login script or similar automated device
' Author Chris Anderson cander@realworldis.com
' - Modified the script to drop the custom icon, if specified into the current users 'app data' folder
' more logo-compliant than the old version which hard-coded c:\program files\. it will now run under a
' limited rights user
' - Added prompt to launch the site after creating the shortcut
' - Modified the shortcut creation to be compatible with IE7, the previous version would create the shortcut
' successfully, but the custom icon would not be used.
'-------------------------------------------------------------------------------
Option Explicit

Const URL_SHORTCUT_NAME = "My Intranet Application"
Const TARGET_PATH = "http://intranet/MyApp"
Const ICON_REMOTE_FILE_PATH = "\\server\public\MyApp\MyApp.ico"

'the icon index can allow you to reference an ico resource in the file with many resources (i.e. and .exe or .dll)
'if using a seperate .ico file, set to 0
Dim iIconIndex
iIconIndex = 0

Dim sLocalIconFilePath

'copy icon locally so it shows up regardless of network connection
'logo-compliancy - copy the file to the current users 'Application Data' as they should have write access even when not-admin
CopyIconToLocalApplicationData ICON_REMOTE_FILE_PATH, sLocalIconFilePath

'the script then creates a shortcut on their desktop, to the target url, with the local path of the icon
CreateURLShortcut URL_SHORTCUT_NAME, TARGET_PATH, sLocalIconFilePath

'prompt the user to open the shortcut now
Dim sMessage
sMessage = "There is now an icon on your desktop for " & URL_SHORTCUT_NAME & ". Would you like to open it now?"

if MsgBox(sMessage,vbYesNo) = vbYes then
OpenPath TARGET_PATH
end if

Private Sub CreateURLShortcut(ByVal ShortcutName, Byval TargetPath, ByVal IconLocation)

Dim WSHShell
Set WSHShell = createobject("wscript.shell")

Dim sDesktop
sDesktop= WSHShell.specialfolders("Desktop")

Dim oURLLink
Set oURLLink = WSHShell.createshortcut(sDesktop & "\" & ShortcutName & ".url")
oURLLink.targetpath = TargetPath
oURLLink.save

Dim sURLLinkFile
sURLLinkFile = oURLLink.FullName

'set the icon file
if Not IsEmpty(iIconIndex) AND NOT IsEmpty(IconLocation) Then

'WScript.Echo IconLocation

WriteINIString "InternetShortcut", "IconIndex", iIconIndex, sURLLinkFile
WriteINIString "InternetShortcut", "IconFile", IconLocation, sURLLinkFile

end if

set oURLLink = nothing
set WSHShell = nothing

End Sub

Private Sub CopyIconToLocalApplicationData(Byval RemotePath, ByRef LocalPath)

Dim WSHShell
Set WSHShell = WScript.CreateObject("WScript.Shell")

Dim fso
Set fso = CreateObject("Scripting.filesystemobject")

Dim objFile
Set objFile = fso.GetFile(RemotePath)

'local path will be directly under the users app data
LocalPath = WSHShell.ExpandEnvironmentStrings("%AppData%") & "\" & fso.GetFileName(objFile)

fso.CopyFile RemotePath, LocalPath

Set fso = Nothing

Set WSHShell = Nothing

End Sub

private sub OpenPath(byval TargetPath)

Dim WSHShell
Set WSHShell = createobject("shell.application")

WSHShell.Open TargetPath

set WSHShell = nothing

end sub


'----------------------------------------------------------------
'INI File Handling

'Work with INI files In VBS (ASP/WSH)
'v1.00
'2003 Antonin Foller, PSTRUH Software, http://www.motobit.com
'Function GetINIString(Section, KeyName, Default, FileName)
'Sub WriteINIString(Section, KeyName, Value, FileName)
'----------------------------------------------------------------

Sub WriteINIString(Section, KeyName, Value, FileName)
Dim INIContents, PosSection, PosEndSection

'Get contents of the INI file As a string
INIContents = GetFile(FileName)

'Find section
PosSection = InStr(1, INIContents, "[" & Section & "]", vbTextCompare)
If PosSection>0 Then
'Section exists. Find end of section
PosEndSection = InStr(PosSection, INIContents, vbCrLf & "[")
'?Is this last section?
If PosEndSection = 0 Then PosEndSection = Len(INIContents)+1

'Separate section contents
Dim OldsContents, NewsContents, Line
Dim sKeyName, Found
OldsContents = Mid(INIContents, PosSection, PosEndSection - PosSection)
OldsContents = split(OldsContents, vbCrLf)

'Temp variable To find a Key
sKeyName = LCase(KeyName & "=")

'Enumerate section lines
For Each Line In OldsContents
If LCase(Left(Line, Len(sKeyName))) = sKeyName Then
Line = KeyName & "=" & Value
Found = True
End If
NewsContents = NewsContents & Line & vbCrLf
Next

If isempty(Found) Then
'key Not found - add it at the end of section
NewsContents = NewsContents & KeyName & "=" & Value
Else
'remove last vbCrLf - the vbCrLf is at PosEndSection
NewsContents = Left(NewsContents, Len(NewsContents) - 2)
End If

'Combine pre-section, new section And post-section data.
INIContents = Left(INIContents, PosSection-1) & _
NewsContents & Mid(INIContents, PosEndSection)
else'if PosSection>0 Then
'Section Not found. Add section data at the end of file contents.
If Right(INIContents, 2) <> vbCrLf And Len(INIContents)>0 Then
INIContents = INIContents & vbCrLf
End If
INIContents = INIContents & "[" & Section & "]" & vbCrLf & _
KeyName & "=" & Value
end if'if PosSection>0 Then
WriteFile FileName, INIContents
End Sub

Function GetINIString(Section, KeyName, Default, FileName)
Dim INIContents, PosSection, PosEndSection, sContents, Value, Found

'Get contents of the INI file As a string
INIContents = GetFile(FileName)

'Find section
PosSection = InStr(1, INIContents, "[" & Section & "]", vbTextCompare)
If PosSection>0 Then
'Section exists. Find end of section
PosEndSection = InStr(PosSection, INIContents, vbCrLf & "[")
'?Is this last section?
If PosEndSection = 0 Then PosEndSection = Len(INIContents)+1

'Separate section contents
sContents = Mid(INIContents, PosSection, PosEndSection - PosSection)

If InStr(1, sContents, vbCrLf & KeyName & "=", vbTextCompare)>0 Then
Found = True
'Separate value of a key.
Value = SeparateField(sContents, vbCrLf & KeyName & "=", vbCrLf)
End If
End If
If isempty(Found) Then Value = Default
GetINIString = Value
End Function

'Separates one field between sStart And sEnd
Function SeparateField(ByVal sFrom, ByVal sStart, ByVal sEnd)
Dim PosB: PosB = InStr(1, sFrom, sStart, 1)
If PosB > 0 Then
PosB = PosB + Len(sStart)
Dim PosE: PosE = InStr(PosB, sFrom, sEnd, 1)
If PosE = 0 Then PosE = InStr(PosB, sFrom, vbCrLf, 1)
If PosE = 0 Then PosE = Len(sFrom) + 1
SeparateField = Mid(sFrom, PosB, PosE - PosB)
End If
End Function


'File functions
Function GetFile(ByVal FileName)
Dim FS: Set FS = CreateObject("Scripting.FileSystemObject")
'Go To windows folder If full path Not specified.
If InStr(FileName, ":\") = 0 And Left (FileName,2)<>"\\" Then
FileName = FS.GetSpecialFolder(0) & "\" & FileName
End If
On Error Resume Next

GetFile = FS.OpenTextFile(FileName).ReadAll
End Function

Function WriteFile(ByVal FileName, ByVal Contents)

Dim FS: Set FS = CreateObject("Scripting.FileSystemObject")
'On Error Resume Next

'Go To windows folder If full path Not specified.
If InStr(FileName, ":\") = 0 And Left (FileName,2)<>"\\" Then
FileName = FS.GetSpecialFolder(0) & "\" & FileName
End If

Dim OutStream: Set OutStream = FS.OpenTextFile(FileName, 2, True)
OutStream.Write Contents
End Function