Quick function for producing numbers

You may want to avoid the disk space and un-cached I/O involved in using a numbers table. These techniques produce the number of numbers you want quick and easy.

Note that there is a limit to the number of rows this can return but depending on the table you use as a source the rows may be cached already.
In this case, with a clean install of 2008 (no tables defined yet), I can generate over 25M numbers.
By adding another param and a simple addition to the function’s query you can return any range.  For example “select n from Numbers(-32768, 32767)”.

-- Returns numbers from 0 up to (but not including) @COUNT 
-- A decent replacement for master.dbo.spt_values when you need more than 0-2047 
CREATE FUNCTION Numbers (@COUNT int) 
RETURNS TABLE AS 
RETURN  
   SELECT TOP (SELECT @COUNT) 
          ROW_NUMBER() OVER (ORDER BY (SELECT 1)) -1 AS N 
FROM master.sys.all_columns A, master.sys.all_columns B;

If you can’t read master.sys, typically for security reasons, you can use almost any table with lots of rows.  But you can also create numbers another way.  The following produces up to 100,000 numbers very quickly and is easily expandable.  In some circumstances this technique can be faster than a physical table.  The drawback is that the source is virtual and therefore never in cache but with no I/O ever needed it’s performance is reliable.

-- Returns numbers from 0 up to (but not including) @COUNT 
-- This tops out at 100,000. Adding N6 would yield 1,000,000 values etc. 
-- Adding more joins does slow the function just a bit so creating several 
-- and using the one with the capacity you need yields top performance. 
CREATE FUNCTION Numbers (@COUNT int)
RETURNS TABLE AS
RETURN
   WITH N(I)AS (
        SELECT 1 UNION ALL
        SELECT UNION ALL
        SELECT UNION ALL
        SELECT UNION ALL
        SELECT UNION ALL
        SELECT UNION ALL
        SELECT UNION ALL
        SELECT UNION ALL
        SELECT UNION ALL
        SELECT 10)
SELECT TOP (SELECT @COUNT)
       ROW_NUMBER() OVER (ORDER BY (SELECT 1)) -1 AS N 
FROM N N1, N N2, N N3, N N4, N N5; 

Update: Leave it to that genius Itzik Ben-Gan to have another/faster way.

CREATE FUNCTION dbo.GetNums(@low AS BIGINT, @high AS BIGINT) RETURNS TABLE
AS
RETURN
WITH
L0 AS (SELECT c FROM (SELECT 1 UNION ALL SELECT 1) AS D(c)),
L1 AS (SELECT 1 AS c FROM L0 AS A CROSS JOIN L0 AS B),
L2 AS (SELECT 1 AS c FROM L1 AS A CROSS JOIN L1 AS B),
L3 AS (SELECT 1 AS c FROM L2 AS A CROSS JOIN L2 AS B),
L4 AS (SELECT 1 AS c FROM L3 AS A CROSS JOIN L3 AS B),
L5 AS (SELECT 1 AS c FROM L4 AS A CROSS JOIN L4 AS B),
Nums AS (SELECT ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS rownum
FROM L5)

SELECT TOP(@high – @low + 1) @low + rownum – 1 AS n
FROM Nums
ORDER BY rownum;

XSLT to transform Visual Studio Documentation to HTML

