I Need the Feed!
Showing newest 8 of 13 posts from August 2008. Show older posts
Showing newest 8 of 13 posts from August 2008. Show older posts

Friday, August 15, 2008

Email Enabled List Alias Management

Ever notice that there is not way to centrally manage or get information about email aliases?  Oh that annoys me!  So I did what any self respecting geek would do, and I started taking it apart...  Here are a couple SQL utility scripts to help you get more out of your SharePoint!  Standard Disclaimer - Don't mess around with the DB... You can break stuff!  Now, here's the goods:

-- SQL Script to find out where an Email Alias is in use

-- Written by Josef Nielsen, 2008
-- nielsenjl_at_ldschurch.org
--
http://www.sharepointblogs.com/echef

-- Run this script against the Farm Configuration DB
SELECT [Alias], [Deleted], [SiteMap].[Path], [Objects].[Name], [ListId]
  FROM [WSS_Farm_Config].[dbo].[EmailEnabledLists]
    INNER JOIN [SiteMap] ON [EmailEnabledLists].[SiteId] = [SiteMap].[Id]
    INNER JOIN [Objects] ON [SiteMap].[DatabaseId] = [Objects].[Id]
-- Change this value to the Alias you are looking for
WHERE [Alias] = 'MyEmailAlias'  -- This is the Name part of Name@SharePoint.server.com

-- Run this script against the Content DB that the Site resides on
SELECT [tp_Title], [tp_ServerTemplate], [tp_ItemCount], [tp_Description], [tp_EmailInsertsFolder], [tp_EmailAlias], [tp_Fields], [tp_ContentTypes], [tp_DefaultWorkflowId]
FROM [WSS_ContentDB_01].[dbo].[AllLists]
--Replace the GUID Below with the GUId of the List you are looking for
WHERE [tp_Id] = 'A4BB3401-3161-430A-B330-42143C3DE879'

 

So, what do you get out of this?  Well, the first script, run against your Config DB will give you the managed path and site collection name where that alias is in use.  It will also tell you which content DB contains that site collection.  It also gives you a GUID for the List.

In the second script, add the GUID you got for the list and run it against the Content DB that was also specified by the first script.  This will give you the friendly name of the list that uses this alias, as well as a few other yummy bits of data about this list.

Enjoy!

Pre-populating Form Fields for a New Item

So for surveys and such I thought it would be nice to pre-populate a SharePoint List "new" form with some data from the link... This makes it very nice for surveys and such from users.  In this case it was to automate and remove error from some user feedback for our helpdesk.  So what I did was make the URL contain an extra parameter for a field value, then I added some JavaScript to the NewItem.aspx page in that list.  This script is specific to one field one (as you can tell by the long auto-ID).  Here is the script I used:

    function getURLParam()
    {
        var strReturn = "null";
        var strHref = window.location.href;
        //find the "Ticket" parameter
        if ( strHref.indexOf("?") > -1 )
        {
            var strQueryString = strHref.substr(strHref.indexOf("?")+1);
            var aQueryString = strQueryString.split("&");
            for ( var iParam = 0; iParam < aQueryString.length; iParam++ )
            {

              //find the Task Parameter
              if (aQueryString[iParam].indexOf("Ticket=") > -1 )
              {
                var aParam = aQueryString[iParam].split("=");
                strReturn = aParam[1];
                break;
              }
            }


            //insert parameter to Task Field
            //This should be one line, not two...
            //the field name is too big to fit in the blog window ;)

document.aspnetForm.ctl00_m_g_2a4ef5db_f38c_4101_b1e9_bd5bce3e5a04_
    ctl00_ctl04_ctl01_ctl00_ctl00_ctl04_ctl00_ctl00_TextField.value = strReturn;
         }
    }
_spBodyOnLoadFunctionNames.push("getURLParam");

Notice the execute line, using _spBodyOnLoadFunctionNames.  This is required to get the script to execute after all the content has been populated.  The URL to feed this function would look something like this:

http://sharepointserver.company.pri/sites/feedback/lists/tickets/NewItem.aspx?Source=http%2A%2F%2Fsharepointserver%2Ecompany%2Epri%2Fsites%2Ffeedback%2FPages%2FThannkYou%2Easpx&Ticket=123456

