James O'Neill's blog

Windows Platform, Virtualization and PowerShell with a little Photography for good measure.
Posts
  • James O'Neill's blog

    Vista activation

    • 2 Comments

     

    One of the things I learnt in the run up to last week’s BETT show was about licensing. I often joke that I have a degree in computer science, 40 Microsoft product certifications and 20 years industry experience but that doesn’t fit me out to understand licensing. The thing I learnt is that schools have volume license agreements too. So it wasn’t surprising that some of the questions we got on the stand were about the activation of Vista. People kept asking about some Scottish bloke called “MacKey” or rather MAK keys. And at this point we need to dive into the rabbit warren which is vista activation.

    We have more than one kind of volume licence key. We have a “Multiple Activation Key” (MAK) or a “Key management service key”.  The best place to learn about this is the Vista Volume Activation Page. Here is a precis, and let me up front and say that this is a shortcut to understanding the other information which is available: if any errors have crept in please remember this blog is subject to the caveat 'This posting is provided "AS IS" with no warranties, and confers no rights.'

    Vista has different keys for different versions sometimes called SKUs (stop Stock keeping units) , and for different channels of supply. The installation media is the same for Ultimate, or business or home basic, but the keys are different. Business has a different keys depending on whether it is purchased Retail, or pre-installed by an OEM, or as part of a Volume license agreement.

    Retail keys can only be used on one computer. Volume keys allow a single key on more than one. All copies of Vista need to be activated.  Depending on how you count the methods there are 3 or 4 ways to activate.

    • Internet activation. This works with both retail and volume versions. If the Internet service thinks that the key has been used the allowed number of times it will fail to activate.
      During this year we plan to introduce a server which goes by the name of "Volume Activation Management Tool (VAMT)". This tool is not out yet, but it will be Proxy for Internet activation for clients who would not otherwise be given Internet access. (Decide for yourself if this counts as an activation method)
    • Phone activation. Intended for people who can't connect or don't believe what we say in our privacy statement about the data used in activation. This is also the route that you use if Vista thinks it has been moved to a new computer and the activation service refuses to re-activate the OS.
    • Key Management service. The easy way to think of this tool is as a block of pre-activated IDs. Every machine using KMS for licensing gets a key for 180 days. It will try to renew at intervals during that time rather than wait till the end. If it can't get find a server or if the server has run out of IDs then it gets a 30 day grace period before falling into Reduced Functionality Mode.

    KMS seems useful for organizations who need to transfer licences to newer machines, and whose users connect to the corporate network at least every 209 days (after 180 + 30 day grace period the machine won't be usable), it only works when there are more than 25 clients, below that MAK needs to be used.

    I've summarized the information in a mind map (click for a larger version)

     As I said before the definitive source for this is the Vista Volume Activation Page. This has detail about how keys are obtained, and entered into the installation process, more detail about the choices between MAK and KMS and so on. If you find any differences between that page and this one, it is correct (but please let me know).

    Update. Thanks to Mark Parris for pointing out my Typo. a SKU is a Stock keeping unit. Even the most state of the rat spell chequer won't pick that up.

  • James O'Neill's blog

    Pigs and drugs and naked dwarves ...

    • 1 Comments

    Yes folks they're all part of life's weird tapestry as a British Microsoft employee at a Microsoft event in Seattle.

     After I referred to Snowclones recently it I should point out that blank and drugs and blank blank blank is a snow clone modeled on Ian Dury's "Sex and Drugs and Rock and Roll". Dury said he was from Upminster, where I was born, although according to his Wikipedia entry he was actually actually born in Harrow.  There is a an old joke - based on the stations on London Underground's district line; "You've got mad, Barking Mad, and Upminster"... "Upminster ?" "Serveral stops beyond Barking".

    So what of the Pigs, the Drugs and the naked dwarves ?

    First the pigs. Seattle has "Pigs on Parade" going on at the moment and wherever I walk in this city there are fabulous decorated pigs. Microsoft is one of the many sponsors I'm pleased to say.  I've been grabbing pictures with the camera on my smartphone when I see them. Here are couple

    IMAGE_319.jpg IMAGE_315.jpg

    Next the Drugs.  Steve and I have ended up doing some unscheduled research into the American Health Care system. He can tell what happened to him for himself. As for me, well for the last five years or so a prescription drug has helped me lead a bit more normal life than would otherwise be the case. I bought a supply with me to the US. Sometime in the last couple of days I lost it. I'm got going to die or  go "Upminster" for lack of my drug, but withdrawal isn't fun, and it will need a few days of taking it to again to get back to normal. So I called the emergency number we have for just these kinds of things, got referred to a Doctor who could prescribe me enough to see me home. I had to pay for my own, and at £2.30 per tablet my usual prescription charge of £6.50 for 28 looks a real bargain. Our system works. My phone says I made the call at 3:16, and the receipt from the Pharmacy is timed at 5:40, and more than half the time was spent in or waiting for Taxis. I don't actually inhabit the kind of World that William Gibson writes about - but it reminded me of the the opening of Count Zero, a few sentences in, it has this "Because he had a good agent, he had a good contract. Because he had a good contract, he was in Singapore an hour after the explosion. Most of him, anyway."  (The very first sentences of Gibson's books are often great Count Zero starts "They set a Slamhound on Turner's trail in New Delhi, slotted it to his pheromones and the color of his hair").

    But if you've read this far, you want to know about the Naked Dwarves.

    There are a bunch of memorable quotes from this week. One was Bill Gates talking about PBX's as Mainframes "an expensive way of doing things in a rigid way". One was a product manager talking about a product which is still secret, and referring to the next product which is so hush-hush they've code named it "Shshhhh".  (Which reminds me of a programming language called "KEEP". The developer was asked what KEEP stood for. "It's not an acronym" he said "I just found a good way not to have people throw program listings away was if the header page said 'KEEP' in big letters" ) However the prize for the best single line of the week (and I have permission from someone in Legal to blog this), is the explanation of how a Microsoft employee, in the context of a legitimate business conversation came to shout down the phone to someone "If you don't get a naked dwarf in my office by this afternoon, I'm coming over there to get one for myself".

    I will explain the context of this ... but in another post :-)

  • James O'Neill's blog

    Pigs and blogs and Naked dwarves (Part 2)

    • 2 Comments

    "The Sow borg" by James KelseyI'm back from Seattle, and after my outbound trip, the return was uneventful. I'd hoped to come back with plenty of stuff to blog about but most of what I heard that was interesting is still confidential. Before I left I had time to do "the Walk of Pork"  and check out some more of Seattle's Pigs on Parade . This one was actually sponsored by Microsoft. Who says we don't have a sense of humour ? 

    One of the side meetings we had in Seattle was a "Bloggers' town hall meeting", and the usual subjects came up. A commonly asked question goes "If I can't write it on a 'work' blog can I write it on a 'personal' one ?" .  "Ben", my blog, stalker mailed Eileen (as none@none.com but we have his IP address), because he didn't think I should post about "business travel rage"; he suggested I get "two blogs; one that deals with IT from a Microsoft angle that I can legitimately read at work and a 'violence' blog where we can all get our daily fix of automatic weapons, the 'red mist'".  I'm unapologetic that I don't stick squarely to my technology cluster, but blog interesting things that I come into contact with in my working life. The problem with having multiple blogs is that as soon mention that you work for Microsoft and things that you say will be linked to that if it makes sense. Political issues do have a place on a work blog because policies set by governments affects what we do, but Party politics shouldn't appear on a company platform. - I want to write "Gordon Brown is a moron" or "Gordon Brown is a genius" a private blog would be the place and no-one is likely to run a headline "Microsoft attacks/praises Prime Minister" as a result. However if I were to write either of those about, say, Steve Jobs, you can see the headline "Microsoft attacks/praises Apple Boss" followed by "A Microsoft employee, writing on his blog said ..."  Talking to Steve (Lamb - not Jobs) he thought it was a sad that we can't have individual freedom of speech because what we say isn't seen as the speech of individuals. Of course people can blog under a pseudonym  (I quite fancy "Borg-Pig 4/19"); but if you have to guard your anonymity that's hardly individual freedom of speech either. There are things which might make good posts which I self-censor but so few could go on an out-of-Microsoft blog that I don't see the point of having one.

    It was in the process of explaining the importance of context that a lawyer from our games division told us the following - which he was happy for me to retell. In making modern video games it's now quite common to make clay sculptures of the characters. These characters are dressed in their costume so that the clothes look right - which matters if the digitized image of the figure appears in the final game; underneath the characters are naked. The characters also need to be seen by people from legal, and during the production of Shadowrun they had to check out the figures of Naked Dwarves, Elves, Humans and Trolls. It was in this context that a lawyer came to demand a naked dwarf in his office. Not that the person who overheard him necessarily understood that at the time ...

  • James O'Neill's blog

    Getting PDF Preview in Vista and Outlook. A "must have".

    • 2 Comments

    In place preview of files is a great feature of Vista's shell and Outlook 2007.  The lack of support for PDF files really got an my nerves. It seems it got  Tim Heuer too. Except Tim did something about it. He worked with the folks at Foxit software - who do a lot of tools for PDF manipulation and and produced on. Currently it's Vista only, but it works in the shell as well as in Outlook. The details, download link and screen shots are on Tim's blog

    I put "Must have" in quotes, because this is not a Microsoft endorsement. My evaluation so far has been brief and positive; you should do your own evaluation.

    Thanks to Arthur of the Unified communications user group for passing this on

     

  • James O'Neill's blog

    How to get user input more nicely in PowerShell

    • 2 Comments

    Long, long ago when I was using my first Microsoft product, I knew one way to get input from the user. The product was Commodore BASIC (in those days we wrote it in uppercase and knew it stood for Beginners All-purpose Symbol Instructional Code). and the method was INPUT. This was back in early 1979 : the user typed something pressed Enter and you could then process it. Later I learnt about GET so you could input with a single keystroke (and process it to see if the user had given you the right input). After all the myriad ways of getting input in the GUI,   PowerShell seems a bit retro (on the surface at least). But recently, I was poking around looking for something else and found that under the surface PowerShell has got some useful tricks which I’ve started to use and I’ll share here.

    PowerShell has a variable $host which contains information about the program where it is running (the console host or the ISE environment). $host.ui contains a “User Interface” object which has some interesting methods

    • Prompt / PromptForChoice / PromptForCredential
    • ReadLine / ReadLineAsSecureString
    • Write  /  WriteDebugLine  /  WriteErrorLine  / WriteLine  / WriteProgress  / WriteVerboseLine / WriteWarningLine

    The write ones have associated write- cmdlets, and the read ones are the basis of the read-host cmdlet. What about the prompt ones ? PowerShell has get-Credential but the  $host.ui.PromptForCredential has a couple of extra options: for example you can change the caption on the title bar and the message above the text boxes in the prompt. Like this:

    $Host.ui.PromptForCredential("","Enter an account to add the machine to the domain","$env:userdomain\$env:username","")

    The two empty strings are the caption, which defaults to “Windows PowerShell credential Request” and the password field; so the result looks like this.

    image

    What about promptForChoice ? For some time I have been using a function first named “choose-list” and now named “Select list” to fall in line with the “approved verbs” from the PowerShell team. Dan who wrote the “soliciting new verbs”  post on the team blog got in touch with me to say I ought to do this, I didn’t think what “choose” did matches the description of “select” and put forward “choose” as new verb. It didn’t get approved but at some point the definition of Select will be broadened. This works well when you want to choose from something which is naturally a table, but if you want something like PowerShell’s own prompts.

    image

    That is where Prompt for choice comes into play

    the choices which are passed to the method are in a slightly awkward format , you need to  use New-Object System.Collections.ObjectModel.Collection[System.Management.Automation.Host.ChoiceDescription]
    and for each item on the list use its Add method so the natural thing was to wrap it in a function.

    Function Select-Item 
    {    
    <# .Synopsis
            Allows the user to select simple items, returns a number to indicate the selected item.
        .Description
            Produces a list on the screen with a caption followed by a message, the options are then
    displayed one after the other, and the user can one.
            Note that help text is not supported in this version.
        .Example
            PS> select-item -Caption "Configuring RemoteDesktop" -Message "Do you want to: " -choice "&Disable Remote Desktop",
    "&Enable Remote Desktop","&Cancel"  -default 1
           Will display the following
            Configuring RemoteDesktop
            Do you want to:
            [D] Disable Remote Desktop  [E] Enable Remote Desktop  [C] Cancel  [?] Help (default is "E"):
        .Parameter Choicelist
            An array of strings, each one is possible choice. The hot key in each choice must be prefixed with an & sign
        .Parameter Default
            The zero based item in the array which will be the default choice if the user hits enter.
        .Parameter Caption
            The First line of text displayed
         .Parameter Message
            The Second line of text displayed    
    #>
    Param( [String[]]$choiceList,
             [String]$Caption="Please make a selection",
             [String]$Message="Choices are presented below",
             [int]$default=0
          )
       $choicedesc = New-Object System.Collections.ObjectModel.Collection[System.Management.Automation.Host.ChoiceDescription]
       $choiceList | foreach  { $choicedesc.Add((New-Object "System.Management.Automation.Host.ChoiceDescription" -ArgumentList $_))}
       $Host.ui.PromptForChoice($caption, $message, $choicedesc, $default)

    One of the things on my blogging backlog is the some the of the V2 features like the help text which I’ve used here. As you can see there is a lot more help than anything else, and the parameters take up more space than the business end of the code. The function will return a number, starting from zero which indicates which option was chosen. There are a couple of ways I have been using this, because two options return 0 or 1 I can easy convert that to true or false – the first one will always be FALSE. Also notice the selection character for an option is prefixed with &

    PS > $enabled=[boolean](select-item -Caption "Configuring RemoteDesktop" -Message "Do you want to: " -choice "&Disable Remote Desktop", 
    "&Enable Remote Desktop"  -default 1 ) 

    Configuring RemoteDesktop Do you want to: [D] Disable Remote Desktop  [E] Enable Remote Desktop  [?] Help (default is "E"): d

    PS C:\Users\jamesone\Documents\windowsPowershell> $enabled False

    This throws up an issue though – what if the user doesn’t want to change the state ? I can have Disable , Enable and Cancel  but cancel will return 2 , and any non zero value evaluates to true, so cancel will enable remote desktop in that case! The obvious thing to do is to use a switch statement, which does nothing if the cancel option is chosen.

    Switch (select-item -Caption "Configuring RemoteDesktop" -Message "Do you want to: " -choice "&Disable Remote Desktop",
    
                       "&Enable Remote Desktop","&Cancel"  -default 1 )
                  {
                       1 {Enable-RemoteDesktop -confirm } 
                       0 { Disable-RemoteDesktop -confirm } 
                  }

    Enable and disable- remotedesktop are functions I'm working on , not standard powershell cmdlets. More on that another time. This is part of a menu for configuring systems and I’m making use of something I got from James Brundage (who post more on the PowerShell blog than his own these days). I don’t want to steal his thunder because it’s another technique which I’m using in lots of places and I think should go on the list of good practices.



  • James O'Neill's blog

    Where Microsoft went wrong with Vista

    • 47 Comments

    As I mentioned in my last post I've made my way to Microsoft HQ with a Visit to Canada on the way; this meant flying out through Heathrow Terminal 5.

    T5 got off to a bad start, and we made contingency plans for lost luggage, delays etc. The reality: the easiest taxi drop-off I've seen at a UK airport, very short queues to check in in, lower security hassles than most airports, and as pleasant a place to wait for my flight as I've found; and baggage arrived successfully at the other end. The story is doing the rounds that the initial problems weren't just teething troubles, but were down to BA not training its staff on what was new... I understand that they showed up for work on the morning the terminal opened and had to work out where they were supposed to park and go on from there...

    Now one of the things that has come up in the meetings I have been in is that we've done a lot of survey work around Vista. 94% of PCs sold via retail have Vista on them. In our recent financial statements to Wall street we said we'd sold 180 Million licences. Corporate customers are buying Vista licences faster than they are deploying, but the same happened with XP, and the rate of deployment of Vista is about the same as XP was at the same point in its life. But Vista is not getting the good press it deserves.

    click for full size image. 2 years ago, at every meeting I went to someone would try it plug their laptop into a projector to show their slides. And it wouldn't work "Press Function F5" someone would call out "No, this one's a Dell , F5 is for the HP" another would say. "Oh... try F8" .  People would slip out of the room to get a coffee or make a quick call. By the time it had been sorted out 5 minutes had passed. It's a very conservative estimate to say I lost 10 minutes a week this way. Over a year that's a whole working day. 

    Then Vista came along and it has the Mobility Center. Press [Window key] [X] and up it Pops. Click connect to display and WHOOSH the presentation is on the screen. That's a day saved: and knowing what Microsoft consulting Services used to charge for my time, that's worth more than cost of the upgrade licence, and the deployment cost and so on.

    I brought this up in the group meeting this morning when someone said something about "people not being able to use PowerPoint because of Vista".. The betas of Nvidia's Vista driver 6 months before launch didn't work when a monitor was plugged in, but 3 Months before launch that problem went away. I must have sat through upwards of 500 PowerPoint presentations since Vista came out, and I've never seen a problem related to Vista. If the battery fails in someone's slide clicker what I hear is "That's vista for you", if the projector won't focus "It's vista". That's wearing a bit thin. What shocked me was someone at the same table leant over after I'd said all that and asked "What was the key combination for that ?"

    Earlier in the session, a senior Microsoft person said she'd really valued the training everyone received on XP, and how she missed that with Vista. Anyone can switch from XP to Vista without re-training. You get security benefits, a better network stack, easier deployment  but it takes a little time to show people what can be done. How you get the best out of search, use tagging and previews in explorer, turn off the sound for one irritating application without turning them all off. The list goes on. We didn't teach people those things. And not everything about a brand new OS is positive.  Some hardware isn't up to the task - I will tell the story of my Home PC another time, but the short form is it needed me to spend £40 on RAM and the 5 year old graphics card doesn't support Glass; it works better and does more than it did under XP. Some things won't have drivers in the early days. The number of drivers available at launch was a creditable 30,000 but that's increased by over 150% (77,000 at SP1). Some applications don't work on a new service pack never mind a new release: not everyone has got to grips with the Application Compatibility Toolkit which has helped to provide an environment where some real horrors can be persuaded to run. And user account control annoys IT Professionals like the seat-belt alarm in my car annoys drivers. I don't need to be told I'm manoeuvring the car with my belt off. I do want to know if my children undo their belts when we're driving down the motorway. I hope the safety parallel is obvious.

    We didn't give our own people the skills to talk about these things. And our own gleaming new state of the art product had a "Terminal 5" experience. SP1 for Vista was a milestone which gave people the feeling they could go back and have another look at Vista (in fact almost all of key changes had happened before SP1). I wonder how long it will be before people stop trying to avoid T5.

     

    Update. Fixed several typos. Jet lag. Grrrr.

  • James O'Neill's blog

    Managing Windows Update with PowerShell

    • 9 Comments

    I mentioned some of the server management and config tools I’ve been creating with Server 2008 R2 core in mind, and I’m going to put the major bits here. I’ll post the whole script at the end of the set of posts but for now here is the code to look after Windows update

    First I created two hash tables to map the numbers used in the functions to some meaningful text

    $AutoUpdateNotificationLevels= @{0="Not configured"; 1="Disabled" ; 2="Notify before download"; 
    3="Notify before installation"; 4="Scheduled installation"}
    $AutoUpdateDays=@{0="Every Day"; 1="Every Sunday"; 2="Every Monday"; 3="Every Tuesday"; 4="Every Wednesday";
    5="Every Thursday"; 6="Every Friday"; 7="EverySaturday"}

    Next, there is a COM object for everything relating to auto-update. It has a settings property which contains the notification level and update days, the hour at which updates are fetched and how recommended updates are processed.  Setting the properties is pretty easy, and there is is a save method to commit them  - I’ve been lazy here and haven’t got a hash table mapping names to numbers for the notification level so or multiple switches so the user would need to know that notification levels in the hash table (or enter  $AutoUpdateNotificationLevels at the prompt to see what is in the table) – I might fix that for the final script.

     Function Set-WindowsUpdateConfig
    
    {Param ($NotificationLevel , $Day, $hour, $IncludeRecommended)
    $AUSettings = (New-Object -com "Microsoft.Update.AutoUpdate").Settings
    if ($NotificationLevel)  {$AUSettings.NotificationLevel        =$NotificationLevel}
    if ($Day)                {$AUSettings.ScheduledInstallationDay =$Day}
    if ($hour)               {$AUSettings.ScheduledInstallationTime=$hour}
    if ($IncludeRecommended) {$AUSettings.IncludeRecommendedUpdates=$IncludeRecommended}
    $AUSettings.Save
    }

    To show what the settings are, I decode them and return a custom object with the decoded properties.

    Function Get-WindowsUpdateConfig
    
    {$AUSettings = (New-Object -com "Microsoft.Update.AutoUpdate").Settings
    $AUObj = New-Object -TypeName System.Object
     Add-Member -inputObject $AuObj -MemberType NoteProperty -Name "NotificationLevel"   `
        -Value $AutoUpdateNotificationLevels[$AUSettings.NotificationLevel]
    Add-Member -inputObject $AuObj -MemberType NoteProperty -Name "UpdateDays"      `
           -Value $AutoUpdateDays[$AUSettings.ScheduledInstallationDay]
    Add-Member -inputObject $AuObj -MemberType NoteProperty -Name "UpdateHour"        `
       -Value $AUSettings.ScheduledInstallationTime Add-Member -inputObject $AuObj -MemberType NoteProperty -Name "Recommended updates" `
    -Value $(IF ($AUSettings.IncludeRecommendedUpdates) {"Included."}  else {"Excluded."}) $AuObj
    } 

    Checking on MSDN I found there is another object used in a script WUA_SearchDownloadInstall , which does what it says – it searches Windows update for updates, downloads them and installs them I added the logic to my function to over-ride the selection criteria, and auto-Restart if a restart is needed. Since it is sometimes useful to patch Virtual Machines, then shut them down, then Patch the host and then reboot it and bring the VMs back again , I’ve also put in a shutdown after Update switch.

    The logic is simple enough, create a Session object which has CreateSearcher, CreateDownloader and CreateInstaller Methods. Then create a searcher and use it to get updates matching the default or specified criteria. If there are any updates, create a downloader object, hand it the list of updates found by the searcher and start a download. If the download completes successfully, filter out the successfully downloaded items, and pass those into a newly created installer object. Run the installation process and afterwards output a table showing the state of the updates. Finally reboot if needed.

    Function Add-WindowsUpdate
    
    {param ($Criteria="IsInstalled=0 and Type='Software'" , [switch]$AutoRestart, [Switch]$ShutdownAfterUpdate)
    $resultcode= @{0="Not Started"; 1="In Progress"; 2="Succeeded"; 3="Succeeded With Errors"; 4="Failed" ; 5="Aborted" }
    $updateSession = new-object -com "Microsoft.Update.Session"
    write-progress -Activity "Updating" -Status "Checking available updates" 
    $updates=$updateSession.CreateupdateSearcher().Search($criteria).Updates
    if ($Updates.Count -eq 0)  { "There are no applicable updates."}  
    else {
           $downloader = $updateSession.CreateUpdateDownloader()
           $downloader.Updates = $Updates 
            write-progress -Activity 'Updating' -Status "Downloading $($downloader.Updates.count) updates" 
           $Result= $downloader.Download() 
           if (($Result.Hresult -eq 0) –and (($result.resultCode –eq 2) -or ($result.resultCode –eq 3)) ) {
    
           $updatesToInstall = New-object -com "Microsoft.Update.UpdateColl"
           $Updates | where {$_.isdownloaded} | foreach-Object {$updatesToInstall.Add($_) | out-null }
           $installer = $updateSession.CreateUpdateInstaller()
           $installer.Updates = $updatesToInstall
           write-progress -Activity 'Updating' -Status "Installing $($Installer.Updates.count) updates'
            $installationResult = $installer.Install()
            $Global:counter=-1
            $installer.updates | Format-Table -autosize -property Title,EulaAccepted,@{label='Result';
                                   expression={$ResultCode[$installationResult.GetUpdateResult($Global:Counter++).resultCode ] }}
           if ($autoRestart -and $installationResult.rebootRequired) { shutdown.exe /t 0 /r }
           if ($ShutdownAfterUpdate) {shutdown.exe /t 0 /s }
    }
    } }

    So now I can run
    Add-WindowsUpdate –Auto to download updates and reboot if needed,
    Set-WindowsUpdateConfig –n 4 –i to schedule updates (Including the merely recommended)  and
    Get-WindowsUpdateConfig

    So next up it’s Get-RemoteDesktopConfig and Set-RemoteDesktopConfig.

  • James O'Neill's blog

    Bootable USB keys

    • 4 Comments

    Since I raised the subject I've had a mail from a couple of people on the subject of making a bootable key.

    I described the steps making a USB key bootable using the Vista / Windows PE version of Diskpart. Here are the commands

    • select disk 1 {or the number of your USB key, be careful !}
    • clean  {Like I said, be careful ! This erases the disk}
    • create partition primary
    • select partition 1
    • active
    • format fs=fat32
    • assign
    • exit

    Now at this point you have a disk which will try to boot using BootMgr in the style of Windows PE/Vista/Longhorn server. Several people have asked about making a key which boots in the style of Server 2003/XP/Windows 2000/Windows NT. I can't make the Vista/PE version of disk part run on Windows XP, and the older version won't prepare a USB key. So you need to do this from Vista or the Vista build of Windows PE. Once the drive is formatted it has a Vista Boot sector - this won't boot NT / 200x / XP operating systems. You need to use the BootSect utility:
    Boosect /nt52 E:
    stamps a Window 2003 Server boot sector (one which uses boot.ini) onto drive E:. I haven't tried it but you should be able copy NTLDR, BOOT.INI and NTDETECT.COM onto a USB key as a way of starting a machine which with a corrupt boot environment.

    For now, as far as I can tell, there's no way to set-up such a device under XP/Server 2003. I'd welcome any correction on this.

     

    Technorati tags: , , ,
  • James O'Neill's blog

    How to manage the Windows firewall settings with PowerShell

    • 1 Comments

    I mentioned recently that I’m writing a PowerShell configuration tool for the R2 edition of Hyper-V server and Windows server core.   One of the key parts of that is managing the firewall settings…. Now… I don’t want to plug my book too much (especially as I only wrote the PowerShell part) but I had a mail from the publisher today saying copies ship from the warehouse this week and this code appears in the book (ISBN  9780470386804 , orderable through any good bookseller)

    The process is pretty simple. Everything firewall-related in Server 2008/Vista / Server R2/ Windows 7, is managed through the HNetCfg.FwPolicy2 COM object, so. First I define some hash tables to convert codes to meaningful text, and I define a function to translate network profiles to names. So on my home network

    $fw=New-object –comObject HNetCfg.FwPolicy2  ;  Convert-fwprofileType $fw.CurrentProfileTypes  

    returns “Private”


    $FWprofileTypes= @{1GB=”All”;1=”Domain”; 2=”Private” ; 4=”Public”}
    $FwAction      =@{1=”Allow”; 0=”Block”}
    $FwProtocols   =@{1=”ICMPv4”;2=”IGMP”;6=”TCP”;17=”UDP”;41=”IPv6”;43=”IPv6Route”; 44=”IPv6Frag”;
                      47=”GRE”; 58=”ICMPv6”;59=”IPv6NoNxt”;60=”IPv6Opts”;112=”VRRP”; 113=”PGM”;115=”L2TP”;
                      ”ICMPv4”=1;”IGMP”=2;”TCP”=6;”UDP”=17;”IPv6”=41;”IPv6Route”=43;”IPv6Frag”=44;”GRE”=47;
                      ”ICMPv6”=48;”IPv6NoNxt”=59;”IPv6Opts”=60;”VRRP”=112; ”PGM”=113;”L2TP”=115}
    $FWDirection   =@{1=”Inbound”; 2=”outbound”; ”Inbound”=1;”outbound”=2}

     

    Function Convert-FWProfileType
    {Param ($ProfileCode)
    $FWprofileTypes.keys | foreach –begin {[String[]]$descriptions= @()} `
                                    -process {if ($profileCode -bAND $_) {$descriptions += $FWProfileTypes[$_]} } `
                                    –end {$descriptions}
    }


    The next step is to get the general configuration of the firewall; I think my Windows 7 machine is still on the defaults, and the result looks like this

    Active Profiles(s) :Private 
    

    Network Type Firewall Enabled Block All Inbound Default In Default Out
    ------------ ---------------- ----------------- ---------- -----------
    Domain                   True             False Block      Allow     
    Private                  True             False Block      Allow     
    Public                   True             False Block      Allow     

    The Code looks like this 
    Function Get-FirewallConfig {
    $fw=New-object –comObject HNetCfg.FwPolicy2
    "Active Profiles(s) :" + (Convert-fwprofileType $fw.CurrentProfileTypes)
    @(1,2,4) | select @{Name=“Network Type”     ;expression={$fwProfileTypes[$_]}},
                       @{Name=“Firewall Enabled” ;expression={$fw.FireWallEnabled($_)}},
                       @{Name=“Block All Inbound”;expression={$fw.BlockAllInboundTraffic($_)}},
                       @{name=“Default In”       ;expression={$FwAction[$fw.DefaultInboundAction($_)]}},
                       @{Name=“Default Out”      ;expression={$FwAction[$fw.DefaultOutboundAction($_)]}}|
                Format-Table -auto
    }

    Finally comes the code to get the firewall rules. One slight pain here is that the text is often returned as pointer to a resource in a DLL, so it takes a little trial and error to find grouping information.
    The other thing to note is that a change to a rule takes effect immediately, so you can enable a group of rules as easily as :

    Get-FireWallRule -grouping "@FirewallAPI.dll,-29752" | foreach-object {$_.enabled = $true}

     

    Function Get-FireWallRule
    {Param ($Name, $Direction, $Enabled, $Protocol, $profile, $action, $grouping)
    $Rules=(New-object –comObject HNetCfg.FwPolicy2).rules
    If ($name)      {$rules= $rules | where-object {$_.name     –like $name}}
    If ($direction) {$rules= $rules | where-object {$_.direction  –eq $direction}}
    If ($Enabled)   {$rules= $rules | where-object {$_.Enabled    –eq $Enabled}}
    If ($protocol)  {$rules= $rules | where-object {$_.protocol  -eq $protocol}}
    If ($profile)   {$rules= $rules | where-object {$_.Profiles -bAND $profile}}
    If ($Action)    {$rules= $rules | where-object {$_.Action     -eq $Action}}
    If ($Grouping)  {$rules= $rules | where-object {$_.Grouping -Like $Grouping}}
    $rules}

    Since this the rules aren’t the easiest thing to read I usually pipe the output into format table for example

    Get-firewallRule -enabled $true | sort direction,applicationName,name | 
                format-table -wrap -autosize -property Name, @{Label=”Action”; expression={$Fwaction[$_.action]}},
                @{label="Direction";expression={ $fwdirection[$_.direction]}},
    @{Label=”Protocol”; expression={$FwProtocols[$_.protocol]}} , localPorts,applicationname

     

    Last, but not least if you want to create a rule from scratch you want to create a rule object with New-object –comObject HNetCfg.Fwrule, you can then pass it to the add method of the Policy object’s rules collection.  If I ever find time to finish the script it will probably have new-firewallRule, but for now you need to write your own.

  • James O'Neill's blog

    Privacy again

    • 17 Comments

    I've managed to get a lot of my concerns about privacy down to a simple statement. "Databases of everything" worry me. Where we've been, what we've bought, who we've associated with. I alluded to a conversation I was in last week where we talked about the information that could be gathered by Live ID -  during that conversation someone made the observation that people stop worrying about privacy when they see utility.  Even with my paranoia I'm fairly happy for Amazon to tell me things I might like, because the know what I've bought in the past. I haven't bought many things - and some gifts I've bought lead to odd recommendations. But I don't use a supermarket loyalty card because (or even use the same credit/debit card each time I shop) because that's somehow the wrong side of the line.

    I thought there might a place where everyone would draw the line... ?  For example implanting RFID into people is pure sci-fi, right ? Wrong: I thought when I read that doctors were talking doing just that to track patients with Alzheimer's - the technology comes from Verichip makers of "VeriGuard™ "the first radio frequency identification (RFID) security solution to combine access control [with] VeriChip's patented, human-implantable RFID microchip. "  

    The BBC has previously reported on surveillance uses of RFID tags and last Friday they reported how RFID can be used in combination with Wifi : 
    'Angelo Lamme, from Motorola, said tracking students on a campus could help during a fire or an emergency. "You would know where your people are at any given moment," he said. ' 
    Yes. You'd know where they are every moment of every day - a classic "database of everything".  1.8 Million people signed the Downing Street Petition against tracking every vehicle movement for road-pricing - clearly this didn't offer enough utility to offset the loss of privacy. But the Motorola representative thinks Emergency protection does.

    As I said, we were chatting informally about the Utility/Privacy trade-off and was it acceptable for Windows Live to be a database of everything ? Around the same time, Google's CEO, Eric Schmidt was telling to the press he has grander ambitions in that direction.. To quote the FT he said

    Gathering more personal data was a key way for Google to expand and the company believes that is the logical extension of its stated mission to organize the world’s information. Asked how Google might look in five years’ time, Mr Schmidt said: “We are very early in the total information we have within Google. The algorithms will get better and we will get better at personalization. “The goal is to enable Google users to be able to ask the question such as ‘What shall I do tomorrow?’ and ‘What job shall I take?’ " 

    Worrying for privacy or great utility ? The next day a piece by Mark Lawson in the Guardian was introduced with the words "Anyone stupid enough to do a computer's bidding is not losing civil liberties so much as their marbles" Over at ZDnet Andrew Keen really had a swing at Eric. He calls him "the Chauncey Gardiner of Silicon Valley" (twice) and "Google’s Chief Eccentric Officer" (also twice) ouch. "Eric" he says "I thought you were a businessman rather than a looney". I remember Eric's time in charge of Novell, so I've got a view on which he is. Andrew's colleague on ZDNet, Donna Bogatin - who posted a summary of my post on Google's stance on T-shirts - calls him "Harmless" with links to explanatory posts.

    Plainly I'm not the only one worrying about databases of everything. It doesn't matter who it is. What I wonder, and would love your comments on, is just what privacy will people give up for utility ?

    Technorati tags: , , ,
  • James O'Neill's blog

    A Windows 7 trick for multiple sound cards

    • 2 Comments

    imageI’ve mentioned here before background noise drives me nuts (it’s one of boxes that gets ticked doing Asperger’s questionnaires). Some noise in the office is unavoidable, but it’s long been my view that filling other peoples workspace with noise from your computer is plain rude :  I have been known to ask people “Do you need to borrow some headphones”.

    I still have not replaced the headphones which were stolen along with my laptop bag a few weeks ago, but I have another, quite bulky, set of headphones with a boom Mic: they plug into the USB port and show up as a second sound device.  This gives me a problem. How do I now if sound is going to come out the speakers in my laptop or out of the headphones ? Given my attitude to other people when they fail to keep their computers silent I’m going to deserve some flack if I start a broadcast to the whole office.

    Quite by chance I discovered that Windows 7 can display volume controls for each of the sound devices (right click the volume control, and go to volume control options to decide what is displayed.)  So, I can mute one device and have sound coming out of the other. That’s perfect. It turns out that the headset becomes the default audio device when it is plugged in, but if I come back to my desk, don’t plug it in the on board sound stays muted – so I don’t disturb the office, but if I plug the headset back in, it is not muted. Perfect.



  • James O'Neill's blog

    Hyper-v and Snapshots (Part 1)

    • 5 Comments

    We often talk about "rolling back" to a snapshot, but here, some of the snapshots we can apply aren't simply forward or backward, hence Hyper-V talks about applying snapshots.

    It also talks about Deleting snapshots which causes some confusion. Deleting a snapshot means foregoing the ability to return to that point - we can't apply a deleted snapshot, that's obvious enough. The saved memory state (if there is one) is deleted but what about the data in the AVHD file ? If a Snapshot has children we can either delete the whole subtree, or we can delete just the parent snapshot. Internally Hyper-v works out when it can merge and/or delete AVHD files - a process which can take some time (you can tell if this operation is pending because the edit button for the hard disk in the machine's settings is grey'd out). 

    Here's an example The machine is running quite happily and has never been snapped. Late on Monday make a snapshot. This does two thingsHyper-V-Snapshots

    1.If the Machine is running or in a saved state we make a copy of memory

    2. We stop writing changes to its VHD and start writing changes to a new AVHD file. (Lets call this AVHD-1)

    At any point when we want to revert, we go back to the original hard disk and the Monday memory state. Throughout Tuesday changes are written to the AVHD-1then on Tuesday night we do another Snapshot. The same thing happens

    1.If the Machine is running or in a saved state we make a copy of memory

    2. We stop writing changes to AVHD-1 file and start writing changes to a new AVHD file. (Lets call this one AVHD-2)

    Now we can revert to two points, Monday's memory state and the original VHD or Tuesdays memory state and the combination of the original VHD and AVHD-1

    Lets assume that on Wednesday something happens to cause us to go back to Monday's state. We can either (a) Keep AVHD-2 and save the memory state as it was on Wednesday or (b) Discard AVHD-2 and memory state. Either way the server now starts a new AVHD file - lets call this one AVHD3. Thursdays changes get written to this, and on Thursday night as before we do another snapshot and start AVHD4 for Friday's changes and keep the memory state as it was on Thursday.

    Now we can apply 3 states (or 4 if we kept Wednesday's).

    Now for the obligatory bit of powershell, because of course this is scriptable.

       Function New-VmSnapshot  
    {Param( $vm=$(Throw "You must specify a VM") )
    if ($vm -is [string]) {$vm=(Get-VM $vm) }

    $arguments=($vm,$Null,$null) $result=$VSMgtSvc.psbase.invokeMethod("CreateVirtualSystemSnapshot",$arguments) if ($result -eq 4096) { $arguments[2] }  else  {"Error, code:" + $result}
    }

    [Update. A bit of PowerShell 2.0 crept into the above. In 1.0 you can't call the .InvokeMethod  method of a WMI object directly, you have to call it via .psbase]

    In an earlier post I described Get-VM and explained that I set up a variable

       $vsMgtSvc = Get-wmiObject -nameSpace root\virtualization -class Msvm_virtualSystemManagementService

    All the work here is done by the CreateVirtualSystemSnapshot method, and we pass it the Machine and 2 nulls. Normally it will return 4096 - the code for "started processing in the background" and the second Null magically contains the job ID so the function returns that. So you can invoke the function as $JobId=(New-VmSnapshot  $Tenby) and make tracking the job afterwards that bit easier. There are two more methods which we can call, RemoveVirtualSystemSnapshot, and ApplyVirtualSystemSnapshot oddly the latter only requires the machine and the snapshot reference, even though the snapshot says which machine it came from but trying to apply a snapshot to a new, clean VM fails. Maybe it's something that's under consideration for a future version. I'll describe these two in my next post.

     

    [Update somehow the order of the paragraphs got scrambled, they're back in the right order now]

  • James O'Neill's blog

    How to activate Windows from a script (even remotely).

    • 2 Comments

    I have been working on some PowerShell recently to handle the initial setup of a new machine, and I wanted to add the activation. If you do this from a command line it usually using the Software Licence manager script (slMgr.vbs) but this is just a wrapper around a couple of WMI objects which are documented on MSDN so I thought I would have a try at calling them from PowerShell. Before you make use of the code below, please understand it has had only token testing and comes with absolutely no warranty whatsoever, you may find it a useful worked example but you assume all responsibility for any damage that results to your system. If you’re happy with that, read on.  

    So first, here is a function which could be written as  one line to get the status of Windows licensing. This relies on the SoftwareLicensingProduct WMI object : the Windows OS will have something set in the Partial Product Key field and the ApplicationID is a known guid. Having fetched the right object(s) it outputs the name and the status for each – translating the status ID to text using a hash table.

    $licenseStatus=@{0="Unlicensed"; 1="Licensed"; 2="OOBGrace"; 3="OOTGrace"; 
                     4="NonGenuineGrace"; 5="Notification"; 6="ExtendedGrace"} 
    Function Get-Registration 
    
    { Param ($server="." ) get-wmiObject -query  "SELECT * FROM SoftwareLicensingProduct WHERE PartialProductKey <> null
    AND ApplicationId='55c92734-d682-4d71-983e-d6ec3f16059f'
    AND LicenseIsAddon=False" -Computername $server | foreach {"Product: {0} --- Licence status: {1}" -f $_.name , $licenseStatus[[int]$_.LicenseStatus] } }

     

    On my Windows 7 machine this comes back with Product: Windows(R) 7, Ultimate edition --- Licence status: Licensed

    One of my server machines the OS was in the “Notification” state meaning it keeps popping up the notice that I might be the victim of counterfeiting  (all Microsoft shareholders are … but that’s not what it means. We found a large proportion of counterfeit windows had be sold to people as genuine.)  So the next step was to write something to register the computer. To add a licence key it is 3 lines – get a wmi object, call its “Install Product Key” method, and then call its “Refresh License Status method”.  (Note for speakers of British English, it is License with an S, even though we keep that for the verb and Licence with a C for the noun).  To Activate we get a different object (technically there might be multiple objects), and call its activate method. Refreshing the licensing status system wide and then checking the “license Status”  property for the object indicates what has happened. Easy stuff, so here’s the function.

    Function Register-Computer 
    {  [CmdletBinding(SupportsShouldProcess=$True)] 
       param ([parameter()][ValidateScript({ $_ -match "^\S{5}-\S{5}-\S{5}-\S{5}-\S{5}$"})][String]$Productkey , 
              [String] $Server="."   )

     

    $objService = get-wmiObject -query "select * from SoftwareLicensingService" -computername $server if ($ProductKey) { If ($psCmdlet.shouldProcess($Server , $lStr_RegistrationSetKey)) {
                               $objService.InstallProductKey($ProductKey) | out-null 
                               $objService.RefreshLicenseStatus() | out-null }
        }   get-wmiObject -query  "SELECT * FROM SoftwareLicensingProduct WHERE PartialProductKey <> null
                                                                       AND ApplicationId='55c92734-d682-4d71-983e-d6ec3f16059f'
                                                                       AND LicenseIsAddon=False" -Computername $server |

          foreach-object { If ($psCmdlet.shouldProcess($_.name , "Activate product" ))

    { $_.Activate() | out-null

    $objService.RefreshLicenseStatus() | out-null

    $_.get()
    If     ($_.LicenseStatus -eq 1) {write-verbose "Product activated successfully."} Else   {write-error ("Activation failed, and the license state is '{0}'" `
    -f $licenseStatus[[int]$_.LicenseStatus] ) }
                                If     (-not $_.LicenseIsAddon) { return }
                  }              
    else { write-Host ($lStr_RegistrationState -f $lStr_licenseStatus[[int]$_.LicenseStatus]) }
        }
    }

    Things to note

    • I’ve taken advantage of PowerShell V2’s ability to include validation code as a part of the declaration of a parameter.
    • I as mentioned before, it’s really good to use the SHOULD PROCESS feature of V2 , so I’ve done that too.
    • Finally, since this is WMI it can be remoted to any computer. So the function takes a Server parameter to allow machines to be remotely activated.

    A few minutes later windows detected the change and here is the result.

    image

     

    
    


  • James O'Neill's blog

    Getting started with Windows PE

    • 3 Comments

    One of the tools you'll need to get to grips with if you are going to support or deploy vista is Windows PE - the pre Installation environment. In order to get a copy to work with, you need to Install the Windows Automated Installation Kit.  This is keeping something of a low profile at the moment. I'll post a link to it when I have one. Kudos to Nathan Mercer who says that you can register for it on connect. I will still post a link to the release version when it breaks cover :-) It is now available here. There are 3 steps to getting a copy of PE you can use.

    1. Copy the Windows PE source files somewhere,
    2. Customize Windows PE 
    3. Put it on a bootable USB key or
      make an ISO and burn that to a CD

    Copying the source files. Chose a working directory for Windows PE files, the notes I have suggest C:\WinPE_x86. Open a command prompt, go to the where the AIK is installed, and enter the command:

    Copype.cmd x86 C:\WinPE_x86

    At this point you can Customize the image in the ISO subfolder of C:\WinPE_X86. I'm going to cover that separately but there are 2 things to know here. Firstly PE boots from a WIM file in the BOOT folder this contains Windows itself so drivers Windows options get added and removed here; once you have your WIM file it goes in the ISO\BOOT folder. Second most programs run under PE, so you can put them in ISO\Anything_you_like  own folders.

    The notes I have suggest the command to make the ISO folder into an ISO image is as follows. 
    Oscdimg -n –bc:\winpe_x86\etfsboot.com c:\winpe_x86\ISO c:\winpe_x86\winpe_x86.iso
    I've found that this gives an error, the parameters I've found to work are

    Oscdimg -n c:\winpe_x86\ISO c:\winpe_x86\winpe_x86.iso -n -bc:\winpe_x86\etfsboot.com

    I.e. it goes  SOURCE_FOLDER, ISO_FILE, Switches. -n allows long filenames, and -b specifies a boot sector.  The tool gives a copyright date of 2000 and says it is for Microsoft internal use only.... Sigh. I don't know why we didn't include a CD burning tool either. Steve recently explained that you can get this in the Windows Server 2003 resource kit.

    If you want to make a bootable USB key you use the VISTA DISKPART utility. The commands you use in diskpart are

    • select disk 1 {or the number of your USB key, be careful !}
    • clean  {Like I said, be careful this erases the disk}
    • create partition primary
    • select partition 1
    • active
    • format fs=fat32
    • assign
    • exit

    Having done that you copy the ISO folder to the USB key

    That's it. Now you have your universal tool for imaging and repairing Vista.

     

    Technorati tags: , , ,

    Updated (1) to include the link to the WAIK, and thanks to Jesper, to point out this needs the Vista version of disk part.
    Updated (2) Active and format had merged into one step above. Thanks Alun.
    Updated (3) The download link moved.

  • James O'Neill's blog

    Checking and enabling Remote Desktop with PowerShell

    • 6 Comments

    A couple of posts back I mentioned that I was working on a configuration library for Server 2008 R2 Core and Hyper-V Server R2 and this includes checking and setting the configuration for remote desktop.

    It turns out that this is controlled from just 2 registry entries – hence it is controlled by the SCRegEdit script. One turns is fDenyTSConnections under  'HKLM:\System\CurrentControlSet\Control\Terminal Server' and the other is UserAuthentication  under 'HKLM:\System\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp. So if the Values exist they appear as Item property in PowerShell and can be set, otherwise it can be created. I’ve found the safest way is to try to set  the value and trap the error which occurs if it doesn’t exist then create it specifying that it is a DWORD. So my function enables RemoteDesktop UNLESS –Disable is specified , and -lowSecurity is a boolean which tells it whether to demand user stronger authentication.

     

    Function Set-RemoteDesktopConfig 
    
    {Param ([switch]$LowSecurity, [switch]$disable) if ($Disable) {
    set-ItemProperty -Path 'HKLM:\System\CurrentControlSet\Control\Terminal Server'`
    -name "fDenyTSConnections" -Value 1 -erroraction silentlycontinue if (-not $?) {new-ItemProperty -Path 'HKLM:\System\CurrentControlSet\Control\Terminal Server' `
    -name "fDenyTSConnections" -Value 1 -PropertyType dword }
           set-ItemProperty -Path 'HKLM:\System\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp' `
    -name "UserAuthentication" -Value 1 -erroraction silentlycontinue
          if (-not $?) {new-ItemProperty -Path 'HKLM:\System\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp'
    -name "UserAuthentication" -Value 1 -PropertyType dword}
    }
    else {
    set-ItemProperty -Path 'HKLM:\System\CurrentControlSet\Control\Terminal Server' `
    -name "fDenyTSConnections" -Value 0 -erroraction silentlycontinue
            if (-not $?) {new-ItemProperty -Path 'HKLM:\System\CurrentControlSet\Control\Terminal Server' `
    -name "fDenyTSConnections" -Value 0 -PropertyType dword }
           if ($LowSecurity) {
    set-ItemProperty -Path 'HKLM:\System\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp'`
    -name "UserAuthentication" -Value 0 -erroraction silentlycontinue
            if (-not $?) {new-ItemProperty -Path 'HKLM:\System\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp'`
    -name "UserAuthentication" -Value 0 -PropertyType dword}
    }
         } 
    
    }

    Finding out what the settings are is even easier.

    Function Get-RemoteDesktopConfig
    {if ((Get-ItemProperty -Path 'HKLM:\System\CurrentControlSet\Control\Terminal Server').fDenyTSConnections -eq 1)
    
              {"Connections not allowed"}
    elseif ((Get-ItemProperty -Path 'HKLM:\System\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp').UserAuthentication -eq 1)
             {"Only Secure Connections allowed"}
    else {"All Connections allowed"}
    }

    The next part of the configurator to share will be for checking and setting firewall rules.

Page 1 of 56 (840 items) 12345»