This isn’t really the greatest script but it does a fair job and makes a great starting point if you want to roll your own.

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <!--                Created by Rick Bielawski - published 2011-02-18                   -->
  <!--                             last updated 2011-06-05                               -->
  <!--  To display an XML documentation file generated by Visual Studio with a browser   -->
  <!--  add the line below immediately after the ?xml version line in your XML document  -->
  <!--  then open the XML file with your browser. Obviously it must point to THIS file.  -->
  <!--        <?xml-stylesheet href="visual-studio-xml-doc.xsl" type="text/xsl"?>        -->
  <!--  Or, use an XSLT generator with this code on your XML document to create html     -->
 
  <!-- ======================================================================
       Here we declare ancilary routines used to extract data
       ====================================================================== -->
  <!--  Replace a given string with another.  Basically this is only needed because long
        parameter lists don't wrap at a comma in HTML without a space being inserted.  -->
  <xsl:template name="tReplaceSubString">
    <xsl:param name="pText" />
    <xsl:param name="pLookFor" select="','" />
    <xsl:param name="pNewValue" select="' ,'" />
    <xsl:choose>
      <xsl:when test="contains($pText,$pLookFor)">
        <xsl:value-of select="substring-before($pText,$pLookFor)" />
        <xsl:value-of select="$pNewValue" />
        <xsl:call-template name="tReplaceSubString">
          <xsl:with-param name="pText"     select="substring-after($pText,$pLookFor)" />
          <xsl:with-param name="pLookFor"  select="$pLookFor" />
          <xsl:with-param name="pNewValue" select="$pNewValue" />
        </xsl:call-template>
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="$pText" />
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
 
  <!--  Counting the number of levels in a member's name allows me to tell
        where the name of the entity being documented starts (after the last one).  -->
  <xsl:template name="tCountOccurances">
    <xsl:param name="pText" />
    <xsl:param name="pLookFor" select="'.'" />
    <xsl:param name="pCount" select="0" />
    <xsl:choose>
      <xsl:when test="contains($pText,$pLookFor)">
        <xsl:call-template name="tCountOccurances">
          <xsl:with-param name="pText"    select="substring-after($pText,$pLookFor)" />
          <xsl:with-param name="pLookFor" select="$pLookFor" />
          <xsl:with-param name="pCount"   select="$pCount + 1" />
        </xsl:call-template>
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="$pCount" />
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
 
  <!--  Replaces the pCount instance of pLookFor with pSeparator.  Used to split a string.
        pCount=0 doesn't look for the pLookFor.  It just puts pSeperator at the beginning.
        pCount=1 splits at the 1st occurance, 2 splits at the 2nd occurance....
        Splitting on a count greater than the number of occurances puts pSeperator at the end.  -->
  <xsl:template name="tSplitAtInstance">
    <xsl:param name="pText" />
    <xsl:param name="pCount" select="0" />
    <xsl:param name="pLookFor" select="'.'" />
    <xsl:param name="pSeparator" select="'|'" />
    <xsl:param name="pStartEmpty" />
    <xsl:choose>
      <xsl:when test="$pCount &gt; 0 and contains($pText,$pLookFor)">
        <xsl:variable name="temp">
          <xsl:if test="$pStartEmpty = ''">
            <xsl:value-of select="substring-before($pText,$pLookFor)" />
          </xsl:if>
          <xsl:if test="$pStartEmpty != ''">
            <xsl:value-of select="concat($pStartEmpty,$pLookFor,substring-before($pText,$pLookFor))" />
          </xsl:if>
        </xsl:variable>
        <xsl:call-template name="tSplitAtInstance">
          <xsl:with-param name="pText"       select="substring-after($pText,$pLookFor)" />
          <xsl:with-param name="pCount"      select="$pCount - 1" />
          <xsl:with-param name="pLookFor"    select="$pLookFor" />
          <xsl:with-param name="pSeparator"  select="$pSeparator" />
          <xsl:with-param name="pStartEmpty" select="$temp" />
        </xsl:call-template>
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="concat($pStartEmpty,$pSeparator,$pText)" />
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
 
  <!-- ======================================================================
       These format individual parts of the document.
       ====================================================================== -->
 
  <!--  This seems to be the only thing that can be done generically -->
  <xsl:template name="tElementName">
    <xsl:param name="pText" />
    <span class="ElementName"><xsl:value-of select="$pText" />: </span>
  </xsl:template>
 
  <!-- ======================================================================
 
       This is where actual transformation starts
 
       ====================================================================== -->
 
  <!--  Set a var with the name of the assembly for the documented project. -->
  <xsl:variable name="vAssembly">
    <xsl:value-of select="doc/assembly/name" />
  </xsl:variable>
 
  <!--  This creates the HTML document within which the XML content is formatted. -->
  <xsl:template match="doc">
    <HTML>
      <HEAD>
        <style type="text/css">                 
          h1 {font-weight:bold; text-decoration:underline; text-align:center}
          pre {margin-top:0; margin-bottom:0}
          table {margin-left:5mm; margin-top:0; margin-bottom:0}
          tr#FirstRow {font-size:1.2em; text-decoration:underline}
          td {padding-left:2em}
          
          .AttributeName {font-weight:bold; padding-right:1em; color:blue; font-family:"Monospace"}
          .ClassName {color:red}
          .CodeItem {font-family:"Monospace"}
          .ElementName {padding-right:5px; text-transform:capitalize; font-weight:bold; font-style:italic}
          .EntityName {margin-left:2em; font-weight:bold; font-size:1.2em; font-family:"Monospace"}
          .MemberTypeName {color:blue}
 
          .summary {margin-top:0.3em; margin-bottom:0.3em}
          .returns {margin-top:0.3em; margin-bottom:0.3em}
          .exception {margin-top:0.3em; margin-bottom:0.3em}
          .remarks {margin-top:0.3em; margin-bottom:0.3em}
        </style>
        <TITLE><xsl:value-of select="$vAssembly" /> documentation</TITLE>
      </HEAD>
      <BODY>
        <h1><xsl:value-of select="$vAssembly" /> documentation</h1><p />
        <xsl:apply-templates select="members/member" />
      </BODY>
    </HTML>
  </xsl:template>
 
  <!--  This template first extracts information about the Member being formatted   -->
  <!--  Then formats the individual doc sections: summary, param, return...   -->
  <xsl:template match="member">
 
    <!-- I decided to use the <para> tag to flag the entity as public.  This way I can
         document internal stuff for intellisense but not for users.  It works well
         since intellisense ignores <para> formatting anyway.  -->
    <xsl:if test="count(summary/para) > 0">
 
      <!--  The whole name has the type, namespace, class name, and member name.   -->
      <xsl:variable name="vWholeName">
        <xsl:value-of select="@name" />
      </xsl:variable>
 
      <!--  The type of member being documented is encoded in the first character   -->
      <xsl:variable name="vMemberType">
        <xsl:value-of select="substring-before($vWholeName,':')" />
      </xsl:variable>
      <xsl:variable name="vMemberTypeName">
        <xsl:choose>
          <xsl:when test="$vMemberType = 'E'">Event</xsl:when>
          <xsl:when test="$vMemberType = 'F'">Field</xsl:when>
          <xsl:when test="$vMemberType = 'M'">Method</xsl:when>
          <xsl:when test="$vMemberType = 'N'">NameSpace</xsl:when>
          <xsl:when test="$vMemberType = 'P'">Property</xsl:when>
          <xsl:when test="$vMemberType = 'T'">Type</xsl:when>
          <xsl:otherwise>Unknown</xsl:otherwise>
        </xsl:choose>
      </xsl:variable>
 
      <!--  We need the number of name parts to get the last part (the name of the entity).
            Unfortunately there might be periods in parameter data types so we must count
            only those that come before any open paren.  -->
      <xsl:variable name="vNumPeriods">
        <xsl:variable name="temp">
          <xsl:choose>
            <xsl:when test="contains($vWholeName,'(')">
              <xsl:value-of select="substring-before($vWholeName,'(')" />
            </xsl:when>
            <xsl:otherwise>
              <xsl:value-of select="$vWholeName" />
            </xsl:otherwise>
          </xsl:choose>
        </xsl:variable>
        <xsl:call-template name="tCountOccurances">
          <xsl:with-param name="pText" select="$temp" />
          <xsl:with-param name="pLookFor" select="'.'" />
        </xsl:call-template>
      </xsl:variable>
 
      <!--  Split the full name between entity name (and any args) and the path (ns,class...)  -->
      <xsl:variable name="vSplitName">
        <xsl:call-template name="tSplitAtInstance">
          <xsl:with-param name="pText"      select="$vWholeName" />
          <xsl:with-param name="pCount"     select="$vNumPeriods" />
          <xsl:with-param name="pLookFor"   select="'.'" />
          <xsl:with-param name="pSeparator" select="'|'" />
        </xsl:call-template>
      </xsl:variable>
 
      <!--  Get the entity name (and any args).
            Add space to commas so browsers can wrap them if needed  -->
      <xsl:variable name="vEntityName">
        <xsl:call-template name="tReplaceSubString">
          <xsl:with-param name="pText"     select="substring-after($vSplitName,'|')" />
          <xsl:with-param name="pLookFor"  select="','" />
          <xsl:with-param name="pNewValue" select="', '" />
        </xsl:call-template>
      </xsl:variable>
 
      <!--  We'll assume the assembly name is also the prime Namespace name and omit it.
            The 'class' name might also include any sub-namespace names.  -->
      <xsl:variable name="vClass">
        <xsl:value-of select="substring-after(substring-before($vSplitName,'|'),'.')" />
      </xsl:variable>
 
      <!--  Variables are populated.  This formats member data on the page.  -->
      <xsl:if test="not($vClass='')">
        <span class="ClassName">
          <xsl:value-of select="$vClass" /> -
        </span>
      </xsl:if>
      <span class="MemberTypeName">
        <xsl:value-of select="$vMemberTypeName" />
      </span>:
      <div class="EntityName">
        <xsl:value-of select="$vEntityName" />
        <xsl:if test="$vMemberType = 'M' and not(contains($vWholeName,'('))">()</xsl:if>
      </div>
      <!-- And now, report all the sub-elements -->
      <xsl:apply-templates select="summary" />
      <xsl:apply-templates select="param" />
      <xsl:apply-templates select="returns" />
      <xsl:apply-templates select="interface" />
      <xsl:apply-templates select="exception" />
      <xsl:apply-templates select="example" />
      <xsl:apply-templates select="remarks" />
      <hr />
    </xsl:if>
  </xsl:template>
 
  <!-- These format the primary documentation elements -->
 
  <xsl:template match="summary">
    <div class="summary">
      <xsl:call-template name="tElementName">
        <xsl:with-param name="pText" select="name()" />
      </xsl:call-template>
      <xsl:apply-templates select="node()" />
    </div>
  </xsl:template>
  <xsl:template match="param">
    <div class="param">
      <xsl:call-template name="tElementName">
        <xsl:with-param name="pText" select="name()" />
      </xsl:call-template>
      <span class="AttributeName"><xsl:value-of select="@name" /></span>
      <xsl:apply-templates select="node()" />
    </div>
  </xsl:template>
  <xsl:template match="returns">
    <div class="returns">
      <xsl:call-template name="tElementName">
        <xsl:with-param name="pText" select="name()" />
      </xsl:call-template>
      <xsl:apply-templates select="node()" />
    </div>
  </xsl:template>
  <xsl:template match="interface">
    <div class="interface">
      <xsl:call-template name="tElementName">
        <xsl:with-param name="pText" select="name()" />
      </xsl:call-template>
      <span class="AttributeName"><xsl:value-of select="@name" /></span>
      <xsl:apply-templates select="node()" />
    </div>
  </xsl:template>
  <xsl:template match="exception">
    <div class="exception">
      <xsl:call-template name="tElementName">
        <xsl:with-param name="pText" select="name()" />
      </xsl:call-template>
      (<xsl:value-of select="substring-after(@cref,'.')" />)
      <xsl:apply-templates select="node()" />
    </div>
  </xsl:template>
  <xsl:template match="example">
    <div class="example">
      <xsl:call-template name="tElementName">
        <xsl:with-param name="pText" select="name()" />
      </xsl:call-template>
      <pre><xsl:value-of select="." /></pre>
    </div>
  </xsl:template>
  <xsl:template match="remarks">
    <div class="remarks">
      <xsl:call-template name="tElementName">
        <xsl:with-param name="pText" select="name()" />
      </xsl:call-template>
      <xsl:apply-templates select="node()" />
    </div>
  </xsl:template>
 
  <!-- Document elements can contain custom formatting elements.  -->
 
  <xsl:template match="para">
    <xsl:if test="not(.='')">
      <xsl:apply-templates select="node()" />
      <br />
    </xsl:if>
  </xsl:template>
 
  <xsl:template match="c">
    <span class="CodeItem">
      <xsl:value-of select="." />
    </span>
  </xsl:template>
 
  <xsl:template match="list">
    <table>
      <tr id="FirstRow">
        <td>Item</td>
        <td>Description</td>
      </tr>
      <xsl:apply-templates select="node()" />
    </table>
  </xsl:template>
  <xsl:template match="item">
    <tr><xsl:apply-templates select="node()" /></tr>
  </xsl:template>
  <xsl:template match="term">
    <td><xsl:value-of select="." /></td>
  </xsl:template>
  <xsl:template match="description">
    <td><xsl:value-of select="." /></td>
  </xsl:template>
 
