Wednesday, June 6, 2012

Powershell Add-Type – Where’s That Assembly!

I’ve been working a lot lately with SMO and the differences between the various versions between SQL 2005, 2008, and 2012. Through this process, I’ve come to understand why “[Reflection.Assembly]::LoadWithPartialName” is not a good option in PowerShell. Not only is it obsolete, it doesn’t allow you to choose which version of the SMO library you want to load and always loads the most recent. So, if you have SQL 2005, 2008, and 2012, you’ll get the 2012 versions regardless.

I wanted more control, so started to switch from LoadWithPartialName to Add-Type. I used the following code on my workstation and attempted to load the SMO assembly and it worked just fine.
Add-Type -AssemblyName "Microsoft.SqlServer.SMO"

When I checked what version of the assembly that had loaded, I realized that it had chosen the 2005 version? I thought, great, this does the opposite of LoadWithPartialName and loads the oldest… So, I tried it on box that did not have the 2005 client installed. To my surprise, it failed with the following error:
Add-Type : Could not load file or assembly 'Microsoft.SqlServer.Smo, Version=9.0.242.0, Culture=neutral, 
PublicKeyToken=89845dcd8080cc91' or one of its dependencies. The system cannot find the file specified.

A quick Bing search found an interesting Connect posting that offered some explanation. To quote “Microsoft” in the comment “The list is hard coded so that anybody writing “Add-Type –Assembly Microsoft.SqlServer.Smo” gets the same version.” In a similar vein, the documentation for Add-Type states that if “you enter a simple or partial name, Add-Type resolves it to the full name, and then uses the full name to load the assembly”. While this makes some sense, neither of these statements is clear exactly from what list this pulls from.

I spent some time with ProcessMonitor trying to determine if it was getting it from the registry or possibly from a different DLL with no luck. After spending some intimate time Bingling, trying to hit up methods and properties of the AddTypeCommand class, and otherwise coming up empty handed, I decided to take an alternate approach.

All the assemblies that I currently care to load for my work will be stored in one of the six folders of the GAC (Global Assembly Cache) on my Windows 7 Workstation. I decided to take this known list of assemblies and toss it to Add-Type and see what fell out.

The script below will take all of the assembly names that it can find and throw them at the Add-Type cmdlet. If the cmdlet loads the assembly, the current assembly list is examined to determine the full name of the assembly that was loaded.

If the cmdlet fails, the type of failure is recorded. If the assembly could not be loaded because the short name references an assembly that just doesn’t exist. Technically, Add-Type has that assembly in its list, so we can take the information out of the exception and know what the full assembly name was and store that value.

There are several assemblies that Add-Type does not seem to have a reference for. These will throw a custom error of ASSEMBLY_NOT_FOUND which means that the lookup failed. These assemblies are not in the list.

The full code is below. I understand, this is a very resource intensive approach, but there is little other choice that I could find that would tell me what versions the cmdlet would be loading for any given assembly. On my machine, it attempted to load 1073 assemblies (took a while). Of those, I was able to determine that 308 of them are in the Add-Type list. I’ve also included my list below. I do not believe this list to be comprehensive, but I do think it is safe to say that anything on this list reflects the accurate full name that Add-Type will resolve to if you provide a partial name.

About Kyle Neier
Husband of a magnificent woman, father of 5, SQL Server geek, IndyPASS Vice President and Food Guy, DBA automation zealot, amateur Powershell evangelist. Follow Me on Twitter

#Best to Start this in a powershell.exe -noprofile session

$CSVLocation = "$Env:USERPROFILE\Add_Type_Lookup.csv"

#Initialize Array to hold assemblies to attempt to load
$AssemblyNames = @()
$AssemblyReferences = @()

#Get all assemblies currently in the _old_ GAC
Get-ChildItem "C:\Windows\assembly\GAC" | Select -Unique Name |
    ForEach-Object{$AssemblyNames += $_.Name}
    
#32/64 bit compatibles
Get-ChildItem "C:\Windows\assembly\GAC_MSIL" | Select -Unique Name |
    ForEach-Object{if(
        $AssemblyNames -notcontains $_.Name){$AssemblyNames += $_.Name}}

#Get any 32-bit specific assemblies not already loaded
Get-ChildItem "C:\Windows\assembly\GAC_32" | Select -Unique Name |
    ForEach-Object{if(
        $AssemblyNames -notcontains $_.Name){$AssemblyNames += $_.Name}}

#Get any 64-bit specific assemblies
Get-ChildItem "C:\Windows\assembly\GAC_64" | Select -Unique Name |
    ForEach-Object{if(
        $AssemblyNames -notcontains $_.Name){$AssemblyNames += $_.Name}}

#New GAC

#Combined 32/64
Get-ChildItem "C:\Windows\Microsoft.NET\assembly\GAC_MSIL" | 
    Select -Unique Name |
    ForEach-Object{if(
        $AssemblyNames -notcontains $_.Name){$AssemblyNames += $_.Name}}
    
#32 only
Get-ChildItem "C:\Windows\Microsoft.NET\assembly\GAC_32" | 
    Select -Unique Name |
    ForEach-Object{if(
        $AssemblyNames -notcontains $_.Name){$AssemblyNames += $_.Name}}
    
#64 only
Get-ChildItem "C:\Windows\Microsoft.NET\assembly\GAC_64" | 
    Select -Unique Name |
    ForEach-Object{if(
        $AssemblyNames -notcontains $_.Name){$AssemblyNames += $_.Name}}


#Now that I have all the assembly names in my GAC, loop over each of them
#and see how add-type reacts
foreach($AssemblyName in $AssemblyNames)
{
    
    #Create object to throw into array for further evaluation
    $AssemblyReference = "" | select Name, FullName
    
    #The name of the assembly is present, no need to gather that
    #from any of the code below
    $AssemblyReference.Name = $AssemblyName
    
    try
    {
        Add-Type -AssemblyName $AssemblyName -ErrorAction Stop
        
        
        #If there is no error, the assembly is in the hard-coded list within
        #Add-Type, so let's interrogate the current appdomain assembly list 
        #to determine the actual full name that was loaded
        
        $AssemblyReference.FullName = (
            [AppDomain]::CurrentDomain.GetAssemblies() |
                ?{$_.FullName -like "$AssemblyName,*"}).FullName
    }
    catch [System.IO.FileNotFoundException]
    {
        #If the name is in the Add-Type hard-coded list, it attempts to load it
        #If it can't be loaded, it throws a convenient FileNotFoundException
        #Fortunately, the "FileName" is the full name of the assembly
        #that was attempted to be loaded
        
        $AssemblyReference.FullName = $_.Exception.FileName
        
    }
    catch 
    {

        if($_.FullyQualifiedErrorID -like "ASSEMBLY_NOT_FOUND*")
        {
            #Add-Type throws an error of ASSEMBLY_NOT_FOUND if the short name
            #is not in the list - so regardless of how hard we wish, we can't
            #load this assembly unless we use the full name
            $AssemblyReference.FullName = "Not In List"
        }
        else
        {
            #Some other error occured that is not expected
            #Log the fullname as unknown so that it can be evaluated later
            $AssemblyReference.FullName = "UNKNOWN"
        }
    }
    
    #Add the assembly object which has the short and full name to the array
    $AssemblyReferences += $AssemblyReference
}

#Send the array out to a CSV file and open it
$AssemblyReferences | ?{("Not In List") -notcontains $_.FullName} | 
    Sort-Object Name | 
    Export-Csv -NoTypeInformation -Path $CSVLocation

Invoke-Item $CSVLocation

Add-Type Assembly Reference List from my Windows 7 64-bit workstation:

NameFullName
AccessibilityAccessibility, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
ADODBADODB, Version=7.0.3300.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
AspNetMMCExtAspNetMMCExt, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
CppCodeProviderCppCodeProvider, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
cscompmgdcscompmgd, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
CustomMarshalersCustomMarshalers, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
EnvDTEEnvDTE, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
EnvDTE80EnvDTE80, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
EnvDTE90EnvDTE90, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
EventViewerEventViewer, Version=6.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
EventViewer.ResourcesEventViewer.resources, Version=6.0.0.0, Culture=en, PublicKeyToken=31bf3856ad364e35
ExtensibilityExtensibility, Version=7.0.3300.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
IEExecRemoteIEExecRemote, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
IEHostIEHost, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
IIEHostIIEHost, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
ipdmctrlipdmctrl, Version=11.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c
ISymWrapperISymWrapper, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
MFCMIFC80MFCMIFC80, Version=1.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.AnalysisServicesMicrosoft.AnalysisServices, Version=9.0.242.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91
Microsoft.AnalysisServices.AdomdClientMicrosoft.AnalysisServices.AdomdClient, Version=9.0.242.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91
Microsoft.AnalysisServices.DeploymentEngineMicrosoft.AnalysisServices.DeploymentEngine, Version=9.0.242.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91
Microsoft.Build.Conversion.v3.5Microsoft.Build.Conversion.v3.5, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.Build.EngineMicrosoft.Build.Engine, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.Build.FrameworkMicrosoft.Build.Framework, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.Build.TasksMicrosoft.Build.Tasks, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.Build.Tasks.v3.5Microsoft.Build.Tasks.v3.5, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.Build.UtilitiesMicrosoft.Build.Utilities, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.Build.Utilities.v3.5Microsoft.Build.Utilities.v3.5, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.DataWarehouse.InterfacesMicrosoft.DataWarehouse.Interfaces, Version=9.0.242.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91
Microsoft.ExceptionMessageBoxMicrosoft.ExceptionMessageBox, Version=9.0.242.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91
Microsoft.GroupPolicy.InteropMicrosoft.GroupPolicy.Interop, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
Microsoft.GroupPolicy.ReportingMicrosoft.GroupPolicy.Reporting, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
Microsoft.GroupPolicy.Reporting.ResourcesMicrosoft.GroupPolicy.Reporting.resources, Version=2.0.0.0, Culture=en, PublicKeyToken=31bf3856ad364e35
Microsoft.InkMicrosoft.Ink, Version=6.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
Microsoft.Ink.ResourcesMicrosoft.Ink.resources, Version=6.0.0.0, Culture=en, PublicKeyToken=31bf3856ad364e35
Microsoft.Internal.VisualStudio.Shell.Interop.9.0Microsoft.Internal.VisualStudio.Shell.Interop.9.0, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.Interop.Security.AzRolesMicrosoft.Interop.Security.AzRoles, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
Microsoft.JScriptMicrosoft.JScript, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.ManagementConsoleMicrosoft.ManagementConsole, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
Microsoft.ManagementConsole.ResourcesMicrosoft.ManagementConsole.resources, Version=3.0.0.0, Culture=en, PublicKeyToken=31bf3856ad364e35
Microsoft.mshtmlMicrosoft.mshtml, Version=7.0.3300.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.MSXMLMicrosoft.MSXML, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.NetEnterpriseServers.ExceptionMessageBoxMicrosoft.NetEnterpriseServers.ExceptionMessageBox, Version=9.0.242.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91
Microsoft.Office.InfoPathMicrosoft.Office.InfoPath, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c
Microsoft.Office.InfoPath.Client.Internal.HostMicrosoft.Office.InfoPath.Client.Internal.Host, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c
Microsoft.Office.InfoPath.Client.Internal.Host.InteropMicrosoft.Office.InfoPath.Client.Internal.Host.Interop, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c
Microsoft.Office.InfoPath.FormControlMicrosoft.Office.InfoPath.FormControl, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c
Microsoft.Office.InfoPath.PermissionMicrosoft.Office.InfoPath.Permission, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c
Microsoft.Office.InfoPath.VstaMicrosoft.Office.InfoPath.Vsta, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c
Microsoft.Office.Interop.AccessMicrosoft.Office.Interop.Access, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c
Microsoft.Office.Interop.Access.DaoMicrosoft.Office.Interop.Access.Dao, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c
Microsoft.Office.Interop.ExcelMicrosoft.Office.Interop.Excel, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c
Microsoft.Office.Interop.GraphMicrosoft.Office.Interop.Graph, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c
Microsoft.Office.Interop.InfoPathMicrosoft.Office.Interop.InfoPath, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c
Microsoft.Office.Interop.InfoPath.SemiTrustMicrosoft.Office.Interop.InfoPath.SemiTrust, Version=11.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c
Microsoft.Office.Interop.InfoPath.XmlMicrosoft.Office.Interop.InfoPath.Xml, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c
Microsoft.Office.Interop.OneNoteMicrosoft.Office.Interop.OneNote, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c
Microsoft.Office.Interop.OutlookMicrosoft.Office.Interop.Outlook, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c
Microsoft.Office.Interop.OutlookViewCtlMicrosoft.Office.Interop.OutlookViewCtl, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c
Microsoft.Office.Interop.PowerPointMicrosoft.Office.Interop.PowerPoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c
Microsoft.Office.Interop.PublisherMicrosoft.Office.Interop.Publisher, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c
Microsoft.Office.Interop.SmartTagMicrosoft.Office.Interop.SmartTag, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c
Microsoft.Office.Interop.WordMicrosoft.Office.Interop.Word, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c
Microsoft.Office.Tools.CommonMicrosoft.Office.Tools.Common, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.Office.Tools.ExcelMicrosoft.Office.Tools.Excel, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.Office.Tools.OutlookMicrosoft.Office.Tools.Outlook, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.Office.Tools.WordMicrosoft.Office.Tools.Word, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.PowerShell.Commands.DiagnosticsMicrosoft.PowerShell.Commands.Diagnostics, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
Microsoft.PowerShell.Commands.ManagementMicrosoft.PowerShell.Commands.Management, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
Microsoft.PowerShell.Commands.Management.ResourcesMicrosoft.PowerShell.Commands.Management.resources, Version=1.0.0.0, Culture=en, PublicKeyToken=31bf3856ad364e35
Microsoft.PowerShell.Commands.UtilityMicrosoft.PowerShell.Commands.Utility, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
Microsoft.PowerShell.Commands.Utility.ResourcesMicrosoft.PowerShell.Commands.Utility.resources, Version=1.0.0.0, Culture=en, PublicKeyToken=31bf3856ad364e35
Microsoft.PowerShell.ConsoleHostMicrosoft.PowerShell.ConsoleHost, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
Microsoft.PowerShell.ConsoleHost.ResourcesMicrosoft.PowerShell.ConsoleHost.resources, Version=1.0.0.0, Culture=en, PublicKeyToken=31bf3856ad364e35
Microsoft.PowerShell.EditorMicrosoft.PowerShell.Editor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
Microsoft.PowerShell.Editor.ResourcesMicrosoft.PowerShell.Editor.resources, Version=1.0.0.0, Culture=en, PublicKeyToken=31bf3856ad364e35
Microsoft.PowerShell.GPowerShellMicrosoft.PowerShell.GPowerShell, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
Microsoft.PowerShell.GPowerShell.ResourcesMicrosoft.PowerShell.GPowerShell.resources, Version=1.0.0.0, Culture=en, PublicKeyToken=31bf3856ad364e35
Microsoft.PowerShell.GraphicalHostMicrosoft.PowerShell.GraphicalHost, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
Microsoft.PowerShell.GraphicalHost.ResourcesMicrosoft.PowerShell.GraphicalHost.resources, Version=1.0.0.0, Culture=en, PublicKeyToken=31bf3856ad364e35
Microsoft.PowerShell.SecurityMicrosoft.PowerShell.Security, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
Microsoft.PowerShell.Security.ResourcesMicrosoft.PowerShell.Security.resources, Version=1.0.0.0, Culture=en, PublicKeyToken=31bf3856ad364e35
Microsoft.ReportViewer.CommonMicrosoft.ReportViewer.Common, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.ReportViewer.DesignMicrosoft.ReportViewer.Design, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.ReportViewer.ProcessingObjectModelMicrosoft.ReportViewer.ProcessingObjectModel, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.ReportViewer.WebDesignMicrosoft.ReportViewer.WebDesign, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.ReportViewer.WebFormsMicrosoft.ReportViewer.WebForms, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.ReportViewer.WinFormsMicrosoft.ReportViewer.WinForms, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.SqlServer.BatchParserMicrosoft.SqlServer.BatchParser, Version=9.0.242.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91
Microsoft.SqlServer.ConnectionInfoMicrosoft.SqlServer.ConnectionInfo, Version=9.0.242.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91
Microsoft.SqlServer.CustomControlsMicrosoft.SqlServer.CustomControls, Version=9.0.242.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91
Microsoft.SqlServer.GridControlMicrosoft.SqlServer.GridControl, Version=9.0.242.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91
Microsoft.SqlServer.InstapiMicrosoft.SqlServer.Instapi, Version=9.0.242.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91
Microsoft.SqlServer.MgdSqlDumperMicrosoft.SqlServer.MgdSqlDumper, Version=9.0.242.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91
Microsoft.SqlServer.RegSvrEnumMicrosoft.SqlServer.RegSvrEnum, Version=9.0.242.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91
Microsoft.SqlServer.ReplicationMicrosoft.SqlServer.Replication, Version=9.0.242.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91
Microsoft.SqlServer.Replication.BusinessLogicSupportMicrosoft.SqlServer.Replication.BusinessLogicSupport, Version=9.0.242.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91
Microsoft.SqlServer.RmoMicrosoft.SqlServer.Rmo, Version=9.0.242.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91
Microsoft.SqlServer.ServiceBrokerEnumMicrosoft.SqlServer.ServiceBrokerEnum, Version=9.0.242.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91
Microsoft.SqlServer.SmoMicrosoft.SqlServer.Smo, Version=9.0.242.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91
Microsoft.SqlServer.SmoEnumMicrosoft.SqlServer.SmoEnum, Version=9.0.242.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91
Microsoft.SqlServer.SqlEnumMicrosoft.SqlServer.SqlEnum, Version=9.0.242.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91
Microsoft.SqlServer.SqlTDiagMMicrosoft.SqlServer.SqlTDiagM, Version=9.0.242.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91
Microsoft.SqlServer.SStringMicrosoft.SqlServer.SString, Version=9.0.242.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91
Microsoft.SqlServer.WizardFrameworkLiteMicrosoft.SqlServer.WizardFrameworkLite, Version=9.0.242.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91
Microsoft.SqlServer.WmiEnumMicrosoft.SqlServer.WmiEnum, Version=9.0.242.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91
Microsoft.StdFormatMicrosoft.StdFormat, Version=7.0.3300.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.TpmMicrosoft.Tpm, Version=6.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
Microsoft.Tpm.ResourcesMicrosoft.Tpm.resources, Version=6.0.0.0, Culture=en, PublicKeyToken=31bf3856ad364e35
Microsoft.Transactions.BridgeMicrosoft.Transactions.Bridge, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.Transactions.Bridge.DtcMicrosoft.Transactions.Bridge.Dtc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.Vbe.InteropMicrosoft.Vbe.Interop, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c
Microsoft.Vbe.Interop.FormsMicrosoft.Vbe.Interop.Forms, Version=11.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c
Microsoft.VisualBasicMicrosoft.VisualBasic, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.VisualBasic.CompatibilityMicrosoft.VisualBasic.Compatibility, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.VisualBasic.Compatibility.DataMicrosoft.VisualBasic.Compatibility.Data, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.VisualBasic.VsaMicrosoft.VisualBasic.Vsa, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.VisualCMicrosoft.VisualC, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.VisualC.STLCLRMicrosoft.VisualC.STLCLR, Version=1.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.VisualC.VSCodeParserMicrosoft.VisualC.VSCodeParser, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.VisualC.VSCodeProviderMicrosoft.VisualC.VSCodeProvider, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.VisualStudioMicrosoft.VisualStudio, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.VisualStudio.CommandBarsMicrosoft.VisualStudio.CommandBars, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.VisualStudio.CommonIDEMicrosoft.VisualStudio.CommonIDE, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.VisualStudio.ConfigurationMicrosoft.VisualStudio.Configuration, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.VisualStudio.Debugger.InteropMicrosoft.VisualStudio.Debugger.Interop, Version=8.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.VisualStudio.Debugger.InteropAMicrosoft.VisualStudio.Debugger.InteropA, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.VisualStudio.DebuggerVisualizersMicrosoft.VisualStudio.DebuggerVisualizers, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.VisualStudio.DesignMicrosoft.VisualStudio.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.VisualStudio.Designer.InterfacesMicrosoft.VisualStudio.Designer.Interfaces, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.VisualStudio.Diagnostics.ServiceModelSinkMicrosoft.VisualStudio.Diagnostics.ServiceModelSink, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.VisualStudio.EditorsMicrosoft.VisualStudio.Editors, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.VisualStudio.EnterpriseToolsMicrosoft.VisualStudio.EnterpriseTools, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.VisualStudio.EnterpriseTools.ClassDesignerMicrosoft.VisualStudio.EnterpriseTools.ClassDesigner, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.VisualStudio.EnterpriseTools.ShellMicrosoft.VisualStudio.EnterpriseTools.Shell, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.VisualStudio.EnterpriseTools.TypeSystemMicrosoft.VisualStudio.EnterpriseTools.TypeSystem, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.VisualStudio.HostingProcess.UtilitiesMicrosoft.VisualStudio.HostingProcess.Utilities, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.VisualStudio.HostingProcess.Utilities.SyncMicrosoft.VisualStudio.HostingProcess.Utilities.Sync, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.VisualStudio.ManagedInterfacesMicrosoft.VisualStudio.ManagedInterfaces, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.VisualStudio.ModelingMicrosoft.VisualStudio.Modeling, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.VisualStudio.Modeling.ArtifactMapperMicrosoft.VisualStudio.Modeling.ArtifactMapper, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.VisualStudio.Modeling.ArtifactMapper.VSHostMicrosoft.VisualStudio.Modeling.ArtifactMapper.VSHost, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.VisualStudio.Modeling.DiagramsMicrosoft.VisualStudio.Modeling.Diagrams, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.VisualStudio.Modeling.Diagrams.GraphObjectMicrosoft.VisualStudio.Modeling.Diagrams.GraphObject, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.VisualStudio.OLE.InteropMicrosoft.VisualStudio.OLE.Interop, Version=7.1.40304.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.VisualStudio.Package.LanguageServiceMicrosoft.VisualStudio.Package.LanguageService, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.VisualStudio.ProjectAggregatorMicrosoft.VisualStudio.ProjectAggregator, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.VisualStudio.PublishMicrosoft.VisualStudio.Publish, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.VisualStudio.QualityTools.ResourceMicrosoft.VisualStudio.QualityTools.Resource, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.VisualStudio.QualityTools.UnitTestFrameworkMicrosoft.VisualStudio.QualityTools.UnitTestFramework, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.VisualStudio.ShellMicrosoft.VisualStudio.Shell, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.VisualStudio.Shell.9.0Microsoft.VisualStudio.Shell.9.0, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.VisualStudio.Shell.DesignMicrosoft.VisualStudio.Shell.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.VisualStudio.Shell.InteropMicrosoft.VisualStudio.Shell.Interop, Version=7.1.40304.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.VisualStudio.Shell.Interop.8.0Microsoft.VisualStudio.Shell.Interop.8.0, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.VisualStudio.Shell.Interop.9.0Microsoft.VisualStudio.Shell.Interop.9.0, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.VisualStudio.TeamSystem.PerformanceWizardMicrosoft.VisualStudio.TeamSystem.PerformanceWizard, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.VisualStudio.TemplateWizardInterfaceMicrosoft.VisualStudio.TemplateWizardInterface, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.VisualStudio.TextManager.InteropMicrosoft.VisualStudio.TextManager.Interop, Version=7.1.40304.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.VisualStudio.TextManager.Interop.8.0Microsoft.VisualStudio.TextManager.Interop.8.0, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.VisualStudio.TextManager.Interop.9.0Microsoft.VisualStudio.TextManager.Interop.9.0, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.VisualStudio.Tools.Applications.AdapterMicrosoft.VisualStudio.Tools.Applications.Adapter, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.VisualStudio.Tools.Applications.Adapter.v9.0Microsoft.VisualStudio.Tools.Applications.Adapter.v9.0, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.VisualStudio.Tools.Applications.AddInManagerMicrosoft.VisualStudio.Tools.Applications.AddInManager, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.VisualStudio.Tools.Applications.BlueprintsMicrosoft.VisualStudio.Tools.Applications.Blueprints, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.VisualStudio.Tools.Applications.ComRPCChannelMicrosoft.VisualStudio.Tools.Applications.ComRPCChannel, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.VisualStudio.Tools.Applications.ContractMicrosoft.VisualStudio.Tools.Applications.Contract, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.VisualStudio.Tools.Applications.Contract.v9.0Microsoft.VisualStudio.Tools.Applications.Contract.v9.0, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.VisualStudio.Tools.Applications.DesignTimeMicrosoft.VisualStudio.Tools.Applications.DesignTime, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.VisualStudio.Tools.Applications.HostingMicrosoft.VisualStudio.Tools.Applications.Hosting, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.VisualStudio.Tools.Applications.Hosting.v9.0Microsoft.VisualStudio.Tools.Applications.Hosting.v9.0, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.VisualStudio.Tools.Applications.InteropAdapterMicrosoft.VisualStudio.Tools.Applications.InteropAdapter, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.VisualStudio.Tools.Applications.RuntimeMicrosoft.VisualStudio.Tools.Applications.Runtime, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.VisualStudio.Tools.Applications.ServerDocumentMicrosoft.VisualStudio.Tools.Applications.ServerDocument, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.VisualStudio.Tools.Office.RuntimeMicrosoft.VisualStudio.Tools.Office.Runtime, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.VisualStudio.VCCodeModelMicrosoft.VisualStudio.VCCodeModel, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.VisualStudio.VCProjectMicrosoft.VisualStudio.VCProject, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.VisualStudio.VCProjectEngineMicrosoft.VisualStudio.VCProjectEngine, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.VisualStudio.VirtualTreeGridMicrosoft.VisualStudio.VirtualTreeGrid, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.VisualStudio.VSContentInstallerMicrosoft.VisualStudio.VSContentInstaller, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.VisualStudio.VSHelpMicrosoft.VisualStudio.VSHelp, Version=7.0.3300.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.VisualStudio.VSHelp80Microsoft.VisualStudio.VSHelp80, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.VisualStudio.Windows.FormsMicrosoft.VisualStudio.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.VisualStudio.WizardFrameworkMicrosoft.VisualStudio.WizardFramework, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.VisualStudio.ZipMicrosoft.VisualStudio.Zip, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.VsaMicrosoft.Vsa, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.Vsa.Vb.CodeDOMProcessorMicrosoft.Vsa.Vb.CodeDOMProcessor, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.VSDesignerMicrosoft.VSDesigner, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.WSMan.ManagementMicrosoft.WSMan.Management, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
Microsoft_VsaVbMicrosoft_VsaVb, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
MiguiControlsMIGUIControls, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
MiguiControls.ResourcesMIGUIControls.resources, Version=1.0.0.0, Culture=en, PublicKeyToken=31bf3856ad364e35
MMCExMMCEx, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
MMCEx.ResourcesMMCEx.resources, Version=3.0.0.0, Culture=en, PublicKeyToken=31bf3856ad364e35
MMCFxCommonMMCFxCommon, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
MMCFxCommon.ResourcesMMCFxCommon.resources, Version=3.0.0.0, Culture=en, PublicKeyToken=31bf3856ad364e35
MSClusterLibMSClusterLib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91
mscomctlmscomctl, Version=10.0.4504.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
mscorcfgmscorcfg, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
mscorlibmscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
MSDATASRCMSDATASRC, Version=7.0.3300.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
msddslmpmsddslmp, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
msddspmsddsp, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
napcryptnapcrypt, Version=6.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
naphlprnaphlpr, Version=6.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
napinitnapinit, Version=6.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
napinit.resourcesnapinit.resources, Version=6.0.0.0, Culture=en, PublicKeyToken=31bf3856ad364e35
napsnapnapsnap, Version=6.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
napsnap.resourcesnapsnap.resources, Version=6.0.0.0, Culture=en, PublicKeyToken=31bf3856ad364e35
officeoffice, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c
Policy.1.0.Microsoft.InkPolicy.1.0.Microsoft.Ink, Version=6.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
Policy.1.0.Microsoft.Interop.Security.AzRolesPolicy.1.0.Microsoft.Interop.Security.AzRoles, Version=6.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
Policy.1.2.Microsoft.Interop.Security.AzRolesPolicy.1.2.Microsoft.Interop.Security.AzRoles, Version=6.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
Policy.1.7.Microsoft.InkPolicy.1.7.Microsoft.Ink, Version=6.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
Policy.11.0.Microsoft.Office.Interop.AccessPolicy.11.0.Microsoft.Office.Interop.Access, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c
Policy.11.0.Microsoft.Office.Interop.ExcelPolicy.11.0.Microsoft.Office.Interop.Excel, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c
Policy.11.0.Microsoft.Office.Interop.GraphPolicy.11.0.Microsoft.Office.Interop.Graph, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c
Policy.11.0.Microsoft.Office.Interop.InfoPathPolicy.11.0.Microsoft.Office.Interop.InfoPath, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c
Policy.11.0.Microsoft.Office.Interop.InfoPath.XmlPolicy.11.0.Microsoft.Office.Interop.InfoPath.Xml, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c
Policy.11.0.Microsoft.Office.Interop.OutlookPolicy.11.0.Microsoft.Office.Interop.Outlook, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c
Policy.11.0.Microsoft.Office.Interop.OutlookViewCtlPolicy.11.0.Microsoft.Office.Interop.OutlookViewCtl, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c
Policy.11.0.Microsoft.Office.Interop.PowerPointPolicy.11.0.Microsoft.Office.Interop.PowerPoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c
Policy.11.0.Microsoft.Office.Interop.PublisherPolicy.11.0.Microsoft.Office.Interop.Publisher, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c
Policy.11.0.Microsoft.Office.Interop.SmartTagPolicy.11.0.Microsoft.Office.Interop.SmartTag, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c
Policy.11.0.Microsoft.Office.Interop.WordPolicy.11.0.Microsoft.Office.Interop.Word, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c
Policy.11.0.Microsoft.Vbe.InteropPolicy.11.0.Microsoft.Vbe.Interop, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c
Policy.11.0.officePolicy.11.0.office, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c
PresentationBuildTasksPresentationBuildTasks, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
PresentationCFFRasterizerPresentationCFFRasterizer, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
PresentationCorePresentationCore, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
PresentationFrameworkPresentationFramework, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
PresentationFramework.AeroPresentationFramework.Aero, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
PresentationFramework.ClassicPresentationFramework.Classic, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
PresentationFramework.LunaPresentationFramework.Luna, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
PresentationFramework.RoyalePresentationFramework.Royale, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
PresentationUIPresentationUI, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
ReachFrameworkReachFramework, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
SMDiagnosticsSMDiagnostics, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
soapsudscodesoapsudscode, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
stdolestdole, Version=7.0.3300.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
sysgloblsysglobl, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
SystemSystem, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
System.AddInSystem.AddIn, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
System.AddIn.ContractSystem.AddIn.Contract, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
System.ConfigurationSystem.Configuration, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
System.Configuration.InstallSystem.Configuration.Install, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
System.CoreSystem.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
System.DataSystem.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
System.Data.DataSetExtensionsSystem.Data.DataSetExtensions, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
System.Data.LinqSystem.Data.Linq, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
System.Data.OracleClientSystem.Data.OracleClient, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
System.Data.SqlXmlSystem.Data.SqlXml, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
System.DeploymentSystem.Deployment, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
System.DesignSystem.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
System.DirectoryServicesSystem.DirectoryServices, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
System.DirectoryServices.AccountManagementSystem.DirectoryServices.AccountManagement, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
System.DirectoryServices.ProtocolsSystem.DirectoryServices.Protocols, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
System.DrawingSystem.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
System.Drawing.DesignSystem.Drawing.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
System.EnterpriseServicesSystem.EnterpriseServices, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
System.IdentityModelSystem.IdentityModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
System.IdentityModel.SelectorsSystem.IdentityModel.Selectors, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
System.IO.LogSystem.IO.Log, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
System.ManagementSystem.Management, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
System.Management.AutomationSystem.Management.Automation, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
System.Management.Automation.ResourcesSystem.Management.Automation.resources, Version=1.0.0.0, Culture=en, PublicKeyToken=31bf3856ad364e35
System.Management.InstrumentationSystem.Management.Instrumentation, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
System.MessagingSystem.Messaging, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
System.NetSystem.Net, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
System.PrintingSystem.Printing, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
System.Runtime.RemotingSystem.Runtime.Remoting, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
System.Runtime.SerializationSystem.Runtime.Serialization, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
System.Runtime.Serialization.Formatters.SoapSystem.Runtime.Serialization.Formatters.Soap, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
System.SecuritySystem.Security, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
System.ServiceModelSystem.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
System.ServiceModel.InstallSystem.ServiceModel.Install, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
System.ServiceModel.WasHostingSystem.ServiceModel.WasHosting, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
System.ServiceModel.WebSystem.ServiceModel.Web, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
System.ServiceProcessSystem.ServiceProcess, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
System.SpeechSystem.Speech, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
System.TransactionsSystem.Transactions, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
System.WebSystem.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
System.Web.ExtensionsSystem.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
System.Web.Extensions.DesignSystem.Web.Extensions.Design, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
System.Web.MobileSystem.Web.Mobile, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
System.Web.RegularExpressionsSystem.Web.RegularExpressions, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
System.Web.ServicesSystem.Web.Services, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
System.Windows.FormsSystem.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
System.Windows.PresentationSystem.Windows.Presentation, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
System.Workflow.ActivitiesSystem.Workflow.Activities, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
System.Workflow.ComponentModelSystem.Workflow.ComponentModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
System.Workflow.RuntimeSystem.Workflow.Runtime, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
System.WorkflowServicesSystem.WorkflowServices, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
System.XmlSystem.Xml, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
System.Xml.LinqSystem.Xml.Linq, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
TaskSchedulerTaskScheduler, Version=6.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
TaskScheduler.ResourcesTaskScheduler.resources, Version=6.0.0.0, Culture=en, PublicKeyToken=31bf3856ad364e35
UIAutomationClientUIAutomationClient, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
UIAutomationClientsideProvidersUIAutomationClientsideProviders, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
UIAutomationProviderUIAutomationProvider, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
UIAutomationTypesUIAutomationTypes, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
VSLangProjVSLangProj, Version=7.0.3300.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
VSLangProj2VSLangProj2, Version=7.0.5000.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
VSLangProj80UNKNOWN
VsWebSite.InteropVsWebSite.Interop, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
WebDev.WebHostWebDev.WebHost, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
WindowsBaseWindowsBase, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
WindowsFormsIntegrationWindowsFormsIntegration, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35

