Moving Computers to another OU during deployment – Webservice style

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.

image
The action that moves the computer to the final 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.

The AD Webservice extracted 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

Testing the MoveComputerToOU method.

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

A successful move.

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%

The Set Staging OU action added.

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"

The final actions added to the task sequence.

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
group Managed Service Account in AD,
Application pool configured with a group Managed Service Account

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.

image
Debugging the webservice.

Happy Deployment, Johan

About the author

Johan Arwidmark

5 1 vote
Article Rating
Subscribe
Notify of
guest
35 Comments
Newest
Oldest Most Voted
Inline Feedbacks
View all comments
Emil Jonsson
Emil Jonsson
6 months ago

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).

Andrew
Andrew
6 months ago

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 »

Andrew
Andrew
5 months ago

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 »

Rob
Rob
9 months ago

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)

Rob
Rob
8 months ago

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.

Pete
Pete
2 years ago

Is there a way to move computers to an OU based on their hostname using this process?

Dan Totman
2 years ago

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?

Last edited 2 years ago by Dan Totman
Maicon Santos
Maicon Santos
6 months ago
Reply to  Dan Totman

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?

Robert Bigelow
Robert Bigelow
2 years ago

Is it possible to do this without the webservice? I'd like to do it without requiring interaction, purely automatic.

Pete
Pete
2 years ago

Is there a way to dynamically assign the OU based on hostname or IP address or some other property?

Kyle
Kyle
3 years ago

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

Tyler Provick
Tyler Provick
3 years ago

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,

Derek
Derek
7 months ago

Is it possible to use a Group Managed Service Account for authentication?

Derek
Derek
6 months ago

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.

Derek
Derek
6 months ago

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?

Derek
Derek
5 months ago

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?

Thomas
Thomas
3 years ago

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 »

Thomas
Thomas
3 years ago

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 »

Rob
Rob
3 years ago

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 »


>