PowerShell Cookbook

Search

Categories

 

On this page

Solo Long Cross-Country
PowerShell 'Suggestion Mode'
Admins, Developers, and Constructive Feedback
Pain is Temporary
Client-free PowerShell Remoting - a Live Mesh Command Line
Workaround: The OS handle's position is not what FileStream expected
PowerShell Execution Policies in Standard Images
First Solo – and a Ripped Shirt to Prove It
Importing and Exporting Credentials in PowerShell
Flight Training, Episode 2

Archive

Blogroll

Disclaimer
I work for Microsoft.

The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

RSS 2.0 | Atom 1.0 | CDF

Send mail to the author(s) E-mail

Total Posts: 222
This Year: 0
This Month: 0
This Week: 0
Comments: 536

Sign In

 Tuesday, September 09, 2008
Tuesday, September 09, 2008 7:11:22 AM (Pacific Daylight Time, UTC-07:00) ( )

One of the biggest accomplishments in getting your private pilot's license is the "Solo Long Cross-Country." It marks the home-stretch of a lot of training, practice maneuvres, landing drills, and solo flights of increasing complexity.

This flight is where it all comes together: 150 nautical miles total, landing at a minimum of 3 airports, with one leg at least 50 nautical miles.

I planned this flight as a tour of the San Juans and airports I have never been. It took me from Renton (RNT,) to Skagit Regional (BVS,) through Orcas Island (ORS,) Friday Harbor (FHR,) Sequim Valley (W28,) and then finally back to Renton.

image

Cross-country flights all begin with flight planning, and plenty of it.

Once you've drawn your intended route on the sectional chart (making sure to avoid those pesky restricted areas and military operation areas,) you identify (and plan for) checkpoints that fall every 30 miles or so. For each leg of your journey, you calculate the true direction and distance between each checkpoint. You factor in the magnetic deviation for the area (roughly -18 degrees for most of Western Washington,) and then account for the current atmospheric winds. This gives you a magnetic heading by which you can navigate. Add in the distances and estimated ground speed, and you get a navigation method known as "Dead Reckoning."

Dead Reckoning isn't usually the primary form of navigation, however. The modern aviation world is filled with navigation beacons that help you travel along specific paths from beacon to beacon. These are known as VOR Radials. During your preparations, you identify helpful VOR radials and frequencies, and then account for them in your flight plan.