Tuesday, May 1, 2012

The 2012 Powershell Scripting Game(shows) in review


Over the past few weeks, those around me know that I’ve been talking a lot about Powershell, how much it can improve your life, and about the 2012 Powershell Scripting Games. Nearly everyone I’ve shared with has asked “What are the Scripting Games?”

My answer to them was and will always be “It’s a bunch of geeks learning new stuff by attempting to solve 10 real-world scenarios by using Powershell.” For the less technical, I would follow that up with “It’s kind of like a reality game show only with computers and stuff.” Oddly enough, that made sense to most people, so I’ll continue with that theme as I share a few of my observations below.

“Survivor” it was not

When others around me (both technical and non-technical) heard this was titled “Games”, the near immediate response was “What do you get if you win?” Before feeling compelled to look it up, the first few people got the answer “I don’t know…” I really didn’t know, and I wouldn’t be surprised if others competing would have had a similar response. Never did I feel like the other competitors were in it to beat me – I know I wished no ill will on any of the other competitors. To the contrary – unlike Survivor – I found that those who were participating did their best to help everyone else while not giving up the actual solutions. The Powershell community is a group of people who like sharing knowledge, not a bunch of people who want to out-wit their peers, clamoring to win. Even as the games came to a close, the winners were grateful for their recognition.

“Wheel of Fortune”

Growing up, my Papaw Neier was an avid wheel-watcher. He would watch Wheel of Fortune every night. If we were at his house, it was mandatory to watch it with him. Each of us grandchildren would sometimes randomly scream letters at the TV, but Papaw would always be there to offer sage advice on what letter combinations made the most sense and guide us to the correct solution, never letting on that he knew the answer. These games, as in real life as an IT professional, were a lot like Wheel of Fortune. The initial event description provided the basis – the RSTLN and E. However, it didn’t stop there. We weren’t left to blindly guess with only the letters first put on the board. A lot of the information was available, but it was the comments to the posts that helped to complete the picture. Scripters would ask questions and someone, usually IamMred, would clarify the requirements, but always without giving up too much information as to give away the solution. Without this careful dissemination of information, some of these events would have been difficult at best. This is a good practice to take back into real life – always be ready to help out someone else, but be slow to give up the answer. Encourage learning, not leeching.

“Beat the Clock”

During the first week of the games, I was able to get the scripts turned in within a reasonable time frame, some within the same day. I even won one of the daily prizes donated by O’Reilly Media! As the second week came, life happened. I had to leave the games on the back burner, not knowing whether I’d get back to them or not. As the second week ended and life returned to normal, I realized I still had time to get all the events completed, but it wouldn’t be easy. I had work to be done and leaving the family to fend for themselves favor of the scripting games was not an option. Each evening, after everyone was in bed, I began working feverishly into the early morning (fortunately, Eastern time-zone) to get the events completed just minutes to hours before each of the deadlines. I did my best to make certain that my wife and kids were only moderately affected by my own personal game of “Beat the Clock”. I knew the task, I knew how much time I had to get it done, and I knew no one else could do it for me. As a microcosm of real life – we only have so much time, so use it wisely, do it right, and don’t forget those who love you.

