Monday, October 3, 2011

Using functions inside Powershell scripts

I had a task today that required mounting some content databases to my Sharepoint 2010 farm from an old WSS 3.0 environment that we are currently updating. Tasks like this often involve putting together a script file of some sort, a task that I quite frankly always find clunky and  boring to do and has always been performed on a need-to-do basis only in the past. However, I seem to have been bitten by the "what does this button do???" bug today and decided to investigate if I could make this whole experience a wee bit more exciting (and robust, god I do not want to mess up sharepoint content databases & have to roll back). Since I love working with a nix-style shell environment from my open-source days (hint hint: caffiene), I really love working with windows power shell. I feel it is MS's first real attempt at creating a decent shell scripting environment, and quite frankly PS cmdlet's are wicked.

Firstly, a bit of googling for some sort of IDE safe-heaven revealed the existence PowerGUI which can get for free (bit of $$ gets you a Pro version) and offer's a really wicked environment with PS specific intellisense & debugging enabled in a very Visual Studio'esque look & feel. Definitely a must have for nube's like myself.  The tool also offers VS2010 integration (see codeplex), which depends on the PowerGUI env being installed first but I was happy with the basic tool itself.

As for the scripting itself, my task required repeatedly calling the Sharepoint 2010 admin console cmdlet function "Mount-SPContentDatabase" which basically updates migrated content DB's from a WSS 3.0/2007 environment. What I wanted to achieve was basically execute the command for each content DB, if it is a success continue on, otherwise stop. So basically what I wanted to do was to write a function that I can call with my param's that will execute the call, and if unsuccessful exit the script. Oh and I also wanted to call this custom executable we made, called "MyLogTruncator.exe" to truncate sql log files on our db server that hosted the content databases prior to mounting them (otherwise you run the risk of running out of disk space if you dont have a lot to work with like me).

So basically I came up with this

function TruncateLog{param ($dbName, $LogFileName)
 .\MyLogTruncator.exe $dbName $LogFileName
 if(-not($?))
 {
  Write-Host 'Could not truncate log for ' $dbName $LogFileName
  Write-Host 'Exiting Script'
  exit
 }
}
function MountSPContentDB{param ($dbName) 
#this is the SP2010 cmdlet that will mount the content db's 
Mount-SPContentDatabase $dbName  -DatabaseServer 'MySharepointDBServer' -WebApplication 'http://MySPWebApplication'
 if(-not($?))
 {
  Write-Host 'Could not mount SP Content DB for ' $dbName
  Write-Host 'Exiting Script'
  exit
 }
}
#repeated calls to the functions 
TruncateLog WSS_DB1 WSS_DB1_log
MountSPContentDB 'WSS_DB1' 
TruncateLog WSS_DB2 WSS_DB2_log
MountSPContentDB 'WSS_DB2'

TruncateLog WSS_DB3 WSS_DB3_log
MountSPContentDB 'WSS_DB3' 

#other db's ......

As you can see, I have two functions specified with params to each function that I can call it with. The function body is enclosed with curly braces, followed by the first line outlining the list of params that the function can take. My TruncateLog function takes 2 parameters, the name of the db, denoted by the variable $dbName & the the name of the SQL log file to truncate, denoted by the variable $LogFileName. The function MountSPContentDB only needs to know the name of the content db to mount. Simply enough, once I have them declared I can continuously call them, passing in my parameters as shown.

Another tiny pearl I uncovered is catered towards adding a degree of robustness. If you could shift your attention to the PS if statement (which again is not very hard to write), you may notice a variable declared like so: $? . This is basically a boolean PS variable which stores the outcome of the previously executed statement, i.e if successful will store true otherwise false. I simply use this to make sure the previous command ran ok, if not I simply exit the script (call to "exit") and leave it to the user to work out what's gone wrong (the plethora of calls to Write-Host should outline where it failed hopefully). 

Well that was basically all I needed to do. Hope this helps. Happy shell'ing everybody.

No comments:

Post a Comment

Feel free to provide any feedback