</xsl:stylesheet>

Getting around not having inline scalar functions

It is well-known that Scalar functions (still) perform poorly (as of 2012) when used in selects returning a large number of rows.  Although it’s often advantageous to encapsulate certain logic, too often it’s not worth the performance hit to use a scalar function.
Below I demonstrate a technique using an inline table function that, while not pretty, does provide encapsulation WITHOUT the scalar function performance impact. In this example I encapsulate a formula to display only YYYY-MM from a date field.

CREATE FUNCTION itf_YYYY_MM(@Date DATETIME) RETURNS TABLE
RETURN SELECT CAST(YEAR(@Date) AS CHAR(4)) + '-'
      + RIGHT('0' + CAST(MONTH(@Date) AS VARCHAR(2)),2) AS [YYYY-MM]; 

Unfortunately this can’t simply be used like a scalar function. IOW this does NOT work:

 SELECT itf_YYYY_MM(MyDate) [YYYY-MM] FROM DataSource; 

You must jump thru a bit of a hoop.

 SELECT (SELECT [YYYY-MM] FROM itf_YYYY_MM(MyDate)) [YYYY-MM] FROM DataSource; 

The extra code, while not pretty, does in fact produce exactly the same plan as imbedding the original formula into the query. Thus our goal of encapsulation is met. And, generally speaking, any single statement scalar formula can be inlined using this technique.

Fast split function. Turn a delimited list into a rowset.

I’ve not posted in a while so I thought I’d put some queries I’ve found most useful up as a holiday present.
This one splits a delimited list such as ‘this,comma,separated,list,of,words’ into a table with one column and a row for each item in the list.
It’s faster than any other split function I’ve seen but it has the drawback that it might fail if you try to split very very long lists because it convert to XML which lengthens the string considerably.
You can use it, for example, to split up multi-select SSRS params.
A statement like this
SELECT item FROM global.udt_Split('this ,comma ,separated ,list ,of ,words',' ,')
Returns a table this:
item
----------
this
comam
separated
list
of
words
And since it’s an inline function it operates very efficiently in a Cross Apply like this:
SELECT V.item 
  FROM Table_Containing_a_List T
 CROSS Apply global.udt_Split(T.Col_csv,',') V;
Here is the function:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE FUNCTION [global].[udt_Split] (
@Data VARCHAR(max), -- list of delimited values like '1|2|5|7'
@Delimiter VARCHAR(10) -- character(s) seperating elements like '|'
)
 --------------------------------------------------------------------
-- CREATED BY : Rick Bielawski
-- CREATE DATE: 10/23/2010
-- DESCRIPTION: Converts a string of delimited values to a table 
-- with each value on a seperate row.
--------------------------------------------------------------------
RETURNS Table
WITH SCHEMABINDING
AS Return
WITH x AS (SELECT CAST('<root><item>'
+REPLACE (REPLACE (REPLACE (REPLACE(@Data,'&','&amp;'),'<','&lt;'),'>','&gt;')
,REPLACE (REPLACE (REPLACE(@delimiter,'&','&amp;'),'<','&lt;'),'>','&gt;'),'</item><item>')
+'</item></root>' AS XML) as [xml])
SELECT n.c1.value('.[1]','varchar(max)') AS[item]
  FROM x
 CROSS APPLY x.xml.nodes('/root/item') AS n(c1)
Use this to test:
select ''''+item+'''' from global.udt_split('this list,should split,properly, \
even with blanks ,string''s should “behave”,"unbalanced \
or somewhat long strings should not truncate unexpectedly, and imbedded xml \
chars like ><, <or><this><malformed;>''junk''>,should be OK!',',')

Querying information from deployed SSRS packages

It always comes up that people need to know which SSRS reports access a particular table or stored procedure.
They are stored in a database in XML format.  You should be able to query them.  And you can.
I’ve used queries of this form to report on all types of data in deployed RDLs.
 
Note that the name of the database you deploy reports into might be different than the one referenced in these queries.
Also note that the column sizes might need adjusting to accomodate your names. 
The ones I choose were choosen to best fit the width of my screen 🙂
 
---------------------------------------------------------------------------------------
-- List all reports that call stored procedures and the name of the procedure called.
---------------------------------------------------------------------------------------
With XMLNAMESPACES(N'http://schemas.microsoft.com/SQLServer/reporting/reportdesigner' AS rd,
           default N'http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition')
SELECT n.c1.value(N'Query[1]/CommandText[1]',N'varchar(40)')    "Stored Proc"
      ,n.c1.value(N'Query[1]/DataSourceName[1]',N'varchar(15)')"DataSource Name"
      ,n.c1.value(N'@Name',N'varchar(30)')                      "DataSet Name"
      ,cast(path as varchar(80))                                "Report Path"
  from (SELECT path
              ,CAST(CAST(CAST(C.Content AS VARBINARY(MAX)) AS VARCHAR(MAX)) AS XML) as xml
          FROM ReportServer$.dbo.Catalog C
         WHERE c.Type = 2) as x
 CROSS APPLY x.xml.nodes(N'/Report/DataSets/DataSet') AS n(c1)
 where n.c1.value(N'Query[1]/CommandType[1]',N'varchar(20)') = N'StoredProcedure'
 order by "Stored Proc","Report Path","DataSet Name"

 

 

---------------------------------------------------------------------------
-- List all reports that reference a particular table in a query.
-- Replace <table Name here> below with the reference you are looking for.
---------------------------------------------------------------------------
With XMLNAMESPACES(N'http://schemas.microsoft.com/SQLServer/reporting/reportdesigner' AS rd,
           default N'http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition')
SELECT cast(path as varchar(75))"Path"
      ,n.c1.value(N'Query[1]/DataSourceName[1]',N'varchar(15)')"DataSource Name"
      ,n.c1.value(N'@Name',N'varchar(25)')"DataSet Name"
      ,REPLACE(n.c1.value(N'Query[1]/CommandText[1]',N'varchar(max)'),CHAR(10),' ')"Query Text"
  from (SELECT path
              ,CAST(CAST(CAST(C.Content AS VARBINARY(MAX)) AS VARCHAR(MAX)) AS XML) as xml
          FROM ReportServer$.dbo.Catalog C
         WHERE c.Type = 2) as x
 CROSS APPLY x.xml.nodes(N'/Report/DataSets/DataSet') AS n(c1)
 WHERE COALESCE(n.c1.value(N'Query[1]/CommandType[1]',N'varchar(20)'),N'') <> N'StoredProcedure'
   AND n.c1.value(N'Query[1]/CommandText[1]',N'varchar(max)') like N'%<table Name here>%'
 ORDER BY "Path","DataSource Name","DataSet Name";
 --

Adding lots of useful DateTime functions

Here are a couple of really useful methods you could add to the [DateTime] type.
 
Even if some are not exactly what you need it provides a framework for adding your own.
 
I’ve added them by putting the code below into a file in $PSHome named
DateTime.Types.ps1xml
Then in my $PSHome\Profile.ps1 I have the line
Update-TypeData (Join-Path $PSHome ‘DateTime.Types.ps1xml’)
Now anyone on the machine with a PowerShell Session has access to the extensions.
<?xml version="1.0" encoding="utf-8" ?>
<!--<# *******************************************************************

  This extension adds complex date manipulation functionality to
  [system.datetime] data types.  Specifically 2 Methods are added.  Each
  returns a [system.datetime] object with the requested value just like
  native methods such as AddYears or AddDays.

  AddBusinessDays([int]$Count)

    Returns the business day $Count days from $this date where 1 means
    next and -1 is prior.  Zero is treated opposite of TruncateTo('BD')
    i.e. it returns $this or the following Monday.  When the date falls
    on a weekend and $Count is not zero Monday or Friday are counted.
    That is <a-Sunday-date>.AddBusinessDays(1) results in Monday and
    <a-Sunday-date>.AddBusinessDays(-1) results in Friday.

  TruncateTo([string]$Part[,[int]$Offset])

    Truncates $this date to the date part named.

      Examples using:      $mydate = Get-Date '12/31/1999 17:47:12.345'
        $mydate.TruncateTo('Year')     Returns 01/01/1999 00:00:00.000
        $mydate.TruncateTo('QY')       Returns 10/01/1999 00:00:00.000
        $mydate.TruncateTo('BD')       Returns 12/31/1999 00:00:00.000
        $mydate.TruncateTo('Second')   Returns 12/31/1999 17:47:12.000
        $mydate.TruncateTo('Y',0)      Returns 01/01/1999 00:00:00.000
        $mydate.TruncateTo('FBDY',1)   Returns 01/03/2000 00:00:00.000
        $mydate.TruncateTo('18:00',1)  Returns 12/31/1999 18:00:00.000

    $Part is the part of the date to truncate to.  Either the abbreviated
          or long (FullySpelledOut) version of the part can be used.
               Y - Year
               M - Month
               D - Day
               H - Hour
              MI - Minute
               S - Second
          ******** Parts of a year
              HY - HalfYear       (Jan,Jul)
              QY - QuarterYear    (Jan,Apr,Jul,Oct)
            FBDY - FirstBusinessDayYear
          ******** Parts of a month
              HM - HalfMonth      (1st or 16th)
            FBDM - FirstBusinessDayMonth
          ******** Parts of a day
              HD - HalfDay        Midnight or Noon (12 hr period)
              TD - ThirdDay       Midnight, 8:am, 4:pm
              QD - QuarterDay     Midnight, 6:am, Noon, 6:pm
              BD - BusinessDay    BOD Today or most recent Fri on Sat or Sun
           hh:mm - SPECIFIC TIME  Some examples: "07:30", "14:00", "23:59"
          ******** Parts of an hour
              HH - HalfHour       :00 or :30 (30 minute period)
              TH - ThirdHour      :00, :20, :40 (20 minute periods)
              QH - QuarterHour    :00, :15, :30, :45 (15 minute periods)
              SH - SixthHour      :00, :10, :20, ... (10 minute periods)
          ******** Parts of a week
             Sun - Sunday         Truncates to most recent Sunday
             Mon - Monday
             Tue - Tuesday
             Wed - Wednesday
             Thu - Thursday
             Fri - Friday
             Sat - Saturday

    Note: Truncation without an offset will never return a future date.

    $Offset ..defaults to 0.  When non-zero, adds that number of $part
              periods to the result.  For example ('Y',2) first truncates
              to the current year then adds 2 years.  ('QH',1) used with
              17:37 yields 17:45 and ('QH',3) gives 18:15.
********************************************************************#> -->
<Types>
  <Type>
    <Name>System.DateTime</Name>
    <Members>
      <ScriptMethod>
        <Name>AddBusinessDays</Name>
        <Script>
    param ([int]$Count,[datetime]$From = $([datetime]::MinValue))
    # Use this if params don't seem to get passed 
    #[int]$Count = $args[0] 
    #[datetime]$From = [datetime]::MinValue 
    if ($From -eq [datetime]::MinValue) {$From = $This.AddDays(0)}
    while (!$Count -and 1..5 -notcontains $From.DayOfWeek.value__) {
        $From = $From.AddDays(1)}
    if ($Count -lt 0) {
      while ($Count++) {
        $From = $From.AddDays(-1)
        while (1..5 -notcontains $From.DayOfWeek.value__) {
          $From = $From.AddDays(-1)}
      }}
    else {
      while ($Count--) {
        $From = $From.AddDays(1)
        while (1..5 -notcontains $From.DayOfWeek.value__) {
          $From = $From.AddDays(1)}
      }}
    $From
        </Script>
      </ScriptMethod>
      <ScriptMethod>
        <Name>TruncateTo</Name>
        <Script>
    param ([string]$Part,[int]$Offset,[switch]$KeepTime)
    # Use this if params don't seem to get passed 
    #[string]$Part = $args[0] 
    #[int]$Offset = $args[1] 
    #[switch]$KeepTime = $args[2] 
    $Date = $this.Date
    $Time = $this.TimeOfDay
    $Year = $Date.AddDays((1-$this.DayOfYear))
    $DowB = [datetime]'1995/01/01'
    $Days = [math]::Truncate(($Date - $DowB).TotalDays)
    $Sign = [math]::Sign([math]::Sign($Days+1)-1)
    switch -regex ($Part) {
      # Parts of DateTime 
      '^(0?1|10|Y|Year)$' {
          $Year.AddYears($Offset)}
      '^(0?2|20|M|Month)$' {
          ($Date.AddDays((1-$Date.Day))).AddMonths($Offset)}
      '^(0?3|30|D|Day)$' {
          $Date.AddDays($Offset)}
      '^(0?4|40|H|Hour)$' {
          $Date.AddHours($Time.Hours+$Offset)}
      '^(0?5|Mi|Minute)$' {
          $Date.AddMinutes([math]::Truncate($Time.TotalMinutes)+$Offset)}
      '^(0?6|S|Second)$' {
          $Date.AddSeconds([math]::Truncate($Time.TotalSeconds)+$Offset)}
      # Parts of Year 
      '^(11|HY|HalfYear)$' {
          $Year.AddMonths(([math]::Truncate(($Date.Month -1)/6)+$Offset)*6)}
      '^(12|QY|QuarterYear)$' {
          $Year.AddMonths(([math]::Truncate(($Date.Month -1)/3)+$Offset)*3)}
      '^(19|FBDY|FirstBusinessDayYear)$' {
          $t1 = $t2 = $Year
          while (1..5 -notcontains $t1.DayOfWeek.value__)
            {$t1 = $t1.AddDays(1)}
          if ($Date.DayOfYear -lt $t1.DayOfYear) {
            $t2 = $t2.AddYears($Offset - 1)}
          else {
            $t2 = $t2.AddYears($Offset)}
          while (1..5 -notcontains $t2.DayOfWeek.value__)
            {$t2 = $t2.AddDays(1)}
          $t2}
      # Parts of Month 
      '^(21|HM|HalfMonth)$' {
          $t = $Date.AddMonths([math]::Truncate($Offset/2))
          if ($t.Day -ge 16) {
            switch ($Offset%2) {
              1 {$t.AddDays(1-$t.Day).AddMonths(1)}
             -1 {$t.AddDays(1-$t.Day)}
              0 {$t.AddDays(16-$t.Day)}}}
          else {
            switch ($Offset%2) {
              1 {$t.AddDays(16-$t.Day)}
             -1 {$t.AddDays(16-$t.Day).AddMonths(-1)}
              0 {$t.AddDays(1-$t.Day)}}}}
      '^(29|FBDM|FirstBusinessDayMonth)$' {
          $t1 = $t2 = $Date.AddDays(1-$Date.Day)
          while (1..5 -notcontains $t1.DayOfWeek.value__)
            {$t1 = $t1.AddDays(1)}
          if ($Date.Day -ge $t1.Day) {
            $t2 = $t2.AddMonths($Offset)}
          else {
            $t2 = $t2.AddMonths($Offset - 1)}
          while (1..5 -notcontains $t2.DayOfWeek.value__) {
            $t2 = $t2.AddDays(1)}
          $t2}
      # Parts of Day 
      '^(31|HD|HalfDay)$' {
          $Date.AddHours(([math]::Truncate($Time.Hours/12)+$Offset)*12)}
      '^(32|TD|ThirdDay)$' {
          $Date.AddHours(([math]::Truncate($Time.Hours/8)+$Offset)*8)}
      '^(33|QD|QuarterDay)$' {
          $Date.AddHours(([math]::Truncate($Time.Hours/6)+$Offset)*6)}
      '^(39|BD|BusinessDay)$' {
          $t = $Date
          while (1..5 -notcontains $t.DayOfWeek.value__)
            {$t = $t.AddDays(-1)}
          $this.AddBusinessDays($Offset,$t)}
      # Time of day 
      '^[0-9][0-9]?:[0-9][0-9]$' {
          $TimeOfDay = [TimeSpan]$_
          $(if ($this.TimeOfDay -gt $TimeOfDay) {
              $this.date + $TimeOfDay}
            else {$this.date.AddDays(-1) + $TimeOfDay}).AddDays($Offset)}
      # Parts of Hour 
      '^(41|HH|HalfHour)$' {
          $Date.AddMinutes(([math]::Truncate($Time.TotalMinutes/30)+$Offset)*30)}
      '^(42|TH|ThirdHour)$' {
          $Date.AddMinutes(([math]::Truncate($Time.TotalMinutes/20)+$Offset)*20)}
      '^(43|QH|QuarterHour)$' {
          $Date.AddMinutes(([math]::Truncate($Time.TotalMinutes/15)+$Offset)*15)}
      '^(44|SH|SixthHour)$' {
          $Date.AddMinutes(([math]::Truncate($Time.TotalMinutes/10)+$Offset)*10)}
      # Parts of Week 
      '^(71|Sun|Sunday)$' {
          $DowB.AddDays(([math]::Truncate(($Days -(0+$Sign))/7)+$Offset+$Sign)*7+0)}
      '^(72|Mon|Monday)$' {
          $DowB.AddDays(([math]::Truncate(($Days -(1+$Sign))/7)+$Offset+$Sign)*7+1)}
      '^(73|Tue|Tuesday)$' {
          $DowB.AddDays(([math]::Truncate(($Days -(2+$Sign))/7)+$Offset+$Sign)*7+2)}
      '^(74|Wed|Wednesday)$' {
          $DowB.AddDays(([math]::Truncate(($Days -(3+$Sign))/7)+$Offset+$Sign)*7+3)}
      '^(75|Thu|Thursday)$' {
          $DowB.AddDays(([math]::Truncate(($Days -(4+$Sign))/7)+$Offset+$Sign)*7+4)}
      '^(76|Fri|Friday)$' {
          $DowB.AddDays(([math]::Truncate(($Days -(5+$Sign))/7)+$Offset+$Sign)*7+5)}
      '^(77|Sat|Saturday)$' {
          $DowB.AddDays(([math]::Truncate(($Days -(6+$Sign))/7)+$Offset+$Sign)*7+6)}
      default {
        # The numeric syntax is for testing and unsupported numbers return $null
        if ($_ -notmatch '^[0-9][0-9]?$') {
          throw ("Expecting one of`nY M D H Mi S HY QY FBDY HM FBDM " +
                 "HD TD QD hh:mm HH TH QH SH BD SUN MON TUE WED THU FRI SAT`n" +
                 "Year Month Day Hour Minute Second HalfYear " +
                 "QuarterYear FirstBusinessDayYear HalfMonth`n" +
                 "FirstBusinessDayMonth HalfDay ThirdDay QuarterDay " +
                 "BusinessDay HalfHour ThirdHour QuarterHour SixthHour`n" +
                 "Sunday Monday Tuesday Wednesday Thursday Friday Saturday")}}
    }
         </Script>
      </ScriptMethod>
    </Members>
  </Type>
