At the end of this week I fly off for a few days Scuba diving, and shortly after I get back I have a major PowerShell presentation to do. As usual with such things the struggle is what to include and what to leave out. Do I show some of the cool stuff that has been done around PowerShell by other people ? Since I can't include everyone the fairest thing would be not to talk about anyone. But would that be less interesting for the audience. So I've made a conscious effort to look at two tool sets. PowerGadgets and the PowerShell Community Extensions (which for the sake of a sensible post length I'll cover another time). On the plus side both of them provide some great features to what is already a great tool. On the negative side both of them suffer from poor documentation (which isn't PowerShell's strongest area either) and the tumble weed blowing through both their discussion areas gives the impression of something petering out without being finished.
Power-gadgets positions itself as "Desktop Reporting and Monitoring for IT/DB professionals who don't write code" and that's not an unreasonable claim to make. It does Graphs, Maps and Gauges. I suspect it will be gauges that interest IT Pros monitoring systems - you can see the battery monitor which I put together with a command as simple as
GET-WMIObject win32_battery | Out-Gauge [Parameters]
Out-gauge is provided by PowerGadgets but it needs a command line which goes on forever.
-Type Radial -Refresh 0:0:1 -Value estimatedChargeRemaining -mainscale_max 100 -glass -border_glare false -mainindicator_color {if ($_.estimatedchargeRemaining -gt 40) {"green"} else {"red"} } -palette professional -Titles_0_Text "Battery" -Titles_0_Layout_Target AnchorPoint -Titles_0_Layout_AnchorPoint "0, -0.3" -mainScale_stripes_0_max 20 -mainScale_stripes_0_radius 1.2 -mainScale_stripes_0_color RED -innerGauges_add digital -innerGauges_0_layout_alignment bottomCenter -innerGauges_0_size 1,0.4 -innerGauges_0_digitalPanel_border_glare false -innerGauges_0_digitalPanel_value {$_.EstimatedRunTime}
-Type specifies which of 4 gauge types I want, and -Refresh means it will get updated 0:1:0 means every 0hours, 1 Minute, 0 Seconds. -Value links to the the property of the WMI object. The last thing to do for a useful battery gauge is to set the scale.If this were VB script we'd have lines which did things like MainScale.max=100, but here the "sub-objects" which make up are set with parameters like MainScale_Max , Titles(0).Text etc . With the basics in place I can get the look I want.-glass turns on the glass effect in vista (it looks quite good here, but I prefer the -floating parameter which lets the gauge float without a Window) -border_glare controls the effect of a light shining on the gauge - very smart but harder to read when the gauge is small. For added ease of reading, I wanted to change the needle colour to show when the battery was getting low, so that was -mainIndicator_color. I didn't like default colour scheme, but rather annoyingly Tab expansion fails to bring up the -Palette parameter - the first of several rough edges. Rough edge number 2 was the Parameter "Caption" doesn't set the title as it is supposed to, it's stuck as "PowerGadgets". So the -title parameters let me put text in the middle of gauge. Trawling through the help I stumbled on the stripe feature, so I added that with -mainscale_stripes, there is probably some sense to a radius of 1.0 being on the tick marks and not on the outside edge of the gauge, but it was one of several things I had to find by trial and error. Finally the -innerGauges parameters let me add a little digital readout for minutes of time left instead of %full, don't ask me why its value needs to be a code block when the one for the main indicator doesn't... I don't know and the "help" - isn't much help.
This kind of thing seems to be the sweet spot the "Digital Panel" gauge (I found wasn't flexible enough for things like displaying my IP configuration); but inner Gauges were the root cause for two more rough edges. First: you can add PowerGadgets to your Vista SideBar: what goes in is a place holder with a name like "Gadget 1" , you add -SideBar Gadget1 to the command line and Whoosh! the gauge goes on the sidebar. This has a major wow factor. Unfortunately my gadget crashes sidebar if I click on it (it works if I take the inner gauge out). Secondly there is a GUI PowerGadgets Creator and it comes up with a variety of errors when I try to stuff with inner gauges. The GUI editor has no help of its own, and I never worked out how to bind data values in it. The editor can output gadgets as a file and they can be started on the desktop or side bar, but no way is provided to get them back as a command line (the files are XML format, so some hacking can extract the information, and no doubt some clever soul could write a PowerShell function to do it) similarly there is no way to get a gadget on the desktop into the editor or back to PowerShell - though it is possible to specify a -Configure switch in PowerShell to edit the gadget into the editor.
I tried the Out-map feature, and needless to say the first thing I wanted was to create a custom map of my own. PowerGadgets maps use SVG format - a way of writing Scalable Vector Graphics in XML. Visio can save as SVG, so this offers the hope of having PowerGadgets light up your network plan depending on the state of machines on it. Sadly it is incredibly picky about what's in the XML file (which suggests a poor XML parser) and gets thrown by the smallest thing. I found I could hand craft SVG files, but when I made an error in one PowerGadgets crashed and took PowerShell with it. So of the three gadget types Maps looks the least complete.
By contrast charts are quickest and easiest to use, of the three types in earlier post I was importing dive profiles and I can reproduce the charts my dive software creates with one, by selecting one dive and piping it into relatively simple Out-Chart
Out-Chart -Values {-1 * $_.segmentDepth} -Gallery 3 -label {$_.dateTime.toString("hh:mm")} -legendBox_visible false
All three gadget types support an output switch so you can save the gadget as .BMP .PNG or WMF file (though oddly not as a JPG), and they offer the opportunity to "drill down" into a selected data item; so if a chart or a map region has underlying data you can do something interesting with it (a demo on the PowerGadgets site shows charting the handles used by Processes, and killing a process by clicking its column in the chart), the "drill down command" isn't required to take data so a CPU gauge could open Task Manager.
Although I didn't start out to write a review of PowerGadgets that's what this has become, so what conclusions would I draw ? The silence that has fallen over the forums part of the PowerGadgets Web site worries me: because this is a product with great potential which deserves to succeed: but potential isn't enough and I can't see it getting to required level of quality without a decent base of early adopters. Would I recommend people to adopt it or avoid it ? Neither: it offers great functionality, but it doesn't serve it up on a plate for you, which can be frustrating. People working with PowerShell should try PowerGadgets for themselves and decide if the functionality to frustration ratio is good enough to justify buying it.
It's only 7 months since I first installed Powershell. Hard to believe that last week I saw a copy of the OCS res kit with my name on the cover as a result of the PowerShell scripts I wrote, and worth remembering before criticizing other people's scripts.
Over on Ben Armstrong's blog he has applied his virtualization expertise to showing how to use the newly published WMI management interface, posting samples using VB and "VB in powershell syntax" for example
$VMs = gwmi -class "MSVM_ComputerSystem" -namespace "root\virtualization" -computername "."foreach ($VM in $VMs){ if ($VM.Caption -match "Microsoft Virtual Computer System"){ write-host "==================================" write-host "VM Name: " $VM.ElementName write-host "VM GUID: " $VM.Name write-host "VM State: " $VM.EnabledState } }
VMs = (get-wmiobject -class "MSVM_ComputerSystem" -namespace "root\virtualization") | where {$_.caption -match "Virtual"}
$VMs = get-wmiobject -namespace "root\virtualization" -query `"SELECT * FROM Msvm_ComputerSystem WHERE Caption Like '*virtual*' "
$VMs | Format-Table -autosize ElementName, Name, Enabledstate
$VMs | Format-Table -autosize @{Label="VM Name"; expression={$_.ElementName}} ,@{Label="VM GUID"; expression={$_.Name}} , Enabledstate
@{Label="State"; expression={switch ($_.EnabledState) { 2 {"Running"} 3 {"Stopped"} 32768 {"Paused"} 32769 {"Suspended"} 32770 {"Starting"} 32771 {"Snapshotting"} 32773 {"Saving"} 32774 {"Stopping"} } }}
Function Choose-VM{$global:Counter=-1 $VMs = get-wmiobject -namespace "root\virtualization" -query ` "SELECT * FROM Msvm_ComputerSystem WHERE Caption Like '%virtual%' " Format-Table -inputobject $VMS @{ Label = "ID"; Expression={($global:counter++) }} , @{Label="VM Name"; expression={$_.ElementName}} , @{Label="VM GUID"; expression={$_.Name}} , @{Label="State"; expression={switch ($_.EnabledState) { 2 {"Running"} 3 {"Stopped"} 32768 {"Paused"} 32769 {"Suspended"} 32770 {"Starting"} 32771 {"Snapshotting"} 32773 {"Saving"} 32774 {"Stopping"} } }} | out-host $VMs[ [int[]](Read-Host "Which ones? ").Split(",")]}
Ben did a second post to show starting a virtual machine - to do this I can just use
(choose-vm ) | foreach-object {$_.requestStateChange(2)}
You could use anything which returns Msvm_ComputerSystem WMI objects and you can stop or pause one a machine just by requesting a different state to change to. Shutting down a machine just by setting it's state to 3 for stopped is the virtual equivalent of hitting the power switch. The hyper-v integration components include one to trigger a clean shutdown and Ben shows how that can be used; here's my version
(choose-vm ) | foreach-object { (get-wmiobject -namespace "root\virtualization" -query ` "SELECT * FROM Msvm_ShutdownComponent WHERE SystemName='$($_.name)' ").InitiateShutdown($true,"Because I said so") }
For the last year I have been saying that the mentality of waiting for a Service pack is a way of thinking which belongs to the 1990s (wait 6 months might make sense, but a service pack is not the milestone it was). Still, SP1 has released and whilst the majority of its changes were already pushed out though Windows update there are some additional bits in the SP1, so deploying it is, basically a Good Thing.
My laptop has been messed about with dreadfully over the last year and a bit. I blogged that sleep wasn't working properly, and the battery life was terrible. This turned out to be a faulty battery - I swapped it with one from an identical machine we have for roadshow demos and life went from less than an hour to somewhere between 3 and 4 hours. Fantastic. I also noticed that my BIOS was out of date, so I hatched a plan.
I have a secondary hard disks which replaces the DVD in the laptop, and because Vista likes run backups as a scheduled task this is reasonably up to date, and I could do a clean installation. I made myself a Vista+SP1 install disk from the files on an internal server and got to work.
I didn't install any anti-virus software as that we get pushed down to me anyway, to keep the image size small I chose to leave MapPoint off and I forgot the driver for my Presenter Mouse . With the software more or less as I wanted it next step was to run SYSPREP. I told it to generalize the machine as this should help the install process on different hardware. Then it was time to boot into Windows PE and image the machine. Out came my trusty bootable USB key from the prompt I had to run
imagex.exe /flags “Ultimate” /capture c: C:\gold.wim "ULTIMATE Golden Image" /compress maximum /verify
I've explained this command line before. The crucial bit is without the /FLAGS switch you can't use the image on an install DVD. Since Gold.wim is way to big for a DVD the next step was to run
imagex /split C:\Gold.wim C:\install.swm 3000
This gives me Install.swm and install2.swm (an SWM - or split WIM file is just like a WIM. Experience tells me that setup will fail if the split files have WIM extensions).
Next step, make a folder named VistaDVD, in that make a folder named SOURCES and create a dummy INSTALL.WIM it. The XCOPY the vista install DVD into VISTA DVD. When it asks to overwrite INSTALL.WIM say no (that saves copying a huge file to delete it later) then remove the dummy install.wim and copy in INSTALL.SWM. Finally make a second folder named VISTA2 with a SOURCES folder and copy in INSTALL2.SWM
Now I can make two DVD ISO images.
oscdimg -n –m –lGoldDisc1 –h –b"D:\etfsboot.com" c:\VistaDVD c:\Vista1.iso oscdimg -n –m –lGoldDisc2 –h c:\Vista2 c:\Vista2.iso
The extra bits in the first one make it bootable. Before burning the ISOs I copied then to my secondary disk, and booted up Hyper V. I created a new virtual machine and installed from the ISOs. Happy that worked I burnt the disks and reinstalled the demo machine using them. All seemed well.
I took one last backup of my laptop to the secondary disk and about 11:40 yesterday I booted from my new DVDs and set the installation in motion. It asks to swap to DVD2 during the copy phase and back to DVD1 at the end of it, and about 12:00 I went to lunch. I returned at 12:30 to find the machine had finished installing and was waiting for me to set up an initial user account. Setup has a few final tasks to do and then I was able to log in and join the domain, and log on with my usual account - creating an empty profile.
I took my machine to a 1:00 presentation and set the restore going - it failed because it needed to be able to check accounts against the domain. This was a bit unexpected as I'd done a partial restore on an unjoined machine without problems. I plugged a network cable in and and 50GB or so restored at about 1GB per minute. I had to recreate my outlook offline store, set-up links with my phone and set a few other settings but start to finish the process was done inside 3 hours - and for most of that time I wasn't touching the machine. One pleasant surprise was media center was ready to go when I plugged in my TV stick at home. The only unpleasant surprise was that MindGenius doesn't like being imaged when it has had a serial number entered: it wouldn't start. Since I still have the image I built on the demo machine I might go back and add the intellipoint drivers for the Mouse and remove and reinstall Mindgenius and make some new disks. It only takes 7 steps (sysprep, imagex /capture imagex /split, 2 copies, 2 oscdimg, 2 burn operations)
My machine is definitely running better - how much that is SP1 and how much just cleaning it out I don't know. But the ease with which you can make build disks and give them to every laptop user in the company is just one more reason why I say Vista is superior to anything we've had before.
My morning has gone to ruin, I was supposed to be doing a Live Meeting to show some of things we'd done on 2008 Terminal Services on the last road show, my plan was to record it and edit the video to give some screen casts like the ones I've already posted on Virtualization. Sadly the customer had a bit of a disaster and we had to reschedule.
Last night I found my self laughing out loud at David Salaguinto's office Offline blog (3 favourites being Maybe she'll outgrow it , Stop the insanity and Dada-ism or Daddy-ism ). David makes his Visio template available via his blog so you can draw your own. It's a different style of cartoon from the ones I've been dabbling with....
I've aired my views on the way flash is used a number of times (Janina Köppel's Excellent SP-Studio site notwithstanding), and I'm delivering presentations two days out of three at the moment: maybe I'm just growing tired of the Powerpoint decks or maybe I'm stuffing from some the problems referred to here and here.)
One thing to try to do with slide decks is to break them up a bit. Whether use Janina's stuff to make cartoons which you can feed into something else, or David's Visio template to liven up your presentation. This took about 2 minutes.
This is, I'm afraid, another of those "Wow! what can you do with a couple of long lines of PowerShell" posts.
I wanted to create a Scalable Vector Graphics (SVG) file for PowerGadgets' OUT-MAP cmdlet to do UK county maps. PowerGadgets, as I discovered is fussy about the SVG data it is passed, and I still have a bit more exploring to do on this: but an outline SVG file looks like this
<?xml Version=1.0?> <svg width="1200", height="1200", Viewbox="0,0,1200,1200"><g> <g> <shape> <text>Label1</text> </g> <g> <g> <shape1> <shape2> </g> <text>Label2</text> </g></g></svg>
The G tags are Groups. So the the whole document is a group, and all it's subgroups are treated as map objects by PowerGadgets. These either contains one shape and text element - which PowerGadgets uses as its name - or a group of shapes and a text element. The SVG spec defines Rectangles, circles, Ellipses, Polygons and "paths", and I've only used paths with PowerGadgets so far. A Path looks like this.
<path d="M580,595 L574,590 L572,586 L576,590 L582,594 L580,595 Z" />
Everything is in the d parameter. Incidentally, be warned, a lot of this stuff is case sensitive. Inside the data says Move to 580,595, Line to574,590, Line to 572,586, and the Z at the end says close the path Capital letters designate absolute co-ordinates and Lower Case ones are relative, all my data is in absolute form. PowerGadgets doesn't like very long paths, so I made a decision to round the data I got from Nearby.Org.UK. Fitting about 10.5 degrees of Latitude into 1200 pixels of screen says there's little point in dealing with anything after the second decimal place. I also made a decision to ditch points which were very close together. That way I could keep the PATH in the SVG file inside PowerGadgets' limit.
Now I'm pretty impressed with the whoever did the work to produce the data on that site (the blog there says it's a chap called Barry Hunter). Each county in Britain and Ireland has its own file. If a county includes Islands, each Island gets a file - this is perfect creating those Paths, each file is a path statement in the SVG file. There are 300 files. There is no way on earth I'm going to hand process that lot. I mean... I could load them into Excel, do the rounding, calculate the distance between each point and it's predecessor, isolate the points with a suitable gap and then - somehow - get that data into the SVG format, but 300 times must be automated. Guess which tool I chose ? Yep PowerShell.
I created a script called do-map and called it for each file . Do-map takes a filename as a parameter and is, essentially 2 (long) lines of PS. I added 3 little filters as much as anything to make the rest easier to read. So here is the beginning of do-map
param($filename)
filter round2 {Param ($Number) [System.math]::round($number,2)}filter sqr {Param ($Number) [System.math]::pow($number,2)}filter cos {Param ($Number); [System.math]::cos($number * [system.math]::pi /180)}
(@("Lat,long") + (get-content $filename | where {$_ -notMatch '^#'})) > temp.csv
My 3 filters all call the .NET math library: Round2 rounds to 2 decimal places, SQR squares a number, and COS takes a number in degrees and returns the cosine (which I need to do get the projection right). So the first line of proper code, takes the text file from Nearby.Org.UK, strips it's initial comments and adds a header to make it a valid csv file. This goes into temp.CSV Next comes the longest line of PowerShell I have yet written, and bear in mind I've shortened it with those filters. To ease reading I've split it over 12 lines but it is really one line in the form Import-CSV | select-Object | where | foreach-object.
(import-csv temp.csv | select-object @{NAME="Lat"; expression={round2 $_.lat}}, @{NAME="Long"; expression={round2 $_.long}}, @{Name="Delta"; expression={(sqr((round2 $_.lat)-$global:lastLat)) + (sqr((round2 $_.long)-$global:Lastlong)); $global:LastLat=(Round2 $_.lat); $global:Lastlong=(round2 $_.long)}}) | where {$_.delta -gt .0004 }| foreach-object -Begin {[String] $MyXml='<g><path d="M'} ` -Process {$myXml += 'L'+[string](885+100*$_.long) + ',' + [string][int](3500-30*$_.lat/(cos $_.lat)) + ' '} ` -end {$myXml.REPLACE('ML','M') + 'Z" /><text transform="matrix(1 0 0 1 ' + [string] (885+100*$global:LastLong) +' ' + [string][int](3500-30*$global:Lastlat/(cos $global:Lastlat))+')">' + ($filename.replace("C:\Users\jamesone\Counties\GBCountyBoundaryWGS84-","")).replace(".txt","")+'</text></g>'}
The import CSV is obvious, so lets look at the other bits. The select-object section has 3 calculated fields, Lat and Long are the result of rounding columns in the CSV file. Delta is doing a bit of Pythagoras on the latitude and longitude. I'm using a technique I've shown before: setting variables in the script block of a calculated field for select object to use outside the context of the current calculation; each row leaves its lat/long data for the next (The first row will get a big delta, which is fine) There's no need to work out the distance itself, testing the Square of the distance in the where to filter out any points with very small Deltas. I'm aware that if there are many points all very close together they will all be lost (instead of taking out some to leave a more widely spaced set). In practice this hasn't been a problem.
Next we have a for in 3 parts. -begin - create string $myXML with the start of the path statement. -process - for each data point add LineTo its X,Y co-ordinates. These are scaled, and make this a Mercator project the Y co-ordinate is based on latitude/Cos(latitude) [at Latitude Θ, 1 minute of Latitude is 1 Nautical mile, but 1 second of longitude is Cos Θ Nautical miles. If lines of longitude are drawn as parallel 1 unit apart then at latitude Θ the lines of latitude need to be drawn 1/cos Θ units apart] - End: Return the XML, first change the first point in the path to be M - because it will be built as ML. Add the Close path "Z", and close the XML tag. Then add the label as a text tag, position it using the data left in LastLat and LastLong by the calculation of deltas. The actual text is extracted from the file name - I've been very lazy with this
So I invoke this script for each of the files -
dir C:\Users\jamesone\Counties\GB*.txt | %{C:\Users\jamesone\Do-Map.ps1 $_.fullName} > temp.xml
it took 7 minutes 20 seconds to do all 303 files. You can find this out with
Get-History | format table -auto CommandLine , StartExecutionTime, EndExecutionTime
(I'll leave a calculated field for run time as an Exercise for the reader). Temp.XML needs a small amount of cleaning up to become a usable SVG file - toping and tailing, then merging counties and their islands into a group and deleting islands with just one or two points, that's another 5-10 minutes. I test the file by opening it in Visio and assuming I haven't made any errors it looks fine so I can test it with out map, first to get a list of the object names, and then to use them to display a map
out-map -mapsource "custom maps\uk-counties" -ListObjects Import-Csv countyData.csv | out-map -values value -Label county -mapsource "custom maps\uk-counties" -legendbox_visible false
You can see the result - click it to get a comparison with the non-Mercator projection. One final thing. The data that this was based on was shared under Creative Commons by-sa 2.5 and I've attached the map on the same basis. You can use it as you see fit, just acknowledge the work of Nearby.Org.Uk geting the data and mine/Microsoft's in formatting it for this use. If you create another data-set using this, the CC license as placed on the data I used says you have to share the data, but not any app which uses the data.
Update, fixed a bunch of typos, bad edits etc.
–I referred to the PowerShell Community extensions in the last post. It's interesting, but not especially surprising to find that
Lets start with the first of these. There's certainly some cool stuff in the Community extensions. Its a mixture of Scripts, Filters and Functions (which you can look at to get your own ideas) and compiled cmdlets, plus three new providers. It deals with Active Directory, handling files and the file system (everything from Calculating a Hash to Modifying the disk volume label), basic Bitmap handling, Clipboard handling, XML processing, Terminal services management an RSS provider, a speech generator and a lot general stuff to help you get around, including querying information about DLLs and a new tab-expansion function.
The problem is that this can give the impression of "a very unevenly-edited [work which] contains many [things] which simply seemed to its editors like a good idea at the time."* Of course the question comes up "would you like to be the editor and have to tell people their code can't go in until their documentation is up to scratch." ? I wouldn't. How about "if it should be segmented would you like to be the one deciding what is spun off and what stays in the main part". Probably not. The profile script that comes with the extensions gives you the chance to see what's being loaded apart from the basic snap-in and leave out any bits out that don't appeal to you.
The discussion area on codeplex for the Extensions is has a handful of active threads which suggests that work is going on, but some aspects haven't been touched for a long time. For example everyone seems to expect to be able to pass an object to Get-Member to find out what its Properties and Methods are; but this doesn't work with Posts returned by RSS provider. It was suggested that this be corrected some while back but to date nothing has happened (you need to know the properties for the IFEED object). It was also suggested that some documentation be written for the feed provider and (in common with other places) this has not happened.
I don't know who is going to need, for example, speech output and AD support at the same time. Still, I have already found some of the bits pretty useful. Take this bit of code, for example, which I used to create a post at the end of last week.
dir E:\DCIM\102PENTX\Develops\*small* | ForEach-Object -Begin {[String]$myHtml=""} -Process {$myHtml += '<p><img src="' + (upload-blogfile $_.fullname) + '" /></p><p><b>' + (get-image $_.fullname).title + '</b></p>'} -end {New-BlogPost -body $myHtml -Title "Testing Pictures"}
It gets all the pictures named SMALL in a given folder, uploads them to my blog and builds the body of a blog post as it does so; at the end of the process it uploads the post .
Now the MetaWebLogAPI - which I've already written about needs the picture to be encoded in BASE64 format and the community extensions has ConvertTo-Base64. So the code for Upload-BlogFile is
function upload-Blogfile {param($filename, [string] $postUrl=$postUrl, [string] $blogid=$blogID, [string] $username=$username, [string] $password=$password) #Requires -pssnapin PSCX $base64=convertto-base64 $fileName $ContentType=(get-itemproperty "hklm:\SOFTWARE\Classes\$($filename.substring($filename.lastIndexof('.')))" "content type")."content type" $postTemplate = "<methodCall><methodName>metaWeblog.newMediaObject</methodName><params> <param><value>$blogid</value></param> <param><value>$username</value></param> <param><value>$password</value></param> <param><value><struct> <member><name>name</name><value><string>$($filename.substring($filename.lastIndexof('\')+1))</string></value></member> <member><name>type</name><value><string>$contentType</string></value></member> <member><name>bits</name><value><base64>$BASE64</base64></value></member></struct></value></param></params></methodCall>" write-progress "Uploading to blog" "Sending" -cu $filename
([xml]((new-object System.Net.WebClient).UploadString($postURL , $postTemplate) )).methodresponse.params.param.value.struct.member.value.string }
This breaks down as Do the transformation to base 64, get the MIME type for that kind of file. Build the XML to upload. Put up a progress screen as the upload can be slow Perform the upload and extract the URL assigned to the image from the XML returned.
So that command line was building up HTML which repeated the following for each image <P><IMG SRC="url"/></P><P><b>Image title</b></P>
Get-Image in that code is a filter for "new-object" using my Exif library to get the title. As I said at the time I like this of for loop - the begin and end blocks let you do stuff outside the actual loop but keeping it to one command, so the -begin {block} sets up an empty string, and the -end {block} posts the completed string to my blog.
You may be wondering how I got pictures which contained the word "SMALL" That was using 3 more cmdlets from the extensions
dir "E:\DCIM\102PENTX\Develops\*1*" | ForEach Object {Import-Bitmap -Path $_.fullname | resize-bitmap -percent 20 | export-bitMap -path ($_.fullname.replace("IMGP","SMALL")) -Format JPEG -Quality 70}
Import-BitMap, and resize-bitmap are pretty self explanatory. Export-Bitmap will change the format, and JPEG quality, since these pictures are being resized for the web I'm dropping the size from 3900x2600/4MB to 780x520/32KB
Playing with the -Output option on PowerGadgets I realized I can do Import-bitmap temp.bmp | set-clipboard to make it easy to paste a chart straight into another application.
Despite the poor documentation I think most people who use PowerShell will find something useful in the community extensions. They are so diverse that everyone will find different bits useful. But if you haven't found which bits are useful to you go and download them from Codeplex and have a look.
*Foot note: Last week I got a copy of Bruce Payette's book "PowerShell in Action" which seems to be accepted as the standard repository of all knowledge and wisdom when it comes to PowerShell, I was delighted to find chapter one starts with a quote from the Hitch Hikers guide to the Galaxy. Bruce is a guy who clearly knows where his towel is
It's no use trying to pretend otherwise, we didn't do a great job on making Vista SP1 available. Some of us in the field (Keith for one, Matt for another, Daniel for a third) felt the heat from customers and we did our bit to get the update out sooner. There was a lot of frustration internally.
Well if you're a technet subscriber the Update is at http://technet.microsoft.com/en-us/subscriptions/default.aspx. (Ditto for MSDN) You might expect it to be under downloads and product keys. It isn't (at the moment). Kathy has posted more information to the Technet Plus blog.
The slipstreamed install version will be posted soon. After what Mike Nash said I would have thought that would have be first - but what do I know ?
Incidentally there's a "notable features in Vista SP1" document which gives you a run down of the changes. Most of it is made up of a listing of the hotfixes which came out before SP1 and have been rolled into it, but also gives an idea of what's SP1 specific.
Technorati Tags: Microsoft,Windows Vista,Windows,Vista,Service Pack,SP1
I said I couple of posts back that I have to remind myself that I haven't been doing PowerShell long enough to lay claim to being an expert, but I think I've found one aspect of it which might not be fully appreciated.
Calculated fields can run any code.
I've just used it to create the equivalent of a SQL Join between two CSV files. I used this ability before
Function Choose-Process{$global:Counter=-1$proc=Get-ProcessFormat-Table -inputobject $Proc @{ Label = "ID"; Expression={($global:counter++) }} , processName$proc[(read-host "Which one ?")] }
So where other people would use one or fields from their data, I'm using a variable which I increment. OK. What's the big deal ?
I was writing about geotagging photos with PowerShell the other day; but -to date - I haven't been collecting much GPS data. But I do have some photos - a lot of photos - with information which I want to apply to them: my scuba photos. On every dive I wear a Suunto wrist mounted "computer" which tracks the dive and tells me when I need to come up (or stay down) if I want to avoid getting the bends. It downloads the information it has logged to my PC so I can see a dive "profile" - a plot of depth against time - and the Suunto Dive manager software* helps me record information about the dive like where it was, who I dived with and so on: it can dump output as a set of CSV files. One file describes the dive itself (one line per dive), the another lists the "Profile" records (many lines per dive) Here's a list of the fields I'm interested in.
Time of day is when the dive starts, SampleRate says the computer samples every twenty seconds, and in the profile, SegmentNumber is how many twenty second intervals into the dive we have gone. Once upon a time I would have imported these into Access and done a query to join the two tables, calculate a time for each data point and merge fields to get description. These days I'm doing everything in PowerShell. So... Step one, get an array of objects representing the dives - it's one line Import-CSV | Select object {properties} but broken up for easy viewing
$Dives=(import-csv "MyDives.csv" | select-object -property UniqueDiveID , @{Name="DateTime"; expression={[DateTime]::ParseExact(($_.DiveDate + $_.TimeOfDay), "dd/MM/yyyyHH:mm",[System.Globalization.CultureInfo]::InvariantCulture)}} , SampleRate , @{Name="Description"; expression={$_.Site +"," + $_.Location + ": "+ $_.WaterTemp + "°C"}} )
Import-CSV | Select object is easy stuff. No it's not a typo, in Format-table the calculated fields have a LABEL and in Select-Object they have a NAME. One calculated field merges the date and time, and forces it into a DateTime type (which also sorts out the issues of US formatted and sensible formatted dates). The other calculated fields give me a description like "Horsea Island, Portsmouth: 4°C" or "Black Coral Forest,Turks and Caicos: 28°C" . All very neat, but not wildly clever, step two is to bring in the profile information and for each data point, work out the absolute time, and return the depth and description. Again in ONE Import-CSV | Select object construction: although I've put a where in to reduce the number of dives I'm going to process. Here it is , again formatted to help readability
$profileInfo (import-csv "Profiles.csv" | where-object {[int]$_.uniqueDiveID -gt 150} | select-object ` @{name="DateTime"; expression= {$global:DiveID=$_.UniqueDiveID $global:dive = ($dives | where-object {$_.UniqueDiveID -eq $global:DiveID}) $global:dive.DateTime.AddSeconds([int]$_.SegmentNumber * [int]$global:dive.SampleRate )}} , SegmentDepth , @{name="Description"; expression={$_.SegmentDepth +"M - " +$global:Dive.description}} )
WHOA ! what on earth is going here. Lets pull the calculated fields apart - they're where the clever stuff happens.
One more calculated field gives gets me to record for the photo I'm looking at. Of course the time which links the photo to this record isn't an exact match - and the clock on my camera was on the wrong time zone and 3 minutes 28' fast (I took a picture of it so I could work this out later), but I can use the same "Fuzzy match" method I used in the post about GPS "| Sort-on (Absolute Difference between GPS time and photo time) | select the first one" It's a another calculated field - this time a in a Sort-object .
$profileInfo | sort -Property @{ Expression={[system.math]::abs(($_.datetime - $myphoto.DateTimeTaken.AddSeconds(-(28+(60*3)+(3600*6)))).totalMilliseconds) }} | select-object -First 1
So in the case of the Shark picture what I get is
All set and ready to set the GPS altitude field and description fields in the photo. I've said it before, and this won't be the last time I say it . The efficiency of doing this in powershell amazes me. Here's the pseudo code tagging a whole holiday's photos.
Add headers to Dives.CSVAdd headers to Profiles.csv$Dives=[as above]$ProfileInfo=[As above]get-childItem *.JPG | forEach { $myPicture = Get-Picture ($_.name) $DiveData=$profileInfo | sort [as above] | selectObjectFirst $MyPicture.Description=$DiveData.description $MyPicture.GPSAltitude=-($DiveData.Segment Depth) $MyPicture.Save }
For the next trip I'll have the GPS unit with me and I'll probably at latitude / longitude with depth as "negative altitude".
*Foot note. I prefer the older version of this software, but I think the feature I'm using is unchanged in the new version
I provided Eileen with a quote to use in the Management Excellence programme she's been involved in. She called me a "Non-manager who championed management Excellence", and I replied I was "in favour of all kinds of Excellence*. My view was summed up in the quote
If you can't do it excellently, don't do it at all. Because if it's not excellent it won't be profitable or fun, and if you're not in business for fun or profit, what the hell are you doing here?
The quote is from Robert Townsend's Up the Organization and the bit in bold was on the cover of the original version.
I think managers divide into Organizational people and Leaders. Townsend was a leader, but companies need both types. This set Eileen and I off into talking about Myers Briggs - which is a classification system we use on some of our soft skills training. It uses 4 axes: Introvert <--> Extrovert , Sensing <--> iNtuiting, Thinking <--> Feeling, Judging <--> Perceiving. Based on the letters (initials, except for iNtutiting which gets the N) people get to a shorthand . You could be an INTP, an ESFP or ...you can work out the combinations.
Like Strengthsfinder (which we also use), or more whimsical tests or other, coarser, classifications (gender, age, cultural background), these divisions aren't good/bad or suitable/unsuitable. The Equal Opportunities Commission had a good slogan Women. Men. Different. Equal. Classifications can help us to understand and predict a little more accurately what people do in difficult situations.With people who are too similar you'll get similar answers which may not be the best for the circumstances (hence my view that diversity isn't something patronizing we do for the benefit of the different groups, but something we do for the strength of the company). Sometimes it seems as if we are trying to build hugely complicated taxonomies to classify people or perhaps that we see behaviour as something like a very complicated, undocumented, computer program for which we're trying to discover the input parameters.
I have another axis which, rather politically incorrectly, I call Apparatchik vs Autistic. "Autisitism" isn't a term one should throw around too freely, it is a spectrum which runs from little more than a personality trait, all the way to serious disorder. Surveys I've done suggest that I'm on the spectrum (not unusual in this business) and a few people think I have Asperger's syndrome - though having done some reading I don't think so. So my use of the term is not out of disrespect to those with more serious forms of autism but because one of its characteristics is a failure to understand the world, and see why some things must be the way they are. Apparatchik is almost as dangerous a term to use, but I can't find a better one for people who live within the system and believe that everything should be the way it is. There is a famous "Serenity prayer" asking for "grace to accept with serenity the things that cannot be changed, courage to change the things that should be changed, and the wisdom to distinguish the one from the other". The "Apps" are short on courage to change things, and the "Auts" long on short on serenity to accept things, it's a rare person who has them both in balance and even they aren't necessarily granted the wisdom to tell the difference.
As the Vista SP-1 saga unfolded last week I quoted the famous “Colin Powell on Leadership”, "Being responsible sometimes means pissing people off." is one of the key points; in the body it says "Trying to get everyone to like you is a sign of mediocrity"; but it's also the "living within the system" mentality of the excessively apparatchik . The right thing regardless of what people think is the mentality of the excessively autistic. The word SOMETIMES in the quote is important; the person who always gets people mad is a lousy leader, and the person who never gets people mad is no leader at all. As I said in a post yesterday (which I wrote while this was in draft) I pulled out the quote that "Real leaders are vigilant, and combative" over things that have an adverse impact on their people. Townsend advocates the same thing: in his view purchasing departments "cost ten dollars in zeal for every dollar they save through purchasing acumen." his solution "fire the whole purchasing department". In my world of "apps" and "auts", no app would come to that conclusion. The implication this has for my classifications is problematic.
This SP-1 business has not been great for the field people. At the root of it, some independent hardware vendors have delivered packages with lousy installation software (the problem isn't with the drivers themselves) - computer world has a piece on this . Do we go out and name and shame these vendors ? It would be so tempting; and if they got mad we'd just quote Colin Powell at them; it would be only OK to annoy the IHV community (who are our friends and partners) if customers got something out of it, otherwise it's pointless: would customers get the revised package any sooner if we did this ? No. So we need a different option: should we let the software out and pretend there isn't a problem ? Hardly the act of a responsible leader is it ? Go ahead with the release to OEMs, set the disk making process running and hold the downloads back ? That's going to annoy some customers... (computerworld covered that too following Kathy's post on the Technet plus blog).
Making the right choices is difficult.. And perhaps we made the wrong one on SP1 (an update to went up yesterday). As a field person in Microsoft, when these cases come up it's hard to know whether accept what the product group say or fight for changes, or what specifically leaders in the company should be combative against. The the more I think about the vista SP1 case, the more I think all the answers are wrong
* Footnote. Saying you're in favour of Excellence is a bit like the famous story of the Bishop who was asked for his views on sin. He said he was against it.
Windows Server 2008 and Windows Vista Service Pack 1 have released to manufacturing. Actually it caught me by surprise because I was expecting it to happen later this week.
Alex Hinrichs breaks the news on the Windows Server blog with pictures of the "Ship room" where the decision is made. Over on the Vista blog Mike Nash does the honours for Vista SP1. Mike explains the steps that kick off between release to manufacturing and customers getting the software. RTM is a big thing for the product folks because that's when they say "It's done. This is what we ship". Manufacturing processes spin up, hardware makers get the code. Eventually the SP goes onto Windows update and is pushed out to those who take updates (and haven't used the service pack blocker). I know there will impatience in the meantime.
Talking of impatience, we've said all along we'll release Hyper-V with 180 days of Server 2008. Add 180 days tto today That's August 2nd. I have no firm information about when it will actually ship; I've got my guess- posting it on a "Microsoft blog" risks giving it a false authenticity. And of course if that guess is anywhere near correct I'll be in hot water for "leaking" it ;-)
Eileen phoned me from a traffic jam yesterday. "I've got a demon in the car" she said. A little late for a technical person Eileen has joined the world of Sat Nav owners and her characterization of hers put me in mind of the personal Dis-organizer device which shows up in some of the Terry Pratchett books.
An extremely annoying personal organiser, it is powered by a (usually incompetent) imp, which can perform various tasks. There have been 3 models encountered so far: the Mark 1, mark 2 and Mark 5. All of these start up with an unusually happy tune such as "bingly-bingly beep!", "bingle bingle bingle" or (when wet) "ob oggle sobble obble". The [Mark 1] claimed to have 10 functions, although it appeared that five were apologising for the useless manner in which it performed the others. ... the Mark 5, the Gooseberry, [is] much more useful than its predecessors. It has games, such as "Splong", and "Guess my weight in pigs". It has an "iHum" feature, and can [send messages using 'BlueNose']
An extremely annoying personal organiser, it is powered by a (usually incompetent) imp, which can perform various tasks. There have been 3 models encountered so far: the Mark 1, mark 2 and Mark 5. All of these start up with an unusually happy tune such as "bingly-bingly beep!", "bingle bingle bingle" or (when wet) "ob oggle sobble obble".
The [Mark 1] claimed to have 10 functions, although it appeared that five were apologising for the useless manner in which it performed the others. ... the Mark 5, the Gooseberry, [is] much more useful than its predecessors. It has games, such as "Splong", and "Guess my weight in pigs". It has an "iHum" feature, and can [send messages using 'BlueNose']
Eileen's late to GPS, but since she can find her position on the Globe with a wrist watch a protractor and a couple of match sticks (another of those Obsolete Skills that I referred to), I can't say I blame her. I'm into old-style navigation myself, having got an 'O' level in Air Navigation: actually I'm even more retro than that, I have prints of 17th century maps hanging on the walls at home - many by a Dutchman called Blaeu. Wikimedia have some of this maps - this one gives an idea of the style of the ones I have, and Taschen recently published some of his Atlases and I had the "Anglia" and "Scotia and Hibernia" volumes as a Christmas present. They have an introduction explain Blaeu's role in making the maps (as publisher rather than surveyor), his business and the role of other cartographers, notably Mercator.
Mercator is famous for two things. One he was the first person to call a collection of Maps an Atlas, and he gave his name to a way of mapping the surface of the roughly spherical earth onto a flat sheet of paper. "Mercator's projection" is still widely used even though it is "wrong". (West wing addicts may remember "Cartographers for social Justice" - the idea behind is here ). Looking at a Mercator Map you'd think that if you were going to fly from Munich (Lat 48 degrees) to Seattle (also Lat 48 degrees) the shortest way would be to follow the line of latitude all the way, right ? The shortest distance between two points is a straight line, right ? But (unless you're building a tunnel) you can't go in a straight line along the earth's surface, you have to go in a arc, and the shortest arc doesn't follow a line of latitude, but follows the edge of a slice which passes through the centre of the earth. Which is why flights from Europe to the use go North.
The problem Mercator solved is simple. As you move away from the equator, lines of latitude are equally spaced - 1 arc minute of Latitude is 1 Nautical Mile*. However lines of longitude are not. Just South of North pole you can jog round 360 degrees of longitude in a few paces. At the equator its over 20,000 miles. How do you draw that ? Mercator's solution draw lines of longitude evenly spaced and parallel (in real life they converge at the poles); but to allow for the fact they are actually narrower as you move away from the equator increase spaces between parallel lines of latitude (in real life they are constant distance). So grabbing a handy Mercator projection map (my local Ordnance Survery map) 5' of latitude takes 18CM of map, and 5' of longitude takes only 11CM.
Why does this matter? Well if you have GPS co-ordinates for mapping the boundary of something, then if you simply plot them as square, then the map looks wrong. I've found data for building the SVG file I need for PowerGadgets to do a British county Map. I processed it into the SVG file using PowerShell (of course - and that will be where part 2 comes in). But although the map is recognisable, it looks wrong because I haven't made allowance for the projection. I'm going to do that later, and then explain the PowerShell which I got me there.
*Foot note. A Nautical Mile is 6076 feet, so one arc second of Latitude is about 100 feet. I've seen GPS numbers locations with fractions quoted greater than 0.1 second acuracy the "10 foot" accuracy quoted for consumer GPS devices
Skimming down my feeds this weekend I found a post from Scoble on obsolete skills (a new wiki has grown up). One was "developing film".
Unless you've done it it's hard to describe the rituals of processing and printing black and white film. It goes something like this.
It's a tactile process, a bit like baking your own bread, and like baking it has it's rituals (the way you you bang the tank, or shake it). Like baking it has its smells too, although I'll take the smell of bread over photographic chemicals any day. I miss all of that, truly I do. But it was so time consuming. There are some photos which are only possible with particular kinds of film nothing in the digital world quite matches Kodak High-Speed Infra-Red, which has just gone out of production. I bought 10 rolls of it because... why exactly ? I guess I can't bear the thought of not being able to create some of the IRs I've done in the past, although I haven't shot a roll of the Kodak in 3 years. Those rolls cost me £10 each.
I've just ordered an extra 4GB SD card for £8.99 (non UK readers, that's a little under $20 US). That's less than cost of that Kodak stock, although you can just about buy a roll of colour print film and get it processed for £8.99. Worst case shooting RAW files that card will hold something like 250 pictures, shooting JPGs it will be more like 1400. So even if I only used the card once - it costs only about 1/30th of film. It does pose the question why do I bother erasing and reusing memory cards... why not just use them once and file them as a backups ? I suspect they don't last forever - I wonder what the expected life of something stored on SD is.
As I forecast when I posted the news of Vista SP1's release the delay in making it widely available has caused some "impatience". Mike Nash has come back with an update on the availability.
I'm always suspicious of people talking down security vulnerabilities, but I don't like to see them over-hyped either; so I'm going down the former path. You are allowed to be skeptical.
A couple of people have mailed me this morning about this story, picked up by the register (a couple even forwarded me the Academic Paper. - SEND A LINK PEOPLE !)
Synopsis. RAM contents don't disappear instantly. If you get to a machine which is powered on including low power "sleep modes" and reboot it, there is a window during which you can mount an attack on the RAM contents. An attacker can can extend this Window by chilling the RAM.
As well as getting at documents I happen to be working on, by attacking the RAM one can also get to the keys used by different kinds of whole drive encryption software - including Bitlocker. These attacks can be prevented by
One of the researchers put it like this "Let's say you're in a coffee shop and you leave your Vista notebook screen-locked and tied to a table while you take a trip to the bathroom". I leave my laptop tied to a table ? With no one watching it ? OK... The attacker has to boot from his device, discover my key, and then what ? Steal the laptop I guess. Or maybe set about decrypting it's contents. I'd need to be in the bathroom a long time.
The register explains that With certain types of DRAM, a simple cold boot won't do the trick. Data fades too quickly after power down. All [attackers] have to do is open up the machine and spray a little liquid nitrogen.
I'm trying to work out how likely the average hacker is to carry a Thermos of Liquid nitrogen with them. Using security screws on the RAM compartment would mean they had to carry more tools - why not just carry a set of cutters to get past any tie, but the simpler way might to carry a knife and force me to give them the keys/passwords they need ?
I know a few companies which use security screws to stop users swapping company parts out of their computers and using them in their home machines, and lock the bios setup to prevent users breaking things. Add those the the good practice list for machines that need to be secure. Group policy can be used to disable Sleep - I'd tend to keep it for power saving - but it can set "Closing lid" to force Hibernate when the lid is shut. Add that to the list of good practices as well.
I try not to stand still when I'm presenting; stand behind a lectern for too long and you end up holding onto it , staring down and droning on to your PC. Radio Mics and the wireless presenter mouse give the freedom to stroll around the stage to my hearts content. The problem with demos is that you end back behind your PC and if I have to show PowerShell I'm behind the PC typing long command-lines. Mistyping them as often as not (and wondering why they didn't work). Getting tempted to go off the script too. Jeffrey Snover came up against this problem and created a fix as he explained here. There's a revised version here. Frankly once you've seen it, a demo without using it would be daft.
Still this leaves the problem of having to press keys. I don't want to be stuck behind my PC, I want to click through the demo like I click though my slides.
I thought about this for a while, and thought there was the option to do some clever button assignment in the Intelli-mouse software. Sure enough you can assign different actions to different programs so I've assigned the Wheel button to [ENTER] (you can choose any key stroke) so now I can just click through the automated script.