Best rack nuts I have ever used

Over the years I have installed and removed countless devices from various racks. Doing this immediately leads you to despise getting your hands cut up by trying to remove rack nuts that are too stiff or trying to remove them with a screw driver and stabbing your hand because you never happen to have that special little tool lying around when you need it.

 

After dealing with those issues I worked to find the best rack nuts on the market and for the last few years we have exclusively used StarTech.com rack nuts like those listed here.

 

These rack nuts are so easy to work with that whenever we move anything we always throw away whatever rack nuts were there and use these instead. They are plyable enough to be clipped in and out with your hands but strong enough to hold the heaviest UCS blade chasis in place without any issues. 

 

Sometimes its the little things in life that make things great and these rack nuts are a joy to work with for anyone who has ever had to struggle with inferior rack nuts before.Image

Restore database backup files in a folder to SQL server using PowerShell

Ever had a directory full of .bak files and need them all restored to a SQL server? Ever tried to find the solution to that problem through PowerShell instead of some narly looking VBscript on spiceworks?

If you said yes to either of these then the code below is for you. I will try to document more when/if I can but the code does what it says and handles logicial file names that are not the same as the database names and other common gotchas. I have tried to write this in such a way that it requires little or no stateful information and determines everything it needs from the backup data contained within the files and from the configuration parameters of the SQL instance itself.