Two things to note... first, the "Source" parameter needs to be Escaped (using "%" codes for all symbols), and second, that it doesn't have to be where you came from... It is actually where you go to when you click OK or Cancel.  In this case, I'm sending the user to a Thank You page since they have filled out the feedback.  This can be anything, including a custom page with code to close the browser window if you want.

Scripting the "Connect to Outlook" function

You've got to love the "Actions, Connect to Outlook" function in SharePoint lists... Handy for offline viewing of data, nicer GUI for detail entry, etc.  Wouldn't it be nice to automate the connection of these things for a team or a project, or even a division or company?

You can force these connections via script...  They are URL based using the "stssync://" protocol, which depends on the Office WSS services, a shared component of the desktop Office Suite.  You can find the specific call to connect a library to Outlook (much easier to let SharePoint format it that create from scratch) on any of the AllItems.aspx default list pages for a library or list that is "Outlook Friendly", including Tasks, Calendars, and Document Libraries.   View your page source (on an IE browser, as this is not available in other browsers) and looking for the following:

<ie:menuitem id="zz23_OfflineButton"

There is a lot more to this element, which is jammed on a very long line containing about 6 of these <ie:menuitem> elements.  Specifically out of this element you want to get the "onMenuClick" action, which is a javascript call to "ExportHailStorm".  You will need a copy of this function in your script as well, as this is the function that creates the stssync call.  It is located in the init.js file, located in 12\templates\layouts\1033 folder (for US versions)...

The call to ExportHailStorm should look something like the code below, although I've added line breaks to make it readable. 

ExportHailStorm(
   'documents',
   'http:\u002f\u002fsharepoint.company.com\u002fteam\u002fsitename\u002fsandbox',
   '{ac5b6eaf-744a-4f73-a2e1-6e35b81f109e}',
   'Sandbox',
   'Test Files',
   '\u002fteam\u002fsitename\u002fsandbox\u002fTest\u002520Files',
   '','\u002fteam\u002fsitename\u002fsandbox\u002fTest Files');"

You can use these parameters with the MS code in init.js for ExportHailStorm to make your own script with multiple connections for Outlook.  Each call to ExportHailStorm ends in a window.location.href call to the newly created link, which for a document library will look something like this:

stssync://sts/?ver=1.1&type=documents&cmd=add-folder&base-url=http:\u002f\u002fsharepoint.company.com\u002fteam\u002fsitename\u002fsandbox&list-url=\u002fteam\u002fsitename\u002fsandbox\u002fTest\u002520Files&guid={ac5b6eaf-744a-4f73-a2e1-6e35b81f109e}&list-name=Test\u520Files&site-name=Sandbox

These strings can be captured and put in to a simple vbscript or powershell script or even a bat file (run iexplore.exe <url>) and executed in a post setup command, a login script, or embedded in a web page on the intranet (ie, click here to connect standard outlook folders)...

Mutex Mischief

To clean up an old farm from some setup errors, I recently rebuilt the farm from bare metal, re-attaching all the content DB's after the rebuild to prevent data loss.  Imagine my horror when after 100% successful testing, and flawless installation, the first page I pull up shows this:

Mutex could not be created.

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.InvalidOperationException: Mutex could not be created.

After some research I learned that this is an ASP.Net issue that occasionally crops up when an app pool identity (ie the Web App Service Account in SharePoint) is not a local administrator.  When setting the identity, access to the Windows Registry key where the IIS Mutex Key is kept is supposed to be granted (obviously not an issue for local admins).  If it does not have access to read this key, the above error is generated.  To add it, you have to modify the key and grant permissions for you identity account(s) to read that key, then close all Mutex Threads (or just reboot the server).

A big thanx to Jerry Orman who documented this issue and the fix here:

http://blogs.msdn.com/jorman/archive/2006/07/24/system-invalidoperationexception-mutex-could-not-be-created.aspx

As a side note to any trying to implement least-permission security on a locked down server, make sure your local WSS_WPG group has full control of the Windows\Temp folder, or you'll get an odd ASP.Net Temporary files error (that points to a bogus dir).  The WSS_WPG group contains all your Web App Identity accounts, and is created by the SharePoint Installation.

Getting Search Crawl Details from the DB

Ok, so I must be on a roll... Here's another glorious script that goes directly to the SharePoint DB's... Don't tell Bill!  As usual, this is not recommended by MS, etc., etc., etc.  This one is to get result sets of your Crawl Details.  It will show each attempt to start/stop/delete a crawl, what it's current status is, when it was requested, started, and finished.  Handy for monitoring your Search crawling with home grown tools ;)

