December 2010 - Posts

Probably one of the first scripts any new Windows PowerShell user writes is a custom profile. Your PowerShell profile ($profile in PowerShell speak), is run every time you open a PowerShell window, and it allows you to do a lot of different things to set up your environment the way you want it. Actually, though, there are four profiles that affect your PowerShell window, as described in this MSDN article. There are arguments for which profile you should be editing, but my personal preference is to use the most specific one:

%UserProfile%\My Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1

The only problem is, that’s not really were “My Documents” is for me. So, how to be sure you always work on the right one, wherever it’s located? Easy – let PowerShell tell you!

First, let’s see if we have a $profile yet:

PS1> Test-Path $profile
False

Nope. So, how to make one. First, let’s create the path:

PS1> mkdir (Split-Path $profile)

    Directory: C:\Users\cpr\Documents


Mode                LastWriteTime     Length Name
----                -------------     ------ ----
d----        12/22/2010  12:05 PM            WindowsPowerShell

Now, use your favourite plain text editor to create the file. In my case that would be:

PS1> gvim $profile

And here you can start to build your customizations for PowerShell. There are lots of possibilities, including changing the colouring, updating the title bar, creating aliases and functions that are always available. Really the possibilities are nearly endless.

In my own case, I like to distinguish between a regular window and an elevated one, so I change the colour of all my regular PowerShell windows to white with dark blue text (works better for screen shots), and my elevated windows to dark red with white text. I also use a multiline prompt, and do some other customizations.

Here’s my full $profile:

# This is Charlie's custom PS Profile...
#
# ModHist: 26/05/2007 - Initial
#        : 08/06/2007 - Added clear-host and winzip alias
#        : 10/06/2007 - Changed OS detection
#        : 22/07/2007 - support for running from local home
#        : 14/03/2008 - changed to Microsoft.PowerShell_profile.ps1 and fixed Server 2008 switch statement
#        : 16/03/2008 - added productID test for Vista
#        : 24/03/2009 - added mapdrives for admin shell
#        : 17/10/2010 - minor cleanup before sending to VanTUG
#
#***************************************************************************
#

# Get the name of this version...
$CallingProfile = $myInvocation.mycommand.path
$FileRegEx = "(?<name>.*)(?<dot>\.)(?<extension>[pP][sS]1)"
$CallingProfile -match $FileRegEx

# Find out who we are...
$id = [System.Security.Principal.WindowsIdentity]::GetCurrent()
$p = New-Object system.security.principal.windowsprincipal($id)

# Get System WMI info -- Get it once, use it multiple
$SysWMI =  Get-WmiObject Win32_OperatingSystem
$hostname = $(hostname).tolower()
$otherway = ($ENV:computername).tolower()

$ProductID=(get-item 'HKLM:/Software/Microsoft/Windows NT/CurrentVersion').getvalue('ProductID')

# Build a hashtable with information about versions, etc.
$SystemHash = @{}  # Initialize the variable as a hashtable
$SystemHash["Build"] = $SysWMI.BuildNumber
$SystemHash["SPNumber"] = $SysWMI.CSDVersion
$SystemHash["Caption"] = $SysWMI.Caption
$SystemHash["SKU"] = $SysWMI.OperatingSystemSKU
$SystemHash["Architecture"] = $SysWMI.OSArchitecture
$SystemHash["Hostname"] = $SysWMI.CSName.ToLower()
#$SystemHash["Arch"] = $ENV:Processor_Architecture # redundant, already getting from WMI

# We’ll need the build number to persist in the environment
$Build = $SystemHash["Build"]

switch -regex ($SystemHash["Build"]) {
   2600 { $ver="XP" }
   3790 { if ($SystemHash["Caption"] -match "XP") {
            $ver = "XPx64"
         } else {
            $ver = "Server 2003"
         }
   }
   6000 { $ver="Vista" }
   6001 { if ($SystemHash["Caption"] -match "Vista" ) {
            $ver="Vista"
         } else {
            $ver="Server 2008"
         }
   }
   7600 { if ($SystemHash["Caption"] -match "Windows 7" ) {
      $ver="Windows 7"
      } else {
      $ver="Server 2008 R2"
      }
   }
   7601 { if ($SystemHash["Caption"] -match "Windows 7" ) {
      $ver="Windows 7 SP1"
      } else {
      $ver="Server 2008 R2 SP1"
      }
   }
}

