#
# Enumerate All Users for a Group (including traversing nested groups)
# @param distinguishedName - The distinguished name of the object you want to traverse
# Brock Moeller
# 12/16/2009
#
param (
$distinguishedName = "CN=SuperGroup,OU=Groups,DC=serv,DC=ubercorp,DC=com"
)
$roles = @{};
$indent = -1;
filter EnumMember {
$indent += 1;
if ($_ -is [System.DirectoryServices.DirectoryEntry]){
$adsiObj = $_;
} else {
$adsiObj = New-Object System.DirectoryServices.DirectoryEntry("LDAP://" + $_);
}
if ((-not [String]::IsNullOrEmpty($adsiObj.cn)) -and (-not $roles.ContainsKey($adsiObj.cn))){
$roles[$adsiObj.cn] = 1;
$memberOfCount = $adsiObj.member.Count;
$("`t"*$indent) + $adsiObj.cn + " [$memberOfCount]";
if (($memberOfCount -gt 0) -and ($indent -lt 900)) {
$adsiObj.member | EnumRoles;
}
}
$indent -= 1;
}
$user = [adsi]"LDAP://$distinguishedName";
$user;
$buffer = $user.Path + "`n";
$user | EnumMember | % { $buffer += $_ + "`n" };
"Buffer: " + $buffer.ToString();
[System.IO.File]::WriteAllText("$pwd\$($user.cn).txt", $buffer.ToString());
Sunday, January 31, 2010
Enumeration of All Users in a Group (traversing nested groups) in Active Directory
As a counter part to my previous post, I created a dual of the script which enumerates Groups and their members.
Friday, January 29, 2010
Enumeration of All Groups for a User (traversing nested groups) in Active Directory
I ran into an odd situation where I needed to be able to enumerate all of the groups that a user was a member. I found a lot of programs and scripts that will list the groups for a user, but none that would traverse nested groups.
The script writes the information to a file for better reviewing later. The output adds indentation to help readability.
Here is my solution.
The script writes the information to a file for better reviewing later. The output adds indentation to help readability.
Here is my solution.
#
# Enumerate All Groups for a User (including traversing nested groups)
# @param distinguishedName - The distinguished name of the object you want to traverse
# Brock Moeller
# 12/16/2009
#
param (
$distinguishedName = "CN=Joe Dirt,OU=Users,DC=serv,DC=ubercorp,DC=com"
)
$roles = @{};
$indent = -1;
filter EnumRoles {
$indent += 1;
if ($_ -is [System.DirectoryServices.DirectoryEntry]){
$adsiObj = $_;
} else {
$adsiObj = New-Object System.DirectoryServices.DirectoryEntry("LDAP://" + $_);
}
if ((-not [String]::IsNullOrEmpty($adsiObj.cn)) -and (-not $roles.ContainsKey($adsiObj.cn))){
$roles[$adsiObj.cn] = 1;
$memberOfCount = $adsiObj.memberOf.Count;
$("`t"*$indent) + $adsiObj.cn + " [$memberOfCount]";
if (($memberOfCount -gt 0) -and ($indent -lt 900)) {
$adsiObj.memberOf | EnumRoles;
}
}
$indent -= 1;
}
$user = [adsi]"LDAP://$distinguishedName";
$user;
$buffer = $user.Path + "`n";
$user | EnumRoles | % { $buffer += $_ + "`n" };
"Buffer: " + $buffer.ToString();
[System.IO.File]::WriteAllText("$pwd\$($user.cn).txt", $buffer.ToString());
Tuesday, January 26, 2010
Google Reader Grease Monkey Script
I was bored one day and decided that I wanted to fix up the Google Reader interface a little bit and this was the result. Sure there are more useful GM scripts, but this is a start.
// ==UserScript==
// @name Google Reader Fixup
// @namespace http://intellectualponderings.blogspot.com
// @version 1.0
// @description Hides the sliding navigation pane. Hides header below the blog name and the footer bar. Adds "Info" button next to the blog name to toggle header and footer bar.
// @include htt*://www.google.*/reader*
// @include http://www.google.com/reader/view/*
// ==/UserScript==
var cssHidechromeheader = <><![CDATA[
#viewer-header, #viewer-footer { display: none; }
]]></>.toString();
var cssShowchromeheader = <><![CDATA[
#viewer-header, #viewer-footer { display: inline; }
]]></>.toString();
var cssHideNav= <><![CDATA[
#chrome-lhn-toggle { display: none; }
]]></>.toString();
function getElementPosition(element) {
var pos = {x:0, y:0};
if (element.offsetParent) {
while (element.offsetParent) {
pos.x += element.offsetLeft;
pos.y += element.offsetTop;
element = element.offsetParent;
}
} else if (element.x) {
pos.x += element.x;
pos.y += element.y;
}
return pos;
}
function InfoMouseClick(e) {
var gei = document.getElementById,
header = gei('viewer-header'),
hDisplay = header.style.display,
footer = gei('viewer-footer'),
entries = gei('entries'),
entriesStatus = gei('entries-status');
if ((hDisplay == "none")||(hDisplay == null)||(hDisplay == "")) {
header.style.display = footer.style.display = "inline";
entriesStatus.style.right = "0.5em";
} else {
header.style.display = footer.style.display = "none";
}
entries.style.height = String(d.documentElement.clientHeight - getElementPosition(entries).y - footer.offsetHeight) + "px";
}
(function () {
//Initial Styles
GM_addStyle( cssHidechromeheader );
GM_addStyle( cssHideNav );
var chrome = document.getElementById('chrome-header');
//Button Element
var buttonStr = " Info";
var googbutton=document.createElement('div');
googbutton.className='goog-button-base goog-button-base-outer-box goog-inline-block';
googbutton.style.margin = "0px 0px 0px 6px";
googbutton.innerHTML=buttonStr;
chrome.appendChild(googbutton);
googbutton.addEventListener('click', InfoMouseClick, false);
})();
Friday, November 13, 2009
SharePoint 2007 Forms Authentication Error "Value cannot be null."
Every so often, users logging into a SharePoint 2007 portal via forms authentication with a custom membership provider get the following error message. Once the message starts to be received, it will continue to function in that manner.
The error was not resulting from any of my code which made this incredibly hard to figure out. If you restart the IIS and the OWSTimer, the issue goes away (for a while), but doesn't fix this issue.
This morning I was searching around with a very odd set keywords and ran across this article, Fixing the Elusive “Value Cannot Be Null” FBA Authentication Error. The page doesn't contain the error text or a specific solution, but it does contain a screen shot of exactly what I was experiencing.
I have included the text and solution in this blog to make it crawl-able.
The solution:
The issue appears to be the fact that the web.config, C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\12\TEMPLATE\LAYOUTS\web.config, in the layouts directory of the hive has batch compilation set to false.
The line should read:
After making this change, the performance of the site in general improved significantly on the Windows and Forms authentication sides. It looks like an all-around win.
Batch Compilation Information:
From Microsoft's KB article, How to use the "batch" attribute of the Web.config file compilation element in SharePoint Server 2007 and in Windows SharePoint Services 3.0:
Microsoft has an excellent web performance best practices site, Developing High-Performance ASP.NET Applications. The pertinent part for our issue:
This article explains in depth how debug and batch compilation works. It is worth the read. ASP.NET Resources - Beware Of Deploying Debug Code In Production
Value cannot be null.
Parameter name: value at System.String.EndsWith(String value, StringComparison comparisonType)
at Microsoft.SharePoint.ApplicationRuntime.SPRequestModule.PostAuthenticateRequestHandler(Object oSender, EventArgs ea)
at System.Web.HttpApplication.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)
The error was not resulting from any of my code which made this incredibly hard to figure out. If you restart the IIS and the OWSTimer, the issue goes away (for a while), but doesn't fix this issue.
This morning I was searching around with a very odd set keywords and ran across this article, Fixing the Elusive “Value Cannot Be Null” FBA Authentication Error. The page doesn't contain the error text or a specific solution, but it does contain a screen shot of exactly what I was experiencing.
I have included the text and solution in this blog to make it crawl-able.
The solution:
The issue appears to be the fact that the web.config, C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\12\TEMPLATE\LAYOUTS\web.config, in the layouts directory of the hive has batch compilation set to false.
<compilation batch="false" batchTimeout="600" maxBatchSize="10000" maxBatchGeneratedFileSize="10000" />
The line should read:
<compilation batch="true" batchTimeout="600" maxBatchSize="10000" maxBatchGeneratedFileSize="10000" />
After making this change, the performance of the site in general improved significantly on the Windows and Forms authentication sides. It looks like an all-around win.
Batch Compilation Information:
From Microsoft's KB article, How to use the "batch" attribute of the Web.config file compilation element in SharePoint Server 2007 and in Windows SharePoint Services 3.0:
The batch attribute is used by the ASP.NET compilation element. This attribute controls all compilation for applications to which the Web.config file applies.
When the attribute is set to "true," the delay that you experience when you access files for the first time can be decreased. This is because, when the batch attribute is set to "true," all uncompiled files will be compiled in batch mode by ASP.NET.
However, for larger applications, there may be a significant delay when files are compiled for the first time because there are more file batches to compile. After the initial compilation, delays are decreased when you access the compiled files.
Microsoft has an excellent web performance best practices site, Developing High-Performance ASP.NET Applications. The pertinent part for our issue:
Consider precompiling
A Web application is batch-compiled on the first request for a resource such as an ASP.NET Web page. If no page in the application has been compiled, batch compilation compiles all pages in a directory in chunks to improve disk and memory usage. You can use the ASP.NET Compilation Tool (Aspnet_compiler.exe) to precompile a Web application. For in-place compilation, the compilation tool calls the ASP.NET runtime to compile the site in the same manner as when a user requests a page from the Web site. You can precompile a Web application so that the UI markup is preserved, or precompile the pages so that source code cannot be changed. For more information, see How to: Precompile ASP.NET Web Sites.
This article explains in depth how debug and batch compilation works. It is worth the read. ASP.NET Resources - Beware Of Deploying Debug Code In Production
Labels:
.Net,
asp.net,
Custom Membership Provider,
SharePoint,
SharePoint 2007
Thursday, August 27, 2009
XQuery Rename/Replace Xml Node and Update K2 Workflow Process Instance Xml Fields
I recently ran across a case where a property in our application was re-termed due to a change in requirements. Updating the code was very easy, however it meant that all of the Xml documents needed to be updated and that was not going to be as easy. It would involve updating the serialized object xml documents in our workflow data repository and K2.
Out of curiosity I ran the process using the old Xml to see what would happen. Deserializing the old Xml documents resulted in everything after that renamed property being omitted from the deserialization and it didn't throw and error. That was unexpected, but good information to know.
As it turns out, updating the workflow data repository was easy. K2 has many issues which resulted in the K2 update sql. The code below shows how I accomplished this:
There are a couple caveats, you can't create the XPath location dynamically (unless you are using dynamic sql which I try to avoid at all costs). This means that you can't pass old and new name parameters into the stored procedure and update the records. Disappointing as it is, any future renames should require an easy find and replace.
I tried using a cursor to do this type of updating, but the resulting SQL in execution times in more than more than 90 minutes (I cancelled it at that point) and verified with the DBA's that I was not doing something wrong, I abandoned that path and went back to the set based updates.
Out of curiosity I ran the process using the old Xml to see what would happen. Deserializing the old Xml documents resulted in everything after that renamed property being omitted from the deserialization and it didn't throw and error. That was unexpected, but good information to know.
As it turns out, updating the workflow data repository was easy. K2 has many issues which resulted in the K2 update sql. The code below shows how I accomplished this:
CREATE PROCEDURE [dbo].[usp_brock_RenameXmlNode]
AS
BEGIN
-- UPDATE Workflow Instances
UPDATE [WorkflowInstances] SET InstanceData.modify('
insert element NewTag {/ObjectXML/OldTag/text()} after (/ObjectXML/OldTag)[1]
')
WHERE WorkflowID='7B4DEB62-D462-4FE8-A8E2-2057B5F31B19'
AND InstanceData.exist('/ObjectXML/OldTag') = 1
UPDATE [WorkflowInstances] SET InstanceData.modify('
delete (//OldTag)[1]
')
WHERE WorkflowID='7B4DEB62-D462-4FE8-A8E2-2057B5F31B19'
AND InstanceData.exist('/ObjectXML/OldTag') = 1
-- UPDATE K2 Workflows
-- Create Table Var and Populate
DECLARE @K2ProcXml2XmlType table
(
ProcInstID INT PRIMARY KEY,
WorkflowName VARCHAR(128),
WorkflowID UNIQUEIDENTIFIER,
InstanceData XML,
IsModified BIT
)
PRINT 'POPULATE TABLE VAR';
INSERT INTO @K2ProcXml2XmlType
SELECT pin.ID
,ps.[Name] WorkflowName
, wi.WorkflowID
,CONVERT(XML,REPLACE(CAST(f.string as nvarchar(max)),'<?xml version="1.0" encoding="utf-8"?>','')) InstanceData
, 0 --IsModified
FROM [K2].[dbo]._FieldOnDemand f INNER JOIN [K2].[dbo]._ProcInst pin ON f.ProcInstID=pin.ID
INNER JOIN [DemoDatabase].dbo.WorkflowInstances wi ON wi.ProcessID=pin.ID
INNER JOIN [K2].[dbo]._Proc p ON pin.ProcID = p.ID
INNER JOIN [K2].[dbo]._ProcSet ps ON p.ProcSetID = ps.ID
WHERE (ps.[Name] in ('WorkflowX'))
UPDATE @K2ProcXml2XmlType
SET InstanceData.modify('insert element NewTag {/ObjectXML/OldTag/text()} after (/ObjectXML/OldTag)[1]'), IsModified = 1
WHERE (InstanceData IS NOT NULL)
AND (InstanceData.exist('/ObjectXML/OldTag') = 1)
UPDATE @K2ProcXml2XmlType
SET InstanceData.modify('delete (//OldTag)[1]'), IsModified = 1
WHERE (InstanceData IS NOT NULL)
AND (InstanceData.exist('/ObjectXML/OldTag') = 1)
-- End Result of all updates
--PRINT 'QUERY RESULT:';
--SELECT
-- [ProcInstID]
-- , WorkflowName
-- , InstanceData
-- FROM @K2ProcXml2XmlType src
--WHERE src.IsModified = 1;
-- Populate Original Table and Query
PRINT 'POPULATE TABLE FROM VAR:';
UPDATE dst
SET dst.String = CONVERT(ntext,'<?xml version="1.0" encoding="utf-8"?>'+CAST(src.InstanceData as nvarchar(max)))
FROM @K2ProcXml2XmlType src INNER JOIN [K2].[dbo].[_FieldOnDemand] dst ON src.ProcInstID = dst.ProcInstID
WHERE src.IsModified = 1;
-- END K2 Update
END;
GO
exec dbo.usp_brock_RenameXmlNode
DROP PROCEDURE dbo.usp_brock_RenameXmlNode
It runs quite fast. There are a couple caveats, you can't create the XPath location dynamically (unless you are using dynamic sql which I try to avoid at all costs). This means that you can't pass old and new name parameters into the stored procedure and update the records. Disappointing as it is, any future renames should require an easy find and replace.
I tried using a cursor to do this type of updating, but the resulting SQL in execution times in more than more than 90 minutes (I cancelled it at that point) and verified with the DBA's that I was not doing something wrong, I abandoned that path and went back to the set based updates.
Wednesday, August 26, 2009
Visual Studio 2008 Post-Build Event and Minify Using YUI Compressor
A time tested way to shrink and optimize JavaScript and CSS is to minify and obfuscate your files. Yahoo (High Performance Web Sites Rule 10) and Google (Minimize Payload Size) have best practices recommending minifying JavaScript.
The YUI Compressor is an excellent open source tool for this; the best I have found. My real world use reduced the size of the regular CSS and JavaScript files by 45%. Gzipping the files reduced CSS files by an additional 25% and JavaScript files by an additional 36%. Resulting in 75%+ smaller files.
Here is a batch file snippet which should speed up implementing this into your build process:
Also note that if a build event echos a line starting with "ERROR", not sure if it is case sensitive, the Visual Studio and Team Foundation Server will set that step as a failure and alert as expected. Remove the "ERROR:" text from the echo lines to allow the build to proceed if it cannot find the compressor or java.
The YUI Compressor is an excellent open source tool for this; the best I have found. My real world use reduced the size of the regular CSS and JavaScript files by 45%. Gzipping the files reduced CSS files by an additional 25% and JavaScript files by an additional 36%. Resulting in 75%+ smaller files.
Here is a batch file snippet which should speed up implementing this into your build process:
SET YUICOMPRESSOR=%Minify%\yuicompressor-2.4.2.jar
IF "%JAVA_HOME%" == "" (
ECHO Searching for Java...
for /f %%j in ("java.exe") do (set JAVA_HOME=%%~dp$PATH:j)
)
ECHO Java: %JAVA_HOME%
ECHO YUICOMPRESSOR: %YUICOMPRESSOR%
IF EXIST "%YUICOMPRESSOR%" (
IF NOT "%JAVA_HOME%" == "" (
ECHO Deleting Minified files, TFS can make these readonly and the compressor will not overwrite read only files...
del /F "%CD%\<Path To Script Directory>\core.min.js"
del /F "%CD%\<Path To Styles Directory>\core.min.css"
ECHO Done.
"%JAVA_HOME%java" -jar "%YUICOMPRESSOR%" -v --type JS -o "%CD%\<Path To Script Directory>\core.min.js" "%CD%\<Path To Script Directory>\core.js"
"%JAVA_HOME%java" -jar "%YUICOMPRESSOR%" -v --type CSS -o "%CD%\<Path To Styles Directory>\core.min.css" "%CD%\<Path To Styles Directory>\core.css"
) ELSE (
ECHO ERROR: Java is not installed, no Minification
)
) ELSE (
ECHO ERROR: YUI Compressor not found.
)
Also note that if a build event echos a line starting with "ERROR", not sure if it is case sensitive, the Visual Studio and Team Foundation Server will set that step as a failure and alert as expected. Remove the "ERROR:" text from the echo lines to allow the build to proceed if it cannot find the compressor or java.
Subscribe to:
Posts (Atom)