Seriously, I have no idea how the hell I didn’t came across this before as this technology have been exposed for a few year by now(2006 actually)… Anyway, I would like to thank my dear co-worker Sylvain Lesire for bringing this to my knowledge, this stuff is a game changer and empower everyone with web service knowledge in his leather tool belt.
If you have no idea where a web service fit in the ‘deployment space’, imagine that you need to move computers to a different OU or an SCCM collection during a deployment. The web service will allow you to request your AD/SCCM server to move the machines without requiring manual intervention or remote execution with privileged account. Your deploying machine will politely ask the web service to make the changes using a web request (an URL), and the web service (literally a web server like IIS or Apache !!!) will locally do the job on the server for you. Once done it will reply to your request with some returning data. Sound cool? I’ve just scratched the surface…
So yes it’s possible to build a full web service with just PowerShell and it’s a very good news for all of us that don’t understand PHP, Apache, ASP.Net, C#, IIS or even none of them (my case!) but also for our customers that were always reluctant to deploy a web service because (same song…) : “no one know C# (or any other from the above list) in the team, how are we supposed to maintain or update the tool…” (Very valid statement if you ask me !).
Using a PowerShell web service is as complicated as running a PowerShell script. I tried to pull out from the project every possible blocker to bring to life an easy to maintain solution and to safely go away from borderline solution like WinPE driver or embedded AD powershell module.
If you need more details you can read this quick start guide by Micah Rairdon, and more than that, follow him and read his publication. This guys have serious knowledge about PowerShell web services and have written numerous one including Polaris web server (a fully functional web server in PowerShell).
For the network part, the web service should be placed on the same subnet as your deployed computers and is not intended to run on the internet. Your corporate private network is the target.
when all is ready, you can check that a service called OSD-WebService is running:
![image image]()
… and that there is a firewall rule for it alive and kicking:
Finaly you can check that there is some activity by reading the log file at %ProgramData%\MDT-Manager\\<Your Account>\Logs\WebService-Status.log :
![2019-02-13_07h13_23 2019-02-13_07h13_23]()
Worth noting in the log: the web service is registered under a few different names that you can all call depending of your needs:
![]()
If you are testing from the server where the webservice is installed, you can use http://Localhost:8550. Of course, the service can be called using FQDN but also with DNS suffixes if they exist.
The full solution (including the installer) is stored in %ProgramData%\MDT-Manager and can be exported to be reinstalled anywhere else.
There is also an uninstall script called WebService-UnInstaller.ps1 that you can call if you need to remove the solution.
Ok, now that the web service is running fine, let’s see what is possible to do with it.
Get and Post support
Get and post are the two methods used to send request to the web service. I won’t dive into details as I don’t know much about them, but here is what you need to know:
Multiple output support
When commands are processed, a result is replied to the sender. That result can be delivered as plain text, CSV, JSON, XML for MDT or XML Standard. The choice is up to you, simply add &format=JSON at the end of your URL request to switch from XML for MDT default output.
Automatic validation
If you specify a computer name, an OU, a group or a collection, items will be checked before doing anything. If something is missing the web service will return details on the missing element in the reply. Also computer name length is checked and rejected if longer than 15 characters.
![]()
The formated answer looks like this:
![]()
Note: the web service is not yet able to check if the request has enough right to stage computer in AD, so to keep the solution a bit more secure, you should only grant computer creation rights to a dedicated OU.
This PowerShell example will create a computer object called DVD-003-FR in an OU called Workstations:
Invoke-WebRequest –uri “http://192.168.10.205:8550/OSDInfo?command=AddNewPC&ComputerName=DVD-003-FR&OU=Workstations”
Here is what is returned if the computer creation was successful:
![]()
Generated names can include prefix and/or suffix, and the number of digits to include in the sequential number can also be defined.
Before creating the machine, the generated name will be checked against AD, if a name with the same rules is detected with a lower or equal sequential number, the number will be raised by one to follow his peer and make it unique.
Here is an example with a 4-digit number, a “DIAGG” prefix and a dedicated destination OU. Generated names will have that kind of shape: DIAGG0001, DIAGG0002 etc...
Invoke-WebRequest –uri “http://192.168.10.205:8550/OSDInfo?command=AddGeneratedPC&prefix=DIAGG&Digits=4&OU=Workstations”
Here is another example with a 5-digit number, and a “-SALES” suffix. Machine names will be shaped like this: 00001-SALES, 00002-SALES etc...
Invoke-WebRequest –uri “http://192.168.10.205:8550/OSDInfo?command=AddGeneratedPC&suffix=-SALES&Digits=5”
And here is a third example with a 3-digit number, an “MSFT-” prefix and a “W10” suffix. Generated names will look like: MSFT-001W10, MSFT-002W10 etc...
Invoke-WebRequest –uri “http://192.168.10.205:8550/OSDInfo?command=AddGeneratedPC&prefix=MSFT-&suffix=W10&Digits=3”
When machines are created successfully, the web service should return this answer:
![]()
This PowerShell example will move machine object Diagg00001 to the OU called Workstation:
Invoke-WebRequest –uri “http://192.168.10.205:8550/OSDInfo?command=AddPC2OU&ComputerName=Diagg00001&OU=Workstations”
Once done, the web service will reply with the following info:
![]()
This PowerShell example will add machine object Diagg00001 to the group called Osdc-VIP:
Invoke-WebRequest –uri “http://192.168.10.205:8550/OSDInfo?command=AddPC2Group&ComputerName=Diagg00001&Group=OSDC-VIP”
The reply will throw the following info:
![]()
This PowerShell example will add device W7-X64-ENT to the collection WEBService-Lab Computers:
Invoke-WebRequest –uri “http://192.168.10.205:8550/OSDInfo?command=AddPC2Collection&ComputerName=W7-X64-ENT&Collection=WEBService-Lab Computers”
When SCCM has finished, the following answer will be returned:
![]()
This PowerShell example will query local server time:
Invoke-WebRequest –uri “http://192.168.10.205:8550/OSDInfo?command=GetTime”
The current time is returned like this:
![]()
If you have no idea where a web service fit in the ‘deployment space’, imagine that you need to move computers to a different OU or an SCCM collection during a deployment. The web service will allow you to request your AD/SCCM server to move the machines without requiring manual intervention or remote execution with privileged account. Your deploying machine will politely ask the web service to make the changes using a web request (an URL), and the web service (literally a web server like IIS or Apache !!!) will locally do the job on the server for you. Once done it will reply to your request with some returning data. Sound cool? I’ve just scratched the surface…
So yes it’s possible to build a full web service with just PowerShell and it’s a very good news for all of us that don’t understand PHP, Apache, ASP.Net, C#, IIS or even none of them (my case!) but also for our customers that were always reluctant to deploy a web service because (same song…) : “no one know C# (or any other from the above list) in the team, how are we supposed to maintain or update the tool…” (Very valid statement if you ask me !).
Using a PowerShell web service is as complicated as running a PowerShell script. I tried to pull out from the project every possible blocker to bring to life an easy to maintain solution and to safely go away from borderline solution like WinPE driver or embedded AD powershell module.
How this beauty works (big picture style)?
.Net Framework has an interesting component called HTTP Listener. When configured, it can catch web requests and reply to them. The basic process starts when a request arrives, .Net will catch it and then send it to the PowerShell script that will analyses it, process some stuffs locally (we will go back to that later) and then build the reply. The reply is then sent back to the listener who return the answer to the sender.If you need more details you can read this quick start guide by Micah Rairdon, and more than that, follow him and read his publication. This guys have serious knowledge about PowerShell web services and have written numerous one including Polaris web server (a fully functional web server in PowerShell).
Deployment consideration
As I just told briefly, a key feature of a web service is the ability to process things locally with elevated privileges (or just the rights you need if you want to reduce even further the attack surface). This clearly means that if the machine where the web service is running can send PowerShell commands to an Active Directory, a WSUS server, a Config Manager, an Exchange server, whatever…, you can do anything to those tools with just a web request!
But before rushing to the installation script, pause for a minute or two to think about the best place where the web service should be installed!? Small tip: For the AD/Server stuffs, installing RSAT will do the trick so no needs to deploy on the primary domain controller. The same idea can also be applied to Config Manager: No need to install on primary, a workstation with the admin console can do the job.For the network part, the web service should be placed on the same subnet as your deployed computers and is not intended to run on the internet. Your corporate private network is the target.
How to install
Download scripts from my GitHub repo and launch WebService-Installer.ps1 with admin rights. The script takes care of a few things:
- It will install the web service in the %ProgramData%\MDT-Manager\Tools folder.
- it will download (Internet required !) and install NSSM, a powerful tool that can run any application as a service. This way, there will be no need to worry about server crash or reboot, our web service will run whatever happens.
- it will try to install AD RSAT PowerShell module.
- It will register a bunch of hostnames for ease of use.
- It will install and run the web service on port 8550 with basic AD and SCCM functionalities. (change $Port variable in WebService-Installer.ps1 if you need something else).
- It will create a firewall rule to allow incoming traffic from port 8550.
- It will log activity and responses in the file %ProgramData%\MDT-Manager\\<YourUser Account>\Logs\WebService-Status.log
when all is ready, you can check that a service called OSD-WebService is running:
… and that there is a firewall rule for it alive and kicking:
Finaly you can check that there is some activity by reading the log file at %ProgramData%\MDT-Manager\\<Your Account>\Logs\WebService-Status.log :
Worth noting in the log: the web service is registered under a few different names that you can all call depending of your needs:

If you are testing from the server where the webservice is installed, you can use http://Localhost:8550. Of course, the service can be called using FQDN but also with DNS suffixes if they exist.
The full solution (including the installer) is stored in %ProgramData%\MDT-Manager and can be exported to be reinstalled anywhere else.
There is also an uninstall script called WebService-UnInstaller.ps1 that you can call if you need to remove the solution.
Ok, now that the web service is running fine, let’s see what is possible to do with it.
Features
Before starting, I want to point that this is not exactly your “fully functional” web service. You’d better view it as the backbone of your own web service (remember, you are a PowerShell Hero !!), therefore, I only included basic features and functions for now. Upcoming releases, imagination (yours!!) and requirements (yours!!) will do the rest!
Get and Post support
Get and post are the two methods used to send request to the web service. I won’t dive into details as I don’t know much about them, but here is what you need to know:
- Get method are embedded in the URL, they looks like http://WebserviceURL.com?Mycommand=DoStuff&Param1=This&Param2=That. and can be executed directly in your browser.
- Post method are packed in the header of the HTTP request, so they do not appear in the URL http://WebserviceURL.com. You usually need a tool or a scripting language to generate them.
Multiple output support
When commands are processed, a result is replied to the sender. That result can be delivered as plain text, CSV, JSON, XML for MDT or XML Standard. The choice is up to you, simply add &format=JSON at the end of your URL request to switch from XML for MDT default output.
Automatic validation
If you specify a computer name, an OU, a group or a collection, items will be checked before doing anything. If something is missing the web service will return details on the missing element in the reply. Also computer name length is checked and rejected if longer than 15 characters.
Functions
Out of the box, the web service is able to do a few things that can be called by adding a ?Command=MyRandomCommand to the web service URL. Most interesting command are listed below:GETPCINFO
This function will query machine information against Active Directory based on computer name. Using PowerShell you can ask about any AD joined machine like this:Invoke-WebRequest –Uri “http://MyWebServer:8550/OSDInfo?command=GetPCInfo&ComputerName=DVD-002-FR”
The web service will return the following information that you can easily use in your script by retrieving the Content property of the response’s object (in the example below, $Truc.Content):
The formated answer looks like this:

