diff --git a/Deployment/WindowsPowerShell/Modules/CoreFunctions/Config.ps1 b/Deployment/WindowsPowerShell/Modules/CoreFunctions/Config.ps1
new file mode 100644
index 0000000..acf2f51
--- /dev/null
+++ b/Deployment/WindowsPowerShell/Modules/CoreFunctions/Config.ps1
@@ -0,0 +1,29 @@
+<#
+Naming convention:
+
+== Normal variables
+** Set: $NormalVar = 123
+** Get: Write-Host $NormalVar
+
+== Script-scope variables
+** Set: $script:__ScriptScopeVar = 123
+** Get: Write-Host $__ScriptScopeVar
+
+== Global-scope variables
+** Set: $global:__GlobalScopeVar__ = 123
+** Get: Write-Host $__GlobalScopeVar__
+#>
+
+$script:__ModulePath = $PsScriptRoot
+$script:__ModuleName = $PsScriptRoot.Split("\")[-1]
+$script:__DefaultLogPath = [IO.Path]::Combine([IO.Path]::GetTempPath(), "PowerShell_$__ModuleName.log")
+
+
+$script:__RequiredModules = @("ServerManager", "DnsClient")
+$script:__ImportModulesExplicitely = $true
+$script:__ImportModulesErrorAction = "Stop"
+
+
+$global:__StopExecutionThrowsExeption__ = $true
+$global:__StopExecutionExitsSession__ = $false
+
diff --git a/Deployment/WindowsPowerShell/Modules/CoreFunctions/CoreFunctions.psd1 b/Deployment/WindowsPowerShell/Modules/CoreFunctions/CoreFunctions.psd1
new file mode 100644
index 0000000..0d52bf7
Binary files /dev/null and b/Deployment/WindowsPowerShell/Modules/CoreFunctions/CoreFunctions.psd1 differ
diff --git a/Deployment/WindowsPowerShell/Modules/CoreFunctions/CoreFunctions.psm1 b/Deployment/WindowsPowerShell/Modules/CoreFunctions/CoreFunctions.psm1
new file mode 100644
index 0000000..dc9abfe
--- /dev/null
+++ b/Deployment/WindowsPowerShell/Modules/CoreFunctions/CoreFunctions.psm1
@@ -0,0 +1,34 @@
+# Import config first
+. "$PsScriptRoot\Config.ps1"
+
+# Import functions from 'Include' subfolder
+Get-ChildItem "$PsScriptRoot\Include" -Filter "*.ps1" |
+    ForEach-Object {
+        . "$($_.FullName)"
+    }
+
+trap { Stop-Execution $_ }
+
+Export-ModuleMember -Function * -Alias *
+
+if ($__ImportModulesExplicitely) {
+    foreach ($Module in $__RequiredModules) {
+        Write-Log "Importing module '$Module' ..."
+        Import-Module -Name "$Module" -ErrorAction "$__ImportModulesErrorAction"
+    }
+}
+
+Write-Log "Module loaded from '$PsScriptRoot'"
+
+#-------------------------------------------------------------------------------
+
+switch ($Args[0]) {
+    'installTo' {
+        Install-Module -InstallPath $args[1] -ModulePath $PsScriptRoot
+    }
+    'register' {
+        Register-Module "$PsScriptRoot"
+    }
+    default {
+    }
+}
diff --git a/Deployment/WindowsPowerShell/Modules/CoreFunctions/en-US/about_CoreFunctions.help.txt b/Deployment/WindowsPowerShell/Modules/CoreFunctions/en-US/about_CoreFunctions.help.txt
new file mode 100644
index 0000000..e69de29
diff --git a/Deployment/WindowsPowerShell/Modules/CoreFunctions/include/Functions.ps1 b/Deployment/WindowsPowerShell/Modules/CoreFunctions/include/Functions.ps1
new file mode 100644
index 0000000..3de8ff3
--- /dev/null
+++ b/Deployment/WindowsPowerShell/Modules/CoreFunctions/include/Functions.ps1
@@ -0,0 +1,747 @@
+Function Stop-Execution {
+<#
+.SYNOPSIS
+Breaks execution with specified error code.
+
+.DESCRIPTION
+Function break script execution with error code provided. Error code may be 0 in case of non-error stop.
+
+It also tries to parse ErrorRecord or Exception object (if provided) and logs this information.
+#>
+	param (
+		$InputObject = $null,
+		[String] $ExitString = "",
+		[Int] $ExitCode = 1,
+		[Switch] $Success
+	)
+	
+	Function Do-ExitFailure {
+		Write-LogFatal "STOP ($ExitCode): $ExitString"
+        if ($__StopExecutionThrowsExeption__) {
+            throw $InputObject
+        }
+        elseif ($__StopExecutionExitsSession__) {
+		    exit $ExitCode
+        }
+        else {
+            break
+        }
+	}
+	
+	Function Do-ExitSuccess {
+		Write-LogInfo "STOP (0): $ExitString"
+        if ($__StopExecutionThrowsExeption__) {
+            exit 0
+        }
+        elseif ($__StopExecutionExitsSession__) {
+    		exit 0
+        }
+        else {
+            break
+        }
+	}
+
+	if ($Success -eq $true) {
+		if ($ExitString -eq "") {
+			$ExitString = "Script stopped with NO ERROR."
+		}
+		Do-ExitSuccess
+	}
+
+	if ($ExitString -ne "") {
+		Do-ExitFailure
+	}
+
+
+	if ($InputObject -eq $null) {
+		$ExitString = "***** SCRIPT INTERRUPTED *****"
+		Do-ExitFailure
+	}
+
+
+	if ($ExitString -eq "") {
+		try {
+			$ErrorRecord = [System.Management.Automation.ErrorRecord] $InputObject
+			$ExitString = @"
+$($ErrorRecord.ToString())
+
+*** Invocation Info ***
+$($ErrorRecord.InvocationInfo.PositionMessage)
+
+*** CategoryInfo ***
+$($ErrorRecord.CategoryInfo.ToString())
+
+*** FullyQualifiedErrorId ***
+$($ErrorRecord.FullyQualifiedErrorId.ToString())
+
+*** ScriptStackTrace ***
+$($ErrorRecord.ScriptStackTrace.ToString())
+*** *** ***
+"@
+		}
+		catch {
+			$ErrorRecord = $null
+			Write-LogWarning "Unable to cast InputObject to [System.Management.Automation.ErrorRecord]"
+		}
+	}
+
+
+	if ($ExitString -eq "") {
+		try {
+			$Exception = [System.Exception] $InputObject
+			$ExitString = $Exception.ToString()
+		}
+		catch {
+			$Exception = $null
+			Write-LogWarning "Unable to cast InputObject to [System.Exception]"
+		}
+	}
+
+	
+	if ($ExitString -eq "") {
+		try {
+			$ExitString = [String] $InputObject
+		}
+		catch {
+			Write-LogWarning "Unable to cast InputObject of type [$($InputObject.GetType())] to any of supported types."
+		}
+	}
+    
+	Do-ExitFailure
+}
+
+
+Function Set-ComputerName {
+    param (
+        [String] $Name
+    )
+    
+    
+	# Rename the computer
+	if ($Name -ne "") {
+		if (Test-ComputerName -ComputerName $Name) {
+			Stop-Execution -Success -ExitString "Computer name already configured"
+		}
+		else {
+			Write-Log "Renaming computer to '$Name'"
+				
+			Rename-Computer -NewName $NewName -Force -ErrorAction Stop
+
+			Stop-Execution -ExitCode 3010 -ExitString "Please restart the computer now"
+		}
+	}
+}
+
+
+
+Function Test-ComputerName {
+<#
+.SYNOPSIS
+Test if computer name is set, and the computer belongs to specified domain / workgroup.
+
+.DESCRIPTION
+Function tests the following conditions:
+* the computer name is equal to the provided one
+* the computer is a part of domain
+* the computer belongs to the specified domain
+* the computer belongs to the specified workgroup
+
+Multiple checks are logically ANDed.
+#>
+    [CmdletBinding()]
+	param (
+		[String] $ComputerName,
+		[String] $DomainName,
+		[String] $WorkgroupName,
+		[Switch] $PartOfDomain
+	)
+	process {
+    	$ComputerSystem = Get-WmiObject Win32_ComputerSystem
+    	
+    	if (($ComputerName -ne "") -and ($ComputerSystem.Name -ne "$ComputerName")) {
+            Write-Error "ComputerName is not equal to '$ComputerName'"
+    		return $false
+    	}
+    	
+    	if (($DomainName -ne "") -and ($ComputerSystem.Domain -ne "$DomainName")) {
+            Write-Error "DomainName is not equal to '$DomainName'"
+    		return $false
+    	}
+    	
+    	if (($WorkgroupName -ne "") -and ($ComputerSystem.Workgroup -ne "$WorkgroupName")) {
+            Write-Error "WorkgroupName is not equal to '$WorkgroupName'"
+    		return $false
+    	}
+    	
+    	if (($PartOfDOmain -eq $true) -and ($ComputerSystem.PartOfDomain -eq $false)) {
+            Write-Error "Computer is not the part of any domain."
+    		return $false
+    	}
+    	
+    	return $true
+    }
+}
+
+
+
+Function Show-EthernetNetworkAdapters {
+    Get-WmiObject Win32_NetworkAdapter -Filter "PhysicalAdapter = 'True' AND AdapterTypeId = '0'" |
+        Select-Object 'Index','MACAddress','NetConnectionId'
+}
+
+
+
+Function Set-NetworkAdapterConfiguration {
+<#
+.SYNOPSIS
+Set network adapter configuration.
+
+.DESCRIPTION
+
+
+.EXAMPLE
+PS> Set-NetworkAdapterConfiguration -MACAddress aa:bb:cc:dd:ee:ff -Auto
+
+Convert "dynamic" parameters (DHCP) to "static" (manual) for network adapter with MAC address aa:bb:cc:dd:ee:ff
+
+.EXAMPLE
+PS> Set-NetworkAdapterConfiguration -MACAddress aa:bb:cc:dd:ee:ff -DNSServer "192.168.0.1","192.168.0.2"
+
+Configure DNS servers list for network adapter with MAC address aa:bb:cc:dd:ee:ff
+
+#>
+	param (
+		[String] $MACAddress = "",
+		
+		[Parameter(ParameterSetName="ManualConfig")]
+		[String] $IPAddress = "",
+		
+		[Parameter(ParameterSetName="ManualConfig")]
+		[String] $IPNetmask = "",
+		
+		[Parameter(ParameterSetName="ManualConfig")]
+		[String[]] $IPGateway = @(),
+		
+		[Parameter(ParameterSetName="ManualConfig")]
+		[String[]] $DNSServer = @(),
+		
+		[Parameter(ParameterSetName="ManualConfig")]
+		[Switch] $FirstAvailable,
+
+		[String] $Name = "",
+		
+		[Parameter(ParameterSetName="AutoConfig",Mandatory=$true)]
+		[Switch] $Auto,
+
+		[Parameter(ParameterSetName="AutoConfig")]
+		[Switch] $All
+	)
+    
+	Write-Log "Configuring network adapter(s) ..."
+    
+	:SetIPAddress switch($PSCmdlet.ParameterSetName) {
+		"AutoConfig" {
+            Write-Log "'auto' mode"
+            
+			$IPv4RegExp = "\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}"
+			
+			if ($All -eq $true) {
+				$Filter = { $_.AdapterTypeId -eq 0 }
+				$Name = ""
+			}
+			else {
+				$Filter = { $_.MACAddress -eq $MACAddress }
+			}
+			
+			Get-WmiObject Win32_NetworkAdapter |
+				Where-Object $Filter |
+				ForEach-Object {
+					$NetworkAdapter = $_
+					$AdapterConfig = Get-WmiObject Win32_NetworkAdapterConfiguration |
+						Where-Object { $_.Index -eq $NetworkAdapter.DeviceId }
+					
+					Write-Log "Configuring '$($NetworkAdapter.Name)' ..."
+					
+					for ($i = 0; $i -lt $AdapterConfig.IPAddress.Length; $i++) {
+						if ($AdapterConfig.IPAddress[$i] -match $IPv4RegExp) {
+							$IPAddress = $AdapterConfig.IPAddress[$i]
+							$IPNetmask = $AdapterConfig.IPSubnet[$i]
+							$IPGateway = $AdapterConfig.DefaultIPGateway
+                            $DNSServer = $AdapterConfig.DNSServerSearchOrder
+							
+							Write-Log "Setting IP address ($IPAddress), netmask ($IPNetmask) ..."
+							$AdapterConfig.EnableStatic($IPAddress, $IPNetmask) | Out-Null
+                            
+                            Write-Log "Setting default gateways ($IPGateway) ..."
+							$AdapterConfig.SetGateways($IPGateway) | Out-Null
+                            
+                            Write-Log "Setting DNS servers ($DNSServer) ..."
+                            $AdapterConfig.SetDNSServerSearchOrder($DNSServer) | Out-Null
+						}
+					}
+                    
+                    Write-Log "'$($NetworkAdapter.Name)' configured"
+				}
+		}
+		"ManualConfig" {
+            Write-Log "'manual' mode"
+			if ( $FirstAvailable ) {
+                Write-Log "Selecting first available network adapter ..."
+				$NetworkAdapter = Get-WmiObject Win32_NetworkAdapter |
+					Where-Object { $_.AdapterTypeId -eq 0 } |
+					Select-Object -First 1
+			}
+			else {
+				$NetworkAdapter = Get-WmiObject Win32_NetworkAdapter |
+					Where-Object { $_.MACAddress -eq $MACAddress }
+			}
+			
+			if ( $NetworkAdapter -eq $null ) {
+				Write-LogError "Network adapter with MAC = '$MACAddress' not found."
+				return
+			}
+			
+			$AdapterConfig = Get-WmiObject Win32_NetworkAdapterConfiguration |
+				Where-Object { $_.Index -eq $NetworkAdapter.DeviceId }
+
+			if (($IPAddress -ne "") -and ($IPNetmask -ne "")) {
+				Write-Log "Configuring IP address / netmask for '$($NetworkAdapter.Name)' ..."
+				
+				<#
+				for ($i = 0; $i -lt $AdapterConfig.IPAddress.Length; $i++)
+				{
+					if (($AdapterConfig.IPAddress[$i] -eq $IPAddress) -and ($AdapterConfig.IPSubnet[$i] -eq $IPNetmask))
+					{
+						Write-Log "There is an adapter with required configuration."
+						break SetIPAddress
+					}
+				}
+				#>
+				Write-Log "Setting IP address $IPAddress, netmask $IPNetmask"
+				$AdapterConfig.EnableStatic("$IPAddress", "$IPNetmask") | Out-Null
+				
+				Write-Log "IP address configured."
+			}
+			
+			if ($IPGateway.Count -gt 0) {
+				Write-Log "Configuring IP gateway for '$($NetworkAdapter.Name)' ..."
+				
+				$AdapterConfig.SetGateways($IPGateway) | Out-Null
+				
+				Write-Log "IP gateway configured."
+			}
+			
+			if ($DNSServer.Count -gt 0) {
+				Write-Log "Configuring DNS server(s) for '$($NetworkAdapter.Name)' ..."
+				
+				$AdapterConfig.SetDNSServerSearchOrder($DNSServer) | Out-Null
+				
+				Write-Log "DNS configured."
+			}
+		}
+	}
+
+	if ($Name -ne "") {
+		Write-Log "Changing adapter name '$($NetworkAdapter.NetConnectionId)' --> '$Name'"
+		$NetworkAdapter.NetConnectionId = "$Name"
+		$NetworkAdapter.Put() | Out-Null
+	}
+}
+
+
+
+Function Test-WmiReturnValue {
+<#
+.SYNOPSIS
+Check the ReturnValue property of the object provided.
+
+.DESCRIPTION
+This funciton checks if ReturnValue property is equal to 0.
+
+=== TODO ===
+If it is not, then funtion should try to provide desctiption for the error code based on the WMI object type.
+WMI object type must be provided explicitely.
+#>
+	param (
+		[Parameter(ValueFromPipeline=$true,Mandatory=$true)]
+		$InputObject,
+		[String] $Type = ""
+	)
+		
+	try {
+		$ReturnValue = $InputObject.ReturnValue
+	}
+	catch {
+		throw "Property 'ReturnValue' not found on this object"
+	}
+		
+	if ($ReturnValue -eq 0) {
+		Write-Log "WMI operation completed successfully"
+	}
+	else {
+		throw "Operation failed with status code = $ReturnValue"
+	}
+}
+
+
+
+Function Add-WindowsFeatureWrapper {
+<#
+.SYNOPSIS
+Wraps Install-WindowsFeature function.
+
+.DESCRIPTION
+This function adds some logic to multiple feature installation.
+
+It fails if any of required features fails.
+
+It reports that reboot required if it is required, or restarts the computer.
+#>
+	param (
+		[Parameter(Mandatory=$true)]
+		[String[]] $Name,
+		[Switch] $IncludeManagementTools,
+		[Switch] $AllowRestart,
+        [Switch] $NotifyRestart
+	)
+	
+    $RestartNeeded = $false
+    
+	foreach ($Feature in $Name) {
+		Write-Log "Installing feature '$Feature' ..."
+		$Action = Install-WindowsFeature `
+			-Name $Feature `
+			-IncludeManagementTools:$IncludeManagementTools `
+			-ErrorAction Stop
+		
+		if ($Action.Success -eq $true) {
+			if ($Action.FeatureResult.RestartNeeded -eq $true) {
+				Write-LogWarning "Restart required"
+				$RestartNeeded = $true
+			}
+			Write-Log "Feature '$Feature' installed successfully"
+		}
+		else {
+			Stop-Execution "Failed to install feature '$Feature'"
+		}
+	}
+	
+    if ($RestartNeeded) {
+        Write-Log "Restart required to finish feature(s) installation."
+        if ($AllowRestart) {
+            Write-Log "Restarting computer ..."
+            Restart-Computer -Force
+        }
+        elseif ($NotifyRestart) {
+            Stop-Execution -ExitCode 3010 -ExitString "Please restart the computer now."
+        }
+    }
+}
+
+
+
+Function Get-PasswordAsSecureString {
+<#
+.SYNOPSIS
+Convert to / request password as secure string.
+#>
+    param (
+        [String] $Password,
+        [String] $Prompt = "Please enter password"
+    )
+    
+    if ($Password -eq "") {
+        Read-Host -Prompt $Prompt -AsSecureString
+    }
+    else {
+        ConvertTo-SecureString -String "$Password" -AsPlainText -Force
+    }
+}
+
+
+
+Function New-Credential {
+<#
+.SYNOPSIS
+Create new creadential object with username and password provided.
+#>
+	param (
+		[Parameter(Mandatory=$true)]
+		[String] $UserName,
+		
+		[String] $Password
+	)
+	
+	$SecurePassword = Get-PasswordAsSecureString -Password "$Password"
+	New-Object System.Management.Automation.PSCredential( "$UserName", $SecurePassword )
+}
+
+
+
+Function Join-Domain {
+<#
+.SYNOPSIS
+Executes "Join domain" action.
+#>
+	param (
+		[String] $DomainName,
+		[String] $UserName,
+		[String] $Password,
+        [Switch] $AllowRestart
+	)
+	
+	$Credential = New-Credential -UserName "$DomainName\$UserName" -Password $Password
+
+	# Add the computer to the domain
+	if (Test-ComputerName -DomainName $DomainName) {
+		#Stop-Execution -Success -ExitString "Computer already joined to domain '$DomainName'"
+        Write-LogWarning "Computer already joined to domain '$DomainName'"
+	}
+	else {
+		Write-Log "Joining computer to domain '$DomainName' ..."
+		
+		Add-Computer -DomainName $DomainName -Credential $Credential -Force -ErrorAction Stop
+		
+        if ($AllowRestart) {
+            Write-Log "Restarting computer ..."
+            Restart-Computer -Force
+        }
+        else {
+		    #Stop-Execution -ExitCode 3010 -ExitString "Please restart the computer now."
+            Write-Log "Please restart the computer now."
+        }
+	}
+}
+
+
+
+Function Invoke-WMSettingsChange {
+    if (-not ("win32.nativemethods" -as [type])) {
+        # Import SendMessageTimeout from Win32
+        Add-Type -Namespace Win32 -Name NativeMethods -MemberDefinition @"
+[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
+public static extern IntPtr SendMessageTimeout(
+    IntPtr hWnd, uint Msg, UIntPtr wParam, string lParam,
+    uint fuFlags, uint uTimeout, out UIntPtr lpdwResult);
+"@
+    }
+
+    $HWND_BROADCAST = [IntPtr]0xFFFF
+    $WM_SETTINGCHANGE = 0x001A
+    $result = [UIntPtr]::Zero
+
+    # Notify all windows of environment block change
+    Write-Log "Executing 'SendMessageTimeout' ..."
+
+    $retval = [Win32.NativeMethods]::SendMessageTimeout($HWND_BROADCAST, $WM_SETTINGCHANGE,
+	    [UIntPtr]::Zero, "Environment", 2, 5000, [ref] $result)
+    
+    Write-Log "'SendMessageTimeout' returned '$retval' (non-zero is OK)"
+}
+
+
+
+Function Set-AutoLogonCredentials {
+	param (
+		[String] $DomainName,
+		[String] $UserName,
+		[String] $Password
+	)
+	
+	$KeyName = "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon"
+
+	if ($DomainName -ne "") {
+		$UserName = "$DomainName\$UserName"
+	}
+    
+    Write-Log "Setting AutoLogon credentials ..."
+	try {
+    	[Microsoft.Win32.Registry]::SetValue($KeyName, "DefaultUserName", "$UserName", [Microsoft.Win32.RegistryValueKind]::String)
+    	[Microsoft.Win32.Registry]::SetValue($KeyName, "DefaultPassword", "$Password", [Microsoft.Win32.RegistryValueKind]::String)
+    	[Microsoft.Win32.Registry]::SetValue($KeyName, "AutoAdminLogon", "1", [Microsoft.Win32.RegistryValueKind]::String)
+    	[Microsoft.Win32.Registry]::SetValue($KeyName, "ForceAutoLogon", "1", [Microsoft.Win32.RegistryValueKind]::String)
+    }
+    catch {
+        Write-LogError "FAILED"
+        return
+    }
+    
+    Write-Log "SUCCESS"
+}
+
+
+
+Function Start-Program {
+	param (
+		[String] $FilePath,
+		[String[]] $ArgumentList = @(' '),
+		[Int] $Timeout = 0,
+		[Switch] $NoWait,
+		[Switch] $PassThru
+	)
+
+	trap {
+		Write-LogError $_.Exception.Message
+		return $null
+	}
+
+	Write-Log "Starting program: $FilePath $ArgumentList"
+		
+	$ProcessStartInfo = New-Object System.Diagnostics.ProcessStartInfo
+	$ProcessStartInfo.FileName = $FilePath
+	$ProcessStartInfo.Arguments = $ArgumentList
+	$ProcessStartInfo.CreateNoWindow = $true
+	$ProcessStartInfo.RedirectStandardOutput = $true
+	$ProcessStartInfo.RedirectStandardError = $true
+	$ProcessStartInfo.UseShellExecute = $false
+		
+	$Process = [System.Diagnostics.Process]::Start($ProcessStartInfo)
+		
+	if ($NoWait) {
+		if ($PassThru) {
+			return $Process
+		}
+		else {
+			return $null
+		}
+	}
+	else {
+		if ($Timeout -eq 0) {
+			$Process.WaitForExit()
+		}
+		else {
+			$Process.WaitForExit($Timeout)
+		}
+	}
+		
+	Write-Log ( "STDOUT:`n{0}" -f $Process.StandardOutput.ReadToEnd() )
+    Write-Log ":STDOUT"
+		
+	Write-Log ( "STDERR:`n{0}" -f $Process.StandardError.ReadToEnd() )
+    Write-Log ":STDERR"
+		
+	Write-Log "Program has finished with exit code ($($Process.ExitCode))"
+
+	if ($PassThru) {
+		return $Process
+	}
+	else {
+		return $null
+	}
+}
+New-Alias -Name Exec -Value Start-Program
+
+
+
+function Test-ModuleVersion {
+<#
+.SYNOPSIS
+Test module version.
+
+.DESCRIPTION
+Function specified module (current module by default), and compares it's version to version provided.
+Returned values:
+* -2 : error occured
+* -1 : module's version is lower than one provided
+*  0 : module's version is equal to one provided
+*  1 : module's version is greater than one provided
+#>
+    param (
+        [String] $Name = "$__ModuleName",
+        [String] $Version
+    )
+
+    $ModuleVersion = (Get-Module -Name $Name -ListAvailable).Version
+    
+    if ($ModuleVersion -eq $null) {
+        Write-Log "Module '$Name' not found."
+        return -2
+    }
+    
+    try {
+        $RequiredVersion = [System.Version]::Parse($Version)
+    }
+    catch {
+        Write-Log "'$Version' is not a correct version string."
+        return -2
+    }
+    
+    $ModuleVersion.CompareTo($RequiredVersion)
+}
+
+
+
+Function Set-LocalUserPassword {
+    param (
+        [String] $UserName,
+        [String] $Password,
+        [Switch] $Force
+    )
+    
+    trap { Stop-Execution $_ }
+    
+    if ((Get-WmiObject Win32_UserAccount -Filter "LocalAccount = 'True' AND Name='$UserName'") -eq $null) {
+        throw "Unable to find local user account '$UserName'"
+    }
+    
+    if ($Force) {
+        Write-Log "Changing password for user '$UserName' to '*****'" # :)
+        ([ADSI] "WinNT://./$UserName").SetPassword($Password) | Out-Null
+    }
+    else {
+        Write-LogWarning "You are trying to change the password for the user '$UserName'. To do this please run the command again with -Force parameter."
+    }
+}
+
+
+
+Function Resolve-LdapDnsName {
+    param (
+        [String] $DomainName
+    )
+    
+    Resolve-DNSName -Type "SRV" -Name "_ldap._tcp.dc._msdcs.$DomainName" |
+        Where-Object { $_.Type -eq "A" } |
+        Select-Object -Property Name,IPAddress
+}
+
+
+
+Function Wait-LdapServerAvailable {
+    param (
+        [String] $DomainName,
+        [Int] $PingSeqCountThreshold = 10,
+        [Int] $PingSeqPerHostThreshold = 5
+    )
+    
+    $LdapServerList = @( Resolve-LdapDnsName $DomainName )
+    Write-Log @( "Ldap server list:", ( $LdapServerList | Out-String ) )
+    
+    :MainLoop foreach ($LdapServer in $LdapServerList) {
+        $PingSeqCount = 0
+        $PingSeqPerHost = 0
+        while ($PingSeqPerHost -lt $PingSeqPerHostThreshold) {
+            if (Test-Connection -ComputerName $LdapServer.IpAddress -Count 1 -Quiet) {
+                Write-Log "Ping '$($LdapServer.Name)' OK"
+                $PingSeqCount++
+            }
+            else {
+                Write-Log "Ping '$($LdapServer.Name)' FAILED"
+                $PingSeqCount = 0
+                $PingSeqPerHost++
+            }
+            
+            if ($PingSeqCount -ge $PingSeqCountThreshold) {
+                Write-Log "Returning true"
+                return $true
+            }
+            
+            Start-Sleep -Seconds 1
+        }
+    }
+    
+    Write-Log "Returning false"
+    return $false
+}
+
+
diff --git a/Deployment/WindowsPowerShell/Modules/CoreFunctions/include/Logger.ps1 b/Deployment/WindowsPowerShell/Modules/CoreFunctions/include/Logger.ps1
new file mode 100644
index 0000000..e04db7b
--- /dev/null
+++ b/Deployment/WindowsPowerShell/Modules/CoreFunctions/include/Logger.ps1
@@ -0,0 +1,139 @@
+Function Initialize-Logger {
+    param (
+        [String] $ModuleName = $__ModuleName,
+        [String] $LogPath = $__DefaultLogPath
+    )
+    
+    if (-not ("log4net.LogManager" -as [type])) {
+        $FileStream = ([System.IO.FileInfo] (Get-Item "$__ModulePath\log4net.dll")).OpenRead()
+
+        $AssemblyBytes = New-Object Byte[] $FileStream.Length
+        [Void] $FileStream.Read($AssemblyBytes, 0, $FileStream.Length)
+
+        $FileStream.Close()
+
+        [Void] [System.Reflection.Assembly]::Load($AssemblyBytes)
+    }
+
+    [log4net.GlobalContext]::Properties["LogPath"] = $LogPath
+    [log4net.GlobalContext]::Properties["ModuleName"] = $ModuleName
+
+    $script:__Logger = [log4net.LogManager]::GetLogger("PowerShell")
+
+    $Log4NetConfig = New-Object System.IO.FileInfo("$__ModulePath\log4net.config")
+
+    [log4net.Config.XmlConfigurator]::Configure($Log4NetConfig)
+    
+    $__Logger.info("Logger initialized. Log file: '$LogPath'")
+}
+
+
+
+Function Write-LogInfo {
+	param (
+		[String[]] $Text
+	)
+    foreach ($Line in $Text) {
+        $__Logger.info($Line)
+    }
+}
+New-Alias -Name Write-Log -Value Write-LogInfo
+
+
+
+Function Out-LogInfo {
+	param (
+		[Parameter(ValueFromPipeline=$true)]
+		[String] $Text
+	)
+	$__Logger.info($Text)
+}
+New-Alias -Name Out-Log -Value Out-LogInfo
+
+
+
+Function Write-LogWarning {
+	param (
+		[String] $Text
+	)
+    foreach ($Line in $Text) {
+	    $__Logger.warn($Line)
+    }
+}
+
+
+
+Function Out-LogWarning {
+	param (
+		[Parameter(ValueFromPipeline=$true)]
+		[String] $Text
+	)
+	$__Logger__.warn($Text)
+}
+
+
+
+Function Write-LogError {
+	param (
+		[String] $Text
+	)
+    foreach ($Line in $Text) {
+	    $__Logger.error($Line)
+    }
+}
+
+
+
+Function Out-LogError {
+	param (
+		[Parameter(ValueFromPipeline=$true)]
+		[String] $Text
+	)
+	$__Logger.error($Text)
+}
+
+
+
+Function Write-LogFatal {
+	param (
+		[String] $Text
+	)
+    foreach ($Line in $Text) {
+	    $__Logger.fatal($Line)
+    }
+}
+
+
+
+Function Out-LogFatal {
+	param (
+		[Parameter(ValueFromPipeline=$true)]
+		[String] $Text
+	)
+	$__Logger.fatal($Text)
+}
+
+
+
+Function Write-LogDebug {
+	param (
+		[String] $Text
+	)
+    foreach ($Line in $Text) {
+	    $__Logger.debug($Line)
+    }
+}
+
+
+
+Function Out-LogDebug {
+	param (
+		[Parameter(ValueFromPipeline=$true)]
+		[String] $Text
+	)
+	$__Logger.debug($Text)
+}
+
+
+
+Initialize-Logger
diff --git a/Deployment/WindowsPowerShell/Modules/CoreFunctions/include/Module.ps1 b/Deployment/WindowsPowerShell/Modules/CoreFunctions/include/Module.ps1
new file mode 100644
index 0000000..0615c60
--- /dev/null
+++ b/Deployment/WindowsPowerShell/Modules/CoreFunctions/include/Module.ps1
@@ -0,0 +1,172 @@
+Function Get-ModuleHelp {
+    param (
+        [String] $ModuleName = $__ModuleName,
+        [String] $Path = "",
+        [Switch] $File,
+        [Int] $Width = 80
+    )
+    
+	$sb = {
+        $Module = Get-Module $ModuleName
+    	
+    	"`n"
+        "Module: $($Module.Name)"
+    	"Module version: $($Module.Version)"
+    	"`n"
+        "{0} Module Description {0}" -f ('=' * 30)
+        "`n"
+        
+    	Get-Help "about_$($Module.Name)" | Out-String -Width $Width
+    	
+        "{0} Exported Functions {0}" -f ('=' * 30)
+        "`n"
+        	
+    	foreach ($CommandName in $Module.ExportedCommands.Keys) {
+            '-' * 80
+    		Get-Help -Name $CommandName -Detailed | Out-String -Width $Width
+    	}
+    }
+    
+    if (($File) -and ($Path -eq "")) {
+        $Path = [IO.Path]::GetTempFileName()
+    }
+    
+    if ($Path -ne "") {
+        & $sb | Out-File -FilePath $Path -Force
+    }
+    else {
+        & $sb | Out-Default
+    }
+    
+    if ($File) {
+        notepad.exe "$Path"
+    }
+}
+
+
+
+function Update-PsModulePath {
+    param (
+        [String] $AddPath = ""
+    )
+
+    $NewPsModulePath = (
+            @([Environment]::GetEnvironmentVariable("PsModulePath", [EnvironmentVariableTarget]::Machine) -split ";") + @($AddPath) `
+            | Select-Object -Unique
+        ) -join ';'
+    
+    [Environment]::SetEnvironmentVariable("PsModulePath", $NewPsModulePath, [EnvironmentVariableTarget]::Machine)
+    
+    Invoke-WMSettingsChange
+}
+
+
+
+Function Install-Module {
+    param (
+        [String] $InstallPath,
+        [String] $ModulePath,
+        [String] $ModuleName
+    )
+
+    if ($ModuleName -eq "") {
+        if ($ModulePath -eq "") {
+            Stop-Execution -ExitString "Don't know which module should be installed."
+        }
+        else {
+             $ModuleName = $ModulePath.Split("\")[-1]
+        }
+    }
+    
+    if ($InstallPath -eq "") {
+        Stop-Execution -ExitString "To install the module destination path must be provided."
+    }
+    else {
+        Write-Log "Installing the module to '$InstallPath'"
+        
+        $NewModulePath = [IO.Path]::Combine($InstallPath, $ModuleName)
+        if ([IO.Directory]::Exists($NewModulePath)) {
+            [IO.Directory]::Delete($NewModulePath, $true)
+        }
+            
+        Copy-Item -Path $ModulePath -Destination $InstallPath -Recurse -Force -ErrorAction Stop
+            
+        Update-PsModulePath -AddPath "$InstallPath"
+    }
+}
+
+
+
+Function Register-Module {
+    param (
+        [String] $ModulePath
+    )
+    $ModuleRoot = Split-Path -Path $ModulePath -Parent
+    Write-Log "Registering the module at '$ModuleRoot'"
+    Update-PsModulePath -AddPath "$ModuleRoot"
+}
+
+
+
+Function New-ModuleTemplate {
+    param (
+        [Parameter(Mandatory=$true)]
+        [String] $Name,
+        
+        [String] $Path = "$($Env:USERPROFILE)\Documents\WindowsPowerShell\Modules",
+        
+        [Switch] $Force
+    )
+    if ([IO.Directory]::Exists("$Path\$Name")) {
+        if ($Force) {
+            [IO.Directory]::Delete("$Path\$Name", $true)
+        }
+        else {
+            Write-Error "Folder '$Path\$Name' already exists. Remove it manually or specify -Force switch."
+            return
+        }
+    }
+    
+    
+    [IO.Directory]::CreateDirectory("$Path\$Name")
+    [IO.Directory]::CreateDirectory("$Path\$Name\en-US")
+    [IO.Directory]::CreateDirectory("$Path\$Name\include")
+    
+    
+    Set-Content -Path "$Path\$Name\en-US\about_$Name.help.txt" -Value @'
+'@
+
+    
+    Set-Content -Path "$Path\$Name\Config.ps1" -Value @'
+$script:__ModulePath = $PsScriptRoot
+$script:__ModuleName = $PsScriptRoot.Split("\")[-1]
+$script:__DefaultLogPath = [IO.Path]::Combine([IO.Path]::GetTempPath(), "PowerShell_$__ModuleName.log")
+
+$global:__StopExecutionExitsSession__ = $false
+'@    
+    
+    
+    Set-Content -Path "$Path\$Name\$Name.psm1" -Value @'
+# Import config first
+. "$PsScriptRoot\Config.ps1"
+
+# Import functions from 'Include' subfolder
+Get-ChildItem "$PsScriptRoot\Include" -Filter "*.ps1" |
+    ForEach-Object {
+        . "$($_.FullName)"
+    }
+
+Export-ModuleMember -Function * -Alias *
+
+Initialize-Logger -ModuleName $__ModuleName -LogPath $__DefaultLogPath
+
+Write-Log "Module loaded from '$PsScriptRoot'"
+'@
+    
+    
+    New-ModuleManifest `
+        -Path "$Path\$Name\$Name.psd1" `
+        -ModuleToProcess "$Name.psm1" `
+        -RequiredModules "CoreFunctions"
+    
+}
diff --git a/Deployment/WindowsPowerShell/Modules/CoreFunctions/include/SqlFunctions.ps1 b/Deployment/WindowsPowerShell/Modules/CoreFunctions/include/SqlFunctions.ps1
new file mode 100644
index 0000000..a8f3215
--- /dev/null
+++ b/Deployment/WindowsPowerShell/Modules/CoreFunctions/include/SqlFunctions.ps1
@@ -0,0 +1,120 @@
+function New-SqlServerConnection {
+    param (
+        [String] $ServerName,
+        [String] $UserName = '',
+        [String] $Password = '',
+        $Credentials,
+        [Switch] $SqlAuth
+    )
+
+    if ($Credentials -eq $null) {
+        if ($UserName -eq '') {
+            throw "User name must be provided in order to create credentials object!"
+        }
+        
+        $Credentials = New-Credential -UserName $UserName -Password $Password
+    }
+
+    $Server = New-Object `
+        -TypeName Microsoft.SqlServer.Management.Smo.Server `
+        -ArgumentList $ServerName
+    
+    $LoginName = $Credentials.UserName -replace("^\\", "")
+
+    try {
+        if ($SqlAuth) {
+            $Server.ConnectionContext.set_LoginSecure($false)
+            $Server.ConnectionContext.set_Login($LoginName)
+            $Server.ConnectionContext.set_SecurePassword($Credentials.Password)
+        }
+        else {
+            throw "Not implemented!"
+        }
+    }
+    catch {
+        return $null
+    }
+
+    $Server
+}
+
+
+
+function Import-SqlServerAssemblies {
+<#
+.SYNOPSIS
+Import assemblies required to work with Sql Server instance from PowerShell
+
+.DESCRIPTION
+Possible assembly list:
+    "Microsoft.SqlServer.Management.Common"
+    "Microsoft.SqlServer.Smo"
+    "Microsoft.SqlServer.Dmf"
+    "Microsoft.SqlServer.Instapi"
+    "Microsoft.SqlServer.SqlWmiManagement"
+    "Microsoft.SqlServer.ConnectionInfo"
+    "Microsoft.SqlServer.SmoExtended"
+    "Microsoft.SqlServer.SqlTDiagM"
+    "Microsoft.SqlServer.SString"
+    "Microsoft.SqlServer.Management.RegisteredServers"
+    "Microsoft.SqlServer.Management.Sdk.Sfc"
+    "Microsoft.SqlServer.SqlEnum"
+    "Microsoft.SqlServer.RegSvrEnum"
+    "Microsoft.SqlServer.WmiEnum"
+    "Microsoft.SqlServer.ServiceBrokerEnum"
+    "Microsoft.SqlServer.ConnectionInfoExtended"
+    "Microsoft.SqlServer.Management.Collector"
+    "Microsoft.SqlServer.Management.CollectorEnum"
+    "Microsoft.SqlServer.Management.Dac"
+    "Microsoft.SqlServer.Management.DacEnum"
+    "Microsoft.SqlServer.Management.Utility"
+
+.LINKS
+http://msdn.microsoft.com/en-us/library/cc281962%28v=sql.105%29.aspx
+#>
+    $AssemblyList = @(
+        "Microsoft.SqlServer.Smo"
+        "Microsoft.SqlServer.SmoExtended"
+    )
+        
+    foreach ($asm in $AssemblyList) {
+        [System.Reflection.Assembly]::LoadWithPartialName($asm) | Out-Null
+    }
+}
+
+
+
+function Import-SqlServerProvider {
+    $SqlPsReg="HKLM:\SOFTWARE\Microsoft\PowerShell\1\ShellIds\Microsoft.SqlServer.Management.PowerShell.sqlps"
+
+    if (Get-ChildItem $SqlPsReg -ErrorAction "SilentlyContinue") {
+        throw "SQL Server Provider for Windows PowerShell is not installed."
+    }
+    else {
+        $Item = Get-ItemProperty $SqlPsReg
+        $SqlPsPath = [System.IO.Path]::GetDirectoryName($Item.Path)
+    }
+
+    #
+    # Set mandatory variables for the SQL Server provider
+    #
+    $global:SqlServerMaximumChildItems = 0
+    $global:SqlServerConnectionTimeout = 30
+    $global:SqlServerIncludeSystemObjects = $false
+    $global:SqlServerMaximumTabCompletion = 1000
+
+    #
+    # Load the snapins, type data, format data
+    #
+    Push-Location
+    Set-Location $sqlpsPath
+    
+    Add-PSSnapin SqlServerCmdletSnapin100
+    Add-PSSnapin SqlServerProviderSnapin100
+    
+    Update-TypeData -PrependPath SQLProvider.Types.ps1xml 
+    Update-FormatData -PrependPath SQLProvider.Format.ps1xml 
+    
+    Pop-Location
+}
+
diff --git a/Deployment/WindowsPowerShell/Modules/CoreFunctions/log4net.config b/Deployment/WindowsPowerShell/Modules/CoreFunctions/log4net.config
new file mode 100644
index 0000000..ea7aa0e
--- /dev/null
+++ b/Deployment/WindowsPowerShell/Modules/CoreFunctions/log4net.config
@@ -0,0 +1,42 @@
+<log4net>
+        <appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender" >
+            <param name="File" type="log4net.Util.PatternString" value="%property{LogPath}" />
+            <param name="AppendToFile" value="true" />
+            <param name="RollingStyle" value="Size" />
+            <param name="MaxSizeRollBackups" value="100" />
+            <param name="MaximumFileSize" value="1024KB" />
+            <param name="StaticLogFileName" value="true" />
+            <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
+            <layout type="log4net.Layout.PatternLayout">               
+                <param name="ConversionPattern" value="%date [%-5level] [%property{ModuleName}] %message%newline" />
+            </layout>
+        </appender>
+		
+		<appender name="ColoredConsoleAppender" type="log4net.Appender.ColoredConsoleAppender">
+			<mapping>
+				<level value="error" />
+				<foreColor value="Red, HighIntensity" />
+			</mapping>
+			<mapping>
+				<level value="warn" />
+				<foreColor value="Yellow, HighIntensity" />
+			</mapping>
+			<mapping>
+				<level value="info" />
+				<foreColor value="Green, HighIntensity" />
+			</mapping>
+			<layout type="log4net.Layout.PatternLayout">
+				<conversionPattern value="%date [%-5level] [%property{ModuleName}] %message%newline" />
+			</layout>
+		</appender>
+
+        <!--root>
+            <level value="info" />            
+        </root-->
+
+     <logger name="PowerShell" additivity="false">
+        <!--level value="info" /-->
+        <appender-ref ref="ColoredConsoleAppender" />
+		<appender-ref ref="RollingFileAppender" />
+     </logger>
+</log4net>
\ No newline at end of file
diff --git a/Deployment/WindowsPowerShell/Modules/CoreFunctions/log4net.dll b/Deployment/WindowsPowerShell/Modules/CoreFunctions/log4net.dll
new file mode 100644
index 0000000..1e66c82
Binary files /dev/null and b/Deployment/WindowsPowerShell/Modules/CoreFunctions/log4net.dll differ