Wtf?
My new neighbor.
I found this little lady nesting in the
window of our storage room.
There are two (2) eggs underneath.
I am now a-rama.com and a-roony.com
I have just bought these two domains. If you’d like to be (something).a-rama.com send email to dan@danielcooper.name and I’ll make it happen.
Love,
Dan
Take a Walk through your SharePoint Farm
When tasked with upgrading our long-neglected ‘intranet’ last year my first job was to work out just how much data was out there and what needed to be upgraded.
The masterpage had been butchered some time in the past so most of the pages were missing navigation, making it hard to follow sites down the hierarchy. And what a hierarchy! The architects of the original instance apparently worked out that you could have more than one document library per site, or that you could create folders. The result is the typical site sprawl. To add to the fun, some sites were created using some custom template that no longer works and others didn’t have any files at all in them.
In order to create a list of all the sites and how they relate, you can use a PowerShell script:
[code lang=”PowerShell”]
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint") > $null
function global:Get-SPSite($url){
return new-Object Microsoft.SharePoint.SPSite($url)
}
function Enumerate-Sites($website){
foreach($web in $website.getsubwebsforcurrentuser()){
[string]$web.ID+";"+[string]$web.ParentWeb.ID+";"+$web.title+";"+$web.url
Enumerate-Sites $web
$web.dispose()
}
$website.dispose()
}
#Change these variables to your site URL and list name
$siteColletion = Get-SPSite(http://example.org)
$start = $siteColletion.rootweb
Enumerate-Sites $start
$start.Dispose()
[/code]
It’s actually pretty simple since we take advantage of recursion. Pretty much a matter of getting a handle to the site collection, outputting its GUID and parent site GUID and then the human-readable title and URL. They you do the same for that site, and so on down the branch.
The reason we’re outputting the GUIDs is that we can use them to relate each site to the rest. The script outputs straight to the console but if you pipe the output to a text file you can use it for the input to a org-chart diagram in visio. The results are terrifying:
Each node on that diagram is a site that may have one, or thousands of documents. Or nothing. Or the site just may not work. As it turned out, when asked to prioritize material for migration, the stakeholders decided it would be easier just to move the day-to-day stuff and leave the old farm going as an ‘archive’. Nothing like asking a client to do work to get your scope reduced!
As a final note on this script, it is recursive so could (according to my first-year Comp. Sci. lecturer) theoretically balloon out of control and consume all the resources in the visible universe, before collapsing into an ultradense back hole and crashing your server in the process, but you’d have to have a very elaborate tree structure for that to happen, in which case you’d probably want to partition it off into separate site collections anyway.
More on Web Log Analysis
In my previous post on web log analysis, I described a Powershell wrapper script for LogParser.exe, which lets you do SQL-style queries to text logfiles. Today I have another script which wraps that script and is used in a timer job to send the filtered logs to the client each month.
[sourcecode language=”powershell”]
#GenerateLogAnalysis will query IIS logfiles and output logs for PDF downloads from the first until
#the last day of the previous month
#function that performs the actual analysis
function RunLogAnalysis(){
$command = "c:\users\daniel.cooper\desktop\scripts\queryLogs.ps1 -inputFolder {0} -outputFile {1} -startDate {2} -endDate {3} -keyword {4}" -f $inputFolder, ($outputPath+$outputFile), (ConvertDateToW3C($startDate)), (ConvertDateToW3C($endDate)), "elibrary"
$command
invoke-expression $command
$emailBody = "<div style=""font-family:Trebuchet MS, Arial, sans-serif;""><img src=""http://www.undp.org/images/cms/global/undp_logo.gif"" border=""0"" align=""right""/><h3 style=""color:#003399;"">Log Analysis</h3>A log anaylsis has been run on the eLibrary for PDF files for "+$monthNames[$startDate.month-1]+" "+$startDate.Year+"<br/>Please find it attached."
sendEmail "recipient@example.org" "sender@example.org" "eLibrary Log Analysis: $outputFile" ($outputPath+$outputFile) $emailBody
}
function ConvertDateToW3C($dateToBeConverted){
return "{0:D4}-{1:D2}-{2:d2}" -f $dateToBeConverted.year, $dateToBeConverted.month, $dateToBeConverted.day;
}
function sendEmail($toAddress, $fromAddress, $subject, $attachmentPath, $body){
$SMTPServer = "yourMailServer"
$mailmessage = New-Object system.net.mail.mailmessage
$mailmessage.from = ($fromAddress)
$mailmessage.To.add($toAddress)
$mailmessage.Subject = $subject
$mailmessage.Body = $body
$attachment = New-Object System.Net.Mail.Attachment($attachmentPath, ‘text/plain’)
$mailmessage.Attachments.Add($attachment)
$mailmessage.IsBodyHTML = $true
$SMTPClient = New-Object Net.Mail.SmtpClient($SmtpServer, 25)
$SMTPClient.Send($mailmessage)
$attachment.dispose()
}
#Current Month
$currentDate = Get-Date
$localDateFormats = new-object system.globalization.datetimeformatinfo
$monthNames = $localDateFormats.monthnames
$localDateFormats.dispose
#Generate first day of last month as a date
$startDate = $currentDate.AddMonths(-1).addDays(-$currentDate.AddMonths(-1).day+1)
#Generate last day of last month as a date
$endDate = $currentDate.AddDays(-$currentDate.day)
#Set the initial parameters
$inputFolder = "c:\temp\www.snap"
$logName = "SNAP"
$outputFile = "LogAnalysis_"+$logName+"_"+$startDate.year+$monthNames[$startDate.month-1]+".csv"
$outputPath = "C:\Users\daniel.cooper\Desktop\"
RunLogAnalysis($inputFolder, $outputFile, $startDate, $endDate)
[/sourcecode]
What’s happening here is that RunLogAnalysis() is the main controller function. What is does is set up the command to run the queryLogs.ps1 script mentioned in the previous post, waits until it’s run and then email the result off. We have another function, ConvertDateToW3C, which takes a date-parsable string and converts it to W3C format, which is what LogParser.exe likes. sendEmail() is pretty straightforward, it’s a generic email-sending function.
After the functions we have a little code to set up parameters. My task was to email the client the last month’s logs for PDF downloads on the first of each month. To do this we get last month’s name (for the output filename) , the date on the first of last month and the date on the last day of the last month.
After parameter generation is done, we perform the log analysis and email the result. This is created as a scheduled task on the webserver and we’re done.