</Types>

P.S. Looking at the code reveals that $part can be a number (not documented).
    This feature has 2 purposes.
    1) I have a scalar valued function in SQL Server with similar functionality.
       Because that is used in queries I wanted a more efficient arg in its case statement.
       These numbers match those...
    2) It makes for easier testing because I don't need to code all the valid type names.
       For example:

    
$e = [datetime]'2009/11/16 22:47:31.562'
1..80|%{'{0:D2}' -f $_}|
  %{if($e.TruncateTo($_))
    {   "$_ =" +
        " $($e.TruncateTo($_,-2).ToString('yyyy/MM/dd HH:mm:ss.f ddd')) |" +
        " $($e.TruncateTo($_,-1).ToString('yyyy/MM/dd HH:mm:ss.f ddd')) |" +
        " $($e.TruncateTo($_, 0).ToString('yyyy/MM/dd HH:mm:ss.f ddd')) |" +
        " $($e.TruncateTo($_, 1).ToString('yyyy/MM/dd HH:mm:ss.f ddd')) |" +
        " $($e.TruncateTo($_, 2).ToString('yyyy/MM/dd HH:mm:ss.f ddd'))"}}

Determining a file’s EOL character

A simple function to determine the type of EOL character used by a file.
When run against non-ascii encoding systems it can give false readings because the high order byte could be 10 or 13.
While I state this is possible, it should not be a problem for most languages.
function Get-EOL_Type ($FileName,[int]$MaxLen = 2000) {
    $Chars = Get-Content $FileName -encoding byte -totalcount $MaxLen
    if ($Chars -contains 13 -and $Chars -contains 10) {’CRLF’}
    elseif ($Chars -contains 13) {’CR’}
    elseif ($Chars -contains 10) {’LF’}
    else {’unk’}

}

Better than Splat @args

The Splat operator doesn’t support named args and and it cannot be used to pass args to a method.   These are serious drawbacks.
 