Finally, you research the airports you plan to land at (and some that you don't) for the communication frequencies, runway information, and traffic patterns. Once you've done all that, a completed flight plan looks something like this:

solo_long_xc_flightplan

I had originally planned to leave at 9:00 AM on Saturday, but low clouds kept me hampered in for the better part of the morning. Even once the clouds had lifted at Renton, the Orcas Islands were still covered by fairly low cloud.

Once the clouds finally lifted, I departed to the north. I had originally planned use one of Paine Field's VOR radials for much of my journey, but fly over their airspace as to not interfere with traffic there. Clouds kept me below the 4500 feet that I would have needed, so I called Paine Field and got clearance to transition over the field. I followed the radial to Skagit Regional airport, notched up my first landing of the day, and checked off the requirement for a leg of 50+ nautical miles.

image

The next checkpoint was Orcas Island. I had originally planned to enter the airport from the north of the island, but the weather favoured a northerly landing. I circled, and instead entered the harbour from the south -- easily the prettiest approach of the day.

image

P1010092 P1010096

The landing went smoothly, so I departed and headed to my next destination. Here's a picture of the Orcas Island airport as you leave:

P1010097

The next landing was at Friday Harbor, a runway I had heard was slightly challenging due to its slope. It proved to be uneventful, so I parked in transient parking and made my way down to the harbour for lunch.

image P1010099

I found a great place right on the harbour -- Downriggers -- and enjoyed an awesome grilled crab and cheese sandwitch. It was also the most expensive meal I had ever had. The bill wasn't so bad, but the commute sure was a killer :)

P1010106 P1010100 P1010104

After leaving Friday Harbor, I climbed to 5,500 ft to fly across the largest span of the journey. Climbing to 5,500 feet gives a glide distance of about 15 nautical miles -- enough to safely make it back to shore should the engine fail part-way.

Once I found Sequim, I got to enjoy my most challenging landing ever. Sequim Valley airport is 40 feet wide, much thinner than the 100-150 feet most regional airports offer. My initial pass at the traffic pattern was much too tight, so I spaced myself again and landed well on the second attempt.

image

After a short-field takeoff from Sequim Valley, I hugged the coast to avoid a small chunk of prohibited airspace over the Navy's submarine base at Bangor, Washington. I followed that path until I hit my planned VOR radial for the SeaTac airport, and followed that toward Vashon Island.

image

As you approach Vashon Island, SeaTac airport becomes quickly evident, as does downtown Seattle.

P1010111P1010112 

P1010113

In the left picture, Seattle's Control Tower is about 25% from the left of the picture, about half-way down. Seattle's runways are nearly perpendicular to you at this point.

As you approach Vashon, you contact Seattle Tower to request a transition across their airspace. Transition across this class of airspace is much more restrictive, since it handles such heavy traffic. They give you an exact altitude to fly (usually 1500 feet,) and ask you to cross over the approach-end of the runway. As you cross the runways, you'll continue to see large commercial jets land below you. Since they are landing, you still have 1/4 mile of vertical separation between you. A typical crossing looks like this. It's amazing how simple and clean it looks when you're not battling lineups, security, and crowds.

P1010114

After crossing the Seattle airspace, you get told to head toward downtown Kent. After a short while, they release you from their radar service, and it's back to landing at Renton. At the end of a 4-hour flight, I had no clue what was in store for me.

image

After transitioning through the SeaTac airspace and getting to downtown Kent, I called Renton with my intention to land. They told me to come straight-in for runway 33 (basically North,) and that I was clear to land. They asked me to report when I was 2 miles from the end of the runway. As I reported, they said that I was #3, clear to land. I had not heard anybody else talking with the tower or being cleared to land, so I clarified "#3 clear to land?" A second controller corrected that I was #2 clear to land. Still not a surprise you want to get on your final approach. They told me I had traffic at 12:00 on (obviously short) final approach, which I found.

At this point, I’m making the final adjustments, adding the final notch of flaps, watching airspeed, and we’re about 1 mile out.

As I get closer, the traffic ahead of me still hasn’t landed, and still hasn’t started rolling down the runway. In fact, they appear to be stationary on the end of the runway, and at this point I thought I might have lost the original traffic and was instead watching somebody who had stumbled onto the runway in the midst of an incursion. After reflection, I now think that we were on exactly the same glide-slope – causing little-to-no relative movement between us.

As I was now about ½ mile from the threshold (later confirmed by my GPS log,) this was much too close for comfort. I told the tower that we were too close, and started to make a tight spacing turn. The tower got upset, and said that they only had to give 3500 feet of spacing (although ½ mile is 2600 feet by my calculations.) He had somebody on downwind (parallel the runway, about 1 mile east of it, heading toward me) make a left turn for safety, as I did the same. We both saw each other, and fortunately had plenty of room between us. My diversion to the right, and the left turn after that are the first crags in the bottom part of the graphic below:

image

He then told me to not turn at all, and started to lose control as I complied. These directions left me heading toward the right, so he finally yelled, "What do YOU want to do?" to which I said that I would be doing a "go around" toward the east channel (the upper-right body of water.) After doing that, I entered the traffic pattern like usual (the loop right, and downward,) and then landed uneventfully.

All-in-all, several errors compounded themselves, but it seems to have started with ATC trying to sequence traffic too tightly together. My initial reaction to do a clearing turn was was stupid of me, and was my first Pilot Error. I have no qualms about the decision I made, but do regret the way I decided to do it. I should have just done a go-around – a spacing turn toward the downwind-final direction was dangerous, and easily could have caused problems.

I completed my landing, post-flight checklists, and headed back to base -- completing a huge milestone in my flying journey. Over the next few weeks, I'll be studying like crazy to prepare for the knowledge test and oral grilling that the official flight examiner will give me. Once I feel ready, I'll complete the last 5-or-so hours of practical flying practice and go for my official check ride!

Comments [2] | | # 
 Monday, September 08, 2008
Monday, September 08, 2008 8:48:59 PM (Pacific Daylight Time, UTC-07:00) ( )

One bit of feedback we frequently get is that PowerShell's learning curve has some steeper bumps than we would like. Or simply, is strongly affected by habits learned from other languages or shells.

Interestingly enough, many of these problems aren't new to us -- we just don't have a good way (aside from help) of exposing them to the user. This was something I touched on in the footnotes of a blog in 2005, and started implementing personally shortly after that. Here's an example of its output:

[C:\temp]
PS:14 > "c:\temp\has space\test.ps1"
c:\temp\has space\test.ps1

Suggestion: Did you mean to run the command in quotes?  If so, try using & "<command>"

The core of this is implemented by a script, Get-TrainingSuggestion.ps1. It retrieves the last item from your history, and runs a bunch of regular expression comparisons against it. If it finds a match in the list of training rules, it outputs the suggestion that corresponds to that rule.

##############################################################################
## Get-TrainingSuggestion.ps1
## Retrieve a training suggestion (if applicable) for the last command
## you typed.
##############################################################################

$history = get-history -Count 1

$suggestions = @{
   "/\?"="To get help on a topic, use -? instead of /?.`nAlternatively, use get-help <command>.";
   ".length"="Try using the .Count property instead of the .Length property.  Although .Length " +
       "often works, .Count is the more consistent way to get the number of objects in a collection.";
   ";[ \t]*$"="Semicolons are not required as line terminators in PowerShell.  Try your command without one.";
   "Regex.*]::Match"="PowerShell's -match evaluator is much more efficent than calling it through the .NET API.";
   "^`".*`"$"="Did you mean to run the command in quotes?  If so, try using & `"<command>`"";
   "start "="Are you trying to run the program associated with that path?  If so, try invoke-item <path>";
   "%.*%"="To access environment variables, try `"`$env:variable`" instead of `"%variable%`"";
   "ren[^ ]* [^ ]+ .*:\.*"="Rename-item takes only a name as its second argument.  Unless you want the " +
       "name to have those path characters, do not include them.";
   "dir.*/s.*"="To get a recursive directory listing, try `"dir . * -rec`".";
   "dir.*/ad"="To get a list of directories, try `"dir | where { `$_.PsIsContainer }`""
   "^get-childitem.*/s.*$"="To get a recursive directory listing, try `"get-childitem . * -rec`".";
   "^grep"="To search files for text patterns, use the Select-String cmdlet.";
}

$helpMatches = ""

if($history)
{
   $lastCommand = $history.CommandLine

   ## Get the suggestions from the baked list
   foreach($key in $suggestions.Keys)
   {
    if($lastCommand -match $key)
    {
        $helpMatches += "`nSuggestion: " + $suggestions[$key]
    }
   }
}