if ($SystemHash["Arch"] -eq "AMD64" ) {
   $64bit=$true
   $32bit=$false
} else
{
   $64bit=$false
   $32bit=$true
}

# Find out if we're running as admin (IsInRole)
# if we are, change the window colour and set effectivename variable
# But only on Windows Vista or Longhorn Server
if ($p.IsInRole([System.Security.Principal.WindowsBuiltInRole]::Administrator) -and ( $build -ge 6000 )) {
      $effectivename = "Administrator"
      $host.UI.RawUI.Backgroundcolor="DarkRed"
      $host.UI.RawUI.Foregroundcolor="White"
      clear-host
      $maps='C:\Windows\system32\mapdrives.cmd'  #cmd file to map standard drives
      if (Test-Path $maps) {& $maps }
   } else {
      $effectivename = $id.name
      $host.UI.RawUI.Backgroundcolor="White"
      $host.UI.RawUI.Foregroundcolor="DarkBlue"
      clear-host
}

$host.ui.rawui.WindowTitle = $effectivename + "@" + $HostName +" >"
function global:prompt {
   if ( $effectivename -eq "Administrator" ) {
      write-host ("[") -nonewline -foregroundcolor red
      write-host ($Hostname) -nonewline -foregroundcolor Magenta
      write-host ("]") -nonewline -foregroundcolor Red
      Write-Host ([string]$(get-location) +":") -foregroundcolor Green
      write-host ("PSH>" ) -nonewline -foregroundcolor White
    } else {
      write-host ("[") -nonewline -foregroundcolor red
      write-host ($Hostname) -nonewline -ForegroundColor Magenta
      write-host ("]") -nonewline -foregroundcolor Red
      Write-Host ([string]$(get-location) + '> ') -ForegroundColor DarkGreen
      write-host ("PSH>" ) -nonewline -foregroundcolor DarkBlue
    }
   return " "
}

# function to elevate a command. Finally.
function sudo ([string]$file, [string]$arguments) {
    $psi = new-object System.Diagnostics.ProcessStartInfo $file;
    $psi.Arguments = $arguments;
    $psi.Verb = "runas";
    $psi.WorkingDirectory = get-location;
    [System.Diagnostics.Process]::Start($psi);
}

# Now, a function to edit the executable script without knowing where it is.
function fvi
{
   param($script )
   $s = (get-command -ea silentlycontinue $script).definition
   if ( $s ) { gvim $s }
   else { "$script not found" }
}

# Update the path to make life easier, and add a function while we're at it...
$ENV:Path="$ENV:PATH;" + "U:\psbin;" + "$ENV:HOMEDRIVE" + "$ENV:HOMEPATH" + "\psbin"
function path {
   write-host $env:path
}

# Now, start to build some aliases. These may be machine specific, so be careful...

if ($64bit) {
set-alias winzip -value "C:\Program Files (x86)\WinZip\WinZip32.exe"
set-alias word -value "C:\Program Files (x86)\Microsoft Office\Office14\WinWord.exe"
set-alias excel -value "C:\Program Files (x86)\Microsoft Office\Office14\Excel.exe"
set-alias OneNote -value "C:\Program Files (x86)\Microsoft Office\Office14\OneNote.exe"
set-alias Visio -value "& mstsc C:\Program Files (x86)\RemotePackages\Visio_2010.rdp"
set-alias hyperv -value "C:\Program Files\Hyper-V\virtmgmt.msc"
set-alias vm -value "C:\Program Files\Hyper-V\vmconnect.exe"
} else {
set-alias winzip -value "C:\Program Files\WinZip\WinZip32.exe"
set-alias word -value "C:\Program Files\Microsoft Office\Office14\WinWord.exe"
set-alias excel -value "C:\Program Files\Microsoft Office\Office14\Excel.exe"
set-alias OneNote -value "C:\Program Files\Microsoft Office\Office14\OneNote.exe"
set-alias Visio -value "& mstsc C:\Program Files\RemotePackages\Visio_2010.rdp"
}