Completely solving the named args issue is currently not possible because PowerShell turns switches and argument names into strings and there is no way to tell if a given string actually had quotes or not in the original call statement (see bug report https://connect.microsoft.com/PowerShell/feedback/ViewFeedback.aspx?FeedbackID=368512 ).  If we ignore the possiblity of ambiguous strings (which should be rare anyway) we can come pretty close to a solution.  In this example, $args are being splatted as arguments to ‘Nested-Command’
 
$args|% -begin{$exp = ‘Nested-Command ‘
               $_ctr_ = 0} `
        -process{if($_ -is [string] -and $_ -match ‘^-[a-z0-9_]+$’) {
                   $exp += "$_ "}
                 else {set-variable (‘_tmp_’+ ++$_ctr_) $_
                       $exp += "`$$(‘_tmp_’ + $_ctr_) "} } `
        -end{Invoke-Expression $exp}
This next algorithm does exactly what the existing splat operator does.  That is, it only spreads the args out but doesn’t try to deal with named args.  But methods don’t need named args so it can pass args on to a method just fine.  In this example $args are being splatted as arguments to $Instance.Function
       $args|
         % -begin  {$exp = ‘$Instance.Function(‘
                    $_ctr_ = 0} `
           -process{set-variable (‘_tmp_’+ ++$_ctr_) $_
                    $exp += "`$$(‘_tmp_’ + $_ctr_),"} `
           -end    {$exp = $exp.Trim(‘,’) + ‘)’
                    Invoke-Expression $exp}

Edit-History

I use this function when working on remote systems where I don't have 
authority to create a function library locally on the remote system.
In such circumstances I can paste commands stored on my own system 
but it's a hasle to edit them and re-paste.  This allows me to easily
edit and re-execute multi-line commands in my remote session history.
######################################################################
#
#   Edit-History {<history number>|<cmd prefix>}
#
#   Creates a pop-up window to allow editing of the history item
#   having ID <history Num> or the most recent command in history
#   starting with <cmd prefix>.  Once edited the new command is added
#   to history and invoked.
#
#   NOTE: Because invocation happens within the scope of Edit-History
#         you may need to dot your invocation to yield proper results.
#         For example:
#   PS> Function myFcn ($parm) {'Do something with $parm'}
#   PS> Edit-History           # Change ' to " and close Textbox
#   Function myFcn ($parm) {"Do something with $parm"}
#   PS> myFcn 'this'
#   Do something with $parm
#
#   The function was modified but only within the scope of Edit-History
#   PS> . Edit-History fun     # cmd already has " type quotes just exit
#   Function myFcn ($parm) {"Do something with $parm"}
#   PS> myFcn 'this'
#   Do something with this
#
#   From what I understand, this problem (the dot needed) can only be
#   overcome by writing this function in a compiled language and
#   importing it into your session.  Interpreted code can't do it.
#   
######################################################################
function Edit-History ($Spec) {
  if ($Spec -is [int]) {$Spec = [int64]$Spec}
  if ($Spec -isnot [int64]) {
    $Entry = $_Cnt = (Get-History -Count 1).id
    while ($_Cnt -gt 0 -and
           ($Entry = $(Get-History -id $_Cnt -ErrorAction silentlycontinue)) -and
            $Entry -notlike ("$Spec" + '*')) {$_Cnt--}
    if ($Entry -and $_Cnt) {$Spec = $_Cnt}
  }
  if ($Spec -is [int64]) {
    $h = Get-History -id $Spec|
         Select-Object CommandLine,EndExecutionTime,ExecutionStatus,
                       Id,StartExecutionTime
      [void][System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms")
      $frmMain = new-object Windows.Forms.form
      $frmMain.Size = new-object System.Drawing.Size @(500,300)
      $frmMain.text = "Fix-History"
      $TextBox = new-object System.Windows.Forms.TextBox
      $frmMain.Controls.Add($TextBox)
      $TextBox.Dock = [System.Windows.Forms.DockStyle]::Fill
      $TextBox.MultiLine = $true
      $TextBox.AcceptsReturn = $true
      $TextBox.AcceptsTab = $true
      $TextBox.lines = $h.CommandLine.Split("`n")
      $FrmMain.Add_Shown({$FrmMain.Activate()})
      [void]$FrmMain.showdialog()
      $h.CommandLine = [string]::Join("`n",$TextBox.lines)
      if ($h.CommandLine) {
        Add-History $h
        Write-Host $h.CommandLine
        Invoke-Expression $h.CommandLine
      }
    }
  else {"No entry matches $([string]$Spec + '*')"}
}

Get-Signature

Note: Now that version 2 is out there is a similar, native function.

######################################################################
#
#   Get-Signature {<method>|<command>}
#
#   Returns the call signature of methods/functions.
#
#   Examples:
#     Get-Signature get-alias
#     Get-Signature ”.remove
#     Get-Signature [string]::join
#     Get-Signature more
#
######################################################################
function Get-Signature ($Cmd) {
  if ($Cmd -is [Management.Automation.PSMethod]) {
    $List = @($Cmd)}
  elseif ($Cmd -isnot [string]) {
    throw ("Get-Signature {<method>|<command>}`n" +
           "’$Cmd’ is not a method or command")}
  elseif (!($List = @(Get-Command $Cmd -ErrorAction SilentlyContinue)) -and
          $Cmd -like ‘`[*`]::*’ -and
          $Cmd -notlike ‘*)’) {
    $List = @(Invoke-Expression $Cmd  -erroraction SilentlyContinue)}
  if (!$List[0] ) {
    throw "Command ‘$Cmd’ not found"}
  foreach ($O in $List) {
    switch -regex ($O.GetType().Name) {
      ‘AliasInfo’ {
        Get-Signature ($O.Definition)}
      ‘ApplicationInfo’ {
        $O.Definition
        Invoke-Expression "$($O.Definition) /?"}
      ‘(Cmdlet|ExternalScript)Info’ {
        $O.Definition}          # not sure what to do with ExternalScript
      ‘F(unction|ilter)Info’{
        if ($O.Definition -match ‘^param *\(‘) {
          $t = [Management.Automation.PSParser]::tokenize($O.Definition,
                                                          [ref]$null)
          $c = 1;$i = 1
          while($c -and $i++ -lt $t.count) {
            switch ($t[$i].Type.ToString()) {
              GroupStart {$c++}
              GroupEnd   {$c–}}}
          $O.Definition.substring(0,$t[$i].start + 1)}
        else {$O.Name}}
      ‘PSMethod’ {
        foreach ($t in @($O.OverloadDefinitions)) {
          while (($b=$t.IndexOf(‘`1[[‘)) -ge 0) {
            $t=$t.remove($b,$t.IndexOf(‘]]’)-$b+2)}
            $t}}}}}