$helpMatches

To use this, simply update your PROMPT function to call Get-TrainingSuggestion.ps1.

function prompt
{
    $suggestion = Get-TrainingSuggestion
    if($suggestion)
    {
        Write-Host $suggestion
        Write-Host
    }

    "PS >"
}

Comments [0] | | # 
 Tuesday, September 02, 2008
Wednesday, September 03, 2008 4:29:56 AM (Pacific Daylight Time, UTC-07:00) ( )

One tension that sometimes arises in the PowerShell community is between the hard-core developers, and hair-on-fire administrators. As a broad technology, this tension and desire for balance drives our design decisions every day.

PowerShell is all about striking a balance between a range of experiences:

  • Task oriented, and consumption-only. AKA “Copy and Paste Admin.”
    • How do I use PowerShell to restart a computer?
  • Problem oriented, and composition-based. AKA “Admin Scripter.”
    • How do I collect a log file from a cluster of machines I need to parse out of a web page?
  • Technology oriented, and interoperability-focused. AKA “Developer” / ISV
    • How do I expose my product’s transacted object model to PowerShell users?

In general, the output of each category empowers the categories that come before it. As a product becomes PowerShell-enabled, admin scripters can then leverage the cmdlets and providers to solve their problems and scenarios. They might blog them, wrap them in a script or module, or otherwise share them. At that point, they become pre-packaged tasks ready for copy and paste.

We tend to walk a fine line with this goal, but I’ve grouped our 100+ new V2 cmdlets into three buckets: Admin, Developer, and Both. Here is what the comparison looks like right now:

PS >gc newcommands.txt | group { $_.Substring(0,1) }
Count Name                      Group
----- ----                      -----
   75 a                         {a Add-BitsFile, a Add-Module, a Checkpoint
   11 d                         {d Add-Type, d Debug-Process, d Export-Prox
   16 b                         {b Complete-PSTransaction, b ConvertFrom-St

Granted, we’ve spilled more blogging ink on the developer and scripting-oriented features (transactions, modules, eventing, etc,) but that’s largely because it will take some time for our SDK and help documentation to catch up.

In addition, PowerShell’s goal is always to soften the learning curve and blur the distinction between the buckets I mentioned earlier. For example, the scripts and functions you’ve come to know and love now have access to all of the power of compiled cmdlets. Or more simply, some scenarios that used to require .NET scripting (random numbers, split and join, etc) now have task-oriented cmdlets or language features.

Now, what about "constructive feedback?" Frequently, we'll find a blog post or comment saying something along the lines of, "PowerShell just isn't admin-friendly." Or, "PowerShell just isn't developer-friendly." Of course, we're always working to make the product better, but that comment is an ideal spot to help ensure we get this right. The best way to help us is to make your feedback constructive, and something we can act on. Tell us why you feel this way, and it has a chance of improving the product. Aimlessly grumble, and it does not.

Comments [1] | | # 
 Friday, August 29, 2008
Friday, August 29, 2008 3:35:22 PM (Pacific Daylight Time, UTC-07:00) ( )

img057

... Quitting lasts Forever.                     ~ Lance Armstrong

 

I hadn't heard this before yesterday, but it makes a good quote for the whiteboard!

Comments [1] | | # 
 Friday, August 08, 2008
Friday, August 08, 2008 6:55:55 PM (Pacific Daylight Time, UTC-07:00) ( )

Once problem that often arises when trying to manage machines is when the management layer itself is the thing you need to diagnose. For example, trying to diagnose Remote Desktop connectivity issues when port 3389 is blocked, or using PowerShell Remoting when WSMAN is misconfigured.

Alternatively, you might not have the client you need to manage the machine -- such as an SSH client, or a version of PowerShell V2 installed.

One way to get around both of these problems is another communication channel. It may be of lower fidelity, but can help you get your job done.

One perfect example of an alternative communication channel is any of the many synchronization tools out there: Live Mesh, Syncplicity, FolderShare, etc. In addition to managing connectivity, they let you broadcast messages (by way of files) between connected computers. Let's use that as our communication protocol:

 

Mesh-Moting

 

The core of this experience comes from a PowerShell Mesh Monitor. This script monitors a computer-specific directory for new scripts that appear. When it sees a new script, it processes it, captures the output, and then stores the output in a similarly named file. You can then retrieve the file, review its contents, and continue to manage the system this way:

#requires -version 2.0

## Assuming the script is located in the (Mesh-synched folder)
##    D:\Documents\Mesh
## and the computer name is
##     "MESH-CLIENT"
## We'll monitor D:\Documents\Mesh\Computers\MESH-CLIENT for PowerShell
## scripts to run.
##
## Run this script on any machines that you want listening for scriptable
## Mesh management commands:
##
## powershell -noprofile -file D:\Documents\Mesh\Start-MeshMonitor.ps1
##
## Commands that impact the shell's state (such as current location) are
## persisted for future commands. If you want to share data between scripts
## use global variables.

## Set up the environment
$host.UI.RawUI.WindowTitle = "PowerShell Mesh Monitor"
$myWindowHandle = (Get-Process -Id $pid).MainWindowHandle

## Determine the monitoring directory. Create it if we have to.
$scriptLocation = Split-Path -Parent $myInvocation.MyCommand.Definition
$monitorPath = Join-Path $scriptLocation "Computers\$($env:COMPUTERNAME)"
if(-not (Test-Path $monitorPath))
{
    [void] (New-Item -Type Directory $monitorPath -Force)
}

## Create a P/Invoke type that gives us access to the window
## management functions (show / hide)
$windowUtils = Add-Type -memberDefinition @"
[DllImport("user32.dll")]
public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
"@ -name "Win32ShowWindowAsync" -namespace Win32Functions -passThru

## Hide ourselves
[void] $windowUtils::ShowWindow($myWindowHandle, 0)

Set-Location $monitorPath

## Continuously go through all PowerShell scripts in the drop location,
## run them, and store their output back in the drop location.
while($true)
{
    ## Show the window if they create a file called "SHOW"
    if(Test-Path SHOW)
    {
        [void] $windowUtils::ShowWindow($myWindowHandle, 1)
        Remove-Item SHOW
    }
    
    foreach($inputFile in Get-ChildItem $monitorPath -Filter *.ps1 | Sort LastWriteTime)
    {
        $script = $inputFile.FullName
        "Processing input script $script"

        & { trap { $_; continue }; & $script } > "$script.output.txt" 2>&1 
        Move-Item $script "$script.processed"
    }

    Start-Sleep 1
}

With file synchronization as a back-end, you can now write a thin remoting client in nearly any language, and nearly any OS -- as long as it can read and write files, and is supported by your file synchronization client. Taking this same approach, you could also use email, FTP, web pages, or nearly anything else as a communication mechanism.

On top of that, you might want to build a primitive interactive remoting experience. Once Live Mesh completes their Windows Mobile client, I'll be doing that ASAP. Here's a PowerShell script that demonstrates the approach:

## Assuming the script is located in the (Mesh-synched folder)
##    D:\Documents\Mesh
## and the computer name is
##     "MESH-CLIENT"
## We'll drop scripts in D:\Documents\Mesh\Computers\MESH-CLIENT and
## process the resulting output files.
##
## Commands that impact the shell's state (such as current location) are
## persisted for future commands. If you want to share data between scripts
## use global variables.

param($computerName)

## If they specified a computer name, change to that directory
if($computerName)
{
    $scriptLocation = Split-Path -Parent $myInvocation.MyCommand.Definition
    $monitorPath = Join-Path $scriptLocation "Computers\$computerName"
    if(-not (Test-Path $monitorPath))
    {
        throw "$computerName does not have a Mesh Monitor directory"
    }
    
    Set-Location $monitorPath
}


$remotePromptText = "[MESH/$(Split-Path . -Leaf)] PS >"

## Invoke a command and retrieve its output
function InvokeCommand($command)
{
    $filename = [GUID]::NewGuid().ToString() + ".ps1"
    $outputFilename = "$filename.output.txt"
    $processedFilename = "$filename.processed"
    
    $command > $filename
    while(-not (Test-Path $processedFilename)) { Start-Sleep -m 100 }
    while(-not (Test-Path $outputFilename)) { Start-Sleep -m 100 }
    
    Get-Content $outputFilename

    ## Clean up our temporary files
    Remove-Item $outputFilename
    Remove-Item $processedFilename
}

## Get a command from the user, invoke it, and display
## the results
while($true)
{
    Write-Host -NoNewLine $remotePromptText
    $command = $host.UI.ReadLine()

    if($command -eq "exit")
    {
        break
    }
    
    InvokeCommand ($command + " | Out-String -Width $($host.UI.RawUI.BufferSize.Width - 1)")
}

Comments [0] | | # 
 Wednesday, July 30, 2008
Wednesday, July 30, 2008 7:15:16 PM (Pacific Daylight Time, UTC-07:00) ( )

If you have a PowerShell script that you are calling from cmd.exe, you might run into the following error:

Write-Host : The OS handle's position is not what FileStream expected. Do not use a handle simultaneously in one FileStream and in Win32 code or another FileStream. This may cause data loss.

This is bug in PowerShell, and happens when:

  • a PowerShell command generates both regular and error output
  • you have used cmd.exe to redirect the output to a file
  • you have used cmd.exe to merge the output and error streams

For example:

PowerShell -Command '"start"'; Write-Error "Foo"; '"end"' > c:\temp\redirect.log 2>&1

One workaround is to use Start-Transcript for file logging (rather than cmd.exe) or have PowerShell do the error stream redirection.

However, if you don't have control over your logging, you can add the following snippet to any scripts that get launched this way.

Note: this is an unsupported workaround. It will almost definitely break as future versions of PowerShell are released.

 

V1

$bindingFlags = [Reflection.BindingFlags] "Instance,NonPublic,GetField"
$consoleHost = $host.GetType().GetField("externalHost", $bindingFlags).GetValue($host)
[void] $consoleHost.GetType().GetProperty("IsStandardOutputRedirected", $bindingFlags).GetValue($consoleHost, @())
$field = $consoleHost.GetType().GetField("standardOutputWriter", $bindingFlags)
$field.SetValue($consoleHost, [Console]::Out)

V2 CTP2

$bindingFlags = [Reflection.BindingFlags] "Instance,NonPublic,GetField"
$objectRef = $host.GetType().GetField("externalHostRef", $bindingFlags).GetValue($host)

$bindingFlags = [Reflection.BindingFlags] "Instance,NonPublic,GetProperty"
$consoleHost = $objectRef.GetType().GetProperty("Value", $bindingFlags).GetValue($objectRef, @())

[void] $consoleHost.GetType().GetProperty("IsStandardOutputRedirected", $bindingFlags).GetValue($consoleHost, @())
$bindingFlags = [Reflection.BindingFlags] "Instance,NonPublic,GetField"
$field = $consoleHost.GetType().GetField("standardOutputWriter", $bindingFlags)
$field.SetValue($consoleHost, [Console]::Out)

 

How does this work, and why does this happen in the first place? When PowerShell sends output to its output stream the first time, it keeps a reference to the output stream for future use. However, this output stream is really a wrapper around a lower-level stream. When cmd.exe writes to the output stream, it writes to the lower-level stream. This makes the .NET wrapper complain that the underlying stream has changed from beneath it.

This workaround modifies some private engine state to not keep a reference to the output stream -- but instead to re-examine the output stream on every use.

Comments [0] | | # 
 Thursday, July 24, 2008
Thursday, July 24, 2008 5:11:22 PM (Pacific Daylight Time, UTC-07:00) ( )

Once in awhile, we get questions about the best practice for PowerShell's execution policy when it is included as part of a standard desktop image.

This is one of the main reasons that PowerShell ships with a "Restricted" execution policy. Since you have to explicitly enable or install PowerShell, we've frequently been asked why we aren't more permissive by default. After all, you did just install / enable it! The reason is that separating the execution policy decision from the installation decision gives you a lot more freedom on installing PowerShell. It lets you push PowerShell to your whole enterprise via SMS (or include on a standard image,) and then later selectively configure the Execution Policy via Group Policy or other mechanisms.

When it comes to configuring these systems, the answer to this is largely determined by who will be using PowerShell. Is it primarily the end users, or as a target for logon scripts? The 80% rule is key here. You want to make a well-reasoned decision that applies to as many of your systems as possible, rather than have everybody make an un-informed decision on their own.

If it’s mostly for logon scripts, and you have a certificate you can sign these scripts with:

  • Set the execution policy to AllSigned
  • Add your signing certificate to the TrustedPublisher store

If scripting is likely to be extremely common (as with Exchange,) or you can’t obtain a code signing certificate, set the execution policy to RemoteSigned.

See here for some more guidance on this: http://www.leeholmes.com/blog/3rdPartiesAndPowerShellExecutionPolicies.aspx

As an brief caveat for logon scripts, some machines are configured to treat UNC paths as the same security zone as the internet (as opposed to the intranet.) This is Internet Explorer's "Enhanced Security Configuration." In this case, PowerShell responds the same as the Explorer Shell when it runs scripts from a UNC path: “While scripts from the internet can be useful, this script can potentially harm your computer. Do you want to run <script>?”

One way to fix this is by adding the source server to Internet Explorer’s Trusted Sites, or changing the “UncAsIntranet” configuration property (http://technet.microsoft.com/en-us/library/bb457150.aspx). This is also covered on page 341 of the (my) PowerShell Cookbook.

As another caveat, it is currently not possible to directly assign a .ps1 script as a logon script, since the architecture that enables this implies that you must be able to double-click on a PowerShell script to run it. We don’t want double-clicking to run a script by default for security reasons, so you can write a VBS script or batch file to call PowerShell with the correct arguments. The team blog goes into a bit more detail on this.

Comments [0] | | # 
 Tuesday, June 24, 2008
Wednesday, June 25, 2008 4:17:45 AM (Pacific Daylight Time, UTC-07:00) ( )

Last night, I flew my first half-hour as Pilot in Command of N8756C, a 1977 Piper Warrior. In flying, a pilot’s First Solo is a huge milestone. After hours of training and ground study, you finally take to the air on your own.

FirstSolo

The most difficult part of flying is getting back down, so the First Solo is three takeoffs and landings -- about half-an-hour in the traffic pattern. It seemed to be the flight that would never come, though.

We first planned our pre-solo flight for Thursday, followed by the solo on Sunday. The pre-solo flight is a comprehensive review, so we booked the airplane from 5 to 7 PM. When we went through our pre-flight checklist, we realized that none of the avionics were working: I could hear myself, but couldn’t speak with my instructor. We tried everything we could to resolve the problem (including accidentally enabling the Emergency Locator Transmitter / Distress Beacon,) but couldn’t fix it. Dejected, we re-parked the plane and returned to base. I later learned that the squelch on the radio was wrongly adjusted. The squelch control determines the signal strength required for transmission. It is normally used to suppress low-level static, but in this case was set to exclude almost everything.

With that flight aside, we re-booked for Sunday – this time for both the pre-solo and solo flight.

Sunday came around bright and sunny, as did our 6 PM flight time. We patiently waited for our plane to arrive back from a previous lesson, filling time with some ground work in the meantime. We planned a flight to Thun Field, with detours for maneuver practice and instrument flying. Then, we waited some more. And some more. The plane finally got back 75 minutes late, but we went out hoping to get at least part of the lesson done.

When we got to the plane for our pre-flight checklist, we of course found it bone-dry. The gas truck took seemed to take its sweet time, but the real kicker came as we prepared to taxi out of the parking area. There was traffic to our left: a brand spanking new Boeing 737 being towed SLOWLY back toward the Boeing hangar in all of its unpainted glory. By slowly, I mean walking pace. This taxi would have taken 45 or 50 minutes, so we had to call off that flight, as well. We re-booked for Monday: 5 to 9 PM.

Boeing 737

Monday (yesterday) finally came around, and my study work for Sunday night was to read up on how to use the VOR system for navigation, rather than use the primarily visual navigation we were previously planning. VORs are directional beacons that let a flight instrument determine the direction from the VOR ground station to your airplane. To find a specific point, you generally use two VORs at the same time to triangulate your position.

The flight was intense. It was 2.8 hours in the air and reviewed:

  • Slow flight, where you fly and maneuver at near-stall speeds
  • Power-On and Power-Off stalls, and stall recovery
  • Ground reference maneuvers (Turns around a point, S-turns, rectangular courses)
  • Steep turns and standard turns
  • Emergency procedures (We “lost our engine,” so I had to pick and prepare for a landing)
  • Go-Arounds (Calling a mulligan on un-safe or un-certain landings)
  • 5 landings at Thun field, with my instructor having his eyes closed for the final 3 or 4

I was recording this on my GPS, so here are some highlights. First, the Thun Field landings:

Thun Field landings

Then, some ground-reference maneuvres:

image

On the way back to Renton airport, we also did 30 minutes of Instrument Training. For instrument training, you don a mask that prevents you from seeing outside the cockpit, and maneuver the airplane by instruments alone.

When we finally landed back at Renton airport, we practiced another 2 landings, finally coming to a full stop at the tie-down area. My instructor got out, wished me luck, and watched as went through the pre-flight checklist again. I alerted the tower as I prepared to taxi:

Renton Ground, this is Warrior 8756 Charlie at North Tower. Student pilot on first solo, requesting closed traffic with information Alpha.

I was given clearance to taxi to runway 15 (150 degrees, roughly north to south,) and prepared for my first flight. I waited for a minute as a few other planes landed, and then was given clearance for takeoff. I had too much power on my first run around the traffic pattern, so ended up lining up with the runway a little too high. Rather than try to rescue the landing in a potentially nervous state, I let the tower know I was doing a go-around, and climbed back to the traffic pattern. The controller mentioned that the winds were fairly variable and gusty, approaching 8 knots at times. She offered the south to north landing on runway 33, which I declined (as the winds weren’t affecting my landings.) The second attempt was much better, marking my first landing as Pilot in Command.

Now for landing number two.

Take-off is usually a breeze, but the nose appeared unusually high as I gave the plane full power on the ground. I quickly brought the power down, and exited one of the taxiways to determine the cause. After checking everything (flaps, elevator, etc,) I realized it was just a mind trick: I had been in a basically nose-down attitude (for the descents) for the last 10 or 15 minutes, so it was a lot like Velocitization in a car. You get so used to something (speed in a car, or nose angle in an airplane,) that it becomes your mind’s new definition of normal. You combat velocitization once you realize you have it, so I requested clearance to taxi back on the runway and complete my landings.

In the air again, the controller mentioned that they were just about to close, and asked if I wanted her to stay on. I didn’t want to keep her late, so I let her know I’d make my next landing a full-stop. She was awesome, and said she had no problem staying so I could get the solo done, so I continued with my next landing – still OK, but with definite room for improvement.

My final takeoff is where it really kicked in. After lifting into the air, an enormous thrill washed over me as I took a relaxed breath of fresh air. It was physically impossible for me to NOT land a third time. I grinned as I made my final approach, and settled in for the smoothest and straightest landing yet.

As recorded by my GPS:

image 

As I taxied off the runway, the tower controller congratulated me on my landings as I thanked her for her help. The landings were nothing for the highlight reels, of course, but it gave a satisfying end-cap to 30 minutes that I will never forget.

And the ripped shirt to prove it? Well, in-line with tradition, my instructor cut up the back of my shirt. Before modern electronics, in-cockpit communication was mainly through shirt tugging and hollers from the instructor that sat behind you. Cutting off the back of the shirt symbolizes this very important step -- as your instructor won't need to be yanking on it any more.

Comments [5] | | # 
 Wednesday, June 04, 2008
Wednesday, June 04, 2008 3:40:28 PM (Pacific Daylight Time, UTC-07:00) ( )

One question that comes up fairly often when dealing with (or writing!) secure cmdlets is how to properly handle usernames and passwords. The solution there is to use (or make) the -Credential parameter of type PSCredential. A PSCredential object helps ensure that your password stays protected in memory, unlike cmdlets that accept a straight username / password combination.

If a parameter is of type PSCredential, PowerShell supports several types of input:

  • empty: If you supply no input to a mandatory -Credential parameter, PowerShell prompts you for the username and password.
  • string: If you supply a string to the -Credential parameter, PowerShell treats it as a username and prompts you for the password.
  • credential: If you supply a credential object to the -Credential parameter, PowerShell accepts it as-is.

This is great for interactive use, but what if you want to write an automated script for a cmdlet that accepts a -Credential parameter? The solution lies in passing a pre-constructed PSCredential object. The solution to this is covered by recipe 16.9 in the PowerShell Cookbook:

 

Securely Store Credentials on Disk

Problem

Your script performs an operation that requires credentials, but you don’t want it to require user interaction when it runs.

Solution

To securely store the credential’s password to disk so that your script can load it automatically, use the ConvertFrom-SecureString and ConvertTo-SecureString cmdlets.

Save the credential’s password to disk

The first step for storing a password on disk is usually a manual one. Given a credential that you’ve stored in the $credential variable, you can safely export its password to password.txt using the following command:

PS >$credential.Password | ConvertFrom-SecureString | Set-Content c:\temp\password.txt

Recreate the credential from the password stored on disk

In the script that you want to run automatically, add the following commands:

$password = Get-Content c:\temp\password.txt | ConvertTo-SecureString

$credential = New-Object System.Management.Automation.PsCredential `

    "CachedUser",$password

These commands create a new credential object (for the CachedUser user) and store that object in the $credential variable.

Discussion

When reading the solution, you might at first be wary of storing a password on disk. While it is natural (and prudent) to be cautious of littering your hard drive with sensitive information, the ConvertFrom-SecureString cmdlet encrypts this data using Windows’ standard Data Protection API. This ensures that only your user account can properly decrypt its contents.

While keeping a password secure is an important security feature, you may sometimes want to store a password (or other sensitive information) on disk so that other accounts have access to it anyway. This is often the case with scripts run by service accounts or scripts designed to be transferred between computers. The ConvertFrom-SecureString and ConvertTo-SecureString cmdlets support this by allowing you to specify an encryption key.

When used with a hard-coded encryption key, this technique no longer acts as a security measure. If a user can access to the content of your automated script, they have access to the encryption key. If the user has access to the encryption key, they have access to the data you were trying to protect.

Note: Due to limitations in Version 1 of PowerShell, passwords encrypted with a specific encryption key can only be successfully decrypted by the same instance of PowerShell.exe process. Trying to decrypt the passwords with a different PowerShell.exe process will not be successful. To encrypt the passwords to disk in a way that can be read by other processes, use the .NET Encryption APIs: http://poshcode.org/116.

Although the solution stores the password in a specific named file, it is more common to store the file in a more generic location—such as the directory that contains the script, or the directory that contains your profile.

To load password.txt from the same location as your profile, use the following command:

$passwordFile = Join-Path (Split-Path $profile) password.txt

$password = Get-Content $passwordFile | ConvertTo-SecureString

To learn how to load it from the same location as your script, see “Find your Script’s Location.”

For more information about the ConvertTo-SecureString and ConvertFrom-SecureString cmdlets, type Get-Help ConvertTo-SecureString or Get-Help ConvertFrom-SecureString.

Comments [0] | | # 
 Tuesday, June 03, 2008
Wednesday, June 04, 2008 6:42:09 AM (Pacific Daylight Time, UTC-07:00) ( )

After what seems like an eternity, I finally got to start my official flight training. As a Canadian (AKA "Alien,") applying for flight school also means getting your fingerprints taken and being put in a special registration system. My training permission cleared late last week, so I booked my first lessons as soon as I could. In fact, for a government agency, the flight registration process was surprisingly efficient. Finding a place to get TSA-approved fingerprints outside of work hours? Well, that's a different story.

Anyways.

One of the things I really missed about my intro flights was a good understanding of exactly where I traveled during the flight. I remembered some landmarks, but didn't really catch on to many streets or things I knew from my ground travels. Recording my tracks through a GPS system seemed to be the best approach, so I finally settled on a Lowrance Airmap 2000C. Its features rival most of the top-end aircraft GPS products (aside from XM weather and traffic, which I'm not in the market for,) at a fraction of the price. For about the same cost, I would have been able to use some computer-based GPS software on my Tablet PC, but messing around with a Tablet PC in the cockpit seems to be a lot more trouble than it's worth.

clip_image001

I took it on a long camping trip during the Memorial Day long weekend, and it was fun watching it trace my path around the Puget Sound. It warned me plenty as I passed through the restricted airspaces (McChord airforce base, SeaTac airport, etc,) so luckily I wasn't actually flying.

On Thursday, I went for my first real lesson, flying AcuWings' Piper Warrior PA28-151. This is the kind of plane I want to do most of my training on -- as the Cirrus SR20 (while newer and nicer) felt like it might prevent me from learning some of the subtle basics -- like rudder control, or use of the nose-wheel while on the ground.

clip_image001[5]

In the introductory flights, the instructor does almost all of the ground work, aside from giving you a brief overview of what they are doing. For your first training flight, though, you start to take over the technical preparations: aircraft examination, engine start procedures, pre-takeoff work, and the post-flight run-down. We spent about 45 minutes on these preparations, learning the how and why behind 80+ items in the pre-flight and post-flight checklists.

In the air, we practiced straight and level flight, ascents, descents, and (level, ascending, descending) turns. Like the flight-preparation work, non-introductory training means that you begin to take over much more of the landing preparations. During this flight, we did 2 landings, one being a touch-and-go. For both, I flew the traffic pattern, lined up the approach, and helped guide us toward the runway. I did a little less of the actual landing than I had done during my introductory flights, but I think that was probably because of higher wind. This flight gave me 0.8 hours of qualified dual-instruction to apply to my flight training.

On Sunday, we put in another 1.1 hours of dual instruction, with the learning curve continuing just as steep. Since I had been taught the checklists, pre-flight this time was all my own – including the inevitable splashing of leaded, high-octane Avgas on my hands while testing for fuel contaminants. As we prepared for takeoff, I was shown how to talk with the tower, request permission to taxi, take-off, and practice landings. That's a massive system of verbal cryptography that will take a while to get used to, but you feel like part of a club when you're doing it.

While in the air, we practiced slow flight (near-stall conditions,) stalls, and recovering from stalls. These are the most common "emergency" situations in flight, and are relatively easy to recover from as long as you know what you are doing. If you haven't practiced them, then you'll just panic and donate some iron to the earth's mantle.

After practicing those, we started working on landings. As a skill in flying, landings are a unique breed. They are a skill within a skill: a technique that gets lavish attention in the context of flying, but completely independent of it. Pilots obsess about landings the same way that cigar aficionados gush about about the tower of ash emanating from their cigar, or how developers delight in "Perl Golf,"

It's a journey that's just beginning -- I can't wait for more.

Comments [1] | | #