“Dancing with the Stars”

I’ve tried on multiple occasions to get through an entire episode of “Dancing with the Stars” without success. While I’m certain that it has significant entertainment value to others, I have never been able to enjoy watching it. However, the premise of the show seems clear – learn from the expert and you’ll do better. I am incredibly grateful for the time that the expert judges took to not only analyze and run our scripts, but take the time to comment and offer advice in the process. In Event 2, it was suggested to me to avoid using Read-Host and switch to using PromptForChoice() by Boe Prox. I had never heard of this before, but soon realized how cool it was, implementing it in Event 8. In the comments of my Event 3, Bartek Bielawski introduced me to the ConvertToDateTime WMI method, which I have used professionally already. My scripting and therefore my career are now better off having been granted the privilege of “Dancing with the Stars” during the scripting games. These guys are masters of the craft. For as much time as I put in just writing 10 scripts, I can’t imagine how many hours these judged sacrificed to make each of us better at what we do – for free. They deserve an award.

Thanks again to the Scripting Guys, all the judges, and their families for creating an environment where we can all learn to do our jobs better, for free, and have fun doing it. Congratulations to the winners and to everyone, both beginner and advanced who competed.

I look forward to gaining more knowledge and experience next year!

About Kyle Neier
Husband of a magnificent woman, father of 5, SQL Server geek, IndyPASS Vice President and Food Guy, DBA automation zealot, amateur Powershell evangelist. Follow Me on Twitter

Thursday, April 19, 2012

PowerShell: Using Exponents and Logs to Format Byte Sizes

In a recent Scripting Games event, I had to format some byte values into their most appropriate size according to how many bytes were present. Anyone who hangs around with me long enough will realize I love numbers and the preciseness that they provide. This is one of many reasons why I enjoy computer programming and especially working with SQL Server. Even more than my love of numbers is my hatred toward duplicating work.

This is one of my longer posts, but I promise some neat stuff if you stick with me on this…

When I started to code for the event, I headed down the path of using the PowerShell switch statement. I had never known that you could use an expression to evaluate a switch – so that was something really cool. This is the function I initially came up with (all the commenting and help removed for brevity):

switch ($a)
{
    #each step in the switch increases by a multiplier of 1024
    {$_ -lt 1024} {"{0:N2} Bytes" -f ($a)}
    {$_ -ge 1024 -and $_ -lt (1048576) } {"{0:N2} KiloBytes" -f ($a/1024)}
    {$_ -ge 1048576 -and $_ -lt (1073741824) } {"{0:N2} MegaBytes" -f ($a/1048576)}
    {$_ -ge 1073741824 -and $_ -lt (1099511627776) } {
        "{0:N2} GigaBytes" -f ($a/1073741824)}
        
    #Stop @ TeraBytes, could be more than 1024 TeraBytes, but that is acceptable
    default {{"{0:N2} TeraBytes" -f ($a/1099511627776)}}
    
}

This was a workable function, but it didn’t feel right. I had to do a lot of typing and we all know we only have so many keystrokes in our lives, so I stepped back and re-evaluated.

At each expression, I was looking at a multiplier of 1024. Like the veil was removed, I realized that these were exponents. Time for the .NET Math Class (pun intended). Among some of the other cool methods of this class is the Pow method. No, we’re not in the original Batman series fighting the super villain, it’s the equivalent of the T-SQL POWER function. I soon had a simple function and all those large nasty numbers replaced with their exponential equivalents. Here is version two:

function Get-Power
{
    
    param([double]$RaiseMe)
    
    [Math]::Pow(1024, $RaiseMe)

}

switch ($a)
{
    #each step in the switch increases by a multiplier of 1024
    {$_ -lt (Get-Power 1)} {"{0:N2} Bytes" -f ($a)}
    {$_ -ge (Get-Power 1) -and $_ -lt (Get-Power 2) } {
        "{0:N2} KiloBytes" -f ($a/(Get-Power 1))}
        
    {$_ -ge (Get-Power 2) -and $_ -lt (Get-Power 3) } {
        "{0:N2} MegaBytes" -f ($a/(Get-Power 2))}
        
    {$_ -ge (Get-Power 3) -and $_ -lt (Get-Power 4) } {
        "{0:N2} GigaBytes" -f ($a/(Get-Power 3))}
        
    #Stop @ TeraBytes, could be more than 1024 TeraBytes, but that is acceptable
    default {"{0:N2} TeraBytes" -f ($a/(Get-Power 4))}
    
}

This worked the same and it was a little cleaner, but it still bothered me. There was a lot of copied and pasted code in there and it was all to determine what text to slap on the end of a quotient. I once again stepped back and realized that it was the switch’s fault. I then made it my goal to eliminate the switch.

In the process, I remembered that 1024 is 2^10… this meant that 1024^2 was 2^20, 1024^3 was 2^30 and so on. Believe it or not, this made my path clear.

A quick Algebra refresher – exponents and logs are functionally the same things, just expressed in a way that makes each valuable for different circumstances. For instance, 2^10=1024 is the functional equivalent of LOG_2(1024) = 10. For our purposes, we will want to know the power of 2 each number being provided is. To find the unknown “power” value in an equation, (the 10 above) the log base is technically irrelevant. With that in mind, we can use the natural logarithm (ln) to determine what power of 2 any number represents.

2^x = 1024 bytes
ln(2^x) = ln(1024 bytes)
ln(2)x = ln(1024 bytes)
x = ln(1024) / ln(2)
x = 6.93 / 0.693
x = 10

Before you think, that’s great, thanks for the math lesson and stop reading - this information really does have some decent uses in PowerShell. Let’s see how this math can be applied to make my function above re-usable and easily maintainable code.

The Math class has a method named Log . When only provided with a single value, this function will use “e” as the base – the natural algorithm which is the functional equivalent of “ln” used above. Armed with this function, we can determine which power of 2 any particular number is. More importantly, this information can eventually be used to format any size of number appropriately.

In the code below, I use PowerShell to extract the closest whole power of 2 that makes up the $byte value by implementing the Floor method.

$PowerOfTwo = [Math]::Floor([Math]::Log($byte)/[Math]::Log(2))

If I now create an array of my “descriptors”, I can use this text to be added to the end of each of the numbers to make it pretty.

$ByteDescriptors = ("B", "KB", "MB", "GB", "TB", "PB", 
                "EB", "ZB", "YB", "WYGTMSB")

With the array prepared, the $PowerOfTwo variable can be divided by 10 (and Floored) to provide the index into the descriptor array.

$DescriptorID = [Math]::Floor($PowerOfTwo/10)

Finally, we use the format method to combine all this information into an output. The $Scale variable is set in the script to be 2. Not only is the $DescriptorID used to determine the description, it is also used as a power of 2 in the divisor with the total byte value as the dividend.

Write-Output ("{0:N$Scale} $($ByteDescriptors[$DescriptorID])" -f (
                $byte / [Math]::Pow(2, ($DescriptorID*10))))

I’ve included the full function below which includes all of these pieces as well as full comments and a few extra parameters. While I may have been able to use the first function, the flexibility that the most recent iteration of this script provides seems worth the effort. Not only do I think this is a neat function, I now have an answer for my kids when they ask “When am I ever going to use this stuff in real life?” :-)


function Format-Byte
{
<#    
    .SYNOPSIS
    Formats a number into the appropriate byte display format.

    .DESCRIPTION
    Uses the powers of 2 to determine what the appropriate byte descriptor
    should be and reduces the number to that appropriate descriptor.
    
    The LongDescriptor switch will switch from the generic "KB, MB, etc."
    to "KiloBytes, MegaBytes, etc."
    
    Returns valid values from byte (2^0) through YottaByte (2^80).
    
    .PARAMETER ByteValue        
    Required double value that represents the number of bytes to convert.
    
    This value must be greater than or equal to zero or the function will error.

    This value can be passed as a positional, named, or pipeline parameter.    
    
    .PARAMETER LongDescriptor
    Optional switch parameter that can be used to specify long names for 
    byte descriptors (KiloBytes, MegaBytes, etc.) as compared to the default
    (KB, MB, etc.) Changes no other functionality.
    
    .PARAMETER Scale
    Optional parameter that specifies how many numbers to display after 
    the decimal place.
    
    The default value for this parameter is 2. 
    
    .EXAMPLE
    Format-Byte 123456789.123
    
    Uses the positional parameter and returns returns "117.74 MB"
    
    .EXAMPLE
    Format-Byte -ByteValue 123456789123 -Scale 0
    
    Uses the named parameter and specifies a Scale of 0 (whole numbers). 
    
    Returns "115 GB"
    
    .EXAMPLE
    Format-Byte -ByteValue 123456789123 -LongDescriptor -Scale 4
    
    Uses the named parameter and specifies a scale of 4 (4 numbers after the
    decimal) 
    
    Returns "114.9781 GigaBytes"
    
    .EXAMPLE
    (Get-ChildItem "E:\KyleScripts")|ForEach-Object{$_.Length}|Format-Byte
    
    Passes an array of the sizes of all the files in the E:\KyleScripts folder
    through the pipeline.
    
    .NOTES
    Author:    Kyle Neier
    Blog: http://sqldbamusings.blogspot.com
    Twitter: Kyle_Neier
    
    Because of the 14 significant digit issue, anything nearing 2^90
    will be marked as WYGTMSB aka WheredYouGetThatMuchStorageBytes. If you
    have that much storage, feel free to find a different function and or
    travel back in time a hundred years years or so and slap me...

#>    

    [CmdletBinding()]
    
    param(
        [parameter(
                Mandatory=$true, 
                Position=0,
                ValueFromPipeline= $true
                
            )]
             #make certain value won't break script
             [ValidateScript({$_ -ge 0 -and 
                 $_ -le ([Math]::Pow(2, 90))})] 
        [double[]]$ByteValue,
        
        [parameter(
                Mandatory=$false, 
                Position=1,
                ValueFromPipeline= $false
                
            )]
        [switch]$LongDescriptor,
        
        [parameter(
                Mandatory=$false, 
                Position=2,
                ValueFromPipeline= $false
                
            )]
            [ValidateRange(0,10)]
             [int]$Scale = 2
        
    )
    
    #2^10 = KB, 2^20 = MB, 2^30=GB...
    begin
    {
        if($LongDescriptor)
        {
            Write-Verbose "LongDescriptor specified, using longer names."
            $ByteDescriptors = ("Bytes", "KiloBytes", "MegaBytes", "GigaBytes", 
                "TeraBytes", "PetaBytes", "ExaBytes", "ZettaBytes", 
                "YottaBytes", "WheredYouGetThatMuchStorageBytes")
        }
        else
        {
            Write-Verbose "LongDescriptor not specified, using short names."
            $ByteDescriptors = ("B", "KB", "MB", "GB", "TB", "PB", 
                "EB", "ZB", "YB", "WYGTMSB")
        }
    }
    
    process
    {
        foreach($byte in $ByteValue)
        {
            #Determine which power of 2 this value is based from
            Write-Verbose "Determine which power of 2 the byte is based from."
            $PowerOfTwo = [Math]::Floor([Math]::Log($byte)/[Math]::Log(2))
            
            #Determine position in descriptor array for the text value
            Write-Verbose "Determine position in descriptor array."
            $DescriptorID = [Math]::Floor($PowerOfTwo/10)

            #Determine appropriate number by rolling back up through powers of 2
            #format number with appropriate descriptor
            Write-Verbose ("Return the appropriate number with appropriate "+
                "scale and appropriate desciptor back to caller.")
                
            Write-Output ("{0:N$Scale} $($ByteDescriptors[$DescriptorID])" -f (
                $byte / [Math]::Pow(2, ($DescriptorID*10))))
            
        }
    }
}

