Microsoft's official enterprise support blog for AD DS and more
Ned here with a quick blurb:
The latest version of the Ultrasound tool has been released to the web. This version adds support for monitoring FRS on Windows Server 2008 and allows the use of SQL Server 2005 for hosting the Ultrasound database. No other new features have been added in this version, and it does not monitor DFSR (the older version didn't either).
The download location for the tool is the same as before - http://www.microsoft.com/downloads/details.aspx?FamilyID=61acb9b9-c354-4f98-a823-24cc0da73b50&displaylang=en. To deploy the Ultrasound WMI provider on an x64 version of Windows Server 2008, the hotfix KB954737 must be installed (this fact is also mentioned in the release notes). - Ned Pyle
Hi Rob here again. I recently had a customer that needed the functionality of MoveUser.exe from the Windows 2000 Resource Kit available in Windows Vista. The customer had quite a few Windows Vista machines that were not joined to the domain but were now migrating to Active Directory. For their own business reasons they were previously unable to join the machines to the domain, instead all the users logged on with local user accounts. Since they had this new fancy Active Directory they created user accounts in AD for the users and joined the machines to the domain. They then found that they needed a way to attach the users’ existing local profile to their Active Directory user accounts so that the users would have their normal setup and desktop when they logged in-a seamless experience. Now if you have been around forever like most of us here in support in Windows 2000 and up we used a utility named MoveUser.exe to accomplish this.
Well, in Windows Vista moveuser.exe is no longer supported. However, now we expose this functionality with a new WMI provider called Win32_UserProfile, which is discussed in KB930955. This is awesome because we expose things about user profiles in WMI now… and we can also move the profile to another user as well as delete user profiles. However, once I started looking at MSDN to understand what methods were available I quickly found that MSDN has not been updated as of yet for this new class. So we did some digging into the source code to find out how this works and what is supported.
I wrote a sample script that illustrates how you can leverage this provider to move an existing user profile to another user’s profile. I know that I could have made the script smaller by not listing out all the different properties available in the provider, but the different things exposed are just way too many and if you are planning on using this provider they are just way too cool.
Please keep in mind that this is a sample script-you will need to alter it and test it in your environment and for your needs. To use:
1. Copy the below script into Notepad then save as moveuser.vbs
2. You will need to modify the following variables within the script.
3. Run the script by typing cscript moveuser.vbs
Sample Script
' This script is provided "AS IS" with no warranties, and confers no rights. ' For more information please visit ' http://www.microsoft.com/info/cpyright.mspx to find terms of use. ' Option Explicit DIM strComputer, strSourceAcct, strSourceAcctDomain, strTargetAcct DIM strTargetAcctDomain, strTargetAcctSID DIM objProfile, objCommand, objRecordSet, objConnection, objWMIService, objSID DIM dtStart, colProfiles, oSID, oUsr DIM Revision, IssueAuthorities(11), strSDDL, subAuthoritiesDIM strDomainDN
CONST ADS_SCOPE_SUBTREE=2
' This script has hard coded variables in it that must be filled out. ' strComputer = The computer name that this script needs to run against. ' With WMI the "." means this computer. ' ' strSourceAcct = user account that has the source profile on the system. ' ' strSourceAcctDomain = The domain of the source user account that the profile belongs to. ' If the source account that you want to move the profile from ' is a local computer user you put in the computers name for the domain. ' If this is another domain then you type in the domain name. ' ' strTargetAcct = The user account that the source profile should be moved to. ' ' strTargetDomain = The domain of the target user account that the profile should be moved to ' If the target account that you want to move the profile to. ' is a local computer user you put in the computers name. ' If this is another domain then you type in the domain name. ' ' strDomainDN = The Target Account Domains Distinguished Name. ' This is done for the LDAP query to be built to find the target accounts SID '
strComputer ="." strSourceAcct="User1" strSourceAcctDomain="Contoso-Vista" strTargetAcct="User1" strTargetAcctDomain="CONTOSO" strDomainDN="dc=contoso,dc=com"strTargetAcctSID="" dtStart = TimeValue(Now()) Set objConnection = CreateObject("ADODB.Connection") objConnection.Open "Provider=ADsDSOObject;" Set objCommand = CreateObject("ADODB.Command") objCommand.ActiveConnection = objConnection
' We need the proper Active Directory domain name where the user exists in a DN format. You can ' modify the strDomainDN variable to you Active Directory domain name is in DN format.
objCommand.CommandText = _ "SELECT AdsPath, cn FROM 'LDAP:// "+strDomainDN+"' WHERE objectCategory = 'user'" & _ "And sAMAccountName= '"+strTargetAcct+"'" objcommand.Properties("searchscope") = ADS_SCOPE_SUBTREE Set objRecordSet = objCommand.Execute If objRecordset.RecordCount = 0 Then WScript.Echo "sAMAccountName: " & strTargetAcct & " does not exist." ElseIf objRecordset.RecordCount > 1 Then WScript.Echo "There is more than one account with the same sAMAccountName" Else WScript.Echo "Found account: "+strTargetAcctDomain+"\"+strTargetAcct + " in the domain." objRecordSet.MoveFirst Do Until objRecordSet.EOF Set Ousr = GetObject(objRecordSet.Fields("AdsPath").Value) strTargetAcctSID = SDDL_SID(oUsr.Get("objectSID")) WScript.echo "SID for "+ strTargetAcctDomain+"\"+strTargetAcct + _ " is: "+strTargetAcctSID WScript.Echo VBNewLine WScript.Echo VBNewLine
objRecordSet.MoveNext Loop
objConnection.Close
Set objWMIService = GetObject("winmgmts:\\" & strComputer &"\root\cimv2") Set colProfiles = objWMIService.ExecQuery("Select * from Win32_UserProfile") For Each objProfile in colProfiles Set objSID = objWMIService.Get("Win32_SID.SID='" & objProfile.SID &"'") Wscript.Echo"======================================================"& VBNewLine _ &"Sid:" & objProfile.Sid & VBNewLine _ &"User Name:" & objSID.AccountName & VBNewLine _ &"User Domain:" & objSID.ReferencedDomainName & VBNewLine _ &"LocalPath:" & objProfile.LocalPath & VBNewLine _ &"Loaded:" & objProfile.Loaded & VBNewLine _ &"RefCount:" & objProfile.RefCount & VBNewLine _ &"RoamingConfigured:" & objProfile.RoamingConfigured & VBNewLine _ &"RoamingPath:" & objProfile.RoamingPath & VBNewLine _ &"RoamingPreference:" & objProfile.RoamingPreference & VBNewLine _ &"Status:" & objProfile.Status & VBNewLine _ &"LastUseTime:" & objProfile.LastUseTime & VBNewLine _ &"LastDownloadTime:" & objProfile.LastDownloadTime & VBNewLine _ &"LastUploadTime:" & objProfile.LastUploadTime & VBNewLine
' Testing to verify that the current profile handle is for the Source Account that we want to ' Move to the domain user. if UCase(objsid.referencedDomainName+"\"+objsid.AccountName)= _ UCase(strSourceAcctDomain+"\"+strSourceAcct) Then ' Making sure that the source profile is currently not in use. If it is we will bail out. If objProfile.RefCount < 1 Then WScript.echo "Change Profile for: "+ strSourceAcctDomain+"\"+ _ strSourceAcct+" to: "+ strTargetAcctDomain+"\"+strTargetAcct ' ChangeOwner method requires to String SID of Target Account and a Flag setting
' Flag 1 = Change ownership of the source profile to target account ' even if the target account already has a profile on the system.
' Flag 2 = Delete the target account Profile and change ownership ' of the source user account profile to the target account.
' To use the ChangeOwner method, both the source and ' target account profiles (If it exists) must not be loaded.
ObjProfile.ChangeOwner strTargetAcctSID,1 Else Wscript.echo "Could not move the users profile, because " + _ strSourceAcctDomain+"\"+strSourceAcct+" profile is currently loaded" End If End If Next End If Sub Init_IssueAuthorities( ) 'DIM IssueAuthorities(11) IssueAuthorities(0) = "-0-0" IssueAuthorities(1) = "-1-0" IssueAuthorities(2) = "-2-0" IssueAuthorities(3) = "-3-0" IssueAuthorities(4) = "-4" IssueAuthorities(5) = "-5" IssueAuthorities(6) = "-?" IssueAuthorities(7) = "-?" IssueAuthorities(8) = "-?" IssueAuthorities(9) = "-?"
end sub
function SDDL_SID ( oSID ) DIM Revision, SubAuthorities, strSDDL, IssueIndex, index, i, k, p2, subtotal DIM j, dblSubAuth ' ' First byte is the revision value ' Revision = "1-5"' ' Second byte is the number of sub authorities in the ' SID ' SubAuthorities = CInt(ascb(midb(oSID,2,1))) strSDDL = "S-" & Revision IssueIndex = CInt(ascb(midb(oSID,8,1))) ' ' BYtes 2 - 8 are the issuing authority structure ' Currently these values are in the form: ' { 0, 0, 0, 0, 0, X} ' ' We use this fact to retrieve byte number 8 as the index ' then look up the authorities for an array of values ' strSDDL = strSDDL & IssueAuthorities(IssueIndex) ' ' The sub authorities start at byte number 9. The are 4 bytes long and ' the number of them is stored in the Sub Authorities variable. ' index = 9 i = index for k = 1 to SubAuthorities ' ' Very simple formula, the sub authorities are stored in the ' following order: ' Byte Index Starting Bit ' Byte 0 - Index 0 ' Byte 1 - Index + 1 7 ' Byte 2 - Index + 2 15 ' Byte 3 - Index + 3 23 ' Bytes0 - 4 make a DWORD value in whole. We need to shift the bits ' bits in each byte and sum them all together by multiplying by powers of 2 ' So the sub authority would be built by the following formula: ' ' SUbAuthority = byte0*2^0 + Byte1*2^8 + byte2*2^16 + byte3*2^24 ' ' this be done using a simple short loop, initializing the power of two ' variable ( p2 ) to 0 before the start an incrementing by 8 on each byte ' and summing them all together. ' p2 = 0 subtotal = 0 for j = 1 to 4 dblSubAuth = CDbl(ascb(midb(osid,i,1))) * (2^p2) subTotal = subTotal + dblSubAuth p2 = p2 + 8 i = i + 1 next ' ' Convert the value to a string, add it to the SDDL Sid and continue ' strSDDL = strSDDL & "-" & cstr(subTotal) next SDDL_SID = strSDDL end function
Please keep in mind if you have not installed Service Pack 1 for Vista, you will need to download the MSI installer to get the new WMI Profile provider since it was released after Vista shipped.
Well, I hope that you find this functionality helpful. Happy scripting.
- Rob Greene
This is Paul Fragale, coming to you from my little corner of the world. With the launch of Windows Server 2008, there have been several cases around Terminal Server and Terminal Server License Server. I would like to take a moment to review with you some common steps that can help you resolve these issues.
The first case:
Introducing a Windows 2008 Terminal Server into your existing Windows 2003 Environment requires a little preparation. The first main point is that a Windows Server 2008 Terminal Server can only talk to a Windows 2008 License Server. (Additional information can be found at http://technet.microsoft.com/en-us/library/cc770371.aspx) There are two ways to set up the environment to handle this requirement:
The second case:
Limiting your Client Access Licenses (CALs) issuance is a frequent concern. With the auto-discovery process any Terminal Server can search Active Directory for a license server. If it finds one, it can then use the TSLS to issue licenses, thereby possibly depleting your license pool inadvertently. To prevent this, Microsoft has introduced a new group called “Terminal Server Computers”. This group allows you to configure what servers the license server is allowed to talk to. It works in conjunction with the “License server security group” Group policy found in the following location:
Computer Configuration\Administrative Templates\Windows Components\Terminal Services\TS Licensing.
In Windows 2008, we have found that it is a good idea to add all your Terminal Servers to this group when the License server is Windows 2008. A couple of symptoms that people have reported are the following:
Once you have added the servers to the “Terminal Server Computers” group, the server will start communicating and receiving licenses from the TSL. The one catch is that the server has to have already discovered the license server.
The third case:
Upon installing a Windows 2008 TSL, you may find the following event in the System event log:
Event ID: 8195 Task Category: None Level: Warning Keywords: Classic User: N/A Computer: tsl.alpineskihouse.com Description: The computer account for the Terminal Services license server could not be added to the Terminal Server License Servers group in Active Directory Domain Services during the installation of TS Licensing. The action failed with Win32 error code 0x80072037.
This event occurs in the following situations:
(I would like to thank Rob Greene for providing this third piece of information.)
So hopefully this gives you a little insight on troubleshooting your own Terminal Server License Server issues.
Until next time,
-Paul Fragale
Ned here. For all of our bilingual German readers, I wanted to point out that the Microsoft Germany DS support folks also have their own excellent blog:
Aktives Verzeichnis - http://blogs.technet.com/deds/
Be sure to add them to your feed reader of choice. Barbara, Fabian, and Rol write excellent stuff. For example, their latest post covers improving service reliability and performance by reconfiguring Kerberos PAC validation. And if your German is a bit rusty, you can use Windows Live Translator to convert it - here it is in English.
- Ned Pyle