set-alias edit -value "C:\Windows\gvim.bat"
set-alias vi -value "C:\windows\gvim.bat"

# set-alias ping test-connection # disabled. More annoying than useful

# The following is useful if you have automatic startup PowerShell windows...
if ( $effectivename -ne "Administrator" ) {
   cd $home
}

There, that’s complicated enough for most uses. :-) But hopefully you’ll find some useful stuff in this that you can use for your own $profile.

 

Charlie.

Posted by Charlie Russel

As I reported earlier, my HP ML350 G5 died, and it was clearly a motherboard failure. Now that was bad enough, but worse was that I had VHD files on the P400 RAID5 array that were not as recently backed up as was desirable. Given that the ML350 wouldn’t boot at all, how to recover the important information on the array?

Well, thanks to a suggestion from Greg Starks, a friend at HP, I was able to completely and easily recover all the content of that array. The key requirement was to have a second machine that supported a similar HP RAID controller. And, by the way, it looks highly probable that the original RAID controller will be usable in a non-HP machine. But I digress.

I have an HP DL160SE G6 rack mount server here as well. Now it has a similar, though not identical, RAID controller built in to the motherboard. So, here’s what I did to get the files off the RAID array from the failed server:

  1. Built a USB pen drive with a bootable Windows Server 2008 R2 installation image on it. (The DL160SE doesn’t have an optical drive in it at all.)
  2. Removed each of the drives from the failed server, carefully marking each one with a piece of masking tape so I knew which slot they came out of.
  3. Removed each of the drives from the DL160, again marking the drives carefully with masking tape.
  4. Plugged the drives from the failed server in the exact same order and slot number. (These were all 2.5” SFF SAS drives, though the procedure is the same regardless.)
  5. Booted from the USB pen drive, and also plugged in a 1 TB external USB drive.
  6. Selected Recover at the initial boot screen for the Server 2008 R2 setup. This allowed me to get to a command prompt.
  7. At the command prompt, used
      RoboCopy <sourcedrive> <targetUSBdrive> /mir
    to copy the contents of the failed array onto the external USB drive. (Be patient, USB2 is slow.)
  8. Shutdown the HP160, and returned the original drives into their original slots. Removed all USB drives from the HP160 and booted normally.

Now, I had all the data files from the failed server on my 1TB USB disk, and I can put them anywhere.

What’s important to understand about this procedure is that it worked even though my array didn’t have any boot information on it. By making a boot USB stick, I could boot to that and suck off the files. And because the HP P400 RAID array drivers are built in to the Windows Server 2008 R2 installation image, the whole thing was completely painless and transparent.

The other thing I can’t stress enough. MARK EACH DRIVE as soon as you remove it from the array. All the information to use the array is on the drives, but if you screw up the disk order, no promises this will work, in fact it’s a good bet it will not.

I hope this helps someone else who is in the middle of a panic. A failed server is never fun, but this turned out to be a lot less pain than I initially feared.

Charlie.

Posted by Charlie Russel

Well, we seem to have had a bunch of HP related posts lately. This one is pure bad news, however. HP has decided to stop supporting Windows Home server. As reported on WeGotServed.com, HP has stopped selling or developing any servers for the WHS market, effective immediately. HP, of course, claims this has nothing whatsoever to do with the announcement from Microsoft that they were abandoning Drive Extender in the next version of Windows Home Server, code-named Vail. Yup, sure. I believe that.

So where does this leave my little MicroServer? I’m not really sure. But since HP hasn’t announced anything about Windows Storage Server 2008 R2 Essentials, or Windows Small Business Server 2011 Essentials (aka, Aurora), I’m hopeful that they will continue to support those of us who think that small, inexpensive, well-designed, and well-built servers have a place in the SMB market.

Charlie.

Posted by Charlie Russel