Thursday, April 12, 2012

PowerShell and T-SQL: Implementing UNION, INTERSECT, and EXCEPT



I’ve been thoroughly enjoying my experience this year with the Scripting Games. This is the first year I've competed and I decided to participate in the Advanced category just to push myself a little harder. I’ve been using Powershell for quite some time, however, I’ve never had the pleasure of using the platform while performing the duty of a Windows administrator. Those days were all about .bat and .vbs files. It’s been a real treat to be able to get my hands dirty with some of the cmdlets and functionality of Powershell that I have yet to use.

On a couple of events, I’ve found good use of some of my T-SQL set based thinking. Most database geeks understand that the database is designed to work in sets. However, PowerShell, similar to its scripting roots, is designed to think iteratively. However, there are times when understanding how different sets of data compare with each other could be a handy concept to understand. I’m going to spend some time on some very cool operators in T-SQL and show how this same concept can be implemented in PowerShell using arrays of objects.

The T-SQL operators UNION, INTERSECT, and EXCEPT and the Compare-Object cmdlet all operate on entire sets of data. We just came out of Easter, so I encourage you to forget about data for a moment – I know, it’s hard for me too – and think of two baskets of jelly beans.

In your left basket, you have seven jelly beans, one for each color of the rainbow (ROY G BIV). On your right side, your over-sugared children have eaten ROY, leaving you with G BIV and a half eaten Peep. In the middle, we have at this moment an empty basket.

Before we start moving jelly beans around, here are some initial set ups for the T-SQL and PowerShell discussions:

T-SQL:
CREATE TABLE LeftBasket
    (
     ID INT NOT NULL,
     Candy VARCHAR(10) NOT NULL
    )

CREATE TABLE RightBasket
    (
     ID INT NOT NULL,
     Candy VARCHAR(10) NOT NULL
    )

GO
INSERT  INTO LeftBasket
        (ID, Candy)
VALUES
        (1, 'Red'),
        (2, 'Orange'),
        (3, 'Yellow'),
        (4, 'Green'),
        (5, 'Blue'),
        (6, 'Indigo'),
        (7, 'Violet')

INSERT  INTO RightBasket
        (ID, Candy)
VALUES
        (4, 'Green'),
        (5, 'Blue'),
        (6, 'Indigo'),
        (7, 'Violet'),
        (8, 'Peep')

PowerShell:

$LeftBasket = ("Red", "Orange", "Yellow", "Green", "Blue", "Indigo", "Violet")
$RightBasket = ("Green", "Blue", "Indigo", "Violet", "Peep")

UNION

The UNION operator is like taking the ROY G BIV from the left basket, the peep from the right basket, and tossing the G BIV from the right basket across the room because you can’t look at any more jelly beans. UNION will give you the distinct results of the combination of the two baskets of jelly beans. In reality, it doesn’t really toss those from the right, but it made sense in the analogy. You end up with 7 jelly beans and a peep in your middle basket.