function invoke-DatabaseRestore {
    param ([String]$SQLServer="(local)", $BackupPath, [String]$BackupFileFilter = "")
    #load assemblies
    [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SMO") | Out-Null
    [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SmoExtended") | Out-Null
    [Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.ConnectionInfo") | Out-Null
    [Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SmoEnum") | Out-Null
    
    gci $BackupPath -Filter $BackupFileFilter | select fullname | % {
        $backupFile = $_.FullName

        #we will query the database name from the backup header later
        $server = New-Object ( "Microsoft.SqlServer.Management.Smo.Server" ) $SQLServer
        $backupDevice = New-Object( "Microsoft.SqlServer.Management.Smo.BackupDeviceItem" ) ($backupFile, "File")
        $smoRestore = new-object( "Microsoft.SqlServer.Management.Smo.Restore" )
        $backupDevice| FL *

        #Get default log and data file locations http://sqlblog.com/blogs/allen_white/archive/2009/02/19/finding-your-default-file-locations-in-smo.aspx
        $DataPath = if ($server.Settings.DefaultFile.Length -gt 0 ) { $server.Settings.DefaultFile } else { $server.Information.MasterDBLogPath }
        $LogPath = if ($server.Settings.DefaultLog.Length -gt 0 ) { $server.Settings.DefaultLog } else { $server.Information.MasterDBLogPath }

        #restore settings
        $smoRestore.NoRecovery = $false;
        $smoRestore.ReplaceDatabase = $true;
        $smoRestore.Action = "Database"
        $smoRestore.PercentCompleteNotification = 10;
        $smoRestore.Devices.Add($backupDevice)
 
        #get database name from backup file
        $smoRestoreDetails = $smoRestore.ReadBackupHeader($server)
 
        #display database name
        "Database Name from Backup Header : " +$smoRestoreDetails.Rows[0]["DatabaseName"]
 
        #give a new database name
        $smoRestore.Database = $smoRestoreDetails.Rows[0]["DatabaseName"]

        #Relocate each file in the restore to the default directory
        $smoRestoreFiles = $smoRestore.ReadFileList($server)

        foreach ($File in $smoRestoreFiles) {
            #Create relocate file object so that we can restore the database to a different path
            $smoRestoreFile = New-Object( "Microsoft.SqlServer.Management.Smo.RelocateFile" )
 
            #the logical file names should be the logical filename stored in the backup media
            $smoRestoreFile.LogicalFileName = $File.LogicalName

            $smoRestoreFile.PhysicalFileName = $( if($File.Type -eq "L") {$LogPath} else {$DataPath} ) + "\" + [System.IO.Path]::GetFileName($File.PhysicalName)
            $smoRestore.RelocateFiles.Add($smoRestoreFile)
        }
        #restore database
        $smoRestore.SqlRestore($server)
 
    }
}

Find all files with NTFS Alternate Data Streams using PowerShell

  1. Open Powershell
  2. cd to the directory or the root of a drive where you want to recursively look for alternate data streams
  3. Run the following command (requires PowerShell V3)

gci -recurse | % { gi $_.FullName -stream * } | where stream -ne ':$Data'

To test that this works properly navigate to a random directory on your computer and run the following commands:

new-item test.txt -Type file
Add-Content test.txt "test content"
Add-Content test.txt -str HiddenStream "Hidden test content stored in the stream"
get-content .\test.txt
get-content test.txt -str HiddenStream

Now navigate to some folder above the directory where you ran these commands and run the command to find all files with alternate data streams and you should see our test.txt file come up.

For a more complete description of what you can do with NTFS Alternate Data Streams in PowerShell V3 please check out this blog post.

Tagged

SCVMM 2012 SP1 Error when adding clusters with decommissioned nodes

During our recent upgrade to System Center Virtual Machine Manager 2012 SP1 I hit an issue where I got this error when I tried to add two of the Hyper V Clusters in our environment back to SCVMM:

Image(3)

I confirmed that none of the reasons mentioned in the message were preventing us from adding these hosts and after doing a ipconfig /flushdns on the SCVMM server and then trying to add one of the clusters again I noticed that the SCVMM server was querying DNS for an ip for a host that was decommissioned but had not yet been evicted from the cluster.

This brought memories of hitting this issue in SCVMM 2008 R2 back to mind and I confirmed that both clusters that I was trying to add had a single node that was decommissioned but had not yet been evicted.

After evicting the decommissioned nodes I was able to properly add the clusters to SCVMM.

I am now blogging about this so that hopefully I and everyone else can remember that you will hit this issue in SCVMM 2008 R2, 2012, and 2012 SP1 if you try to add clusters to SCVMM that have nodes that are offline.

How to manage development against large databases

We use Dynamics NAV where I work and have a database that has grown to over 500 GB. Due to this, doing a database restore is a time consuming operation that should be avoided whenever possible. Due to the nature of the application it does not work well to have multiple developers in the same database which means we need to have a DB for each developer as well as for our test and stage environments.

The easiest way to accomplish this is through the wonders of virtualization and specifically differencing disks. The basic workflow is this:

  • Create a virtual machine using Hyper V that has a base OS and SQL versions installed for the data your working with and two drives, one for the OS and the other one completely balank
  • Restore the database you need to provide to multiple developers to the secondary drive that does not contain an operating system
  • After the restore, detach the database and shutdown the virtual machine
  • Rename the second vhd with the data and log files on it to _parent.vhd
  • Set the parent vhd to be read only
  • Move the parent vhd to some location where you have the space to store this large restore and where you can provide read access to it via a unc path like \\MyServer\Share\_parent.vhd
  • Open Hyper V manager and create a new differencing disk pointing to the parent vhd through the unc path created earlier
  • Now provide a copy of this vhd to every individual who needs to have their own copy of this data set.

That’s it. If you have developers that need to have a local copy of the data accessible from their laptops now they can simply attach the vhd using disk manager in Windows 7 or 8 and use the data however they like. If your providing a copy of the data to a staging environment that is a virtual machine simply shut down the vm and attach a copy of the child vhd as a new disk.

This process is made even better if you have windows server 2012 as the file server where your parent is stored and either 2012 or windows 8 clients pulling the data as cifs 3 really makes the performance of this solution even better than it has been.

There are many variations on this theme that you can use (snapshots of source data exposed via iscsi directly from your San, keeping the parent and child vhds on the same storage so that you can get better performance, keeping the parent and child vhds on the same disks and then attaching the child vhds to the host file server os and then creating separate shares of the data inside each child vhd so that remote SQL servers can simply attach the data and log files directly has unc paths without any knowledge of the vhd system behind it, etc.) but by using differencing vhds you can worse it more manageable to deal with many copies of a large data set while still keeping cost low.

Tagged ,

Clean up Active Directory Computers and Users with stock PowerShell

Here two commands that will quickly help you delete computers and users from active directory that havn’t logged on for over a month.

For computers use:

Get-ADComputer -properties LastLogonDate -filter * | where LastLogonDate -LT (get-date).AddDays(-30) | Remove-ADObject -Recursive

For users use:

Get-ADUser -properties LastLogonDate -filter * | where LastLogonDate -LT (get-date).AddDays(-30) | Remove-ADObject -Recursive

Both commands will prompt you before deleting the object so that you can sanity check each deletion before it occurs and if your unsure simply choose not to delete that object.

It’s quick, easy, and if you simply delete the things your sure you can delete you will likely be leaps ahead of where you started.

Tagged ,

Get-Member lies

Get-Member lies.

Let me show you.

Here are some arrays:

$Array = @()
$Array2 = 1,2
$Array3 = "Thing1","Thing2"

Here is what GM says about these arrays:

PS H:\> $Array | GM
GM : No object has been specified to the get-member cmdlet.
At line:1 char:10
+ $Array | GM
+          ~~
+ CategoryInfo          : CloseError: (:) [Get-Member], InvalidOperationException
+ FullyQualifiedErrorId : NoObjectInGetMember,Microsoft.PowerShell.Commands.GetMemberCommand

PS H:\> $Array2 | GM


TypeName: System.Int32

Name        MemberType Definition
----        ---------- ----------
CompareTo   Method     int CompareTo(System.Object value), int CompareTo(int value), int

…


PS H:\> $Array3 | GM


TypeName: System.String

Name             MemberType            Definition
----             ----------            ----------
Clone            Method                System.Object Clone(), System.Object ICloneable.Clone()
CompareTo        Method                int CompareTo(System.Object value), int CompareTo(string strB), int IComparab...

…

LIES, ALL LIES!

Here is how you force GM to tell you the truth, we use , . That is right ,, this small period that grew a tail is the truth serum to your filthy lying GM problems.

Let me demonstrate:

PS H:\> ,$Array|GM


TypeName: System.Object[]

…

PS H:\> ,$Array2|GM


TypeName: System.Object[]

…

PS H:\> ,$Array3|GM


TypeName: System.Object[]

…

Now we can clearly see the true type of the object and the methods that are available to us.

Thanks goes out to Marco Shaw for providing this solution here,

Update 2013-02-12:

If you open powershell and run get-help about_array, then navigate down to the heading GET THE MEMBERS OF AN ARRAY you will find the following:

GET THE MEMBERS OF AN ARRAY

To get the properties and methods of an array, such as the Length
property and the SetValue method, use the InputObject parameter of the
Get-Member cmdlet.

When you pipe an array to Get-Member, Windows PowerShell sends the items
one at a time and Get-Member returns the type of each item
in the array (ignoring duplicates).

When you use the InputObject parameter, Get-Member returns the
members of the array.

For example, the following command gets the members of the array in the
$a variable.

Get-Member -InputObject $a

You can also get the members of an array by typing a comma (,) before
the value that is piped to the Get-Member cmdlet. The comma makes the
array the second item in an array of arrays. Windows PowerShell pipes
the arrays one at a time and Get-Member returns the members of the array.

,$a | Get-Member

,(1,2,3) | Get-Member

There you have it, the comma forces PowerShell to dynamically create an array of array’s and then get-member gets the type of the arrays within the array thereby giving us the actual properties of the array we are interested in.

Tagged

How to Fix Evernote’s Capture of ALT+PrintScreen

I am an avid fan of Evernote and use it combined with a fujitsu ScanSnap S1500, an iPhone, and an iPad as my GTD reference system.

Recently with the release of the new version of Evernote that tightly integrates with the windows version of Skitch they introduced a bug talked about in their forums here that captures the ALT+PrintScreen key combination used to launch Skitch without providing you any way through the UI to change that shortcut.

The solution to this issue was provided by Scott (thanks Scott!) which requires setting a registry key and restarting Evernote (including the clipper that sits in your tray by the clock).

Here is a quick one liner in PowerShell that will get this set for you so that you can return to use whatever screen shot tool fits your needs best:

set-itemproperty -Path HKCU:\Software\Evernote\Evernote -Name HotkeyCreateNewSkitchNote -Value 0

You can use the following to validate that the value is now set to 0 from the default (300):

get-itemproperty -Path HKCU:\Software\Evernote\Evernote -Name HotkeyCreateNewSkitchNote

Tagged

Mobile home office

Ergonomic laptop stand, Georgia Tech Tervis, and exercise ball seating. Perfect remote office :-) .

20120827-164625.jpg

How to copy a function in Dynamics NAV C/Side

From the Functions list right click on the bar to the right and click copy, select a new blank line, and click paste.

I know, dead simple right? Some times it helps to have these things out there as it’s easy to miss that this is possible in C/Side.

Tagged , ,
Follow

Get every new post delivered to your Inbox.