diff --git a/WindowsAgent/Tools/NuGet.exe b/WindowsAgent/Tools/NuGet.exe
new file mode 100644
index 0000000..4645f4b
Binary files /dev/null and b/WindowsAgent/Tools/NuGet.exe differ
diff --git a/WindowsAgent/WindowsAgent.sln b/WindowsAgent/WindowsAgent.sln
new file mode 100644
index 0000000..71a494b
--- /dev/null
+++ b/WindowsAgent/WindowsAgent.sln
@@ -0,0 +1,20 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2012
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WindowsAgent", "WindowsAgent\WindowsAgent.csproj", "{F7E2A8D5-6D24-4651-A4BC-1024D59F4903}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{F7E2A8D5-6D24-4651-A4BC-1024D59F4903}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{F7E2A8D5-6D24-4651-A4BC-1024D59F4903}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{F7E2A8D5-6D24-4651-A4BC-1024D59F4903}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{F7E2A8D5-6D24-4651-A4BC-1024D59F4903}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+EndGlobal
diff --git a/WindowsAgent/WindowsAgent/App.config b/WindowsAgent/WindowsAgent/App.config
new file mode 100644
index 0000000..2c1d906
--- /dev/null
+++ b/WindowsAgent/WindowsAgent/App.config
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<configuration>
+	<configSections>
+		<section name="nlog" type="NLog.Config.ConfigSectionHandler, NLog"/>
+	</configSections>
+	<startup> 
+        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
+    </startup>
+	<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
+		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+		<targets>
+			<target name="file" xsi:type="File" fileName="${basedir}/log.txt"
+					layout="${date} ${level}: &lt;${logger:shortName=true}&gt; ${message} ${exception:format=tostring}"/>
+					
+		</targets>
+
+		<rules>
+			<logger name="*" minlevel="Debug" writeTo="file" />
+		</rules>
+	</nlog>
+</configuration>
\ No newline at end of file
diff --git a/WindowsAgent/WindowsAgent/ExecutionPlan.cs b/WindowsAgent/WindowsAgent/ExecutionPlan.cs
new file mode 100644
index 0000000..9c0be86
--- /dev/null
+++ b/WindowsAgent/WindowsAgent/ExecutionPlan.cs
@@ -0,0 +1,20 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Mirantis.Keero.WindowsAgent
+{
+	class ExecutionPlan
+	{
+		public class Command
+		{
+			public string Name { get; set; } 
+			public Dictionary<string, object> Arguments { get; set; }
+		}
+
+		public string[] Scripts { get; set; }
+		public LinkedList<Command> Commands { get; set; }
+	}
+}
diff --git a/WindowsAgent/WindowsAgent/MqMessage.cs b/WindowsAgent/WindowsAgent/MqMessage.cs
new file mode 100644
index 0000000..d77ab79
--- /dev/null
+++ b/WindowsAgent/WindowsAgent/MqMessage.cs
@@ -0,0 +1,25 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Mirantis.Keero.WindowsAgent
+{
+	class MqMessage
+	{
+		private readonly Action ackFunc;
+
+		public MqMessage(Action ackFunc)
+		{
+			this.ackFunc = ackFunc;
+		}
+
+		public string Body { get; set; }
+
+		public void Ack()
+		{
+			ackFunc();
+		}
+	}
+}
diff --git a/WindowsAgent/WindowsAgent/PlanExecutor.cs b/WindowsAgent/WindowsAgent/PlanExecutor.cs
new file mode 100644
index 0000000..7baab0b
--- /dev/null
+++ b/WindowsAgent/WindowsAgent/PlanExecutor.cs
@@ -0,0 +1,139 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Management.Automation;
+using System.Management.Automation.Runspaces;
+using System.Text;
+using Newtonsoft.Json;
+
+namespace Mirantis.Keero.WindowsAgent
+{
+	class PlanExecutor
+	{
+		class ExecutionResult
+		{
+			public bool IsException { get; set; }
+			public object Result { get; set; }
+		}
+
+		private readonly string path;
+
+		public PlanExecutor(string path)
+		{
+			this.path = path;
+		}
+
+		public string Execute()
+		{
+			try
+			{
+				var plan = JsonConvert.DeserializeObject<ExecutionPlan>(File.ReadAllText(this.path));
+				var resultPath = this.path + ".result";
+				List<object> currentResults = null;
+				try
+				{
+					currentResults = JsonConvert.DeserializeObject<List<object>>(File.ReadAllText(resultPath));
+				}
+				catch
+				{
+					currentResults = new List<object>();
+				}
+
+
+				var runSpace = RunspaceFactory.CreateRunspace();
+				runSpace.Open();
+
+				var runSpaceInvoker = new RunspaceInvoke(runSpace);
+				runSpaceInvoker.Invoke("Set-ExecutionPolicy Unrestricted");
+				if (plan.Scripts != null)
+				{
+					foreach (var script in plan.Scripts)
+					{
+						runSpaceInvoker.Invoke(Encoding.UTF8.GetString(Convert.FromBase64String(script)));
+					}
+				}
+
+				while (plan.Commands != null && plan.Commands.Any())
+				{
+					var command = plan.Commands.First();
+
+					var pipeline = runSpace.CreatePipeline();
+					var psCommand = new Command(command.Name);
+					if (command.Arguments != null)
+					{
+						foreach (var kvp in command.Arguments)
+						{
+							psCommand.Parameters.Add(kvp.Key, kvp.Value);
+						}
+					}
+					pipeline.Commands.Add(psCommand);
+					try
+					{
+						var result = pipeline.Invoke();
+						if (result != null)
+						{
+							currentResults.Add(new ExecutionResult {
+								IsException = false,
+								Result = result.Select(SerializePsObject).Where(obj => obj != null).ToList()
+							});
+						}
+					}
+					catch (Exception exception)
+					{
+						currentResults.Add(new ExecutionResult {
+							IsException = true,
+							Result = new[] {
+								exception.GetType().FullName, exception.Message
+							}
+						});
+					}
+					finally
+					{
+						plan.Commands.RemoveFirst();
+						File.WriteAllText(path, JsonConvert.SerializeObject(plan));
+						File.WriteAllText(resultPath, JsonConvert.SerializeObject(currentResults));
+					}
+				}
+				runSpace.Close();
+				var executionResult = JsonConvert.SerializeObject(new ExecutionResult {
+					IsException = false,
+					Result = currentResults
+				}, Formatting.Indented);
+				File.Delete(resultPath);
+				return executionResult;
+			}
+			catch (Exception ex)
+			{
+				return JsonConvert.SerializeObject(new ExecutionResult {
+					IsException = true,
+					Result = ex.Message
+				}, Formatting.Indented);
+			}
+		}
+	
+		private static object SerializePsObject(PSObject obj)
+		{
+			if (obj.BaseObject is PSCustomObject)
+			{
+				var result = new Dictionary<string, object>();
+				foreach (var property in obj.Properties.Where(p => p.IsGettable))
+				{
+					try
+					{
+						result[property.Name] = property.Value.ToString();
+					}
+					catch
+					{
+					}
+				}
+				return result;
+			}
+			else
+			{
+				return obj.BaseObject;
+			}
+		}
+	}
+
+}
diff --git a/WindowsAgent/WindowsAgent/Program.cs b/WindowsAgent/WindowsAgent/Program.cs
new file mode 100644
index 0000000..8bb4942
--- /dev/null
+++ b/WindowsAgent/WindowsAgent/Program.cs
@@ -0,0 +1,78 @@
+using System;
+using System.ComponentModel;
+using System.IO;
+using System.Threading;
+using NLog;
+
+namespace Mirantis.Keero.WindowsAgent
+{
+	[DisplayName("Keero Agent")]
+	sealed public class Program : WindowsService
+	{
+		private static readonly Logger Log = LogManager.GetCurrentClassLogger();
+		private volatile bool stop;
+		private Thread thread;
+		private RabbitMqClient rabbitMqClient;
+
+		static void Main(string[] args)
+		{
+			Start(new Program(), args);
+		}
+
+		protected override void OnStart(string[] args)
+		{
+			base.OnStart(args);
+			this.rabbitMqClient = new RabbitMqClient();
+			this.thread = new Thread(Loop);
+			this.thread.Start();
+		}
+
+		void Loop()
+		{
+			const string filePath = "data.json";
+			while (!stop)
+			{
+				try
+				{
+					if (!File.Exists(filePath))
+					{
+						var message = rabbitMqClient.GetMessage();
+						File.WriteAllText(filePath, message.Body);
+						message.Ack();
+					}
+					var result = new PlanExecutor(filePath).Execute();
+					if(stop) break;
+					rabbitMqClient.SendResult(result);
+					File.Delete(filePath);
+				}
+				catch (Exception exception)
+				{
+					WaitOnException(exception);
+				}
+				
+			}
+
+		}
+
+		private void WaitOnException(Exception exception)
+		{
+			if (stop) return;
+			Log.WarnException("Exception in main loop", exception);
+			var i = 0;
+			while (!stop && i < 10)
+			{
+				Thread.Sleep(100);
+				i++;
+			}
+		}
+
+		protected override void OnStop()
+		{
+			stop = true;
+			this.rabbitMqClient.Dispose();
+			Console.WriteLine("Stop");
+			base.OnStop();
+		}
+
+	}
+}
diff --git a/WindowsAgent/WindowsAgent/Properties/AssemblyInfo.cs b/WindowsAgent/WindowsAgent/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..f7d169b
--- /dev/null
+++ b/WindowsAgent/WindowsAgent/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following 
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("WindowsAgent")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("WindowsAgent")]
+[assembly: AssemblyCopyright("Copyright ©  2013")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible 
+// to COM components.  If you need to access a type in this assembly from 
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("9591bf2c-f38b-47e0-a39d-ea9849356371")]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version 
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers 
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/WindowsAgent/WindowsAgent/RabbitMqClient.cs b/WindowsAgent/WindowsAgent/RabbitMqClient.cs
new file mode 100644
index 0000000..18a5bc2
--- /dev/null
+++ b/WindowsAgent/WindowsAgent/RabbitMqClient.cs
@@ -0,0 +1,124 @@
+using System;
+using System.Collections.Generic;
+using System.Configuration;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using RabbitMQ.Client;
+
+namespace Mirantis.Keero.WindowsAgent
+{
+	class RabbitMqClient : IDisposable
+	{
+		private static readonly ConnectionFactory connectionFactory;
+		private IConnection currentConnecton;
+
+		static RabbitMqClient()
+		{
+			connectionFactory = new ConnectionFactory {
+                HostName = ConfigurationManager.AppSettings["rabbitmq.host"] ?? "localhost",
+                UserName = ConfigurationManager.AppSettings["rabbitmq.user"] ?? "guest",
+                Password = ConfigurationManager.AppSettings["rabbitmq.password"] ??"guest",
+                Protocol = Protocols.FromEnvironment(),
+                VirtualHost = ConfigurationManager.AppSettings["rabbitmq.vhost"] ?? "/",
+                RequestedHeartbeat = 10
+            };
+		}
+		
+		public RabbitMqClient()
+		{
+			
+		}
+
+		public MqMessage GetMessage()
+		{
+			var queueName = ConfigurationManager.AppSettings["rabbitmq.inputQueue"] ?? Environment.MachineName.ToLower();
+			try
+			{
+				IConnection connection = null;
+				lock (this)
+				{
+					connection = this.currentConnecton = this.currentConnecton ?? connectionFactory.CreateConnection();
+				}
+				var session = connection.CreateModel();
+				session.BasicQos(0, 1, false);
+				session.QueueDeclare(queueName, true, false, false, null);
+				var consumer = new QueueingBasicConsumer(session);
+				var consumeTag = session.BasicConsume(queueName, false, consumer);
+				Console.WriteLine("Deq");
+				var e = (RabbitMQ.Client.Events.BasicDeliverEventArgs)consumer.Queue.Dequeue();
+				Console.WriteLine("Message received");
+				Action ackFunc = delegate {
+					session.BasicAck(e.DeliveryTag, false);
+					session.BasicCancel(consumeTag);
+					session.Close();
+				};
+				
+				return new MqMessage(ackFunc) {
+					Body = Encoding.UTF8.GetString(e.Body)
+				};
+			}
+			catch (Exception)
+			{
+
+				Dispose();
+				throw;
+			}
+		}
+
+		public void SendResult(string text)
+		{
+			var exchangeName = ConfigurationManager.AppSettings["rabbitmq.resultExchange"] ?? "";
+			var resultQueue = ConfigurationManager.AppSettings["rabbitmq.resultQueue"] ?? "-execution-results";
+
+			try
+			{
+				IConnection connection = null;
+				lock (this)
+				{
+					connection = this.currentConnecton = this.currentConnecton ?? connectionFactory.CreateConnection();
+				}
+				var session = connection.CreateModel();
+				if (!string.IsNullOrEmpty(resultQueue))
+				{
+					session.QueueDeclare(resultQueue, true, false, false, null);
+					if (!string.IsNullOrEmpty(exchangeName))
+					{
+						session.ExchangeBind(exchangeName, resultQueue, resultQueue);
+					}
+				}
+				var basicProperties = session.CreateBasicProperties();
+				basicProperties.SetPersistent(true);
+				basicProperties.ContentType = "application/json";
+				session.BasicPublish(exchangeName, resultQueue, basicProperties, Encoding.UTF8.GetBytes(text));
+				session.Close();
+			}
+			catch (Exception)
+			{
+				Dispose();
+				throw;
+			}
+		}
+
+		public void Dispose()
+		{
+			lock (this)
+			{
+				try
+				{
+					if (this.currentConnecton != null)
+					{
+						this.currentConnecton.Close();
+					}
+				}
+				catch
+				{
+				}
+				finally
+				{
+					this.currentConnecton = null;
+				}
+			}
+		}
+	}
+}
diff --git a/WindowsAgent/WindowsAgent/SampleExecutionPlan.json b/WindowsAgent/WindowsAgent/SampleExecutionPlan.json
new file mode 100644
index 0000000..333ec85
--- /dev/null
+++ b/WindowsAgent/WindowsAgent/SampleExecutionPlan.json
@@ -0,0 +1,36 @@
+{
+	"Scripts":
+	[
+		"ZnVuY3Rpb24gdDMgeyAxMjsgcmV0dXJuICJ0ZXN0IiB9",
+		"ZnVuY3Rpb24gTmV3LVBlcnNvbigpDQp7DQogIHBhcmFtICgkRmlyc3ROYW1lLCAkTGFzdE5hbWUsICRQaG9uZSkNCg0KICAkcGVyc29uID0gbmV3LW9iamVjdCBQU09iamVjdA0KDQogICRwZXJzb24gfCBhZGQtbWVtYmVyIC10eXBlIE5vdGVQcm9wZXJ0eSAtTmFtZSBGaXJzdCAtVmFsdWUgJEZpcnN0TmFtZQ0KICAkcGVyc29uIHwgYWRkLW1lbWJlciAtdHlwZSBOb3RlUHJvcGVydHkgLU5hbWUgTGFzdCAtVmFsdWUgJExhc3ROYW1lDQogICRwZXJzb24gfCBhZGQtbWVtYmVyIC10eXBlIE5vdGVQcm9wZXJ0eSAtTmFtZSBQaG9uZSAtVmFsdWUgJFBob25lDQoNCiAgcmV0dXJuICRwZXJzb24NCn0=",
+		"ZnVuY3Rpb24gVGVzdFRocm93KCkNCnsNCglUaHJvdyBbc3lzdGVtLkluZGV4T3V0T2ZSYW5nZUV4Y2VwdGlvbl0gDQp9"
+	],
+	"Commands" :  
+	[
+		{
+			"Name": "New-Person",
+			"Arguments" : 
+			{
+				"FirstName": "MyFirstName",
+				"LastName": "MyLastName",
+				"Phone": "123-456"
+			}
+
+		},
+		{
+			"Name": "t3",
+			"Arguments" : 
+			{
+			}
+
+		},
+		{
+			"Name": "Get-Date",
+
+		},
+		{
+			"Name": "TestThrow",
+
+		}
+	]
+}
\ No newline at end of file
diff --git a/WindowsAgent/WindowsAgent/ServiceManager.cs b/WindowsAgent/WindowsAgent/ServiceManager.cs
new file mode 100644
index 0000000..2bcf227
--- /dev/null
+++ b/WindowsAgent/WindowsAgent/ServiceManager.cs
@@ -0,0 +1,111 @@
+using System;
+using System.Configuration.Install;
+using System.Reflection;
+using System.ServiceProcess;
+using NLog;
+
+namespace Mirantis.Keero.WindowsAgent
+{
+    public class ServiceManager
+    {
+        private readonly string serviceName;
+
+        public ServiceManager(string serviceName)
+        {
+            this.serviceName = serviceName;
+        }
+
+        private static readonly Logger Log = LogManager.GetCurrentClassLogger();
+
+        public bool Restart(string[] args, TimeSpan timeout)
+        {
+            var service = new ServiceController(serviceName);
+            try
+            {
+                var millisec1 = TimeSpan.FromMilliseconds(Environment.TickCount);
+
+                service.Stop();
+                service.WaitForStatus(ServiceControllerStatus.Stopped, timeout);
+                Log.Info("Service is stopped");
+
+                // count the rest of the timeout
+                var millisec2 = TimeSpan.FromMilliseconds(Environment.TickCount);
+                timeout = timeout - (millisec2 - millisec1);
+
+                service.Start(args);
+                service.WaitForStatus(ServiceControllerStatus.Running, timeout);
+                Log.Info("Service has started");
+                return true;
+            }
+            catch (Exception ex)
+            {
+                Log.ErrorException("Cannot restart service " + serviceName, ex);
+                return false;
+            }
+        }
+
+        public bool Stop(TimeSpan timeout)
+        {
+            var service = new ServiceController(serviceName);
+            try
+            {
+                service.Stop();
+                service.WaitForStatus(ServiceControllerStatus.Stopped, timeout);
+                return true;
+            }
+            catch (Exception ex)
+            {
+                Log.ErrorException("Cannot stop service " + serviceName, ex);
+                return false;
+            }
+        }
+
+        public bool Start(string[] args, TimeSpan timeout)
+        {
+            var service = new ServiceController(serviceName);
+            try
+            {
+                service.Start(args);
+                service.WaitForStatus(ServiceControllerStatus.Running, timeout);
+                return true;
+            }
+            catch (Exception ex)
+            {
+                Log.ErrorException("Cannot start service " + serviceName, ex);
+                return false;
+            }
+        }
+
+        public bool Install()
+        {
+            try
+            {
+                ManagedInstallerClass.InstallHelper(
+                    new string[] { Assembly.GetEntryAssembly().Location });
+            }
+            catch(Exception ex)
+            {
+                Log.ErrorException("Cannot install service " + serviceName, ex);
+                return false;
+            }
+            return true;
+        }
+
+        public bool Uninstall()
+        {
+            try
+            {
+                ManagedInstallerClass.InstallHelper(
+                    new string[] { "/u", Assembly.GetEntryAssembly().Location });
+            }
+            catch (Exception ex)
+            {
+                Log.ErrorException("Cannot uninstall service " + serviceName, ex);
+                return false;
+            }
+            return true;
+        }
+
+    }
+    
+}
diff --git a/WindowsAgent/WindowsAgent/WindowsAgent.csproj b/WindowsAgent/WindowsAgent/WindowsAgent.csproj
new file mode 100644
index 0000000..60247a2
--- /dev/null
+++ b/WindowsAgent/WindowsAgent/WindowsAgent.csproj
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{F7E2A8D5-6D24-4651-A4BC-1024D59F4903}</ProjectGuid>
+    <OutputType>Exe</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>Mirantis.Keero.WindowsAgent</RootNamespace>
+    <AssemblyName>WindowsAgent</AssemblyName>
+    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <PlatformTarget>AnyCPU</PlatformTarget>
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <PlatformTarget>AnyCPU</PlatformTarget>
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="Newtonsoft.Json">
+      <HintPath>..\packages\Newtonsoft.Json.4.5.11\lib\net40\Newtonsoft.Json.dll</HintPath>
+    </Reference>
+    <Reference Include="NLog">
+      <HintPath>..\packages\NLog.2.0.0.2000\lib\net40\NLog.dll</HintPath>
+    </Reference>
+    <Reference Include="RabbitMQ.Client">
+      <HintPath>..\packages\RabbitMQ.Client.3.0.2\lib\net30\RabbitMQ.Client.dll</HintPath>
+    </Reference>
+    <Reference Include="System" />
+    <Reference Include="System.Configuration" />
+    <Reference Include="System.Configuration.Install" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Management.Automation, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>C:\Program Files (x86)\Reference Assemblies\Microsoft\WindowsPowerShell\3.0\System.Management.Automation.dll</HintPath>
+    </Reference>
+    <Reference Include="System.ServiceProcess" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="Microsoft.CSharp" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="ExecutionPlan.cs" />
+    <Compile Include="MqMessage.cs" />
+    <Compile Include="PlanExecutor.cs" />
+    <Compile Include="Program.cs">
+      <SubType>Component</SubType>
+    </Compile>
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="RabbitMqClient.cs" />
+    <Compile Include="ServiceManager.cs" />
+    <Compile Include="WindowsService.cs">
+      <SubType>Component</SubType>
+    </Compile>
+    <Compile Include="WindowsServiceInstaller.cs">
+      <SubType>Component</SubType>
+    </Compile>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="App.config" />
+    <None Include="packages.config" />
+    <None Include="SampleExecutionPlan.json" />
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <PropertyGroup>
+    <PreBuildEvent>$(SolutionDir)Tools\nuget install $(ProjectDir)packages.config -o $(SolutionDir)Packages</PreBuildEvent>
+  </PropertyGroup>
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>
\ No newline at end of file
diff --git a/WindowsAgent/WindowsAgent/WindowsService.cs b/WindowsAgent/WindowsAgent/WindowsService.cs
new file mode 100644
index 0000000..1ad2d0d
--- /dev/null
+++ b/WindowsAgent/WindowsAgent/WindowsService.cs
@@ -0,0 +1,95 @@
+using System;
+using System.ComponentModel;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using System.ServiceProcess;
+using NLog;
+
+namespace Mirantis.Keero.WindowsAgent
+{
+    public abstract class WindowsService : ServiceBase
+    {
+        private static readonly Logger Log = LogManager.GetCurrentClassLogger();
+        public bool RunningAsService { get; private set; }
+
+	    protected static void Start(WindowsService service, string[] arguments)
+        {
+            Directory.SetCurrentDirectory(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location));
+
+			if (arguments.Contains("/install", StringComparer.OrdinalIgnoreCase))
+            {
+                new ServiceManager(service.ServiceName).Install();
+            }
+			else if (arguments.Contains("/uninstall", StringComparer.OrdinalIgnoreCase))
+			{
+                new ServiceManager(service.ServiceName).Uninstall();
+            }
+			else if (arguments.Contains("/start", StringComparer.OrdinalIgnoreCase))
+			{
+                new ServiceManager(service.ServiceName).Start(Environment.GetCommandLineArgs(), TimeSpan.FromMinutes(1));
+            }
+			else if (arguments.Contains("/stop", StringComparer.OrdinalIgnoreCase))
+			{
+                new ServiceManager(service.ServiceName).Stop(TimeSpan.FromMinutes(1));
+            }
+			else if (arguments.Contains("/restart", StringComparer.OrdinalIgnoreCase))
+			{
+                new ServiceManager(service.ServiceName).Restart(Environment.GetCommandLineArgs(), TimeSpan.FromMinutes(1));
+            }
+			else if (!arguments.Contains("/console", StringComparer.OrdinalIgnoreCase))
+			{
+				service.RunningAsService = true;
+				Run(service);
+			}
+			else
+			{
+				try
+				{
+					service.RunningAsService = false;
+					Console.Title = service.ServiceName;
+					service.OnStart(Environment.GetCommandLineArgs());
+					service.WaitForExitSignal();
+				}
+				finally
+				{
+					service.OnStop();
+					service.Dispose();
+				}
+			}
+        }
+        
+        protected WindowsService()
+        {
+            var displayNameAttribute =
+                this.GetType().GetCustomAttributes(typeof (DisplayNameAttribute), false).Cast<DisplayNameAttribute>().
+                    FirstOrDefault();
+            if(displayNameAttribute != null)
+            {
+                ServiceName = displayNameAttribute.DisplayName;
+            }
+        }
+
+
+        protected virtual void WaitForExitSignal()
+        {
+            Console.WriteLine("Press ESC to exit");
+            while (Console.ReadKey(true).Key != ConsoleKey.Escape)
+            {
+            }
+        }
+
+		protected override void OnStart(string[] args)
+		{
+			Log.Info("Service {0} started", ServiceName);
+
+			base.OnStart(args);
+		}
+
+		protected override void OnStop()
+		{
+			Log.Info("Service {0} exited", ServiceName);
+			base.OnStop();
+		}
+    }
+}
diff --git a/WindowsAgent/WindowsAgent/WindowsServiceInstaller.cs b/WindowsAgent/WindowsAgent/WindowsServiceInstaller.cs
new file mode 100644
index 0000000..ca6e4c2
--- /dev/null
+++ b/WindowsAgent/WindowsAgent/WindowsServiceInstaller.cs
@@ -0,0 +1,39 @@
+using System.ComponentModel;
+using System.Configuration.Install;
+using System.Linq;
+using System.Reflection;
+using System.ServiceProcess;
+
+namespace Mirantis.Keero.WindowsAgent
+{
+	[RunInstaller(true)]
+	public class WindowsServiceInstaller : Installer
+    {
+		public WindowsServiceInstaller()
+        {
+            var processInstaller = new ServiceProcessInstaller { Account = ServiceAccount.LocalSystem };
+            foreach (var type in Assembly.GetEntryAssembly().GetExportedTypes().Where(t => t.IsSubclassOf(typeof(ServiceBase))))
+            {
+                var nameAttribute = type.GetCustomAttributes(typeof (DisplayNameAttribute), false)
+                    .Cast<DisplayNameAttribute>().FirstOrDefault();
+                if(nameAttribute == null) continue;
+                var serviceInstaller = new ServiceInstaller {
+                    StartType = ServiceStartMode.Automatic,
+                    ServiceName = nameAttribute.DisplayName,
+                    DisplayName = nameAttribute.DisplayName
+                };
+                var descriptionAttribute = type.GetCustomAttributes(typeof(DescriptionAttribute), false)
+                    .Cast<DescriptionAttribute>().FirstOrDefault();
+                if(descriptionAttribute != null)
+                {
+                    serviceInstaller.Description = descriptionAttribute.Description;
+                }
+
+                Installers.Add(serviceInstaller);
+            }
+
+            Installers.Add(processInstaller);
+
+        }
+    }
+}
diff --git a/WindowsAgent/WindowsAgent/obj/Debug/TemporaryGeneratedFile_036C0B5B-1481-4323-8D20-8F5ADCB23D92.cs b/WindowsAgent/WindowsAgent/obj/Debug/TemporaryGeneratedFile_036C0B5B-1481-4323-8D20-8F5ADCB23D92.cs
new file mode 100644
index 0000000..e69de29
diff --git a/WindowsAgent/WindowsAgent/obj/Debug/TemporaryGeneratedFile_5937a670-0e60-4077-877b-f7221da3dda1.cs b/WindowsAgent/WindowsAgent/obj/Debug/TemporaryGeneratedFile_5937a670-0e60-4077-877b-f7221da3dda1.cs
new file mode 100644
index 0000000..e69de29
diff --git a/WindowsAgent/WindowsAgent/obj/Debug/TemporaryGeneratedFile_E7A71F73-0F8D-4B9B-B56E-8E70B10BC5D3.cs b/WindowsAgent/WindowsAgent/obj/Debug/TemporaryGeneratedFile_E7A71F73-0F8D-4B9B-B56E-8E70B10BC5D3.cs
new file mode 100644
index 0000000..e69de29
diff --git a/WindowsAgent/WindowsAgent/packages.config b/WindowsAgent/WindowsAgent/packages.config
new file mode 100644
index 0000000..7aabef8
--- /dev/null
+++ b/WindowsAgent/WindowsAgent/packages.config
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+  <package id="Newtonsoft.Json" version="4.5.11" targetFramework="net45" />
+  <package id="NLog" version="2.0.0.2000" targetFramework="net45" />
+  <package id="RabbitMQ.Client" version="3.0.2" targetFramework="net45" />
+</packages>
\ No newline at end of file
diff --git a/WindowsAgent/packages/repositories.config b/WindowsAgent/packages/repositories.config
new file mode 100644
index 0000000..7753eee
--- /dev/null
+++ b/WindowsAgent/packages/repositories.config
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<repositories>
+  <repository path="..\WindowsAgent\packages.config" />
+</repositories>
\ No newline at end of file