This can be represented in T-SQL with the following query (based upon the set up mentioned earlier:
SELECT ID, Candy FROM LeftBasket
UNION
SELECT ID, Candy FROM RightBasket
ORDER BY ID

In PowerShell, we can also represent this same concept using Compare-Object
Compare-Object -ReferenceObject $LeftBasket -DifferenceObject $RightBasket ` 
 -IncludeEqual

The important point of the above command is the –IncludeEqual switch. This switch modifies the behavior of Compare-Object to not just show differences, but to show you all of the values that are the same as well. The results are identical to the UNION operator in T-SQL.

UNION ALL

UNION ALL has a similar function as UNION, but it doesn’t take the time to determine which to throw out and just dumps all the candy in the middle basket. You end up with 11 jelly beans (ROY GG BB II VV) and a peep in your middle basket.

T-SQL:
SELECT ID, Candy FROM LeftBasket
UNION ALL
SELECT ID, Candy FROM RightBasket
ORDER BY ID

PowerShell:
Write-Output ($LeftBasket,$RightBasket)

You’ll notice that I did not use the Compare-Object for the UNION ALL equivalent. This is because no combination of switches for the Compare-Object will show you duplicates. Since all we really want is just the combination of the two string arrays, we can combine them and replicate the results of UNION ALL.

INTERSECT

If you apply the INTERSECT operator to your baskets of jelly beans, you end up with only four jelly beans (G BIV) in the middle. This is because INTERSECT represents the jelly beans that are in common in both baskets. Anything unique on either side is tossed out.

T-SQL:
SELECT ID, Candy FROM LeftBasket
INTERSECT
SELECT ID, Candy FROM RightBasket
ORDER BY ID

PowerShell:
Compare-Object -ReferenceObject $LeftBasket -DifferenceObject $RightBasket `
 -IncludeEqual -ExcludeDifferent

You’ll notice in the PowerShell command that there are two optional switches. We implement the –ExcludeDifferent and the –IncludeEqual switches to make the output not include differences and include any matches. We get only the matched items of the arrays.

EXCEPT

Finally, EXCEPT. This one will take any jelly beans on the left side that do not exist on the right side and put them in your middle basket. In this case, you would have ROY.

T-SQL:
SELECT ID, Candy FROM LeftBasket
EXCEPT
SELECT ID, Candy FROM RightBasket
ORDER BY ID

Powershell:
Compare-Object -ReferenceObject $LeftBasket -DifferenceObject $RightBasket | 
 Where-Object{$_.SideIndicator -eq "<="}

In this PowerShell command, I am adding no switches. Compare-Object is working with default behavior. However, in order to get only those items that exist on the left, we have to implement the Where-Object in the pipeline to get only those that exist on the left and not on the right.

Now, the coolest part about EXCEPT is that if you swap the baskets, you end up with different results. Starting from the right basket, you would end up with nothing more than a peep because all of the jelly beans on the right exist in the set of jelly beans on the left.

T-SQL:
SELECT ID, Candy FROM RightBasket
EXCEPT
SELECT ID, Candy FROM LeftBasket
ORDER BY ID

PowerShell:
Compare-Object -ReferenceObject $RightBasket -DifferenceObject $LeftBasket | 
 Where-Object{$_.SideIndicator -eq "<="}

Ok, if you’re not ready to throw up from all the sugar yet, there is a small gotcha with Compare-Object . If you did a Get-Help on this cmdlet, you may have noticed the –SyncWindow parameter. This parameter tells PowerShell how many array objects in either direction to look for similarities. In PowerShell 1.0, this was a default of 5. This meant that if your two arrays were not ordered by the same property and you had the same object stored more than five items away, you could end up with inaccurate results. Fortunately, in PowerShell 2.0, they have modified this default to [Int32]::MaxValue – so we should be covered.


About Kyle Neier
Husband of a magnificent woman, father of 5, SQL Server geek, IndyPASS Vice President and Food Guy, DBA automation zealot, amateur Powershell evangelist. Follow Me on Twitter

Tuesday, April 10, 2012

T-SQL Tuesday #029 – SQL 2012 and Treating TempDB like it’s really Temporary.


A while back, my young son thought it would be fun to use a CD as a virtual surfboard on our kitchen floor. While he was a very proud boy, all I could think of was how much that CD cost and how unlikely it was that we were going to ever be able to listen to it again.

As my kids got older, I found significant value in exercising my right to make a copy my children’s CDs for personal use. It became part of the process of buying a new CD to copy it and put the original in a safe place – far away from little hands. If the CD copy gets scratched or otherwise destroyed, it is as simple as pulling out the original and making another copy.

We use these copies extensively and, while we encourage treating them properly, life happens. They get left outside, in the car, under the couch, you get the picture. Similarly, we use TempDB extensively, and ever more so as more features of SQL Server use TempDB internally.

In SQL 2008R2 and older, TempDB had to be on a shared disk when implementing SQL Server in a cluster.

This may not seem like a big deal, but think back to the CD analogy. Our user databases are like the original CDs. We need to keep them protected and safe from the children. We keep the databases spread across redundant disks for the highest resiliency. We configure security to be certain that only those who are responsible enough can touch the databases. TempDB is like the copies. Anyone can use it and it gets used all the time by both users and by the system. We have little concern and generally little control over how TempDB gets used.

With the shared disk requirement for TempDB, we have to treat our CD copies in a similar fashion as the originals (the user databases). The data is redundantly protected and, in several cases, spread across the same disks as the user data. Getting the performance necessary out of TempDB in some cases was difficult.

In SQL 2012, this has been changed. A very useful feature of SQL 2012 is the ability to put TempDB on a local disk, even when implementing SQL Server on a cluster. This prevents the use of expensive SAN storage for something temporary and volatile. It also introduces the ability to significantly increase performance of some key functionality of SQL Server (Snapshot Isolation, sorts, hash, CheckDB, etc.) by opening up more high-performance options in the local box. SAN based SSD is possible for shared storage, however, enterprise class shared SSD is still incredibly expensive. Local SSD is not as cheap as spinning disk, but is cheaper, and in some cases, faster than SAN based SSD.

Moving TempDB local is not the ultimate solution for all environments and the significance of this feature may not be universal. However, it is another very useful tool in the DBA toolbox that has the potential to reduce the cost of and increase the performance of a SQL Server deployment.

Links to Microsoft concerning this new feature:
http://msdn.microsoft.com/en-us/library/bb500459%28v=SQL.110%29.aspx
http://msdn.microsoft.com/en-us/library/ms143506.aspx#storagetypes

About Kyle Neier
Husband of a magnificent woman, father of 5, SQL Server geek, IndyPASS Vice President and Food Guy, DBA automation zealot, amateur Powershell evangelist. Follow Me on Twitter

Tuesday, April 3, 2012

Powershell – Validating an IP Address

 

A task that I have had to do several times over the years is determine if an IP Address string entered from a prompt or imported from a file is indeed valid. Even more, determining if that IP Address is in use once verifying that the IP Address is well formed.

I’ve created the following Powershell function – Test-IPAddressString – to handle both of these tasks.

Either provide a single or several IP Address candidates to this function and it will return a $true if it is valid or a $false if it is not. As an added bonus, if you enable the –FailIfInUse swtich,the function will attempt to ping a valid IP Address. If the address responds to a ping, $false is returned.

function Test-IPAddressString
{
<#
        .SYNOPSIS
        Tests to see if an IP address string is a valid address and can determine
        if IP Address is responding on network.

        .DESCRIPTION
        Implements the .Net.IPAddress classes to validate that the string provided
        can parse into an IP Address. If the parse is successful, the function returns
        boolean $true unless the -FailIfInUse switch is provided.
        
        If -FailIfInUse is specified, a $true is only returned if the IP Address
        does not respond to a ping three times.

        This function supports the -Verbose switch as well.
        
        .PARAMETER IPaddressString
        This is a string value representing the address that you want to test.
        
        This value can be passed either from pipeline or as a parameter.
        
        .PARAMETER FailIfInUse 
        This is a switch parameter. Specifying this in the parameter list will
        cause the IP Address, if successfully parsed, to attempt to be pinged.
        
        A successful ping result will result in a $false value being returned
        if this switch is used.
        
        
        .EXAMPLE
        Test-IPAddressString -IPAddressString "192.168.1.1"
        
        Using full parameter name

        .EXAMPLE
        Test-IPAddressString "192.168.1.1" -FailIfInUse
        
        Using Positional parameters and specifiying to fail test if IP Address responds to ping.
        
        .EXAMPLE
        ("192.168.1.1", "192.123456", "IsThisAnIP") | Test-IPAddressString -Verbose
        
        Passing serveral potential IP Address strings to the function through the pipeline. 
        
        FailIfInUse is ommitted, so no ping attempts will be made on valid IP Addresses.
        
        This function supports the verbose switch. Using this switch will provide you with
        several indicators of progress through the process.
        
        .NOTES
        
        Author:    Kyle Neier
        Blog: http://sqldbamusings.blogspot.com
        Twitter: Kyle_Neier
        
        .LINK
        http://sqldbamusings.blogspot.com/2012/04/powershell-validating-ip-address.html
    #>

    param(
    [parameter(
            Mandatory=$true, 
            Position=0,
            ValueFromPipeline= $true
        )]
        [string]$IPaddressString,
    [parameter(
            Mandatory=$false, 
            Position=1,
            ValueFromPipeline= $false
        )]
        [switch]$FailIfInUse
    )

    process
    {
        [System.Net.IPAddress]$IPAddressObject = $null    
        if([System.Net.IPAddress]::tryparse($IPaddressString,[ref]$IPAddressObject) -and
             $IPaddressString -eq $IPAddressObject.tostring())
        {
            Write-Verbose "$IPaddressString successfully parsed."
            if($FailIfInUse -eq $true)
            {
                $Pinger = new-object System.Net.NetworkInformation.Ping
                $p = 1
                $p_max = 3
                do 
                {
                    Write-Verbose "Attempting to ping $IPaddressString - Attempt $p of $p_max"
                    $PingResult = $Pinger.Send("$IPaddressString")
                    Write-Verbose "Connection Result: $($PingResult.Status)"
                    $p++
                    Start-Sleep -Milliseconds 500

                } until ($PingResult.Status -eq "Success" -or $p -gt $p_max)

                if($PingResult.Status -eq "Success")
                {
                    Write-Verbose "The IP Address $IPAddressString parsed successfully but is responding to ping."
                    Write-Output $false
                }
                else
                {
                    Write-Verbose "The IP Address $IPAddressString parsed successfully and is not responding to ping."
                    Write-Output $true
                }
            }
            else
            {
                Write-Verbose "The IP Address $IPAddressString parsed successfull - No ping attempt made."
                Write-Output $true
            }
        
        }
        else
        {
            Write-Verbose "The IP Address $IPAddressString could not be parsed."
            Write-Output $false
        }
    }
}

About Kyle Neier
Husband of a magnificent woman, father of 5, SQL Server geek, IndyPASS Vice President and Food Guy, DBA automation zealot, amateur Powershell evangelist. Follow Me on Twitter