--Begin Script

/*
CrawlLogDetails.sql
Written by
Josef Nielsen
Nov. 2007

Displays MOSS Crawl Details (Type, status, and times)
Point this script at your Search DB (ie. SharedServices_Search_DB)
*/

BEGIN

-- Create temp tables for System values
CREATE TABLE [#CrawlStatus](
[CrawlStatusName] VARCHAR(35),
[CrawlStatusID] INT
)

CREATE TABLE [#CrawlType](
[CrawlTypeName] VARCHAR(25),
[CrawlTypeID] INT
)

-- Populate Crawl Status System Values
INSERT INTO [#CrawlStatus] VALUES ('CRAWL_ACQUIRED', 1)
INSERT INTO [#CrawlStatus] VALUES ('CRAWL_STATUS_INSERTSTARTPAGE', 2)
INSERT INTO [#CrawlStatus] VALUES ('CRAWL_STARTCHECK', 3 )
INSERT INTO [#CrawlStatus] VALUES ('CRAWL_STATUS_START', 4)
INSERT INTO [#CrawlStatus] VALUES ('CRAWL_STATUS_FORBID',  5)
INSERT INTO [#CrawlStatus] VALUES ('CRAWL_UPDATE_SEED', 6 )
INSERT INTO [#CrawlStatus] VALUES ('CRAWL_QUERY_DONE', 7 )
INSERT INTO [#CrawlStatus] VALUES ('CRAWL_STATUS_DELETEUNVISITEDITEMS', 8 )
INSERT INTO [#CrawlStatus] VALUES ('CRAWL_STATUS_PAUSE', 9 )
INSERT INTO [#CrawlStatus] VALUES ('CRAWL_STATUS_RESUME', 10)
INSERT INTO [#CrawlStatus] VALUES ('CRAWL_STATUS_DONE', 11 )
INSERT INTO [#CrawlStatus] VALUES ('CRAWL_UPDATE_STOP', 12 )
INSERT INTO [#CrawlStatus] VALUES ('CRAWL_STATUS_STOP', 13 )
INSERT INTO [#CrawlStatus] VALUES ('CRAWL_STATUS_RESET',  14)
INSERT INTO [#CrawlStatus] VALUES ('CRAWL_START_DELETE', 15 )
INSERT INTO [#CrawlStatus] VALUES ('CRAWL_DELETE_CS', 16 )
INSERT INTO [#CrawlStatus] VALUES ('CRAWL_DELETE_SA', 17 )

-- Populate Crawl Type System Values
INSERT INTO [#CrawlType] VALUES ('CRAWLTYPE_FULL', 1 )
INSERT INTO [#CrawlType] VALUES ('CRAWLTYPE_INCREMENTAL', 2 )
INSERT INTO [#CrawlType] VALUES ('CRAWLTYPE_DELETE', 6 )

-- Join MSCrawlHistory to SCrawlHostList and our two temp tables
SELECT    [CrawlID]
        ,[HostName]
        ,[CrawlTypeName]
        ,[CrawlStatusName]
        ,[RequestTime]
        ,[StartTime]
        ,[EndTime]
  FROM [SharedServices1_Search_DB].[dbo].[MSSCrawlHistory]
  LEFT JOIN [dbo].[MSSCrawlHostList] ON [ProjectID] = [HostID]
  LEFT JOIN [#CrawlStatus] ON [Status] = [CrawlStatusID]
  LEFT JOIN [#CrawlType] ON [CrawlType] = [CrawlTypeID]
  WHERE 1 = 1

  -- Uncomment and use this conditional to filter the results to just one Web App
  --AND [HostName] = 'MySharePointSiteName'
  ORDER BY [RequestTime] DESC

END

-- Do a little clean up and get rid of those pesky temp tables
DROP TABLE [#CrawlStatus]
DROP TABLE [#CrawlType]

--End Script

Security Trimming WebControls and ASP Objects

I hadn't used this yet, and had cause to this week.  It works slick, and is pretty configurable... I used it to hide the SiteActions button on list pages for members, but not admins, as well as admin web parts embedded in a page.  It works with Web Parts, Web Controls, and other ASP.Net objects (ie. SharePoint:*, etc.).  Wrap the content you want trimmed in the following code (using SPD):

<Sharepoint:SPSecurityTrimmedControl runat="server" PermissionsString="BrowseDirectories">
[Content to Trim]
</Sharepoint:SPSecurityTrimmedControl>

You can then swap out the "BrowseDirectories" with whatever you need for the trimming.  Here are the one's I've found handy so far:

  • BrowseDirectories = Anyone but Limited Read (Anonymous is Limited Read)
  • ManageWeb = Site Collection Admins
  • ManageSubwebs = Site Owners
  • AddListItems = Site Members and specified list contributors

Here's a link to all the defined values in the SPBasePermissions Enum.

Details and manual monitoring of the Content DBs

So our Ad-Hoc environment started growing a bit faster than we had originally anticipated.  We knew we would have some disparity between site's content size, so we set our content DB max site limits a bit lower than normal (hey, we have 50 of them, so we thought we'd be safe).  The thought was that way we could help balance the sizing by adjusting the max counts on the DB's to reflect the physical size based on content.

It quickly became way to much of a pain to manually collate the size details with the site details based on content DB...  So here's a little script I wrote up (ok, modified from my original Site Details script) that pulls all the goodness you could want about a content DB direct from the DB itself... <Insert canned warnings about how MS does not recommend querying the DB directly here>

 

/*
ContentDBReport.sql
written by Josef Nielsen
October 2007 

NOTE: You must create a linked server if you use multiple SQL server to house you content DBs
*/ 
 

BEGIN
DECLARE
@ts1 varchar(1000), @ConfigDB VARCHAR(128) 

-- Set your Config DB Name here if it is different
SET
@ConfigDB = 'SharePoint_Config'

-- This creates a temp table to hold the list of content DBs referenced by the Config DB
CREATE TABLE [#TempDbList]
(

DBname VARCHAR(128),
DBInstance VARCHAR(128),
DBServer VARCHAR(128),
MaxSites INT,
WarnSites INT
)

-- Populate the temp table with content DBs
SET @ts1 = 'INSERT INTO #TempDbList
SELECT [DbName].[Name] AS ''DatabaseName'',
[Instance].[Name] AS ''DatabaseInstance'',
[Server].[Name] AS ''DatabaseServer'',
CONVERT(XML, [DbName].[properties]).value (''(/object/sFld/text())[1]'', ''int'') AS ''MaxSites'',
CONVERT(XML, [DbName].[properties]).value (''(/object/sFld/text())[2]'', ''int'') AS ''WarnSites''
FROM '
+'['+@ConfigDB+']'+'.[dbo].[Objects] AS [DbName]
LEFT JOIN '
+'['+@ConfigDB+']'+'.[dbo].[Objects] AS [Instance]
ON [DbName].[ParentId] = [Instance].[ID]
LEFT JOIN '
+'['+@ConfigDB+']'+'.[dbo].[Objects] AS [Server]
ON [Instance].[ParentId] = [Server].[Id]
WHERE [DbName].[Properties] LIKE ''%SPContentDatabase%''
AND [DbName].[Properties] NOT LIKE ''%WebApplication%'''

EXEC (@ts1)

DECLARE @ts2 VARCHAR(1000)

--This creates a temp table to hold the end results of the Site Collection lists from all Content DBs
CREATE TABLE [#TempContentDbList]
(
WebApp
VARCHAR(128),
DBServer VARCHAR(128),
DBName
VARCHAR(128),
DBSites
int,
DBWarnSites
int,
DBMaxSites
int,
DBSize float
)

-- Create a cursor to walk through each content DB
DECLARE DB_cursor CURSOR
FOR
SELECT [DBServer], [DBInstance], [DBName], [MaxSites], [WarnSites]
FROM [#TempDbList] 

OPEN DB_Cursor

-- Declare Variables to populate by Cursor
DECLARE @vDBServer VARCHAR(128)
DECLARE
@vDBInstance VARCHAR(128)
DECLARE @vDBName VARCHAR(128)
DECLARE @vMaxSites INT
DECLARE
@vWarnSites INT
DECLARE
@DBv1 VARCHAR(5000) 

FETCH NEXT FROM DB_cursor INTO @vDBServer, @vDBInstance, @vDBName, @vMaxSites, @vWarnSites
WHILE @@FETCH_STATUS = 0
BEGIN 

-- Add a backslash for DBServers that are not default instances
DECLARE @slash VARCHAR(5)
IF @vDBInstance = ''
SET @slash = ''
ELSE
SET @slash = '\'

-- Script to insert Content DB details to the temp site summery table
SET @DBv1 = 'INSERT INTO [#TempContentDbList]
SELECT [ConfigObjects].[Name] AS ''WebApp'',
(SELECT '''
+ @vDBServer+@slash+@vDBInstance + ''') AS ''SQL Server'',
(SELECT '''
+ @vDBName + ''') AS ''Content DB Name'',
(SELECT COUNT([Webs].[Title])) AS ''Current Site Count'',
(SELECT '
+ CONVERT(VARCHAR(20), @vMaxSites) + ') AS ''Max Site Count'',
(SELECT '
+ CONVERT(VARCHAR(50),@vWarnSites) + ') AS ''Site Size'',
(SELECT round(sum(convert(float,[size])*8/1024),2) AS ''DB Size in MB''
FROM
[sys].[master_files]
WHERE
[state] = 0
AND [data_space_id] = 1
AND db_name([database_id]) = '''
+ @vDBName + '''
GROUP BY [database_id]) AS ''Site Size''
FROM
['
+@vDBServer+@slash+@vDBInstance+'].['+@vDBName+'].[dbo].[sites] AS [Sites] WITH (NOLOCK)
LEFT JOIN ['
+@vDBServer+@slash+@vDBInstance+'].['+@vDBName+'].[dbo].[webs] AS [Webs] WITH (NOLOCK) ON [Webs].[siteID] = [Sites].[Id]
LEFT JOIN '
+'['+@ConfigDB+']'+'.[dbo].[SiteMap] AS [ConfigSiteMap] WITH (NOLOCK) ON [ConfigSiteMap].[Id] = [Sites].[Id]
LEFT JOIN '
+'['+@ConfigDB+']'+'.[dbo].[Objects] AS [ConfigObjects] WITH (NOLOCK) ON [ConfigSiteMap].[ApplicationID] = [ConfigObjects].[Id]
WHERE
[Webs].[ParentWebId] IS NULL
GROUP BY [ConfigObjects].[Name]'
 

EXEC (@DBv1)

FETCH NEXT FROM DB_cursor INTO @vDBServer, @vDBInstance, @vDBName, @vMaxSites, @vWarnSites

END

CLOSE DB_cursor
DEALLOCATE DB_Cursor

END

-- Cursor is closed and released, and now we select the results of the scan
SELECT * FROM #TempContentDbList ORDER BY [WebApp], [DBName]

GO

-- Clean up to get rid of those temp tables
DROP TABLE [#TempDbList]
DROP TABLE [#TempContentDbList]

 

 

Pulling site collections details via direct SQL query

I certainly don't recommend making changes to your content DBs directly in SQL, but there's no harm to be had pulling data from the DB's.  I found that this was the easiest way to poll data about all farm content DBs and Web Apps listed by Site Collection.  Hope you find this useful!

/*

SiteReport.sql

written by Josef Nielsen

September 2007

 

NOTE: You must create a linked server if you use multiple SQL server to house you content DBs

*/

BEGIN

DECLARE @ts1 varchar(1000), @ConfigDB VARCHAR(128)

 

-- Set your Config DB Name here if it is different

SET @ConfigDB = 'SharePoint_Config'

 

-- This creates a temp table to hold the list of content DBs referenced by the Config DB

CREATE TABLE [#TempDbList]

      (

      DBname VARCHAR(128),

      DBInstance VARCHAR(128),

      DBServer VARCHAR(128)

      )

-- Populate the temp table with content DBs

SET @ts1 = 'INSERT INTO #TempDbList

                  SELECT [DbName].[Name] AS ''DatabaseName'',

                        [Instance].[Name] AS ''DatabaseInstance'',

                        [Server].[Name] AS ''DatabaseServer''

                  FROM '+'['+@ConfigDB+']'+'.[dbo].[Objects] AS [DbName]

                        LEFT JOIN '+'['+@ConfigDB+']'+'.[dbo].[Objects] AS [Instance]

                              ON [DbName].[ParentId] = [Instance].[ID]

                        LEFT JOIN '+'['+@ConfigDB+']'+'.[dbo].[Objects] AS [Server]

                              ON [Instance].[ParentId] = [Server].[Id]

                  WHERE [DbName].[Properties] LIKE ''%SPContentDatabase%''

                        AND [DbName].[Properties] NOT LIKE ''%WebApplication%'''

EXEC (@ts1)

 

DECLARE @ts2 VARCHAR(1000)

 

--This creates a temp table to hold the end results of the Site Collection lists from all Content DBs

CREATE TABLE [#TempSiteList]

(

    FullURL VARCHAR(128),

    WebApp VARCHAR(128),

    DBServer VARCHAR(128),

    DBName VARCHAR(128),

    Megs BIGINT,

    Quotamax VARCHAR(128),

    Quotawarning VARCHAR(128),

    Userquota VARCHAR(128),

    Siteowner VARCHAR(128),

    OwnerEmail VARCHAR(128),

    Sitecreationdate VARCHAR(128),

    Lastcontentchange VARCHAR(128)

)

 

-- Create a cursor to walk through each content DB

DECLARE DB_cursor CURSOR

      FOR

            SELECT [DBServer], [DBInstance], [DBName]
 

            FROM [#TempDbList]

OPEN DB_Cursor

DECLARE @vDBServer VARCHAR(128)

DECLARE @vDBInstance VARCHAR(128)

DECLARE @vDBName VARCHAR(128)

FETCH NEXT FROM DB_cursor INTO @vDBServer, @vDBInstance, @vDBName

WHILE @@FETCH_STATUS = 0

      BEGIN

      DECLARE @DBv1 VARCHAR(2000)

 
-- Add a backslash for DBServers that are not default instances

      DECLARE @slash VARCHAR(128)

      IF @vDBInstance = ''

            SET @slash = ''

      ELSE

            SET @slash = '\'

-- Script to insert Site Collection details to the temp site summery table

      SET @DBv1 = 'INSERT INTO [#TempSiteList]

            SELECT [Webs].[FullUrl],

            [ConfigObjects].[Name] AS ''WebApp'',

            (SELECT ''' + @vDBServer+@slash+@vDBInstance + ''') AS ''SQL Server'',

            (SELECT ''' + @vDBName + ''') AS ''Content DB Name'',

            (([Sites].[diskused])/1024)/1024 AS ''Megs'',

            (([Sites].[diskquota])/1024)/1024 AS ''Quota max'',

            (([Sites].[diskwarning])/1024)/1024 AS ''Quota warning'',

            (([Sites].[userquota])/1024)/1024 AS ''User Quota'',

            [User].[tp_login] AS ''Site Owner'',

            [User].[tp_email] AS ''Owner E-mail'',

            CAST([Sites].[timecreated] AS char(30)) AS ''Site Creation Date'',

            CAST([Sites].[lastcontentchange] AS char(30)) AS ''Last Content Change''

      FROM

            ['+@vDBServer+@slash+@vDBInstance+'].['+@vDBName+'].[dbo].[sites] AS [Sites] WITH (NOLOCK)

            LEFT JOIN ['+@vDBServer+@slash+@vDBInstance+'].['+@vDBName+'].[dbo].[webs] AS [Webs] WITH (NOLOCK) ON [Webs].[siteID] = [Sites].[Id]

            LEFT JOIN ['+@vDBServer+@slash+@vDBInstance+'].['+@vDBName+'].[dbo].[userinfo] AS [User]  WITH (NOLOCK) ON [User].[tp_SiteID] = [Sites].[Id]

            LEFT JOIN '+'['+@ConfigDB+']'+'.[dbo].[SiteMap] AS [ConfigSiteMap]  WITH (NOLOCK) ON [ConfigSiteMap].[Id] = [Sites].[Id]

            LEFT JOIN '+'['+@ConfigDB+']'+'.[dbo].[Objects] AS [ConfigObjects]  WITH (NOLOCK) ON [ConfigSiteMap].[ApplicationID] = [ConfigObjects].[Id]

      WHERE

            [Webs].[ParentWebId] IS NULL

            --AND [User].[tp_SiteID] = [Sites].[Id]

            AND [User].[tp_SiteAdmin] = 1

            AND [User].[tp_id] = 1'

      EXEC (@DBv1)
 
FETCH NEXT FROM DB_cursor INTO @vDBServer, @vDBInstance, @vDBName

END

 
CLOSE DB_cursor

DEALLOCATE DB_Cursor

END

-- Cursor is closed and released, ad now we select the results of the scan

SELECT * FROM #TempSiteList ORDER BY [WebApp], [FullURL]

 

-- Clean up to get rid of those temp tables

DROP TABLE [#TempDbList]

DROP TABLE [#TempSiteList]