Here is a step-by-step guide to configure a MDT Lite Touch or ConfigMgr task sequence to move a computer to another OU during deployment. The webservice used in this guide does the same job as Maik Koster's version available here: http://maikkoster.com/moving-computers-in-active-directory-during-mdt-deployments-step-by-step but I have include the C# source code for my version, so you can review, or modify it if you want to.
Note: In the guide I'm using a MDT Lite Touch task sequence, but this works great in ConfigMgr task sequences too. Just add the same actions there 🙂
Update October 20, 2022: Added instructions on using group Managed Service Account (gMSA)
Download the Webservice and sample script
The AD Webservice used in this post is available in compiled format here: https://deploymentresearch.com/DRFiles/ADWebService.zip
If you rather want to check out the source code, and/or compile yourself (C#, Visual Studio 2015), go here: http://github.com/arwidmark/AD-Webservice
The script that actually calls the webservice in the task sequence: https://deploymentresearch.com/DRFiles/ZTIMoveComputer.zip
Scenario #1 – Refreshing or Upgrading Computers
When using MDT or ConfigMgr for OSD, if you are refreshing or upgrading existing computers (keeping the same computer name), it does not really matter what value you assign to the MachineObjectOU variable, the solutions on their own are not going to move the computer to a new OU. That's simply how AD works, the computer account, again when keeping the name, is going to stay in the current OU.
But, by adding a Webservice, you can easily have the task sequence move the computer object to a new OU, even when the computer name is the same.
Scenario #2 – Using a Staging OU
Having group policies breaking your MDT Lite Touch deployment? Continue reading, here is the fix 🙂
When deploying machines with MDT, unlike when using ConfigMgr, the task sequence does not suppress group policy processing, and sometimes you have group policies (admin account renames, or company policy notifications), that simply breaks the MDT task sequence. The best way to work around that is to use a staging OU. Just create an OU to which you don't link the policies, and in the in end of the task sequence, call a web service that moves the computer to the real OU.

Step 1 – Install IIS and the webservice
The first step is to install IIS on your MDT server, or whatever server you want to use, and install the webservice
In this example my MDT server is named MDT01, and I'm using the VIAMONSTRA\MDT_WS service account to run the web service, and I have created two OU's:
ViaMonstra / Staging
ViaMonstra / Workstations
The Staging OU does not have any policies linked to it, and the VIAMONSTRA\MDT_WS has the needed permissions to manage computer objects in those OUs. For a script that sets the correct permissions, check this post: https://deploymentresearch.com/353/PowerShell-Script-to-set-permissions-in-Active-Directory-for-OSD
1. On MDT01, install IIS and some needed components by using the following PowerShell script:
$ServicesToInstall = @(
"Web-Windows-Auth",
"Web-ISAPI-Ext",
"Web-Metabase",
"Web-WMI",
"NET-Framework-Features",
"Web-Asp-Net",
"Web-Asp-Net45",
"NET-HTTP-Activation",
"NET-Non-HTTP-Activ",
"Web-Static-Content",
"Web-Default-Doc",
"Web-Dir-Browsing",
"Web-Http-Errors",
"Web-Http-Redirect",
"Web-App-Dev",
"Web-Net-Ext",
"Web-Net-Ext45",
"Web-ISAPI-Filter",
"Web-Health",
"Web-Http-Logging",
"Web-Log-Libraries",
"Web-Request-Monitor",
"Web-HTTP-Tracing",
"Web-Security",
"Web-Filtering",
"Web-Performance",
"Web-Stat-Compression",
"Web-Mgmt-Console",
"Web-Scripting-Tools",
"Web-Mgmt-Compat"
)
Install-WindowsFeature -Name $ServicesToInstall -IncludeManagementTools
2. On your MDT server, create the ViaMonstraWebServices folder, I used the E: drive in my environment, and grant the VIAMONSTRA\MDT_WS service account modify permissions to the E:\ViaMonstraWebServices folder.
3. Download the webservice from this link, https://deploymentresearch.com/DRFiles/ADWebService.zip and extract the content to the E:\ViaMonstraWebServices folder.

4. Modify the E:ViaMonstraWebServices\ADWebService\Web.config file with your domain (FQDN) and the webservice service account and password.
5. Create the E:\ViaMonstraWebServices\Tracing folder, for the webservice log file.
6. Using Internet Information Services (IIS) Manager, expand Sites, right-click Default Web Site, and select Add Application. Use the following settings for the application:
Alias: ADWebService
Application pool: Default
Physical Path: E:\ViaMonstraWebServices\ADWebService
Note: If running other IIS applications on the MDT server, you may want to create a separate application pool for the web service.
7. Using Computer Management, add the VIAMONSTRA\MDT_WS service account to the local IIS_IUSRS group.
8. Test the MoveComputerToOU function by adding a computer to the Staging OU, and then navigating to http://MDT01/ADWebService/ad.asmx, and use the MoveComputerToOU method to move it to another OU. In the below example, I tested with moving PC0025 to the OU=Workstations,OU=ViaMonstra,DC=corp,DC=viamonstra,DC=com OU

If the move was successful, you should see the following:

Step 2 – Add script, configure Rules and modify Task Sequence
Once you verified that the web service works, you need to add the sample script, configure the CustomSettings.ini file with the needed variables, as well as instructing the task sequence to to the job.
1. Download the ZTIMoveComputer.wsf script from here: https://deploymentresearch.com/DRFiles/ZTIMoveComputer.zip and extract it to your Scripts folder in your deployment share.
2. Add the following info to your CustomSettings.ini file.
[Settings]
Priority=Default
Properties=StagingOU, FinalOU
[Default]
JoinDomain=corp.viamonstra.com
DomainAdmin=VIAMONSTRA\MDT_JD
DomainAdminPassword=P@ssw0rd
StagingOU=ou=Staging,ou=viamonstra,dc=corp,dc=viamonstra,dc=com
FinalOU=ou=Workstations,ou=viamonstra,dc=corp,dc=viamonstra,dc=com<br>FinishAction=REBOOT
[MoveComputerToOU]
WebService=http://MDT01/ADWebService/ad.asmx/MoveComputerToOU
Parameters=OSDComputerName, MachineObjectOU
In the MDT task sequence, add a Set Task Sequence Variable action after the first Gather local only action with the following settings
Name: Set Staging OU
Task Sequence Variable: MachineObjectOU
Value: %StagingOU%

4. In the very end of the task sequence, create a new group named Move Computer to OU and add two actions in it.
The first action is a Set Task Sequence Variable action with the following settings
Name: Set Final Target OU
Task Sequence Variable: MachineObjectOU
Value: %FinalOU%
The second action is a Run Command Line action with the following settings:
Name: Move Computer to Final Target OU
Command line: cscript.exe "%SCRIPTROOT%\ZTIMoveComputer.wsf"

Using a group Managed Service Account (gMSA)
If you want to use a group Managed Service Account (gMSA) instead of a normal service account, you simply need to configure the application pool to use that as an identity instead. Don't forget to add the $ in the end of the account, and also make sure to remove the identity impersonate line from the web.config file.
Below are some PowerShell commands you can use to create and install group Managed Service Accounts. In this example my site server was in the ConfigMgr Site Servers group.
# For lab only, make the key available quickly
Add-KdsRootKey –EffectiveTime ((get-date).addhours(-10))
# On DC01, create the account
w-ADServiceAccount -Name gMSA_WS -PrincipalsAllowedToRetrieveManagedPassword "Domain Controllers", "Domain Admins", "ConfigMgr Site Servers" -DNSHostName gMSA_WS.corp.viamonstra.com -KerberosEncryptionType AES256 -Path "OU=Service Accounts,OU=ViaMonstra,DC=corp,DC=viamonstra,DC=com"
# On the target server (CM01), install and test the account
Add-WindowsFeature RSAT-AD-PowerShell
Install-ADServiceAccount -Identity gMSA_WS
Test-ADServiceAccount gMSA_WS


Troubleshooting
If you run into any issues, check the ZTIMoveComputer.log on the client, and the E:\ViaMonstraWebServices\Tracing\ADWebService.log on the MDT01 server. Here is an example where the service account, VIAMONSTRA\MDT_WS in my case, didn't have permissions on the OU's in Active Directory: Unhandled exception finding provider namespace on server System.UnauthorizedAccessException: Access is denied.
Another example of permissions error is the following, which doesn't appear to be a permission error at all, but it really was: Unhandled exception finding provider namespace on server System.DirectoryServices.DirectoryServicesCOMException (0x80072032): An invalid dn syntax has been specified.

Happy Deployment, Johan
Hi,
Is there a way to restrict access to the webpage used to testing? My client feels it could be a security risk having the webpage accessible by our users. (It's a student environment and they can be.. creative).
You can use various IIS security options like authentication settings, authorization rules, require certificates, etc. Including locking down the files system where the web service lives. Jeremy Saunders has a good post for Maik Kosters Deployment Web Service, and you can use the same techniques for this one. Here is the link: http://www.jhouseconsulting.com/2016/12/22/installing-configuring-securing-and-using-mdt-webservices-part-2-1728
Hello Johan! A question; Is move to Staging OU supposed to work with existing domain computer objects? I can't get it to work with existing domain computers. They are never moved to the Staging OU and the web service log is empty. When testing the web service from a browser it works fine to move computer objects back and forth between the Staging OU and the Final OU and data is written to the log file. The move to final OU works fine during the task sequence however. If I delete the computer object from AD and then run the… Read more »
Yes, it's intended for existing objects, as long as the permissions are correct, it should be able to deal with it.
Ok, so I've tested a bit more and I'm not sure whats going on 🙂 I got the trace log working (my fault, i hadn't changed the trace log path in the Web.config file). And now when I check the log i can see that the value received for MACHINEOBJECTOU is simply blank. And that of course makes it error out. A log example: 2022-12-05 14:25:07: MoveComputerToOU: MACHINEOBJECTOU received was: What is even more strange is that it doesn't matter if I change the %StagingOU% task sequence variable value to the actual distinguishedName for the Staging OU. It is still received… Read more »
Thanks for the update. I'll see if I can make the post a bit clearer.
Hi, I have had this popup recently – any idea on the cause?
8/23/2022 11:17:41 AM: MoveComputerToOU: Unhandled exception finding provider namespace on server System.ArgumentException: The (&(objectClass=computer)(|(userPrincipalName=)(distinguishedName=)(name=))) search filter is invalid.
at System.DirectoryServices.SearchResultCollection.ResultsEnumerator.MoveNext()
at System.DirectoryServices.SearchResultCollection.get_InnerList()
at System.DirectoryServices.SearchResultCollection.get_Count()
at System.DirectoryServices.AccountManagement.ADStoreCtx.FindPrincipalByIdentRefHelper(Type principalType, String urnScheme, String urnValue, DateTime referenceDate, Boolean useSidHistory)
at System.DirectoryServices.AccountManagement.ADStoreCtx.FindPrincipalByIdentRef(Type principalType, String urnScheme, String urnValue, DateTime referenceDate)
at System.DirectoryServices.AccountManagement.Principal.FindByIdentityWithTypeHelper(PrincipalContext context, Type principalType, Nullable`1 identityType, String identityValue, DateTime refDate)
at System.DirectoryServices.AccountManagement.Principal.FindByIdentityWithType(PrincipalContext context, Type principalType, String identityValue)
at System.DirectoryServices.AccountManagement.ComputerPrincipal.FindByIdentity(PrincipalContext context, String identityValue)
at Frontend.ConfigMgr.MoveComputerToOU(String OSDComputerName, String MACHINEOBJECTOU)
Hi Rob, it typically means that the web.config is not configured for your domain, the service account used is incorrect, or it does not have permissions. Does the MoveComputerToOU method load when you open the web service in a browser? (via http://MDT01/ADWebService/ad.asmx)
Yeah the it loads and works fine when running from the browser.
The process still does actually work; moves to staging, then to the final, it just spits out that error still in the process.
I'm glad it works for you, even with the error in the log. I cannot reproduce the issue in my labs, so to troubleshoot that further I would most likely have to debug that live in your environment. Please reach out to me on LinkedIn if you are interested in pursuing that.
Is there a way to move computers to an OU based on their hostname using this process?
Sure, you can add some logic that sets the Final OU value depending on their name. Either via cs.ini, or via script.
Hi John,
Most of my computers are existing machines in AD. I have followed you steps below but the devices are not being moved to the staging OU before install OS. Do i have to change the TS for existing computers? Do i need to run the ZTIMoveComputer.wsf script right after the SetStagingOU task?
Usually issues like that is permissions related. For troubleshooting it's efficient to just use web form manually.
I have this problem too and it is not related to permissions. Here were my attempts:
1 – I followed the entire guide as posted here and new machines are added normally however existing machines do not move to the Staging OU.
2 – After the Staging OU variable in Task Sequence, I added the script "ZTIMoveComputer.wsf", and the machine moved to Staging but during the deploy process it does not automatically log into the "Administrator" user and the deploy process is not completed (very strange this behavior).
Where should I look to fix this problem?
Is it possible to do this without the webservice? I'd like to do it without requiring interaction, purely automatic.
This is purely automatic, the scripts in the task sequence does the move. The manual steps are just for testing/troubleshooting.
/ Johan
Is there a way to dynamically assign the OU based on hostname or IP address or some other property?
Yes, the FinalOU variable can be set using any cs.ini logic or script.
Is it possable to have the OU set by task sequance??
I have multple OUS and would like to automate the moving of workstations to the correct out per task sequence?
Example
TS1 = Move to OU TS1/Workstations
TS2 = Move to OU TS2/Workstations
and so on
Just set the MachineObjectOU variable in the task sequence.
Do you have to specify the password in the .ini? My client is very concerned with password security and doesn't like the password stored plaintext, even if it's an account just used for joining computers to the domain and moving them to the staging OU.
Also, can the webservice be run at HTTPS. Client was also concerned about sending the password unencrypted.
Thanks,
You can do other forms of authentication, and yes, the web service can run as https. A common community solution is to use a secret key for the web service, but you can also ask for credentials, or use certificates.
Is it possible to use a Group Managed Service Account for authentication?
Hi Derek, absolutely. I just updated the blog post with info on how to do that.
I have the service working with a GMSA, however, I can't get past the "Unhandled exception finding provider namespace on server System.UnauthorizedAccessException: Access is denied." permissions error even though they are set the same as the account I was previously using.
I guess my next place to look is at User Rights Assignment in Group Policy to see if anything is there that could cause an issue.
It appears that the permissions that were working in AD do not work with a Group Managed Service Account. Has anyone figured out how to resolve the permission issue using a GMSA?
I haven't tried this web service with a gMSA account, but you can assign AD permissions to a gMSA accounts, for example, via dsacls.exe. Just remember to add the $ after the name, like below: (or add the account to a group that has correct permissions)
$UserAccount = "VIAMONSTRA\gMSA_WS`$"
$OrganizationalUnitDN = "ou=workstations,ou=viamonstra,DC=corp,DC=viamonstra,DC=com"
dsacls.exe $OrganizationalUnitDN /G $UserAccount":RC;;Computer" /I:S
And then all the other permissions needed, see this script: https://github.com/DeploymentResearch/DRFiles/blob/master/Scripts/Set-OUPermissions.ps1
Yeah, it seems like I can apply the permissions to the account but it is still blocked. I also tried using a Security Group that is already working with a standard service account but the gMSA still doesn't work when added to the Group or when permissions are delegated directly to the account.
Has anyone else gotten a gMSA to work?
Hi Johan I am just trying to get this working now. I have got the Web Service working and browsing to http://mdtserver/ADWebService/ad.asmx?op=MoveComputerToOU and running a "MoveComputerToOU" test works nicely. I have added the steps in the task sequence and added variables etc to customsettings.ini During deployment the computers goes to the staging OU. However, the move to finial OU step fails. Checking the ZTIMoveComputer.log states: FinalTargetOU is: ZTIMoveComputer 06/09/2019 07:59:25 0 (0x0000) MoveComputerToOU ZTIMoveComputer 06/09/2019 07:59:25 0 (0x0000) Using DEFAULT VALUE: Ini file = \\HQSUPPORT\DeploymentShare$\Control\CustomSettings.ini ZTIMoveComputer 06/09/2019 07:59:25 0 (0x0000) CHECKING the [MoveComputerToOU] section ZTIMoveComputer 06/09/2019 07:59:25 0 (0x0000) Unexpected… Read more »
You need to set the FinalTargetOU value in the customsettings.ini file, it cannot be blank. Also since it's a custom variable it needs to be defined in the Settings section as well.
/ Johan
Thanks Johan I realized that my customsettings was set to: WebService=http://mdtserver/ADWebService/ad.asmx?op=AddComputerToGroup (which was a valid browseable URL but clearly not 'syntaxly' correct) Instead of: http://mdtserver/ADWebService/ad.asmx/MoveComputerToOU Correcting this sorted it. All working nicely now. THANKS! One thing in case anyone else find this useful, I notice the script ZTIMoveComputer.wsf script sets oEnvironment.Item("DeploymentMethod") = "SCCM". If theZTIMoveComputer.wsf is called earlier in the TS (example is a "Refresh" deployment where computer already exists in AD and you want to move it to staging OU as early as possible), changing DeploymentMethod to SCCM can break USMT User State Restore (and anything else that references… Read more »
Glad you got it solved, and thanks for the other feedback.
Been doing this for years – great post. Be careful when copying text from this page though: – Backslashes have been stripped, eg from %SCRIPTROOT%ZTIMoveComputer.wsf. Should be %SCRIPTROOT%\ZTIMoveComputer.wsf – Double quotes have been typographer-ed! As copied from the post: cscript.exe “%SCRIPTROOT%ZTIMoveComputer.wsf” How it needs to be to actually work: cscript.exe "%SCRIPTROOT%\ZTIMoveComputer.wsf" That second one kept me up a few extra hours last night! Annoyingly, I noticed it when copying from a different page on Johan's blog, but then helpfully forgot when I got here. **EDIT – They've (obviously) been stripped from this comment too! Should have realised.. come on brain.… Read more »
Sorry about that, I noticed that info gone missing from some of the post during the migration from DNN to WordPress. I've updated this post, and I'm slowly working through the others (takes a while since its about 400 of them). / Johan