December, 2009

  • Michael Niehaus' Windows and Office deployment ramblings

    Fixing Office Upcoming Appointments gadget to work with Office 2010

    • 3 Comments

    I just finished installing Office 2010 on all my home computers, and immediately ran into a “wife acceptance factor” issue: the “Outlook Upcoming Appointments” Sidebar gadget didn’t work:

    image

    “Fix it.”  Sigh.  Fortunately, it wasn’t hard to do.  Locate the “C:\Users\<user ID>\AppData\Local\Microsoft\Windows Sidebar\Gadgets\OutlookAppointmentsGadget[1].gadget\en-US\js” folder and in it you’ll see a file called Outlook.vbs.  Open it in your favorite text editor and find the two lines that mention Outlook “12” and change them to reference Outlook “14” instead.  Change this:

    if value = "Outlook.Application.12" then

    to:

    if value = "Outlook.Application.14" then

    and this:

    if mid(outlookApplication.Version, 1, 2) <> "12" then

    to this:

    if mid(outlookApplication.Version, 1, 2) <> "14" then

    Save the changes, close the gadget, and open it again.  You should then see something that works:

    image

    If only all application compatibility issues were that simple…

  • Michael Niehaus' Windows and Office deployment ramblings

    Have questions about MDT 2010?

    • 3 Comments

    We have created a new forum on TechNet specifically for MDT-related questions – no question is too simple or too advanced.  You can access the forum via http://social.technet.microsoft.com/Forums/en-US/mdt/threads.  It’s been around for a couple of months, but we haven’t publicized it too heavily so we could slowly ramp up.

    As always, I seem to be keeping too busy to spent a lot of time responding to questions on the forum, but fortunately there are several other experts (including Tim Mintner, Keith Garner, and Johan Arwidmark) who have been helping out with that.

  • Michael Niehaus' Windows and Office deployment ramblings

    Ready for Office 2010? It’s not far away.

    • 0 Comments

    The Office 2010 Beta has been available for a short while now and should be released sometime next year.  I’m already quite attached to it, and not only because of the “People Pane” in Outlook 2010 and its coming ties to various social networks.

    To help with the coming migration, some new Office compatibility tools have been released.  See http://blogs.technet.com/gray_knowlton/archive/2009/12/04/office-2010-application-compatibility-tools-beta-now-available.aspx for more details.

    Also, if you aren’t yet running the Key Management Service (KMS) or using Multiple Activation Keys (MAK) with Windows Vista or Windows 7, you’ll probably want to study up on Volume Activation, as Office 2010 will use it too.  There’s also a new beta version of the Volume Activation Management Tool (VAMT) 2.0 available for download here.

    12/10/2009 Addendum:  There is another new download that might be useful at http://www.microsoft.com/downloads/details.aspx?FamilyID=600c2142-abc3-4fea-9271-0c326c45dc8f&displaylang=en.  It’s a poster that describes the deployment and installation options for Office 2010.

  • Michael Niehaus' Windows and Office deployment ramblings

    RIS-style naming with MDT 2010: Use a web service

    • 6 Comments

    I’ve been toying around with using a web service that could be used to implement RIS-style computer naming.  Unfortunately, I haven’t had time to work on it much in the last year or so, so I’ll post the code as-is and tell you up front that it’s not really complete – you might need to make some changes to it to meet your specific needs.  So here’s the code (written using Visual Studio 2008 and .NET 3.5), which shows how easy it is to do LDAP queries and object creation using .NET:

    using System;
    
    using System.Collections;
    
    using System.Collections.Generic;
    
    using System.ComponentModel;
    
    using System.Diagnostics;
    
    using System.DirectoryServices;
    
    using System.Data;
    
    using System.Linq;
    
    using System.Web;
    
    using System.Web.Services;
    
    using System.Web.Services.Protocols;
    
    using System.Xml.Linq;
    
    
    
    namespace DemoWebService
    
    {
    
        [WebService(Namespace = "http://tempuri.org/")]
    
        [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    
        [ToolboxItem(false)]
    
        public class NameService : System.Web.Services.WebService
    
        {
    
            [WebMethod]
    
            public String GenerateName(String dnsDomain, String prefix, String uuid, String machineObjectOU)
    
            {
    
                // Build the search
    
                DirectoryEntry entry =
    
                    new DirectoryEntry("LDAP://" + dnsDomain);
    
                DirectorySearcher search = new DirectorySearcher(entry,
    
                   "(name=" + prefix + "*)");
    
    
    
                // Execute the search and build a list of the matching names and their UUIDs
    
                Dictionary<String, Guid> existingNames = new Dictionary<String, Guid>();
    
                foreach (SearchResult result in search.FindAll())
    
                {
    
                    String name = result.Properties["name"][0].ToString().ToUpper();
    
                    Guid netbootGuid = new Guid();
    
                    if (result.Properties["netbootGuid"].Count > 0)
    
                        netbootGuid = new Guid((byte[])result.Properties["netbootGuid"][0]);
    
                    Trace.WriteLine("Found computer " + name + " with GUID " + netbootGuid.ToString());
    
                    existingNames.Add(name, netbootGuid);
    
                }
    
    
    
                // See if we can find an existing match.  If so, return it.
    
                Guid existingUuid = new Guid(uuid);
    
                if (existingNames.ContainsValue(existingUuid))
    
                {
    
                    foreach (String name in existingNames.Keys)
    
                        if (existingNames[name] == existingUuid)
    
                        {
    
                            // TODO: Maybe we want to move the computer object to the specified OU
    
                            return name;
    
                        }
    
                }
    
    
    
                // Find the first available name in sequence
    
                String nextName = null;
    
                for (Int32 i = 1; i <= 999; i++)
    
                {
    
                    String testName = prefix + i.ToString("000");
    
                    if (!existingNames.ContainsKey(testName))
    
                    {
    
                        nextName = testName;
    
                        break;
    
                    }
    
                }
    
                if (nextName == null)
    
                    return null;  // All names were taken
    
    
    
                // Add the computer to AD
    
                try
    
                {
    
                    DirectoryEntry dirEntry = new DirectoryEntry("LDAP://" + machineObjectOU);
    
                    DirectoryEntry newUser = dirEntry.Children.Add("CN=" + nextName, "computer");
    
                    newUser.Properties["samAccountName"].Value = nextName + "$";
    
                    newUser.Properties["netbootGUID"].Value = existingUuid.ToByteArray();
    
                    newUser.Properties["description"].Value = "Added by MDT";
    
                    newUser.CommitChanges();
    
                    newUser.Close();
    
                }
    
                catch (Exception e)
    
                {
    
                    Trace.WriteLine("Unable to add computer: " + e.ToString());
    
                }
    
    
    
                // Return the name
    
                return nextName;
    
            }
    
    
    
        }
    
    }
    

    To use this, you would add an entry to CustomSettings.ini to call the web service.  That would look something like this:

    [Settings]
    Priority=Default, GetName
    Properties=DnsDomain, Prefix

    [Default]
    Prefix=MDTTEST
    DnsDomain=mydomain.com
    MachineObjectOU=OU=Workstations,DC=mydomain,DC=com

    [GetName]
    WebService=http://myserver/NameService.asmx/GenerateName
    Parameters=DnsDomain, Prefix, UUID, MachineObjectOU
    OSDComputerName=string

    The web service would be passed the DNS domain name (mydomain.com), computer prefix (MDTTEST), the current machine’s SMBIOS UUID, and the OU to which new computers should be added.  It will return a name starting with the specified prefix and ending with the next available three-digit number.  So the first machine would be MDTTEST001, the second MDTTEST002, etc.  These computer names are added to Active Directory with the “netbootGUID” attribute set, so that if the machine is ever rebuilt it will use the same computer name again.  (The code purposely doesn’t try to find any computer object with that SMBIOS UUID.  Instead, it only looks for computers with the right prefix that have a matching UUID.  This might not be the behavior you want, but it was the behavior I wanted.)

    The output from ZTIGather.wsf when processing this INI file would look something like this:

    Added new custom property DNSDOMAIN
    Added new custom property PREFIX
    Using from [Settings]: Rule Priority = DEFAULT, GETNAME
    ------ Processing the [DEFAULT] section ------
    Property MACHINEOBJECTOU is now = OU=Workstations,DC=mydomain,DC=com
    Using from [DEFAULT]: MACHINEOBJECTOU = OU=Workstations,DC=mydomain,DC=com
    Property DNSDOMAIN is now = mydomain.com
    Using from [DEFAULT]: DNSDOMAIN = mydomain.com
    Property PREFIX is now = MDTTEST
    Using from [DEFAULT]: PREFIX = MDTTEST
    ------ Processing the [GETNAME] section ------
    Determining the INI file to use.
    Using COMMAND LINE ARG: Ini file = CS.ini
    Finished determining the INI file to use.
    Using COMMAND LINE ARG: Ini file = CS.ini
    CHECKING the [GETNAME] section
    About to execute web service call using method POST to http://server/NameService.asmx/GenerateName: DnsDomain=mydomain.com&Prefix=MDTTEST&UUID=814100CD-CE48-CB11-A536-B7561D1E4450&MachineObjectOU=OU=Workstations,DC=mydomain,DC=com
    Response from web service: 200 OK
    Successfully executed the web service.
    Property OSDCOMPUTERNAME is now = MDTTEST001
    Obtained OSDCOMPUTERNAME value from web service:  string = MDTTEST001

    This isn’t quite as flexible as the RIS naming, where you could use other variables in the computer name, but there’s no reason you couldn’t add more logic to cover those cases too.  There’s also no guarantee that the web service will add the computer account to the same DC that the computer ends up using, which could cause some naming conflicts if the new computer object doesn’t replicate before the computer tries to join the domain.  Use at your own risk :-)

  • Michael Niehaus' Windows and Office deployment ramblings

    Workaround posted for ConfigMgr SP2 issue with USMT 4.0

    • 2 Comments

    Levi Stevens posted a blog entry today describing a workaround for an issue with ConfigMgr SP2 and USMT 4.0 that causes USMT to not capture all of the user state information.  See http://blogs.technet.com/configmgrteam/archive/2009/12/01/known-issue-migrating-from-windows-xp-to-windows-7-with-usmt-when-used-with-configmgr-2007-sp2-os-deployment-may-not-migrate-all-settings.aspx for all the details.

    We are still working on a KB article for MDT 2010 that provides a similar fix.  That KB article (which will be 977565 once it is finally available) will describe the changes necessary to ZTIUserState.wsf.  (They are pretty minor, just adding two lines to set the working directory to the folder containing the USMT binaries before running scanstate.exe or loadstate.exe.)

  • Michael Niehaus' Windows and Office deployment ramblings

    Dynamic application detection with Lite Touch, Revisited

    • 0 Comments

    Over a year ago, I posted a blog entry at http://blogs.technet.com/mniehaus/archive/2008/09/25/dynamic-application-detection-with-lite-touch.aspx with details on how to automatically detect installed applications during a Lite Touch deployment, enabling those to be pre-selected when the application list is presented.  Due to changes in the XML file schemas, this script needs some updates for MDT 2010 to be truly “correct”.  The updated script follows, showing how to create a user exit that leverages the ZTIConfigFile script to enumerate all the available (enabled, visible) applications.

    Option Explicit

    Function UserExit(sType, sWhen, sDetail, bSkip)

        Dim oScriptFile
        Dim oXMLApps, dAllApps
        Dim sGUID
        Dim oNode, oKey
        Dim sValueName, sKey, sValue
        Dim oApplications

        ' Only do this before processing the rule contents

        If sWhen <> "BEFORE" then
            UserExit = Success
            Exit Function
        End if

        ' Make sure ZTIConfigFile is loaded

        On Error Resume Next
        Set oScriptFile = oFSO.OpenTextFile(oUtility.ScriptDir & "\ZTIConfigFile.vbs", 1, false)
        ExecuteGlobal oScriptFile.ReadAll
        On Error Goto 0

        ' Load the applications XML File

        Set oXMLApps = new ConfigFile
        oXMLApps.sFileType = "Applications"
        Set dAllApps = oXMLApps.FindItems

        ' Enumerate the applications

        For each sGUID in dAllApps

            Set oNode = dAllApps(sGUID)

            ' Retrieve the uninstall key node if present

                Set oKey = oNode.selectSingleNode("UninstallKey")

            ' If one was specified, look for the key in the registry

            If not (oKey is nothing) then

                ' Get the key name

                sKey = oKey.Text

                ' Check if the registry key exists by looking for well-known values

                For each sValueName in Array("DisplayName", "UninstallString", "QuietUninstallString")

                    sValue = empty
                    On Error Resume Next
                    sValue = oShell.RegRead("HKLM\Software\Microsoft\Windows\CurrentVersion\Uninstall\" & sKey & "\" & sValueName)
                    On Error Goto 0

                    If IsEmpty(sValue) then
                        On Error Resume Next
                        sValue = oShell.RegRead("HKLM\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\" & sKey & "\" & sValueName)
                        On Error Goto 0
                    End if

                    ' If a value was found, add the application's GUID to the list so it gets pre-selected by the wizard

                    If not IsEmpty(sValue) then

                        oLogging.CreateEntry "Uninstall registry key found for application " & oNode.selectSingleNode("Name").Text & ", application is present and will be reinstalled.", LogTypeInfo

                        ' Add the GUID if it doesn't already exist in the list

                        Set oApplications = oEnvironment.ListItem("Applications")
                        If not oApplications.Exists(oNode.Attributes.getNamedItem("guid").value) then
                            oApplications.Add oNode.Attributes.getNamedItem("guid").value, ""
                            oEnvironment.ListItem("Applications") = oApplications
                        End if

                        Exit For

                    End if

                Next
            Else

                oLogging.CreateEntry "UninstallKey not specified for application " & oNode.selectSingleNode("Name").Text, LogTypeInfo

            End if

        Next

        UserExit = Success

    End Function

    The code has been updated some, but the concepts haven’t, so if you need more details on what this does check out the original article.

  • Michael Niehaus' Windows and Office deployment ramblings

    In the Seattle area? Come to the Windows Networking User’s Group meeting

    • 0 Comments

    On Wednesday, December 2, the Windows Networking User’s Group is having their monthly meeting at the Microsoft office in Bellevue.  Chris Avis is the featured speaker this month, and the topic of his presentation is:

    Windows 7 New Features: Windows XP Mode & Boot to VHD

    Windows 7 introduces host of new features and technologies to simplify your work and make you more productive. Two technologies you may not have heard about are Windows XP Mode and the new “Boot to VHD” feature. 

    Windows XP Mode allows administrators to migrate legacy applications from that Windows XP world into Windows 7 regardless of that applications compatibility with Windows 7. Windows XP Mode provides a virtualized instance of Windows XP that allows you to continue to run older applications while still enjoying the benefits of Windows 7. The best part of this deal is that it is FREE!

    The Boot to VHD feature of Windows 7 allows you to boot a virtualized operating system “natively”. This provides for better resource utilization, access to some hardware components that normally can’t be used in a virtual machine, as well as eliminating boot code issues surrounding dual or multi-boot scenarios. Chris will discuss how to configure and run Boot to VHD features as well as some new options in Windows 7 that make creating and supporting this feature a breeze.

    Pizza and soft drinks will be served at 6pm, with the presentation scheduled for 6:30pm.  If you are in the area and would like to attend, please RSVP.  For more details, visit the WNUG site at http://www.winnetusergroup.com/default.aspx.  (I hope to attend myself.)

Page 1 of 1 (7 items)