ADDNEWPC
This function will create a computer object in the Active Directory if it does not already exist. A destination OU can be specified, if omitted, the computer will end up in the default AD computers container. Note: the web service is not yet able to check if the request has enough right to stage computer in AD, so to keep the solution a bit more secure, you should only grant computer creation rights to a dedicated OU.
This PowerShell example will create a computer object called DVD-003-FR in an OU called Workstations:
Invoke-WebRequest –uri “http://192.168.10.205:8550/OSDInfo?command=AddNewPC&ComputerName=DVD-003-FR&OU=Workstations”
Here is what is returned if the computer creation was successful:

ADDGENERATEDPC
This function act as the old RIS naming function and allow to generate computer names that include sequential numbers Generated names can include prefix and/or suffix, and the number of digits to include in the sequential number can also be defined.
Before creating the machine, the generated name will be checked against AD, if a name with the same rules is detected with a lower or equal sequential number, the number will be raised by one to follow his peer and make it unique.
Here is an example with a 4-digit number, a “DIAGG” prefix and a dedicated destination OU. Generated names will have that kind of shape: DIAGG0001, DIAGG0002 etc...
Invoke-WebRequest –uri “http://192.168.10.205:8550/OSDInfo?command=AddGeneratedPC&prefix=DIAGG&Digits=4&OU=Workstations”
Here is another example with a 5-digit number, and a “-SALES” suffix. Machine names will be shaped like this: 00001-SALES, 00002-SALES etc...
Invoke-WebRequest –uri “http://192.168.10.205:8550/OSDInfo?command=AddGeneratedPC&suffix=-SALES&Digits=5”
And here is a third example with a 3-digit number, an “MSFT-” prefix and a “W10” suffix. Generated names will look like: MSFT-001W10, MSFT-002W10 etc...
Invoke-WebRequest –uri “http://192.168.10.205:8550/OSDInfo?command=AddGeneratedPC&prefix=MSFT-&suffix=W10&Digits=3”
When machines are created successfully, the web service should return this answer:

ADDPC2OU
This function moves the specified machine to a selected Active Directory Organizational unit (OU).This PowerShell example will move machine object Diagg00001 to the OU called Workstation:
Invoke-WebRequest –uri “http://192.168.10.205:8550/OSDInfo?command=AddPC2OU&ComputerName=Diagg00001&OU=Workstations”
Once done, the web service will reply with the following info:

ADDPC2GROUP
This function adds the specified machine to a selected Active Directory Group.This PowerShell example will add machine object Diagg00001 to the group called Osdc-VIP:
Invoke-WebRequest –uri “http://192.168.10.205:8550/OSDInfo?command=AddPC2Group&ComputerName=Diagg00001&Group=OSDC-VIP”
The reply will throw the following info:

ADDPC2COLLECTION
This function adds the specified machine to a selected SCCM collection. Both machine and collection must exist in SCCM to proceed.This PowerShell example will add device W7-X64-ENT to the collection WEBService-Lab Computers:
Invoke-WebRequest –uri “http://192.168.10.205:8550/OSDInfo?command=AddPC2Collection&ComputerName=W7-X64-ENT&Collection=WEBService-Lab Computers”
When SCCM has finished, the following answer will be returned:

GETTIME
This function retrieves current time from the web service. this way you can easily evaluate how long deployments are lasting without caring about WinPE time vs Windows time vs foreign language time.This PowerShell example will query local server time:
Invoke-WebRequest –uri “http://192.168.10.205:8550/OSDInfo?command=GetTime”
The current time is returned like this:
