Here's some sql you can run against your Content DB to find all checked out files. This will work against all files in the content DB, so it will work across multiple site collections.. everything in the DB.
SELECT[tp_Modified],[tp_Created],[tp_IsCurrent],[tp_DirName],[tp_LeafName],tp_login,tp_titleFROM [WSS_Content_CNS].[dbo].[AllUserData]left join [WSS_Content_CNS].[dbo].[UserInfo] on tp_checkoutuserid = userinfo.tp_idwhere tp_CheckoutUserId is not null and tp_iscurrent=1 and tp_deletetransactionid = 0x0order by tp_modified desc,tp_title
Wednesday, July 18, 2012
Friday, June 29, 2012
KB2699988, iFrames, Anchor tags and the headaches that won't stop.
Recently, a page on one of our sites stopped working.
The page lists things and has anchor tags that will take you to the relavant part of the page. We are currently excusivly using IE8.
The trick about this page is that it is displayed on our sharepoint portal using a Page viewer webpart. The page is from a legacy app, and the easiest way to put it on the portal was using an iFrame.
The second notable piece of information is that the page viewer webpart is set with a heigh that is large enough to show the entire page inside the iframe without scrolling, something around 15000px. To the user, it looks as if the page is part of the portal.
Recently, the anchor tags at the top of the page in the iFrame stopped working. The page would no longer scroll down to show the relavant part of the iFrame'd page. Clicking the anchor tags would do nothing.
What's going on? These worked for 2 years without any problems!
After a lot of searching and testing, I found out that this was a potential security hole. The problem is that when the user clicks an anchor tag, the main page has to scroll down to show the part of the inner iframe(the page is like 15000px long).
Because the outer page scrolls, it's possible to setup an exploit that allows the outer page to tell if something exists on the inner page. Someone wrote about it at a blackhat conference: https://media.blackhat.com/bh-eu-10/presentations/Stone/BlackHat-EU-2010-Stone-Next-Generation-Clickjacking-slides.pdf. The explaination starts at page 38.
I found this because the same page does not work in Firefox or chrome. Fortunatly, Firefox is fairly open about their bugs and has a comments section to allow people to discuss the problem and the solution. The firfox bug (https://bugzilla.mozilla.org/show_bug.cgi?id=583889) talks about the problem. This was helpful to track this down as a security update and not something that we changed. They fixed it in early 2011.
It looks like that this same problem was fixed in KB2699988. Reading through the hotfixes that are in KB2699988, nothing really jumps out at me that says that this was fixed or changed. The closest think I can find is "A memory leak may occur when a modal dialog box opens in an iframe in Internet Explorer 8 ". This to me doesn't have anything to do with the problem I'm running into, but if it does, then KB2695422 is the culprit.
Update: Here's a solution that should work - but only if you have access to change the iFrame page's code. - http://matthewmanela.com/blog/making-linking-between-anchors-in-an-iframe-work-in-firefox-11-and-above/comment-page-1/#comment-1787
I haven't found a good solution to this yet. If you setup the iFrame so that the height is less than the page height, you will somewhat fix the problem. It will cause you to have scroll bars, and the iFrame will scroll. It won't cause the outer page to scroll though, so you're users won't be able to see it.
The other solution I'm looking into is changing the code on the page inside the iFrame so that it uses JavaScript to scroll the page. Hopefully this will work for me, but for you, you may not be able change the code inside the iFrame.
I will note that this isn't specifically a SharePoint problem. You can test this out by creating a page that has an iFrame in it. The iFrame height should be set long enough that it's taller than the page - something like 2000+ pixels.
(Replace the curly brackets with GT and LT's, obviously)
At the top of the iframe's page, put a link to an anchor Tag {a href="#end"} go to end {/a}. At the bottom of the iFrame'd page, put an anchr Tag like {a name="end"}end{/a} the End should be way down at the bottom of the page, and not visible(add some gangsta Lorum Ipsum, or just a bunch of {BR}'s to make the page really long, but not so long that it is more than the 2000 pixels you set it to and introduces some scroll bars.
To the user, it would look like one long page with a link at the top and at the bottom. Clicking the 'go to end' link at the top of the page should scroll the page down to the bottom. It will if the page is not in an iFrame. If the page IS in an iframe, it won't work. Nothing happens.
I guess this just shows that Firefox and Chrome are more secure browers. They fixed this 'hole' (and I'm not sure I'm ready to agree that this is a legit security issue given the consequenses of disabling the 'feature') more than a year and a half before IE fixed it.
The page lists things and has anchor tags that will take you to the relavant part of the page. We are currently excusivly using IE8.
The trick about this page is that it is displayed on our sharepoint portal using a Page viewer webpart. The page is from a legacy app, and the easiest way to put it on the portal was using an iFrame.
The second notable piece of information is that the page viewer webpart is set with a heigh that is large enough to show the entire page inside the iframe without scrolling, something around 15000px. To the user, it looks as if the page is part of the portal.
Recently, the anchor tags at the top of the page in the iFrame stopped working. The page would no longer scroll down to show the relavant part of the iFrame'd page. Clicking the anchor tags would do nothing.
What's going on? These worked for 2 years without any problems!
After a lot of searching and testing, I found out that this was a potential security hole. The problem is that when the user clicks an anchor tag, the main page has to scroll down to show the part of the inner iframe(the page is like 15000px long).
Because the outer page scrolls, it's possible to setup an exploit that allows the outer page to tell if something exists on the inner page. Someone wrote about it at a blackhat conference: https://media.blackhat.com/bh-eu-10/presentations/Stone/BlackHat-EU-2010-Stone-Next-Generation-Clickjacking-slides.pdf. The explaination starts at page 38.
I found this because the same page does not work in Firefox or chrome. Fortunatly, Firefox is fairly open about their bugs and has a comments section to allow people to discuss the problem and the solution. The firfox bug (https://bugzilla.mozilla.org/show_bug.cgi?id=583889) talks about the problem. This was helpful to track this down as a security update and not something that we changed. They fixed it in early 2011.
It looks like that this same problem was fixed in KB2699988. Reading through the hotfixes that are in KB2699988, nothing really jumps out at me that says that this was fixed or changed. The closest think I can find is "A memory leak may occur when a modal dialog box opens in an iframe in Internet Explorer 8 ". This to me doesn't have anything to do with the problem I'm running into, but if it does, then KB2695422 is the culprit.
Update: Here's a solution that should work - but only if you have access to change the iFrame page's code. - http://matthewmanela.com/blog/making-linking-between-anchors-in-an-iframe-work-in-firefox-11-and-above/comment-page-1/#comment-1787
I haven't found a good solution to this yet. If you setup the iFrame so that the height is less than the page height, you will somewhat fix the problem. It will cause you to have scroll bars, and the iFrame will scroll. It won't cause the outer page to scroll though, so you're users won't be able to see it.
The other solution I'm looking into is changing the code on the page inside the iFrame so that it uses JavaScript to scroll the page. Hopefully this will work for me, but for you, you may not be able change the code inside the iFrame.
I will note that this isn't specifically a SharePoint problem. You can test this out by creating a page that has an iFrame in it. The iFrame height should be set long enough that it's taller than the page - something like 2000+ pixels.
(Replace the curly brackets with GT and LT's, obviously)
At the top of the iframe's page, put a link to an anchor Tag {a href="#end"} go to end {/a}. At the bottom of the iFrame'd page, put an anchr Tag like {a name="end"}end{/a} the End should be way down at the bottom of the page, and not visible(add some gangsta Lorum Ipsum, or just a bunch of {BR}'s to make the page really long, but not so long that it is more than the 2000 pixels you set it to and introduces some scroll bars.
To the user, it would look like one long page with a link at the top and at the bottom. Clicking the 'go to end' link at the top of the page should scroll the page down to the bottom. It will if the page is not in an iFrame. If the page IS in an iframe, it won't work. Nothing happens.
I guess this just shows that Firefox and Chrome are more secure browers. They fixed this 'hole' (and I'm not sure I'm ready to agree that this is a legit security issue given the consequenses of disabling the 'feature') more than a year and a half before IE fixed it.
Thursday, February 2, 2012
SharePoint 2010 - Documents Tab
while trying to make the transition from sharepoint 2007 to 2010, I've found that the default view of the ribon is confusing. What is the point of the browse tab? Especially if you're in a document library/list? In 07, useres have quick access to upload a document or create a new list item. In 2010, they must click a tab on the ribbon to be able to see that button.
To solve that problem, I want the documents or list items tab to be automatically selected for them.
I found two blogs that talk about this issue. I found that neither one really did what I want.
This site talks about how to set it as the default using the query string. Thought this might work for some, I can't change every link on every page to pass this as a parameter.
http://www.iotap.com/Blog/tabid/673/entryid/149/Displaying-default-tab-in-Sharepoint-2010-Ribbon.aspx
This second page talks about using javascript to set it to a custom tab based on some rules you setup in the javascript. I simplified this code for my use:
http://code.bkwdesign.com/2011/01/11/using-jquery-to-activate-default-sharepoint-tab/
There is probably a better way to do this using some built in sharepoint javascript funciton. I found one blog post that mentioned something like that, but I was unable to get it to work.
The following code will automatically select the Documents tab in a document library and the List Item tab in a list. In any other case it should not do anything, so it's safe to put on every page. You could also add in other options to handle pages librarys or some other case I haven't run into yet.
I added this code to my master page, but you could easily add it to a javascript file and add a reference to your master page or page layout or whatever, even put it in a Content Editor for one particular page.
Here's the code:
<script type="text/javascript">
function setTabDefault(tabid){
$("li[id=" + tabid + "] a span.ms-cui-tt-span").trigger('click');
}
$(document).ready(function () {
setTimeout("setTabDefault('Ribbon.Document-title');",150);
setTimeout("setTabDefault('Ribbon.ListItem-title');",150);
});
</script>
To solve that problem, I want the documents or list items tab to be automatically selected for them.
I found two blogs that talk about this issue. I found that neither one really did what I want.
This site talks about how to set it as the default using the query string. Thought this might work for some, I can't change every link on every page to pass this as a parameter.
http://www.iotap.com/Blog/tabid/673/entryid/149/Displaying-default-tab-in-Sharepoint-2010-Ribbon.aspx
This second page talks about using javascript to set it to a custom tab based on some rules you setup in the javascript. I simplified this code for my use:
http://code.bkwdesign.com/2011/01/11/using-jquery-to-activate-default-sharepoint-tab/
There is probably a better way to do this using some built in sharepoint javascript funciton. I found one blog post that mentioned something like that, but I was unable to get it to work.
The following code will automatically select the Documents tab in a document library and the List Item tab in a list. In any other case it should not do anything, so it's safe to put on every page. You could also add in other options to handle pages librarys or some other case I haven't run into yet.
I added this code to my master page, but you could easily add it to a javascript file and add a reference to your master page or page layout or whatever, even put it in a Content Editor for one particular page.
Here's the code:
<script type="text/javascript">
function setTabDefault(tabid){
$("li[id=" + tabid + "] a span.ms-cui-tt-span").trigger('click');
}
$(document).ready(function () {
setTimeout("setTabDefault('Ribbon.Document-title');",150);
setTimeout("setTabDefault('Ribbon.ListItem-title');",150);
});
</script>
Thursday, December 2, 2010
Installing SharePoint 2010 Without Internet Access
Recently, I was forced to install SharePoint 2010 on a network without internet access. Due to the fact that SP2010 requires about a dozen prerequisites, this is much more difficult than it should be.
There is a way to set up the installer to not attempt to access the internet to download the prerequisites.
First, You'll need a computer that has internet access so that you can download the prerequisites.
Fortunately, someone did the work for me to do this part.
The SharePoint PowerShell script to download all the prerequisite files
SharePoint can be downloaded as an ISO from Microsoft. You'll need to get this and copy all the files into a directory somewhere. Put all the prerequisite files in the ""PrerequisiteInstallerFiles" folder.
This list assumes you are installing on Server 2008 R2. Server 2008 has some slightly different items and hotfixes
Next, create a file called: "PrerequisiteInstaller.Arguments.txt". Open it up in notepad and add:
/SQLNCli:PrerequisiteInstallerFiles\sqlncli.msi /ChartControl:PrerequisiteInstallerFiles\MSChart.exe /IDFXR2:PrerequisiteInstallerFiles\Windows6.1-KB974405-x64.msu /Sync:PrerequisiteInstallerFiles\Synchronization.msi /FilterPack:PrerequisiteInstallerFiles\FilterPack\FilterPack.msi /KB976462:PrerequisiteInstallerFiles\Windows6.1-KB976462-v2-x64.msu /KB976394:PrerequisiteInstallerFiles\Windows6.0-KB976394-x64.msu /ADOMD:PrerequisiteInstallerFiles\SQLSERVER2008_ASADOMD10.msi /Speech:PrerequisiteInstallerFiles\SpeechPlatformRuntime.msi /SpeechLPK:PrerequisiteInstallerFiles\MSSpeech_SR_en-US_TELE.msi /ReportingServices:PrerequisiteInstallerFiles\rsSharePoint.msi
NOTE: This should all be on one line! No New lines!
When you run the SharePoint setup.exe, it'll run the PrerequisiteInstaller.exe which will read the arguments file, and load the files from the prerequisites installer directory instead of trying to go to the internet!
There is a way to set up the installer to not attempt to access the internet to download the prerequisites.
First, You'll need a computer that has internet access so that you can download the prerequisites.
Fortunately, someone did the work for me to do this part.
The SharePoint PowerShell script to download all the prerequisite files
SharePoint can be downloaded as an ISO from Microsoft. You'll need to get this and copy all the files into a directory somewhere. Put all the prerequisite files in the ""PrerequisiteInstallerFiles" folder.
This list assumes you are installing on Server 2008 R2. Server 2008 has some slightly different items and hotfixes
Next, create a file called: "PrerequisiteInstaller.Arguments.txt". Open it up in notepad and add:
/SQLNCli:PrerequisiteInstallerFiles\sqlncli.msi /ChartControl:PrerequisiteInstallerFiles\MSChart.exe /IDFXR2:PrerequisiteInstallerFiles\Windows6.1-KB974405-x64.msu /Sync:PrerequisiteInstallerFiles\Synchronization.msi /FilterPack:PrerequisiteInstallerFiles\FilterPack\FilterPack.msi /KB976462:PrerequisiteInstallerFiles\Windows6.1-KB976462-v2-x64.msu /KB976394:PrerequisiteInstallerFiles\Windows6.0-KB976394-x64.msu /ADOMD:PrerequisiteInstallerFiles\SQLSERVER2008_ASADOMD10.msi /Speech:PrerequisiteInstallerFiles\SpeechPlatformRuntime.msi /SpeechLPK:PrerequisiteInstallerFiles\MSSpeech_SR_en-US_TELE.msi /ReportingServices:PrerequisiteInstallerFiles\rsSharePoint.msi
NOTE: This should all be on one line! No New lines!
When you run the SharePoint setup.exe, it'll run the PrerequisiteInstaller.exe which will read the arguments file, and load the files from the prerequisites installer directory instead of trying to go to the internet!
Wednesday, November 10, 2010
Mapping Office Shared Template Location to a SharePoint Library
A user asked if you can create a new word document from a template that is stored in SharePoint.
Normally, i'd say sure, lets make it a content type, add it to the doc library and just click new! But of course this doesn't work. how many users really do that anyway? None of mine.
So, i found out there is a Word Workgroup Templates folder that you can set. When you click new, my templates, it will show you all the templates from that folder. It even creates tabs for the sub folders. Very nice.
To set the folder in Word 2007
Solution:
Trick Word.
Map a drive to the SharePoint folder path. Then tell word to point to that folder.
I chose to map T:\ to \\portal\somesite\templates\ and then told word that my templates folder is t:\
Problem solved!
Normally, i'd say sure, lets make it a content type, add it to the doc library and just click new! But of course this doesn't work. how many users really do that anyway? None of mine.
So, i found out there is a Word Workgroup Templates folder that you can set. When you click new, my templates, it will show you all the templates from that folder. It even creates tabs for the sub folders. Very nice.
To set the folder in Word 2007
- Word Options
- General -> File Locations
- Set the folder for Workgroup Template.
Solution:
Trick Word.
Map a drive to the SharePoint folder path. Then tell word to point to that folder.
I chose to map T:\ to \\portal\somesite\templates\ and then told word that my templates folder is t:\
Problem solved!
Friday, October 29, 2010
Programtically hiding SharePoint Document Information Panel in an Office Document
Using the Document Information Panel in SharePoint to show document information in Office can be very useful for users. I've used it to show information from a custom database inside of word so that users can find out what a document is about without having to visit the SharePoint site. This is very useful for when a user gets assigned a document from a sharepoint workflow.
The problem with this was that documents that did not connect to our Document Management system would not show any data. In a perfect world, the *special* documents would use a different content type so that using a different Document Information Panel would be easy. This was not the case in our system.
SO! How do you tell Word to hide the DIP when there is no data to show?
Microsoft has put together a nice post on how to do it: http://msdn.microsoft.com/en-us/magazine/cc500578.aspx
The problem is that this does not work. This requires you to have access to the Word API. When using a SharePoint DIP you only have the InfoPath API.
When the document loads, it attempts to get data from the database. The specific key to look-up data from the database is stored as a custom column on the document. Getting this is relatively easy, and many other blogs have written about it.
When the data key is blank(a document that someone uploaded to the Doc Library, not a System generated file), we are unable to get any data. I would like to hide the DIP in this case, but we can't!
Instead, I created a blank view. Then, in the OnLoad event, when the data can't be loaded, I set the default view to be the blank view. You could also do this the other way. Set the blank view as the default and then if data loads OK, set it to be your nice, pretty, data filled view.
The code to set the default view is simple:
e.SetDefaultView("Blank") ;
Where e is passed to you in the FormEvents_Loading parameter: LoadingEventArgs e
Problem Solved!
I also put a nice note on the data filled view that says the data was unable to load, just in case someone switches over to that view.
The problem with this was that documents that did not connect to our Document Management system would not show any data. In a perfect world, the *special* documents would use a different content type so that using a different Document Information Panel would be easy. This was not the case in our system.
SO! How do you tell Word to hide the DIP when there is no data to show?
Microsoft has put together a nice post on how to do it: http://msdn.microsoft.com/en-us/magazine/cc500578.aspx
The problem is that this does not work. This requires you to have access to the Word API. When using a SharePoint DIP you only have the InfoPath API.
When the document loads, it attempts to get data from the database. The specific key to look-up data from the database is stored as a custom column on the document. Getting this is relatively easy, and many other blogs have written about it.
When the data key is blank(a document that someone uploaded to the Doc Library, not a System generated file), we are unable to get any data. I would like to hide the DIP in this case, but we can't!
Instead, I created a blank view. Then, in the OnLoad event, when the data can't be loaded, I set the default view to be the blank view. You could also do this the other way. Set the blank view as the default and then if data loads OK, set it to be your nice, pretty, data filled view.
The code to set the default view is simple:
e.SetDefaultView("Blank") ;
Where e is passed to you in the FormEvents_Loading parameter: LoadingEventArgs e
Problem Solved!
I also put a nice note on the data filled view that says the data was unable to load, just in case someone switches over to that view.
Friday, September 24, 2010
Getting Rows of data as a single column in a SQL query
Recently, I've been working on a Sharepoint Based document workflow solution that uses a custom SQL database. I ran into an issue where I needed to join a database table and get many rows of data back as one column in a query.
For example:
Table A:
ID, Name,
Table B:
childName, ParentID
where parent ID is table A.ID
I needed my results to be in the format:
A.ID, name, (childName1, ChildName2,ChildName3,....)
I found a few options,
One: http://www.simple-talk.com/sql/t-sql-programming/concatenating-row-values-in-transact-sql/
Provided about a dozen different ways to do it. All of them looked overly complex.
Then i stumbled upon:
http://johnnycoder.com/blog/2006/09/05/concatenate-multiple-rows-into-a-single-string/
which provided a simple Scalar function to return the results. I took that method and put together a SQL Scalar function to do it:
CREATE FUNCTION GetChildrenFromParent
(
@ParentID varchar(15)
)
RETURNS varchar(5000)
AS
BEGIN
DECLARE @ChildList varchar(5000)
SET @ChildList = ''
select @ChildList = coalesce(@ChildList + ', ', '') + childName from B where ParentID=@ParentID
-- Return the result of the function
RETURN @ChildList
END
GO
Then my SQL to get the data looks something like:
select *,GetChildrenFromParent(id) as ChildNames from A
This returns results like:
1|Jeff| andy,mark,shannon
so, the one column is a comma separated list of rows of data from another table.
For example:
Table A:
ID, Name,
Table B:
childName, ParentID
where parent ID is table A.ID
I needed my results to be in the format:
A.ID, name, (childName1, ChildName2,ChildName3,....)
I found a few options,
One: http://www.simple-talk.com/sql/t-sql-programming/concatenating-row-values-in-transact-sql/
Provided about a dozen different ways to do it. All of them looked overly complex.
Then i stumbled upon:
http://johnnycoder.com/blog/2006/09/05/concatenate-multiple-rows-into-a-single-string/
which provided a simple Scalar function to return the results. I took that method and put together a SQL Scalar function to do it:
CREATE FUNCTION GetChildrenFromParent
(
@ParentID varchar(15)
)
RETURNS varchar(5000)
AS
BEGIN
DECLARE @ChildList varchar(5000)
SET @ChildList = ''
select @ChildList = coalesce(@ChildList + ', ', '') + childName from B where ParentID=@ParentID
-- Return the result of the function
RETURN @ChildList
END
GO
Then my SQL to get the data looks something like:
select *,GetChildrenFromParent(id) as ChildNames from A
This returns results like:
1|Jeff| andy,mark,shannon
so, the one column is a comma separated list of rows of data from another table.
Subscribe to:
Posts (Atom)