James O'Neill's blog

Windows Platform, Virtualization and PowerShell with a little Photography for good measure.
Posts
  • 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

    Powershell again. Pipes, and "This is not an output"

    • 10 Comments

    My experiences with PowerShell continue and every so often realize that I never really understood something I thought I'd "got" some while back

    I've spent most of my time trying not to use the WRITE cmdlets to send output to the screen. After all if I want to write "Hello, World" to the screen I can have a function

    function hw
      { 'Hello, World' }

    No need for a Print, Write, Echo or any other command: in PowerShell an output with nowhere else to go ends up on the screen. If I want formatted output  FORMAT-LIST and FORMAT-TABLE do a great job, especially since I "discovered" calculated fields. Since I always used to get my queries in Access to do loads of work, shoving the work onto FORMAT-TABLE seems natural enough, even if the syntax is little weird. The field is actually written as a hash table @{ label="Text", Expression={some code}    }. Of course "Some code" can do anything you want and what it returns goes in the table. So I had a bright idea over the weekend. I can have a menu using format-table. Here the code

    Function Choose-Process
    {$global:Counter=-1
    $proc=Get-Process
    Format-Table -inputobject $Proc @{ Label = "ID"; Expression={($global:counter++) }} , processName
    $proc[(read-host "Which one ?")]

    So I set a counter, get a list of processes, and then format a table, in formatting the table I output and increment the counter; the I ask the user to input a number to choose one and that gives me the offset into the array of processes of the one to return. When I run it here's what I get:

    PS C:\Users\Jamesone> choose-proc

    ID ProcessName
    -- -----------
    0 audiodg
    1 CcmExec

    Which one ?: 1

    Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName
    ------- ------ ----- ----- ----- ------ -- -----------
    744 29 13128 10560 92 2204 CcmExec

     

    Of course I  want to save this. So I type in $proc=choose-proc and I get

    Which one ?:

    What the ... ? Where did my menu go ? And the answer is: the menu was OUTPUT. Where did I tell PowerShell that  format-table wasn't to go to standard output but $proc[offset] was ? I didn't so both ended up being stored in the result.

    Anyone who's explored PowerShell's providers will have found there is one for variables. Now I get it ... $varName= MyFunction is actually MyFunction > Variable:varName. This behaviour can work for or against you depending on the situation, and here I have to use a for loop and use WRITE-HOST to force output to go the screen [Update: no I don't need to. See Jeffrey's comment below]

    I guess I was still thinking in Basic, where the last line of your function usually returns the result.  PowerShell's Outputs are different, they go down the "Standard Output" pipe unless told otherwise and standard output ends up on the screen if the "end of pipe" is left Open; just like you'd expect from a Shell.   And since I was quoting my university lecturers a little while ago here's something which was written on the board in our first programming class.

    It is practically impossible to teach good programming style to students that have had prior exposure to BASIC; as potential programmers they are mentally mutilated beyond hope of regeneration.
    (
    Edsger Dijkstra )

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

    Powershell to fix phone number formats (part 1)

    • 2 Comments

    Peter sent me a mail last week suggesting a blog post.

    "You mentioned in http://blogs.technet.com/jamesone/archive/2007/02/21/the-campaign-for-real-numbers.aspx that a transport rule would be cool. Whislt I'm not yet a E2K7 user, wouldn't it be good if you could knock up a powershell script to create the rule and publish it on your blog?

    you get treble value - powershell, exchange, and crappy phone number layout"

    I thought I'd try to do three things.

    1. Fix entries which have built up in my Outlook contacts over time which aren't in E.164 format so everything I have can be dialed.
    2. Apply the same fixes to Active directory user and contact objects
    3. [The bit Peter suggest, and I don't know how to do yet] Create an Exchange 2007 transport rule which fires the does the same thing as my Outlook rule to advise people of broken numbers I might need to pull in some help from Eileen, Brett or Ewan for that one.

    This post just deals with the fist of these.

    I wanted two powershell functions. The first takes a String which holds the phone number and re-formats it.

    function Format-Number-as-E164 ([string]$Number)
    {if ($number.length -gt 5)
     {if ($number.substring(0,2) -ne '08')
       {if ($number.substring(0,2) -eq '00') {$number='+' + $number.substring(2) }
        if ($number.substring(0,1) -eq '0')  {$number='+44 '+ $number.substring(1) }
        $number = $number.replace("+440", "+44")
        $number = $number.replace("+44 0", "+44")
        $number = $number.replace("+44(0)", "+44")
        $number = $number.replace("+44 (0)", "+44")
        $number = $number.replace("+44(0", "+44(")   
        $number = $number.replace("+44 (0", "+44 (")}
     }
    $number
    }

    The logic is pretty simple:

    • ignore anything to short to be a phone number and special codes like 0800, 0870, 0845 which (mostly) can't be dialed from outside the UK.
    • Fix anything where I have entered the local code for international. 001 (234) 555-1234  becomes +1 (234) 555-1234 and UK formatted numbers O118 909 3080 becomes +44 118 909 3080.
    • Finally get rid of 0 in +44 0118, +44 (0) 118 and +44 (0118)  

    The second function takes an outlook contact object and calls the first for each of the 13 different phone numbers - here I'm just showing one.

    function Format-contact-as-e164 ($contact)

    {   if($contact.CompanyMainTelephoneNumber)
        {$temp = Format-Number-as-E164($contact.CompanyMainTelephoneNumber)
          if ($temp -ne $contact.CompanyMainTelephoneNumber)
            {$contact.CompanyMainTelephoneNumber=$temp
            $changed=$TRUE}
        }
        if ($changed) 
        {write-host $contact.fileAs changed
        $contact.save() }
    }

    So now I need to feed my outlook contacts into this function converting code I've been using for years gives me this - Get Default folder can get your inbox, calendar, contacts and so on. 10 is the code for the contacts folder.

    $Outlook= New-Object -comobject "outlook.application"
    $namespace=$outlook.GetNamespace("MAPI")
    $myContacts=$namespace.GetDefaultFolder(10).name

    Of course this can be squeezed into one line.

    $myContacts=(new-object -comobject "Outlook.Application").getnamespace("mapi").getDefaultFolder(10)

    I haven't tried it by I guess you could dispense with the variable altogether and  update my address book with

    foreach ($item in(new-object -comobject "Outlook.Application").getnamespace("mapi").getDefaultFolder(10).items) {Format-contact-as-e164($item) }

    Since I didn't trust my code to work first time (nor should you) I did two things to check it worked properly. The first was to do a global replace of {$contact. with {write-host  so I could see what it was doing  - Powershell syntax is that write-host CompanyMainTelephoneNumber=$temp  will treat CompanyMainTelephoneNumber= as a literal string and expand the variable $temp. There are cases where this is infuriating (at least for new converts) but here it's exactly what I want.

    When I was satisfied that it was  working correctly, I changed the code back and tested a contact which I knew I could fix so I just invoked Format-contact-as-e164( $myContacts.Items.item(1)) when that worked, it was time to go for it and update all the affected contacts with

    foreach ($item in $myContacts.Items) {Format-contact-as-e164($item) }

    It worked. (Phew). I've attached the .ps1 file with the code in it. As with all code posted to this blog it is provided as an example. It doesn't necessarily represent "best practice" and comes with no warranty or support (so if you want to use it against real data of your own, take suitable precautions).

  • James O'Neill's blog

    Persistent chat - what's that then ? A quick guide to collaboration modes.

    • 1 Comments

    Since I posted about Parlano, a couple of people have asked me about persistent chat. Parlano

    So.. (very briefly) most people understand Mail and Instant messaging. IM is usually 1:1, but we can have multiple users in a a chat. One of the major grumbles about LCS 2005 and Communicator 2005 was that when you escalated to Voice or Video chat it couldn't do more than 1:1. This has changed in OCS 2007 with the new communicator client: we have a "hub" component (called an MCU) which brings together the voice and video streams. Although it wasn't strictly necessary when 2007 users go from 1:1 to n-way IM conversation we also use an MCU.

    Most people know about Internet Chat rooms; a hub of some kind has virtual "places" - so the room can be "persistent" i.e. it's always there even if no-one is on-line chatting in it. But the conversations are transient. If you're not in the room when someone says it you don't see it.

    Persistent chat combines the idea of "Rooms" with the idea the chat itself being persistent - so you can look at what was said before you joined. The screen shot gives you some idea, the "rooms" or "Channels" as the Mind--Align product calls them are on the left, the participants on the right and the chat is in the middle. It's easier to manage and search than a Distribution List or Public folder / Newsgroup where each comment is a separate item. But it's not ad-hoc like an IM chat or chat room.

    As I said before I never found myself pining for this functionality, but I know of plenty of customers who did. It will be interesting to see how this integrates with the existing products. It would be interesting too if the next version of Groove linked into both this and traditional IM instead of Groove's silo'd IM.

     

  • James O'Neill's blog

    NSLookup, WMI and Ping - three random things from the "I didn't know that column"

    • 0 Comments

    If you're a regular reader you may know that I've been doing quite a lot of stuff with powershell of late, and Ive mentioned that I'm helping with some of the utilities for the the OCS resource Kit.

    One of the questions I got asked was "Can we have a script to look up an SRV record", I thought this was a bit odd because you can do this from the command line with NSLookup although everyone thinks of NS-Lookup as a tool that you user interactively. If you want to look up a record for a service (SRV) you simply invoke NSLookup with a switch and specify the name of the service, e.g.

         nslookup -q=SRV _sip._tls.microsoft.com

    Next I was trying to test WMI remotely managing a machine and I could not get a connection to the relic which sits in my study running XP, after various searches and much head-scratching I found that if you get the error

        Get-WmiObject : The RPC server is unavailable. (Exception from HRESULT: 0x800706BA)

    It may be because the Windows firewall is blocking it. To unblock you use the NetSh. command as follows

        Netsh firewall set service RemoteAdmin 

    Finally, what about pinging from a script - when I have trouble with a network connection I run IPConfig. That tells me if I have an IP address and what my DNS servers are. I was taught to ping the default gateway first, but I've always found going straight to DNS was easier.

    In Powershell  I can get my IPConfig information with  Get-WmiObject -Class Win32_NetworkAdapterConfiguration -Filter IPEnabled=TRUE
    and if I can get the DNS servers out of this information by piping the results to Select-Object -ExpandProperty DNSServerSearchOrder 
    WMI has a PingStatus class so I can use it from Powershell by piping the list of servers into ForEach-Object -Process {Get-WmiObject -Class Win32_PingStatus -Filter ("Address='" + $_ + "'")}
    and Finally I can display it nicely with Select-Object -Property Address,ResponseTime, TimeToLive

    String them all togehter and I get

    PS C:\Users\Jamesone> Get-WmiObject -Class Win32_NetworkAdapterConfiguration -Filter IPEnabled=TRUE |
    >> Select-Object -ExpandProperty DNSServerSearchOrder |
    >> ForEach-Object -Process {Get-WmiObject -Class Win32_PingStatus -Filter ("Address='" + $_ + "'")} |
    >> Select-Object -Property Address,ResponseTime,timeToLive
    >>

    Address                                         ResponseTime                              timeToLive
    -------                                         ------------                              ----------
    194.168.4.100                                             17                                     128
    194.168.8.100                                             18                                     128

    Technorati tags:
  • James O'Neill's blog

    A VB class for EXIF picture properties - and using it from Powershell.

    • 7 Comments

    I have been carrying on with my project to make EXIF data available in PowerShell.

    When I searched for Powershell and EXIF it turned up this Blog post of Scott Hanselman's. He talks about a "nice little photo library" that extracts and interprets EXIF data from images, but when I tried to get hold of copy the link was dead, so I thought "How hard can it be ?" and looked the example in the VB Express's help. The answer was "Not very hard", and I built a class library I built goes like this.

    Public Class ExifImage

    ' Declare Constants, variables, subs and functions

    ' - use PUBLIC to make them available to things which use the class.

    Public BitMap As System.Drawing.Bitmap

     

    ' I have lots of constants and a couple of functions to process information - just one shown here

    Public Const ExifIDDateTimeTaken As Integer = 36867

     

    ' NEW is invoked when an item of this class is instantiated. Here I want to get a BITMAP object

    Public Sub New(ByVal s As String)

    Me.BitMap = New System.Drawing.Bitmap(s)

    End Sub

     

    ' Now declare code to return properties. I don't want to write properties, so I declare them read only

    ReadOnly Property DateTimeTaken() As String

    Get

    DateTimeTaken = {what ever code you need}

    End Get

    End Property

     

    End class

    This probably the time to say that it should be possible to create a new class which inherits everything from an existing class but System.Drawing.Bitmap doesn't allow this. So I just created a new object which contained a system.drawing.bitmap object - and made it accessible for other code which wanted to do anything beyond providing access to the 40 or so properties I wanted.. Those 40 properties meant quite a lot of code, but it was very repetitive stuff: even where I needed long SELECT ... CASE constructs to output "Flash switched on, but did not fire" or whatever for each of 20 different numbers values, it was mostly cutting and pasting. Parsing the maker note field to get Pentax specific information took a bit more work. Having compiled my code it was simply a case of loading it with  
    [reflection.assembly]::loadfile("C:\...longpath...\OneImage.dll") 

    Now I can do something like this to get an image with my exif properties,

    $foo = New-Object oneimage.exifimage -argumentlist "I:\DCIM\100PENTX\IMGP3797.JPG" 
    The [Tab] Key will expand $foo's properties so I can do this
    PS C:\Users\Jamesone\Pictures> $foo.Flash 
    

    Flash off

    That post of Scott's talks about "spot-welding" new properties on to existing objects. Not object inheritance, mind you, "super-gluing." Like it or hate it, like super-glue, you have to respect that it solves problems. I copied his XML wholesale replaced his type name with mine and loaded it with

    Update-TypeData My.Types.PS1XML

    Which let me get a directory with the DatePhotoTaken field. I got a bit more adventurous and build a different XML file which would show me bytes per pixel - a quick way to find out which files have been heavily compressed and which haven't

    <Types>
         <Type>
            <Name>System.IO.FileInfo</Name>
            <Members>
               <ScriptProperty>
                    <Name>BytesPerPixel</Name>
                    <GetScriptBlock>
                    if ($this.Extension -match "jpg|raw")
                     {
                      $photo = new-object oneimage.exifimage $this.FullName
                      $this.length / ($photo.Height * $photo.width)
                    }
                    </GetScriptBlock>
                </ScriptProperty>
              </Members>
         </Type>
    </Types>

    I've attached the VB code and DLL so you can experiment. Disclaimer . Like any code on my blog, this code is provided as an Example for illustration purposes is only. It comes with No support and No warranty that it is fit for any purpose whatsoever.
    Update - the code has been revised, and the link below has changed

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

    I wish I'd known about Get-Eventlog before

    • 0 Comments

    Having mentioned Powershell in several recent posts, I said in passing I'd discovered that it had a Get-EventLog cmdlet

    I also talked about the problems I was having with sleep - or more to the point the machine waking up and running till it crashed, I said

    "Looking through the event log I found when the machine boots, the event logging service records an Error 6008 - "The previous system shutdown at {time} was unexpected.", if it wasn't shut down cleanly. Now I don't know how it works out the time it happened.  There are 5 of these events in the last 40 days.  Roughly two hours before each is a message recorded by Power-Troubleshooting . "The system has resumed from sleep. Sleep Time: {time} Wake Time: {time}. Wake Source: Device -ACPI Lid""

    In order to do this looking I'd actually exported the information from Event viewer, merged it in Excel and read down it; this process didn't take hours and hours - but it did take a good few minutes. What would it take to get this information in Powershell. I want

    • "Power-TroubleShooter" messages which refer to ACPI lid - although these messages don't seem to parse properly - hence the message that "The description can't be found" but the key strings, including "ACPI Lid" are embedded in this message.
    • Event-log "Started" messages , code 6005
    • Event-log "Previous shut down at {time} was unexpected" messages , code 6008. Usefully the time is near the start of the message

    So a Where-object cmdlet which checks for these, and takes input from Get-EventLog and sends it to Format-Table should do the trick. It took a moment to find that Power-Troubleshooter was actually Microsoft-Windows-Power-Troubleshooter. And then it's east.

    Get-EventLog -logname system | 

    where-object {(($_.source -eq "EventLog") -and (($_.get_eventID() -eq 6005) -or ($_.get_eventID() -eq 6008)))
    -or (($_.source -eq 'Microsoft-Windows-Power-Troubleshooter') -and ($_.Message -like '*ACPI Lid*')) } |

     format-table -Property TimeGenerated, message

    And here's the output. It's pretty easy to see when the system woke up shortly before an unexpected shutdown.

    TimeGenerated                                               Message
    -------------                                               -------
    19/08/2007 13:25:40                                         The description for Event ID '1' in Source 'Microsoft-Wi...
    19/08/2007 12:38:41                                         The Event log service was started.
    18/08/2007 00:34:22                                         The Event log service was started.
    18/08/2007 00:34:22                                         The previous system shutdown at 22:33:54 on 17/08/2007 w...
    16/08/2007 22:05:32                                         The description for Event ID '1' in Source 'Microsoft-Wi...
    16/08/2007 20:42:06                                         The description for Event ID '1' in Source 'Microsoft-Wi...
    16/08/2007 10:15:40                                         The description for Event ID '1' in Source 'Microsoft-Wi...
    15/08/2007 11:31:25                                         The Event log service was started.
    14/08/2007 22:35:33                                         The description for Event ID '1' in Source 'Microsoft-Wi...
    14/08/2007 06:16:28                                         The description for Event ID '1' in Source 'Microsoft-Wi...
    13/08/2007 16:57:21                                         The Event log service was started.
    13/08/2007 10:50:57                                         The Event log service was started.
    13/08/2007 10:50:57                                         The previous system shutdown at 10:24:05 on 13/08/2007 w...
    13/08/2007 10:26:37                                         The description for Event ID '1' in Source 'Microsoft-Wi...
    09/08/2007 22:27:28                                         The Event log service was started.
    09/08/2007 22:27:28                                         The previous system shutdown at 22:16:20 on 09/08/2007 w...
    09/08/2007 21:07:52                                         The description for Event ID '1' in Source 'Microsoft-Wi...
    08/08/2007 22:14:21                                         The description for Event ID '1' in Source 'Microsoft-Wi...
    08/08/2007 15:02:44                                         The description for Event ID '1' in Source 'Microsoft-Wi...
    08/08/2007 14:53:49                                         The description for Event ID '1' in Source 'Microsoft-Wi...
    08/08/2007 11:00:40                                         The description for Event ID '1' in Source 'Microsoft-Wi...
    08/08/2007 00:10:23                                         The Event log service was started.
    08/08/2007 00:10:23                                         The previous system shutdown at 20:29:48 on 07/08/2007 w...
    07/08/2007 18:53:35                                         The description for Event ID '1' in Source 'Microsoft-Wi...
    07/08/2007 10:07:11                                         The description for Event ID '1' in Source 'Microsoft-Wi...
    02/08/2007 18:53:27                                         The description for Event ID '1' in Source 'Microsoft-Wi...
    02/08/2007 11:41:22                                         The description for Event ID '1' in Source 'Microsoft-Wi...
    01/08/2007 14:53:19                                         The description for Event ID '1' in Source 'Microsoft-Wi...
    01/08/2007 14:09:56                                         The description for Event ID '1' in Source 'Microsoft-Wi...
    01/08/2007 10:04:26                                         The Event log service was started.
    01/08/2007 07:19:30                                         The Event log service was started.
    01/08/2007 07:19:30                                         The previous system shutdown at 20:36:18 on 31/07/2007 w...
    31/07/2007 18:53:17                                         The description for Event ID '1' in Source 'Microsoft-Wi...
    29/07/2007 14:00:22                                         The description for Event ID '1' in Source 'Microsoft-Wi...
    29/07/2007 05:42:25                                         The description for Event ID '1' in Source 'Microsoft-Wi...
    28/07/2007 02:49:07                                         The description for Event ID '1' in Source 'Microsoft-Wi...

     

  • James O'Neill's blog

    PowerShell to Fix Phone number formats part II

    • 0 Comments

    I said when I posted about fixing the phone numbers in your Outlook Contacts that I'd come back and do the same thing for Active Directory. Richard told people to look out for that, so no pressure to get it done then...

    Using the Active Directory Services interface (ADSI) from Powershell seems to fill some people with fear. One of the books I picked up said "don't bother" use VB. I found the Mastering PowerShell in your lunch-break pages quite helpful on ADSI; and there are a bunch of tools worth investigating. I wanted to do this without creating a dependency on those, if I could.

    So here are a few bits that might be useful before I dive into the code.

    1. [ADSI]LDAP://{path} will fetch an ADSI object. the LDAP part is case sensitive. You can specify LDAP://serverName:port/name to go to a specific server - if you leave the port out :389 is assumed, and you can specify the search should go against a Global Catalog server with GC://. Leaving the path empty - calling [ADSI]"", you'll return the default naming context for the current domain.
    2. The LDAP bit is required, but when AD gives you a path it usually omits the LDAP:// , causing an error when you try to get the object. The exception to this is the "Searcher" object
    3. ADSI objects aren't saved back to the server until you call their setInfo method
    4. ADSI objects have properties and children. To get the Children use $ADSIobject.psbase.children. Properties can be addressed as $ADSIobject.property.name. However this will return something if the AD property wasn't set. A better way to check properties is with $ADSIObject.psbase.propertyName
    5. The DirectoryServices.DirectorySearcher object is a very useful way to get a collection of objects

    I've kept the same structure as I used in the Outlook Contacts version. I've kept the same function Format-number-as-E164 and I have another function which takes a user or contact object, checks to see if phone numbers are present and if they are, it calls Format-number-as-E164.  This follows the same pattern as the outlook one, but is named function Format-ADPerson-as-e164 and takes an LDAP path as a parameter. The AD fields it looks at are facsimileTelephoneNumber, homePhone, ipPhone, mobile, pager, PrimaryInternationalISDNNumber , TelephoneAssistant  and TelephoneNumber

    Rather than show identical code for all these attributes, I've just shown one below.

    function Format-ADPerson-as-e164 ($LDAPpath) 
    

    {
        $changed=$false
        $Contact=[ADSI]($LDAPPath)
        if($contact.psbase.properties.facsimileTelephoneNumber)
        {$temp = Format-Number-as-E164($contact.facsimileTelephoneNumber)
          if ($temp -ne $contact.facsimileTelephoneNumber)
            {$contact.facsimileTelephoneNumber=$temp
            $changed=$TRUE}
        }   

         if ($changed) {
        write-host $contact.name changed
        $contact.setInfo()
        }
    }

    I  tested the code with the path to a single user e.g. Format-ADPerson-as-e164 ('LDAP://CN=James O'Neill,CN=Users,DC=Contoso,DC=com')

    Then it needs to be called for many AD users, By using [ADSI]"", and filtering to the "Person" objectClass, I selected every user and contact in my domain but you could specify a single OU or a more restrictive filter.

        $searcher= New-Object directoryServices.DirectorySearcher([Adsi]"") 
    

    $searcher.filter="(objectclass=person)"

    $searcher.findall() | forEach-Object {$_.path}

    The last line is there to show which objects are going to be processed. When I'm happy that I've go the right objects and the right code

        $searcher.findall() | foreach-object {Format-ADPerson-as-e164($_.path)}

    Does the processing.

    The code is attached for you to play with, but as I've said before, and will say in the future; any code I provide here is for example purposes. No Warranty or support is provided. You should take steps to validate any such code or yourself before running it.

     

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

    Quality assurance Vs Quality improvement. Which thinking do you want ?

    • 1 Comments

    One of the Microsoft internal discussion lists has had an interesting thread over the last couple of days which started like this. 
    Poster: "I know about bugs in [X], but I work on [Y] and all the objectives I'm measured on are based on getting [Y] right. I can't find time to file bug reports on another teams product."
    Others: "That's terrible"

    And from there the conversation descended into criticism of product [x], the Poster's attitude, the Poster's management's attitude and the bug reporting process, the philosophical nature of objectives, and has now reached the point of  someone posting a picture of their cat...

    This reminded me of something from Long ago, when I was working in product support for RM, and our Managing Director picked up the Juran Quality Improvement (JQI) methodology used in Japan (he talks about it here). I remember 3 principles of JQI, and I'm convinced there was a fourth but I can't track it it down - probably something about counting defects and trying to get to zero. (I was visiting a high tech customer a couple of weeks back and saw a chart which showed defect rates way below what I'd expect for their business - zero in one recent month - with the words "Defect rates remain unacceptably high" in the text beneath it. That's JQI thinking.) The three principles I remember are:

    • Quality is meeting the customer's needs.  [Different customers have different needs. The top need is that the product works, and keeps on working. 'Quality' is not simply a synonym for good or "prestige"]
    • Quality is free [better phrased as quality pays for itself. Unhappy customers, and support have a cost which is more than the cost getting the product right]
    • Quality is everybody's responsibility

    And of course this last point is the one which links to the discussion on the thread. It's also the most difficult one to implement because, responsibility without power achieves nothing. The easiest way to turn "Quality is everybody's responsibility" into an empty slogan, is to make any action that such responsibility requires a career limiting move. To work, management must shift their thinking to be self critical and when their actions hinder meeting the customer's needs they must embrace criticism. I'm not surprised that (in Britain at least) quality improvement went out of fashion in favour of quality assurance (ISO 9000) systems which assume that management knows the best possible way to do things and what's needed is ensure people follow a process: empowering them to change things or criticize management decisions isn't desirable or even necessary.  

     

    Of course the opposite of "Quality is everybody's responsibility" is the Bystander effect or what Douglas Adams called the "Someone else's problem field" (I mentioned this before when talking about mail.). Last week one of the Proxy servers which hooks us up to the Internet had a fault. Steve complimented me on my endurance after I spent 48 minutes on the phone to the "Help desk" to report it. Our help-desk used to be based in Dublin, and it helped. You'd often get someone with a mixed Dutch and Dublin accent (the staff we multi-lingual) and they'd improvise to solve the problem when they needed to. To cut the cost per call the function our helpdesk moved to India, but it's more than the accents that have changed: the staff now won't depart from their scripts, even if the script isn't right for the problem (which I associate with implementations of ISO9000 ) 

    In the old days I would have called Dublin said "When I try to go some web sites I get an error that says Proxy server 11 is out of space" and they'd have answered "We'll send yer-man Dermot down there with a big a hammer. Try again in a few minutes". Now I call Bangalore and someone opens a service request and launches into the "Problem accessing the Internet" Script. He remotes into my machine, relaxes my security settings, turns off auto proxy detection (so IE won't work at home), disables third party add ons, and finds that the proxy server is still giving the same error. So he mails himself the results of IPconfig and tracert. He's amazed when I use "Mode Con COLS=132" in a command window to stop the text from wrapping (which makes me wonder about his ability to go off-script). Normally I'd commend someone for spending 48 minutes trying to find problem on my machine - except I told him the first 48 seconds the error came from the Data centre and affected other people. When he's done I have to put my machine back to its working state and close the service request. Total cost in my time - about an hour. I  still price of my time at the billing rate it was when I was a consultant 1 hour = £200.

    This experience isn't unique: When a I called to get a disabled network port re-connected, the help desk pulled out the "Network connection problem" script and asked my IP address. I couldn't get an IP address because the port was disabled. "Oh". They said can we have the MAC address then. I gave it to them. "We can't see that address". "No" I said, "When I plug into the port on this desk the lights on my network socket don't light up, the port is dead. How did you expect to find me on the network."

    A colleague's  SmartCard split: the chip looked OK but his card wouldn't work in any machine, other cards worked in his machine. He called to find out how to get a replacement  Dublin would have said "Nip down to the security office and they'll get a new one for you". Bangalore got out the "smartcard problem" script and walked him through re-installing the Smartcard Crypto provider, drivers for the reader (he protested every step of the way that the problem was physical damage to the card). After an hour the call went to second line support (who eventually told him how to get a new card).

    Of course Microsoft isn't the organization where people are getting experiences like these. They teach us don't call the help desk; problems affecting shared systems are someone else's problems, and if it really is your problem, find someone on your team to help. With fewer calls and each costing less offshoring the help-desk looks like a success. Unless you look at the meeting the needs of the helpdesk customers (like me).

  • James O'Neill's blog

    Windows Live Writer: Getting a new dictionary

    • 7 Comments

    Adam sent me a mail, saying that he noticed my gripe about Live Writer: that it's behaviour around words like colour was likely to antagonise* English people (it would say it's behavior around words like color was likely to antagonize*). Thanks to him I found a fix.  Adam says that the handling of the personal dictionary in Live writer is sloppy - It seems to be fixed in the build I'm running.

    Technorati tags:

     

    * It always surprises me how few British English writers know that it is perfectly acceptable to write Antagonize. Here's what Gowers says in "Plain Words"

    On the Question of whether words like Organise or Organisation should be spelt with an s or a z, authorities differ. There are some words (e.g Advertise, comprise, despise, advise, exercise and surmise) which are never spelled with a z. There are others (such as Organize)  for which the spelling with z is the only American form , and is also a very common British one. This being so the British writer has the advantage over the American in that we may, if we wish, use an s all the time, for that will never be wrong, whereas a Z sometimes will be. But do not condemn those who use z in it's right place.

  • James O'Neill's blog

    This must be hardware ... mustn't it ?

    • 2 Comments

    Windows Live writer is proving popular. I've been using it in beta for a year and there are only two things that I don't like

    • I can't seem to get a UK English spell check.
    • The "Auto-save" feature is off by default.

    The Auto-save is matters at this point, because in place of the witty and erudite post I was writing yesteday (and I was borrowing from something I had listened to from Clive James) you have this one.I never turned Auto-save on. And last night when unzipped my bag, I could smell that my post was toast. Toast being the key word here - though the smell was not the comforting one of bread browning, but the distinctive tang of hot plastic. I knew before I touched the computer was hot. With no LEDs on there was a slim chance the computer had hibernated but I've seen this before it came as no surprised it had run that battery to zero. Recently, too judging from the heat - I was concerned that it might have damaged the machine  made me a little concerned for it (doubly so as I hadn't removed the secondary drive after doing my last backup). Since the laptop had been in my car for last 3-4 hours and most of that time the car had been parked on the driveway, and this isn't the first time it's happened I want to know what's going on here. According to the event log it woke up at 18:53 and this was triggered by the ACPI Lid. What's odd about this is that the laptop doesn't power up when I open the lid I have to press the power button.   Worse, closing the lid sends it to sleep ONLY when running on battery.

    Looking through the event log I found when the machine boots, the event logging service records an Error 6008 - "The previous system shutdown at {time} was unexpected.", if it wasn't shut down cleanly. Now I don't know how it works out the time it happened.  There are 5 of these events in the last 40 days.  Roughly two hours before each is a message recorded by Power-Troubleshooting . "The system has resumed from sleep. Sleep Time: {time} Wake Time: {time}. Wake Source: Device -ACPI Lid"

    I'd love to hear from anyone out there who has a Dell Latitude D820 which seems to have a problem of this kind. One hypothesis I'm working on is that this a scheduled service is waking the computer up (maybe to record something a 7PM) and the switch message is spurious, and it may be that if the machine wakes with it's lid closed something about the state of the lid switch then prevents it from sleeping - whether this is a bug or a hardware fault.

    Feels like I've got to do a load more investigation before I even call the help desk.

     

    Update. After a quick swap of hard disks between my laptop and Steve's the failure to sleep on closing lid when powered follows the drive not the chassis. Vista is definitely set-up to sleep in both states. But it's something on the hard disk .

  • James O'Neill's blog

    Powershell and Paradigms of VB

    • 3 Comments

    Since I was talking about experiences from long ago in my previous post, here's another. When I was at University one of my tutors, Dr Brian Lings, used the word "Paradigm" in a lecture. And we all went "WHAT !", and went running to dictionaries to find out what he meant. He actually used in the context of looking at something written in one language but actually having the way-of-doing-things that you'd see in another.

    I was reminded of this when I was asked to help with some powershell scripts for the OCS resource kit. I was sent a script which looked like this.

    # Get all SIP domains 
    

    $SIPDomains = Get-WmiObject -class MSFT_SIPDomainData

    # For every SIP domain in environment write SIP domain info to standard output

    foreach ($SIPDomain in $SIPDomains) {

    write-host  "*******************************"

    write-host  SIP domain: $SIPDomain.Address

    write-host "*******************************"

    write-host  `t Default Domain : $SIPDomain.DefaultDomain

    write-host  `t Authoritative : $SIPDomain.Authoritative

    }

    Getting the WMI Object class MSFT_SIPDOMAINdata, gives a collection of Objects: one per domain. So we store that collection in a variable and use a for loop to go through each object and write its properties to to the screen. Simple

    Well except for that fact that write-host can't be redirected to a file. We can't use Get-SIPDomains > domains.txt.

    But even fixing that this isn't  powershell "style" - though I'm still learning what that is, exactly. It's written like we'd write VB.

    Using LISP at university meant that grew to I like one function to feed into the next, so piping functions into each other seems natural and powershell gives me cmdlets like format-table to take the results of Get-WMIobject and reduce the For loop to one line.

    Get-WmiObject -class MSFT_SIPDomainData | Format-Table Address, Authoritative, DefaultDomain.

     I'm beginning to see why they named it POWER shell; one of the other scripts I need to write for the OCS resource kit needs to get information from the event log.  I was presently surprised to find PowerShell has a Get-EventLog cmdlet. With Where-Object to filter the events I can do this in one line.

     

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

    Office Communications Server trial bits available.

    • 2 Comments

    I had a mail from the Unified communications team over the weekend. They were happy to announce that the Microsoft Office Communications Server 2007 Trial Downloads (both Enterprise Edition and Standard Edition Servers) together with their associated client, the Office Communicator 2007 Trial download are now available.  The OCS resource kit is still being worked on - I've proof-read some bits of it - but an early cut of the tools is also available. So is the Software Development Kit.

    Initially these trials will be English only, the plan is to make Japanese, German, French, Spanish, Italian, Korean, Traditional Chinese, Simplified Chinese and Brazilian Portuguese versions available on September 24th.  Like all the best laid plans they are subject to change.

    The idea of a trial is to help customers to evaluate the features, capabilities and scenarios delivered by these products in a lab environment. The evaluation code will expire after 180 days, if you were to use it production it is possible upgrade it with an appropriately licensed version of the product.  We have public forums where customers can post questions and feedback.

    I realize that voice / telephony integration is a big piece of the new product and not many organizations have a PBX in their labs. But the what's new guide runs to 15 pages which aren't all telephony or greater finesse in Communicator . New scenarios worth looking at include notably extranet connections, finer grain permissions, IMing distribution lists and On-premise conferencing; if you want to test the latter to full there is a download of the Web conference scheduler. To save yourself a lot of individual downloads, I'd recommend the documentation roll-up too.

    By the way: if you're in the UK and you click through to the Office Communications server home page (http://www.microsoft.com/office/livecomm) from any of the links above you'll fetch up at a LCS 2005 page not an OCS 2007 one. The usual course of action in this case is either

    1. Curse Microsoft for being an American company which operations overseas, rather than an international company. Send for Michael Kleef (back-story here) or
    2. Edit the url  to en-us instead of en-gb. I suspect this is true of other countries. ... or
    3. Thank me for providing the link to the US version for you

     

  • James O'Neill's blog

    On Writing. And formats for storing writing. Via sockpuppets

    • 3 Comments

    I mentioned the post that I lost last night and that it referred to Clive James, a writer whose words I can hear as I read them. I can't think of many others like that: I hear Bill Bryson's words in the on-the-brink-of-mania tones with which Kerry Shale read them on the radio, rather than Bryson's easy paced burr.

    When I read a transcript of James' essay "Smoking, my lost love" from the series "A point of view" I could hear it in my head. This, I thought, is someone whose blog I'd subscribe to, if he had one - which he doesn't. He does have a web site  and I found myself in the audio section listening to a piece called "Insult to the Language"  It shows a side of him which these days we are supposed to call "pro-detail" for fear that the a constable from the Political Correctness police will whisk us away if we describe someone as "pedantic", but nonetheless it has some quotable passages which show that his best writing is on the subject of the writing of others. For example

    "Such blunders... drive the reader to re-work the sentence himself before he can figure out what the writer must mean. When the writer is getting all of the fee, and the reader is doing at least half the labor the discrepancy can  cause resentment....
    ...There is a brand of Lumpen prose which ... weighs like lead because the reader continually has to join in the writing. "
    and quoting an example "This is just a mass of raw material waiting for the reader to make something of it"

    {Perhaps I should point the irony of quoting this after the passage I pasted into my previous post, lest someone else should point it out for me}  But this idea of sending a "mass of raw material" for the reader to sort out is what I referred to in Why am I the one doing this as "Bad E-mail. Why am I the one who has to organize the writers thoughts into something coherent ?"

    To show how sloppy writing distorts meaning, he talks about metaphors which people use incorrectly because they do not understand the practice which gave rise to them "He shot himself in the foot" James tells us "Originally referred to a solider in the great war, who hoped that a self inflicted wound would buy him a ticket out of the trenches. Perhaps because of the irresistible mental image of a western gunslinger pulling the trigger while getting his revolver out of its holster, the metaphor is nowadays almost universally used to evoke clumsiness, rather than cowardice" . Rather disappointingly neither of the editions of Brewer's Dictionary of Phrase and Fable that I have at home has this phrase in it.

    Of course I'd need something newer than my 1980's copy of Brewer's  to look up a term like Sockpuppet.

    A little time ago I was writing about Open XML and the process of moving from an ECMA ratified standard to an ISO modified one; it was something that was in the news and I felt I had something I wanted to say on the subject. This week an update reached the mail boxes of many Microsoft Bloggers, with a suggestion that we might want to blog about it. I don't mind if someone mails me to say "we've got an event which may be of interest to your customers will you spread the word ?". I have more trouble when it's a news story where I don't really have an angle. The news in this case, and it is good news for Microsoft, is that the Commonwealth of Massachusetts now support both Open XML and ODF formats. Great! You can read their comments about the process they went through here - with a link to the comments they received and the policy itself, though if I am to be honest, I really hope you have something better to do with your time.  (Reading and listening to Clive James for example.)

    I talked to Steve about it. "If we all blogged it at the same time wouldn't we look like a bunch of Sockpuppets" I said. To my surprise an upto-the-minute, on every-social-network, sidewalk-surfer-dude like Steve didn't know the term ,so I checked with both Wikipedia and Wordspy. The thing about a sockpuppet is that it is a false identity, I was spreading the term in the wrong sense - in just the kind of way that Clive James had talked about.

    So having us all blog about it at the same time would make us ... well I don't know what the term is (suggestions please. Any along the lines of "Typical Microsoft employees" won't be accepted.). Of course I'd never blog about the subject. Oh no. Perish the thought. I might mention it in passing to illustrate something rather more literary, but that's completely different :-)

  • James O'Neill's blog

    One small step for search...

    • 0 Comments

    I was talking to a customer (I know he reads this blog, so no names). He was having some trouble because two parts of Microsoft weren't communicating the way you'd expect them to. And I said in passing that one thing which we are unjustly accused of from time to time is underhand collusion: for example product "A" supposedly has some secret API that only the people working on product "B" know about. What we actually do is a bit like that scene at the very end of "Raiders of the lost Ark" where the Ark is hidden by placing it in crate and stored with thousands upon thousands of similar crates. Whilst I can't say for sure that never happened, people who believe "secret collaboration" is widespread really don't understand what Microsoft is like inside. You'd hope that all Microsoft web properties would:This is not a search box. SHAME ON US

    1. Run on Windows, IIS ASP.net etc. Every now and then someone finds a partner developed something Microsoft Branded uses Apache, and PHP. Although these can run on Windows...
    2. Still on the "using our technology" line Use Silverlight instead of Adobe flash. Actually a great deal of the Flash we use is Bad Flash anyway.
    3. Make all phone number Tel: urls. We tell customers that we can put presence and click to call here there and everywhere, but do we do it with our own numbers ? No. Hey we don't even write them all in E.164 format. 
    4. Light up the Search box in IE 7.  Actually I'm appalled by what I find on the Microsoft home page today At the top left "Add Live search to your Browser". Top Centre is what looks like a search box labeled but is actually a disguised link to a the Live web site. Shame on us for that. And at the Top right a "Powered by Live Search" box which leaves something to be desired in UI terms. Do we add search Microsoft.com to the dropdown box. No. 

    But lighting up the search box needs a <link  rel="search" ... > tag on each page; and some parts of the empire are starting to get the message. I was pleased when I saw IE's search drop-down go orange when I was on the support site, clicking it show the "This site only search"

    . support

    But I'll bet something from my "Swag" cupboard that we don't have this on the Microsoft home page before Christmas. (If we do - first person to send a mail to me pointing it out gets the prize) .

Page 1 of 2 (25 items) 12

August, 2007