Cleaned up unused files

* removed outdated files
* moved everything related to windows to contrib/windows
* moved everything related to cirros to contrib/cirros

Change-Id: Ibdffb96e25b94f545a836cb5df75beeae2b286a7
This commit is contained in:
Ruslan Kamaldinov 2014-07-01 16:06:33 +04:00
parent d38e097523
commit f025daeebb
213 changed files with 1897 additions and 5010 deletions

View File

@ -2,20 +2,15 @@ Murano
======
Murano Project introduces an application catalog, which allows application
developers and cloud administrators to publish various cloud-ready
applications in a browsable categorised catalog, which may be used by the
applications in a browsable categorised catalog, which may be used by the
cloud users (including the inexperienced ones) to pick-up the needed
applications and services and composes the reliable environments out of them
in a “push-the-button” manner.
in a "push-the-button" manner.
murano-deployment
-----------------
murano-deployment repository contains scripts and automation tools for
various aspects of Murano deployment. The most noticeable parts of this
repository are:
* Image builder helper for Windows platform;
* Set of PowerShell scripts for deployment Windows environment;
* Manifests for packaging Murano into .deb and .rpm packages.
murano CI system.
Project Resources
-----------------
@ -24,19 +19,3 @@ Project Resources
* `Code Review <https://review.openstack.org/>`__
* `Sources <https://wiki.openstack.org/wiki/Murano/SourceCode>`__
* `Developers Guide <http://murano-docs.github.io/latest/developers-guide/content/ch02.html>`__
How To Participate
------------------
If you would like to ask some questions or make proposals, feel free to reach
us on #murano IRC channel at FreeNode. Typically somebody from our team will
be online at IRC from 6:00 to 20:00 UTC. You can also contact Murano community
directly by openstack-dev@lists.openstack.org adding [Murano] to a subject.
Were holding public weekly meetings on Tuesdays at 17:00 UTC
on #openstack-meeting-alt IRC channel at FreeNode.
If you want to contribute either to docs or to code, simply send us change
request via `gerrit <https://review.openstack.org/>`__.
You can `file bugs <https://bugs.launchpad.net/murano/+filebug>`__ and
`register blueprints <https://blueprints.launchpad.net/murano/+addspec>`__ on
Launchpad.

View File

@ -1,11 +0,0 @@
CloudBase-Init
==============
A few modifications were made to the original CloudBase-Init deployment tools.
They are stored under this folder.
SEE ALSO
========
* `Murano <http://murano.mirantis.com>`__
* `CloudBase-Init <http://www.cloudbase.it/cloud-init-for-windows-instances/>`__

View File

@ -1,11 +0,0 @@
[DEFAULT]
username=Admin
groups=Administrators
inject_user_password=false
network_adapters=
config_drive_raw_hdd=false
config_drive_cdrom=false
verbose=true
logdir=C:\Program Files (x86)\Cloudbase Solutions\Cloudbase-Init\log\
logfile=cloudbase-init.log
plugins=cloudbaseinit.plugins.windows.userdata.UserDataPlugin

View File

@ -1,37 +0,0 @@
import codecs
from cloudbaseinit.osutils.factory import *
from cloudbaseinit.plugins.base import *
from cloudbaseinit.openstack.common import log as logging
opts = [
cfg.StrOpt('agent_config_file', default='C:\\Murano\\Agent\\WindowsAgent.exe.config', help='')
]
CONF = cfg.CONF
CONF.register_opts(opts)
LOG = logging.getLogger(__name__)
class SetHostNamePlugin(BasePlugin):
def execute(self, service):
meta_data = service.get_meta_data('openstack')
if 'meta' not in meta_data:
LOG.debug("Section 'meta' not found in metadata")
return False
if 'agent_config_xml' not in meta_data['meta']:
LOG.debug("Config for agent not found in metadata section")
return False
try:
configFile=codecs.open(CONF.agent_config_file, encoding='utf-8', mode='w+')
configFile.write(meta_data['meta']['agent_config_xml'])
configFile.close()
except:
LOG.error("Unable to update agent file.")
return False
return True

View File

@ -1,20 +0,0 @@
from cloudbaseinit.osutils.factory import *
from cloudbaseinit.plugins.base import *
from cloudbaseinit.openstack.common import log as logging
LOG = logging.getLogger(__name__)
class SetHostNamePlugin(BasePlugin):
def execute(self, service):
meta_data = service.get_meta_data('openstack')
if 'name' not in meta_data:
LOG.debug('Name not found in metadata')
return False
osutils = OSUtilsFactory().get_os_utils()
new_host_name = meta_data['name'].replace('.', '-')
return osutils.set_host_name(new_host_name)

View File

@ -1,24 +0,0 @@
Import-Module CoreFunctions
$ModuleBase = "C:\Murano\Modules"
$NewModule_Name = "ModuleName"
$NewModule_Base64 = @'
%BASE64_STRINGS%
'@
$AgentConfig_Path = "C:\Murano\Agent\WindowsAgent.exe.config"
$AgentConfig_Base64 = @'
%AGENT_CONFIG_BASE64%
'@
ConvertFrom-Base64String -Base64String $NewModule_Base64 -Path "$ModuleBase\$NewModule_Name.zip"
Remove-Item -Path "$ModuleBase\$NewModule_Name" -Recurse -Force
Expand-Zip -Path "$ModuleBase\$NewModule_Name.zip" -Destination "$ModuleBase\$NewModule_Name"
Remove-Item -Path $AgentConfig_Path -Force
ConvertFrom-Base64String -Base64String $NewModule_Base64 -Path $AgentConfig_Path

View File

@ -1,119 +1,119 @@
function Register-WebApp {
<#
.LINKS
http://www.iis.net/learn/manage/powershell/powershell-snap-in-creating-web-sites-web-applications-virtual-directories-and-application-pools
#>
param (
[String] $Source,
[String] $Path = "C:\inetpub\wwwroot",
[String] $Name = "",
[String] $Username = "",
[String] $Password = ""
)
Import-Module WebAdministration
if ($Name -eq "") {
$Name = @([IO.Path]::GetDirectoryName($Source) -split '\\')[-1]
if ($Name -eq "wwwroot") {
throw("Application pool name couldn't be 'wwwroot'.")
}
}
else {
$Path = [IO.Path]::Combine($Path, $Name)
}
Copy-Item -Path $Source -Destination $Path -Recurse -Force
# Create new application pool
$AppPool = New-WebAppPool -Name $Name -Force
#$AppPool = Get-Item "IIS:\AppPools\$Name"
$AppPool.managedRuntimeVersion = 'v4.0'
$AppPool.managedPipelineMode = 'Classic'
$AppPool.processModel.loadUserProfile = $true
$AppPool.processModel.logonType = 'LogonBatch'
#Set Identity type
if ($Username -eq "") {
$AppPool.processModel.identityType = 'ApplicationPoolIdentity'
}
else {
$AppPool.processModel.identityType = 'SpecificUser'
$AppPool.processModel.userName = $Username
$AppPool.processModel.password = $Password
$AppPool | Set-Item
}
# Create Website
$WebSite = New-WebSite -Name $Name -Port 80 -HostHeader $Name -PhysicalPath $Path -Force
#$WebSite = Get-Item "IIS:\Sites\$Name"
# Set the Application Pool
Set-ItemProperty "IIS:\Sites\$Name" 'ApplicationPool' $Name
#Turn on Directory Browsing
#Set-WebConfigurationProperty -Filter '/system.webServer/directoryBrowse' -Name 'enabled' -Value $true -PSPath "IIS:\Sites\$Name"
# Update Authentication
#Set-WebConfigurationProperty -Filter '/system.WebServer/security/authentication/AnonymousAuthentication' -Name 'enabled' -Value $true -Location $name
#Set-WebConfigurationProperty -Filter '/system.WebServer/security/authentication/windowsAuthentication' -Name 'enabled' -Value $false -Location $Name
#Set-WebConfigurationProperty -Filter '/system.WebServer/security/authentication/basicAuthentication' -Name 'enabled' -Value $false -Location $Name
$WebSite.Start()
Add-Content -Path "C:\Windows\System32\Drivers\etc\hosts" -Value "127.0.0.1 $Name"
}
function Deploy-WebAppFromGit {
param (
[String] $URL,
[String] $TempPath = [IO.Path]::Combine([IO.Path]::GetTempPath(), [IO.Path]::GetRandomFileName()),
[String] $OutputPath = [IO.Path]::Combine([IO.Path]::GetTempPath(), [IO.Path]::GetRandomFileName())
)
Write-Log "TempPath = '$TempPath'"
Write-Log "OutputPath = '$OutputPath'"
# Fetch web application
#----------------------
Write-Log "Fetching sources from Git ..."
$null = New-Item -Path $TempPath -ItemType Container
Exec -FilePath 'git.exe' -ArgumentList @('clone', $URL) -WorkingDir $TempPath -RedirectStreams
$Path = @(Get-ChildItem $TempPath)[0].FullName
#----------------------
# Build web application
#----------------------
Write-Log "Building sources ..."
$msbuild = "C:\Windows\Microsoft.NET\Framework64\v4.0.30319\MSBuild.exe"
$null = New-Item -Path $OutputPath -ItemType Container
$SlnFiles = @(Get-ChildItem -Path $Path -Filter *.sln -Recurse)
# Start new processs with additional env variables:
#* VisualStudioVersion = "10.0"
#* EnableNuGetPackageRestore = "true"
Exec -FilePath $msbuild `
-ArgumentList @($SlnFiles[0].FullName, "/p:OutputPath=$OutputPath") `
-Environment @{'VisualStudioVersion' = '10.0'; 'EnableNuGetPackageRestore' = 'true'} `
-RedirectStreams
$AppFolder = @(Get-ChildItem ([IO.Path]::Combine($OutputPath, '_PublishedWebsites')))[0]
#----------------------
# Install web application
#------------------------
Register-WebApp -Source $AppFolder.FullName -Name $AppFolder.Name
#------------------------
}
function Register-WebApp {
<#
.LINKS
http://www.iis.net/learn/manage/powershell/powershell-snap-in-creating-web-sites-web-applications-virtual-directories-and-application-pools
#>
param (
[String] $Source,
[String] $Path = "C:\inetpub\wwwroot",
[String] $Name = "",
[String] $Username = "",
[String] $Password = ""
)
Import-Module WebAdministration
if ($Name -eq "") {
$Name = @([IO.Path]::GetDirectoryName($Source) -split '\\')[-1]
if ($Name -eq "wwwroot") {
throw("Application pool name couldn't be 'wwwroot'.")
}
}
else {
$Path = [IO.Path]::Combine($Path, $Name)
}
Copy-Item -Path $Source -Destination $Path -Recurse -Force
# Create new application pool
$AppPool = New-WebAppPool -Name $Name -Force
#$AppPool = Get-Item "IIS:\AppPools\$Name"
$AppPool.managedRuntimeVersion = 'v4.0'
$AppPool.managedPipelineMode = 'Classic'
$AppPool.processModel.loadUserProfile = $true
$AppPool.processModel.logonType = 'LogonBatch'
#Set Identity type
if ($Username -eq "") {
$AppPool.processModel.identityType = 'ApplicationPoolIdentity'
}
else {
$AppPool.processModel.identityType = 'SpecificUser'
$AppPool.processModel.userName = $Username
$AppPool.processModel.password = $Password
$AppPool | Set-Item
}
# Create Website
$WebSite = New-WebSite -Name $Name -Port 80 -HostHeader $Name -PhysicalPath $Path -Force
#$WebSite = Get-Item "IIS:\Sites\$Name"
# Set the Application Pool
Set-ItemProperty "IIS:\Sites\$Name" 'ApplicationPool' $Name
#Turn on Directory Browsing
#Set-WebConfigurationProperty -Filter '/system.webServer/directoryBrowse' -Name 'enabled' -Value $true -PSPath "IIS:\Sites\$Name"
# Update Authentication
#Set-WebConfigurationProperty -Filter '/system.WebServer/security/authentication/AnonymousAuthentication' -Name 'enabled' -Value $true -Location $name
#Set-WebConfigurationProperty -Filter '/system.WebServer/security/authentication/windowsAuthentication' -Name 'enabled' -Value $false -Location $Name
#Set-WebConfigurationProperty -Filter '/system.WebServer/security/authentication/basicAuthentication' -Name 'enabled' -Value $false -Location $Name
$WebSite.Start()
Add-Content -Path "C:\Windows\System32\Drivers\etc\hosts" -Value "127.0.0.1 $Name"
}
function Deploy-WebAppFromGit {
param (
[String] $URL,
[String] $TempPath = [IO.Path]::Combine([IO.Path]::GetTempPath(), [IO.Path]::GetRandomFileName()),
[String] $OutputPath = [IO.Path]::Combine([IO.Path]::GetTempPath(), [IO.Path]::GetRandomFileName())
)
Write-Log "TempPath = '$TempPath'"
Write-Log "OutputPath = '$OutputPath'"
# Fetch web application
#----------------------
Write-Log "Fetching sources from Git ..."
$null = New-Item -Path $TempPath -ItemType Container
Exec -FilePath 'git.exe' -ArgumentList @('clone', $URL) -WorkingDir $TempPath -RedirectStreams
$Path = @(Get-ChildItem $TempPath)[0].FullName
#----------------------
# Build web application
#----------------------
Write-Log "Building sources ..."
$msbuild = "C:\Windows\Microsoft.NET\Framework64\v4.0.30319\MSBuild.exe"
$null = New-Item -Path $OutputPath -ItemType Container
$SlnFiles = @(Get-ChildItem -Path $Path -Filter *.sln -Recurse)
# Start new processs with additional env variables:
#* VisualStudioVersion = "10.0"
#* EnableNuGetPackageRestore = "true"
Exec -FilePath $msbuild `
-ArgumentList @($SlnFiles[0].FullName, "/p:OutputPath=$OutputPath") `
-Environment @{'VisualStudioVersion' = '10.0'; 'EnableNuGetPackageRestore' = 'true'} `
-RedirectStreams
$AppFolder = @(Get-ChildItem ([IO.Path]::Combine($OutputPath, '_PublishedWebsites')))[0]
#----------------------
# Install web application
#------------------------
Register-WebApp -Source $AppFolder.FullName -Name $AppFolder.Name
#------------------------
}

View File

@ -1,8 +1,8 @@
include Deploy-WebApp.ps1
call Import-Module Name="CoreFunctions"
call Deploy-WebAppFromGit URL="git://github.com/Mirantis/murano-mvc-demo.git"
reboot 0
out out.json
include Deploy-WebApp.ps1
call Import-Module Name="CoreFunctions"
call Deploy-WebAppFromGit URL="git://github.com/Mirantis/murano-mvc-demo.git"
reboot 0
out out.json

View File

@ -1,13 +1,13 @@
Scripts:
- Deploy-WebApp.ps1
Commands:
- Name: Import-Module
Arguments:
Name: "CoreFunctions"
- Name: Deploy-WebAppFromGit
Arguments:
URL: "git://github.com/Mirantis/murano-mvc-demo.git"
RebootOnCompletion: 0
Scripts:
- Deploy-WebApp.ps1
Commands:
- Name: Import-Module
Arguments:
Name: "CoreFunctions"
- Name: Deploy-WebAppFromGit
Arguments:
URL: "git://github.com/Mirantis/murano-mvc-demo.git"
RebootOnCompletion: 0

View File

@ -1,9 +1,9 @@
include Install-WebServer.ps1
call Import-Module Name="CoreFunctions"
call Copy-Prerequisites Destination="C:\Prerequisites"
call Install-WebServer PrerequisitesPath="C:\Prerequisites"
reboot 0
out out.json
include Install-WebServer.ps1
call Import-Module Name="CoreFunctions"
call Copy-Prerequisites Destination="C:\Prerequisites"
call Install-WebServer PrerequisitesPath="C:\Prerequisites"
reboot 0
out out.json

View File

@ -1,17 +1,17 @@
Scripts:
- Install-WebServer.ps1
Commands:
- Name: Import-Module
Arguments:
Name: "CoreFunctions"
- Name: Copy-Prerequisites
Arguments:
Destination: "C:\Prerequisites"
- Name: Install-WebServer
Arguments:
PrerequisitesPath: "C:\Prerequisites"
RebootOnCompletion: 0
Scripts:
- Install-WebServer.ps1
Commands:
- Name: Import-Module
Arguments:
Name: "CoreFunctions"
- Name: Copy-Prerequisites
Arguments:
Destination: "C:\Prerequisites"
- Name: Install-WebServer
Arguments:
PrerequisitesPath: "C:\Prerequisites"
RebootOnCompletion: 0

View File

@ -1,89 +1,89 @@
function Copy-Prerequisites {
param (
[String] $Path = '',
[String] $Destination = ''
)
Write-Log "--> Copy-Prerequisites"
if ($Destination -eq '') {
throw("Copy-Prerequisites: Destination path not specified!")
}
if ($Path -eq '') {
$Path = [Environment]::GetEnvironmentVariable('MuranoFileShare')
if ($Path -eq $null) {
throw("Copy-Prerequisites: Unable to determine source path for prerequisites.")
}
}
Write-Log "Creating new PSDrive ..."
New-PSDrive -Name 'P' -PSProvider 'FileSystem' -Root $Path | Out-Null
Write-Log "Creating destination folder ..."
New-Item -Path $Destination -ItemType Container -Force | Out-Null
Write-Log "Copying items ..."
Copy-Item -Path 'P:\Prerequisites\IIS' -Destination $Destination -Recurse -Force | Out-Null
Write-Log "Removing PSDrive ..."
Remove-PSDrive -Name 'P' -PSProvider 'FileSystem' -Force | Out-Null
Write-Log "<-- Copy-Prerequisites"
}
function Install-WebServer {
param (
[String] $PrerequisitesPath
)
Write-Log "--> Install-WebServer"
$FeatureList = @(
'Web-Server',
'Web-Net-Ext45',
'Web-ASP',
'Web-Asp-Net45',
'Web-ISAPI-Ext',
'Web-ISAPI-Filter',
'Web-Includes'
)
$PrerequisitesList = @(
'AspNetMvc4Setup.exe',
'WebApplications.exe'
)
$PrerequisitesPath = [IO.Path]::Combine($PrerequisitesPath, 'IIS')
Write-Log "Validating prerequisites based on the list ..."
foreach ($FileName in $PrerequisitesList) {
$FilePath = [IO.Path]::Combine($PrerequisitesPath, $FileName)
if (-not (Test-Path -Path $FilePath -PathType Leaf)) {
throw("Prerequisite file not found: '$FilePath'")
}
}
Import-Module ServerManager
Write-Log "Installing Web Server ..."
Install-WindowsFeature $FeatureList -IncludeManagementTools
Write-Log "Installing AspNetMvp4 ..."
$Exec = Exec -FilePath $([IO.Path]::Combine($PrerequisitesPath, 'AspNetMvc4Setup.exe')) -ArgumentList '/q' -PassThru
if ($Exec.ExitCode -ne 0) {
throw("Installation of 'AspNetMvc4Setup.exe' failed. Process exit code '$($Exec.ExitCode)'")
}
# Extract WebApplications folder with *.target files to
# C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v10.0
Write-Log "Installing WebApplication targets ..."
$WebApplicationsTargetsRoot = 'C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v10.0'
$null = New-Item -Path $WebApplicationsTargetsRoot -ItemType Container
$Exec = Exec -FilePath $([IO.Path]::Combine($PrerequisitesPath, 'WebApplications.exe')) -ArgumentList @("-o`"$WebApplicationsTargetsRoot`"", '-y') -PassThru
if ($Exec.ExitCode -ne 0) {
throw("Installation of 'WebApplications.exe' failed. Process exit code '$($Exec.ExitCode)'")
}
Write-Log "<-- Install-WebServer"
}
function Copy-Prerequisites {
param (
[String] $Path = '',
[String] $Destination = ''
)
Write-Log "--> Copy-Prerequisites"
if ($Destination -eq '') {
throw("Copy-Prerequisites: Destination path not specified!")
}
if ($Path -eq '') {
$Path = [Environment]::GetEnvironmentVariable('MuranoFileShare')
if ($Path -eq $null) {
throw("Copy-Prerequisites: Unable to determine source path for prerequisites.")
}
}
Write-Log "Creating new PSDrive ..."
New-PSDrive -Name 'P' -PSProvider 'FileSystem' -Root $Path | Out-Null
Write-Log "Creating destination folder ..."
New-Item -Path $Destination -ItemType Container -Force | Out-Null
Write-Log "Copying items ..."
Copy-Item -Path 'P:\Prerequisites\IIS' -Destination $Destination -Recurse -Force | Out-Null
Write-Log "Removing PSDrive ..."
Remove-PSDrive -Name 'P' -PSProvider 'FileSystem' -Force | Out-Null
Write-Log "<-- Copy-Prerequisites"
}
function Install-WebServer {
param (
[String] $PrerequisitesPath
)
Write-Log "--> Install-WebServer"
$FeatureList = @(
'Web-Server',
'Web-Net-Ext45',
'Web-ASP',
'Web-Asp-Net45',
'Web-ISAPI-Ext',
'Web-ISAPI-Filter',
'Web-Includes'
)
$PrerequisitesList = @(
'AspNetMvc4Setup.exe',
'WebApplications.exe'
)
$PrerequisitesPath = [IO.Path]::Combine($PrerequisitesPath, 'IIS')
Write-Log "Validating prerequisites based on the list ..."
foreach ($FileName in $PrerequisitesList) {
$FilePath = [IO.Path]::Combine($PrerequisitesPath, $FileName)
if (-not (Test-Path -Path $FilePath -PathType Leaf)) {
throw("Prerequisite file not found: '$FilePath'")
}
}
Import-Module ServerManager
Write-Log "Installing Web Server ..."
Install-WindowsFeature $FeatureList -IncludeManagementTools
Write-Log "Installing AspNetMvp4 ..."
$Exec = Exec -FilePath $([IO.Path]::Combine($PrerequisitesPath, 'AspNetMvc4Setup.exe')) -ArgumentList '/q' -PassThru
if ($Exec.ExitCode -ne 0) {
throw("Installation of 'AspNetMvc4Setup.exe' failed. Process exit code '$($Exec.ExitCode)'")
}
# Extract WebApplications folder with *.target files to
# C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v10.0
Write-Log "Installing WebApplication targets ..."
$WebApplicationsTargetsRoot = 'C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v10.0'
$null = New-Item -Path $WebApplicationsTargetsRoot -ItemType Container
$Exec = Exec -FilePath $([IO.Path]::Combine($PrerequisitesPath, 'WebApplications.exe')) -ArgumentList @("-o`"$WebApplicationsTargetsRoot`"", '-y') -PassThru
if ($Exec.ExitCode -ne 0) {
throw("Installation of 'WebApplications.exe' failed. Process exit code '$($Exec.ExitCode)'")
}
Write-Log "<-- Install-WebServer"
}

View File

@ -1,26 +1,26 @@
{
"Scripts": [
"ZnVuY3Rpb24gQ29weS1QcmVyZXF1aXNpdGVzIHsNCglwYXJhbSAoDQoJCVtTdHJpbmddICRQYXRoID0gJycsDQoJCVtTdHJpbmddICREZXN0aW5hdGlvbiA9ICcnDQoJKQ0KDQoJV3JpdGUtTG9nICItLT4gQ29weS1QcmVyZXF1aXNpdGVzIg0KDQogICAgaWYgKCREZXN0aW5hdGlvbiAtZXEgJycpIHsNCiAgICAgICAgdGhyb3coIkNvcHktUHJlcmVxdWlzaXRlczogRGVzdGluYXRpb24gcGF0aCBub3Qgc3BlY2lmaWVkISIpDQogICAgfQ0KDQogICAgaWYgKCRQYXRoIC1lcSAnJykgew0KICAgICAgICAkUGF0aCA9IFtFbnZpcm9ubWVudF06OkdldEVudmlyb25tZW50VmFyaWFibGUoJ011cmFub0ZpbGVTaGFyZScpDQogICAgICAgIGlmICgkUGF0aCAtZXEgJG51bGwpIHsNCiAgICAgICAgICAgIHRocm93KCJDb3B5LVByZXJlcXVpc2l0ZXM6IFVuYWJsZSB0byBkZXRlcm1pbmUgc291cmNlIHBhdGggZm9yIHByZXJlcXVpc2l0ZXMuIikNCiAgICAgICAgfQ0KICAgIH0NCg0KCVdyaXRlLUxvZyAiQ3JlYXRpbmcgbmV3IFBTRHJpdmUgLi4uIg0KCU5ldy1QU0RyaXZlIC1OYW1lICdQJyAtUFNQcm92aWRlciAnRmlsZVN5c3RlbScgLVJvb3QgJFBhdGggfCBPdXQtTnVsbA0KCVdyaXRlLUxvZyAiQ3JlYXRpbmcgZGVzdGluYXRpb24gZm9sZGVyIC4uLiINCglOZXctSXRlbSAtUGF0aCAkRGVzdGluYXRpb24gLUl0ZW1UeXBlIENvbnRhaW5lciAtRm9yY2UgfCBPdXQtTnVsbA0KCVdyaXRlLUxvZyAiQ29weWluZyBpdGVtcyAuLi4iDQoJQ29weS1JdGVtIC1QYXRoICdQOlxQcmVyZXF1aXNpdGVzXElJUycgLURlc3RpbmF0aW9uICREZXN0aW5hdGlvbiAtUmVjdXJzZSAtRm9yY2UgfCBPdXQtTnVsbA0KCVdyaXRlLUxvZyAiUmVtb3ZpbmcgUFNEcml2ZSAuLi4iDQoJUmVtb3ZlLVBTRHJpdmUgLU5hbWUgJ1AnIC1QU1Byb3ZpZGVyICdGaWxlU3lzdGVtJyAtRm9yY2UgfCBPdXQtTnVsbA0KCQ0KCVdyaXRlLUxvZyAiPC0tIENvcHktUHJlcmVxdWlzaXRlcyINCn0NCg0KDQoNCmZ1bmN0aW9uIEluc3RhbGwtV2ViU2VydmVyIHsNCglwYXJhbSAoDQoJCVtTdHJpbmddICRQcmVyZXF1aXNpdGVzUGF0aA0KCSkNCgkNCglXcml0ZS1Mb2cgIi0tPiBJbnN0YWxsLVdlYlNlcnZlciINCg0KCSRGZWF0dXJlTGlzdCA9IEAoDQoJCSdXZWItU2VydmVyJywNCgkJJ1dlYi1OZXQtRXh0NDUnLA0KCQknV2ViLUFTUCcsDQoJCSdXZWItQXNwLU5ldDQ1JywNCgkJJ1dlYi1JU0FQSS1FeHQnLA0KCQknV2ViLUlTQVBJLUZpbHRlcicsDQoJCSdXZWItSW5jbHVkZXMnDQoJKQ0KCQ0KCSRQcmVyZXF1aXNpdGVzTGlzdCA9IEAoDQoJCSdBc3BOZXRNdmM0U2V0dXAuZXhlJywNCgkJJ1dlYkFwcGxpY2F0aW9ucy5leGUnDQoJKQ0KICAgIA0KCSRQcmVyZXF1aXNpdGVzUGF0aCA9IFtJTy5QYXRoXTo6Q29tYmluZSgkUHJlcmVxdWlzaXRlc1BhdGgsICdJSVMnKQ0KICAgIA0KCVdyaXRlLUxvZyAiVmFsaWRhdGluZyBwcmVyZXF1aXNpdGVzIGJhc2VkIG9uIHRoZSBsaXN0IC4uLiINCglmb3JlYWNoICgkRmlsZU5hbWUgaW4gJFByZXJlcXVpc2l0ZXNMaXN0KSB7DQoJCSRGaWxlUGF0aCA9IFtJTy5QYXRoXTo6Q29tYmluZSgkUHJlcmVxdWlzaXRlc1BhdGgsICRGaWxlTmFtZSkNCgkJaWYgKC1ub3QgKFRlc3QtUGF0aCAtUGF0aCAkRmlsZVBhdGggLVBhdGhUeXBlIExlYWYpKSB7DQoJCQl0aHJvdygiUHJlcmVxdWlzaXRlIGZpbGUgbm90IGZvdW5kOiAnJEZpbGVQYXRoJyIpDQoJCX0NCgl9DQoJDQoJSW1wb3J0LU1vZHVsZSBTZXJ2ZXJNYW5hZ2VyDQoJDQoJV3JpdGUtTG9nICJJbnN0YWxsaW5nIFdlYiBTZXJ2ZXIgLi4uIg0KCUluc3RhbGwtV2luZG93c0ZlYXR1cmUgJEZlYXR1cmVMaXN0IC1JbmNsdWRlTWFuYWdlbWVudFRvb2xzDQoJDQoJV3JpdGUtTG9nICJJbnN0YWxsaW5nIEFzcE5ldE12cDQgLi4uIg0KCSRFeGVjID0gRXhlYyAtRmlsZVBhdGggJChbSU8uUGF0aF06OkNvbWJpbmUoJFByZXJlcXVpc2l0ZXNQYXRoLCAnQXNwTmV0TXZjNFNldHVwLmV4ZScpKSAtQXJndW1lbnRMaXN0ICcvcScgLVBhc3NUaHJ1DQoJaWYgKCRFeGVjLkV4aXRDb2RlIC1uZSAwKSB7DQoJCXRocm93KCJJbnN0YWxsYXRpb24gb2YgJ0FzcE5ldE12YzRTZXR1cC5leGUnIGZhaWxlZC4gUHJvY2VzcyBleGl0IGNvZGUgJyQoJEV4ZWMuRXhpdENvZGUpJyIpDQoJfQ0KCQ0KCSMgRXh0cmFjdCBXZWJBcHBsaWNhdGlvbnMgZm9sZGVyIHdpdGggKi50YXJnZXQgZmlsZXMgdG8NCgkjICAgQzpcUHJvZ3JhbSBGaWxlcyAoeDg2KVxNU0J1aWxkXE1pY3Jvc29mdFxWaXN1YWxTdHVkaW9cdjEwLjANCglXcml0ZS1Mb2cgIkluc3RhbGxpbmcgV2ViQXBwbGljYXRpb24gdGFyZ2V0cyAuLi4iDQoJJFdlYkFwcGxpY2F0aW9uc1RhcmdldHNSb290ID0gJ0M6XFByb2dyYW0gRmlsZXMgKHg4NilcTVNCdWlsZFxNaWNyb3NvZnRcVmlzdWFsU3R1ZGlvXHYxMC4wJw0KCSRudWxsID0gTmV3LUl0ZW0gLVBhdGggJFdlYkFwcGxpY2F0aW9uc1RhcmdldHNSb290IC1JdGVtVHlwZSBDb250YWluZXINCgkkRXhlYyA9IEV4ZWMgLUZpbGVQYXRoICQoW0lPLlBhdGhdOjpDb21iaW5lKCRQcmVyZXF1aXNpdGVzUGF0aCwgJ1dlYkFwcGxpY2F0aW9ucy5leGUnKSkgLUFyZ3VtZW50TGlzdCBAKCItb2AiJFdlYkFwcGxpY2F0aW9uc1RhcmdldHNSb290YCIiLCAnLXknKSAtUGFzc1RocnUNCglpZiAoJEV4ZWMuRXhpdENvZGUgLW5lIDApIHsNCgkJdGhyb3coIkluc3RhbGxhdGlvbiBvZiAnV2ViQXBwbGljYXRpb25zLmV4ZScgZmFpbGVkLiBQcm9jZXNzIGV4aXQgY29kZSAnJCgkRXhlYy5FeGl0Q29kZSknIikNCgl9DQoNCglXcml0ZS1Mb2cgIjwtLSBJbnN0YWxsLVdlYlNlcnZlciINCn0NCg0K"
],
"Commands": [
{
"Name": "Import-Module",
"Arguments": {
"Name": "CoreFunctions"
}
},
{
"Name": "Copy-Prerequisites",
"Arguments": {
"Destination": "C:\\Prerequisites"
}
},
{
"Name": "Install-WebServer",
"Arguments": {
"PrerequisitesPath": "C:\\Prerequisites"
}
}
],
"RebootOnCompletion": 0
}
{
"Scripts": [
"ZnVuY3Rpb24gQ29weS1QcmVyZXF1aXNpdGVzIHsNCglwYXJhbSAoDQoJCVtTdHJpbmddICRQYXRoID0gJycsDQoJCVtTdHJpbmddICREZXN0aW5hdGlvbiA9ICcnDQoJKQ0KDQoJV3JpdGUtTG9nICItLT4gQ29weS1QcmVyZXF1aXNpdGVzIg0KDQogICAgaWYgKCREZXN0aW5hdGlvbiAtZXEgJycpIHsNCiAgICAgICAgdGhyb3coIkNvcHktUHJlcmVxdWlzaXRlczogRGVzdGluYXRpb24gcGF0aCBub3Qgc3BlY2lmaWVkISIpDQogICAgfQ0KDQogICAgaWYgKCRQYXRoIC1lcSAnJykgew0KICAgICAgICAkUGF0aCA9IFtFbnZpcm9ubWVudF06OkdldEVudmlyb25tZW50VmFyaWFibGUoJ011cmFub0ZpbGVTaGFyZScpDQogICAgICAgIGlmICgkUGF0aCAtZXEgJG51bGwpIHsNCiAgICAgICAgICAgIHRocm93KCJDb3B5LVByZXJlcXVpc2l0ZXM6IFVuYWJsZSB0byBkZXRlcm1pbmUgc291cmNlIHBhdGggZm9yIHByZXJlcXVpc2l0ZXMuIikNCiAgICAgICAgfQ0KICAgIH0NCg0KCVdyaXRlLUxvZyAiQ3JlYXRpbmcgbmV3IFBTRHJpdmUgLi4uIg0KCU5ldy1QU0RyaXZlIC1OYW1lICdQJyAtUFNQcm92aWRlciAnRmlsZVN5c3RlbScgLVJvb3QgJFBhdGggfCBPdXQtTnVsbA0KCVdyaXRlLUxvZyAiQ3JlYXRpbmcgZGVzdGluYXRpb24gZm9sZGVyIC4uLiINCglOZXctSXRlbSAtUGF0aCAkRGVzdGluYXRpb24gLUl0ZW1UeXBlIENvbnRhaW5lciAtRm9yY2UgfCBPdXQtTnVsbA0KCVdyaXRlLUxvZyAiQ29weWluZyBpdGVtcyAuLi4iDQoJQ29weS1JdGVtIC1QYXRoICdQOlxQcmVyZXF1aXNpdGVzXElJUycgLURlc3RpbmF0aW9uICREZXN0aW5hdGlvbiAtUmVjdXJzZSAtRm9yY2UgfCBPdXQtTnVsbA0KCVdyaXRlLUxvZyAiUmVtb3ZpbmcgUFNEcml2ZSAuLi4iDQoJUmVtb3ZlLVBTRHJpdmUgLU5hbWUgJ1AnIC1QU1Byb3ZpZGVyICdGaWxlU3lzdGVtJyAtRm9yY2UgfCBPdXQtTnVsbA0KCQ0KCVdyaXRlLUxvZyAiPC0tIENvcHktUHJlcmVxdWlzaXRlcyINCn0NCg0KDQoNCmZ1bmN0aW9uIEluc3RhbGwtV2ViU2VydmVyIHsNCglwYXJhbSAoDQoJCVtTdHJpbmddICRQcmVyZXF1aXNpdGVzUGF0aA0KCSkNCgkNCglXcml0ZS1Mb2cgIi0tPiBJbnN0YWxsLVdlYlNlcnZlciINCg0KCSRGZWF0dXJlTGlzdCA9IEAoDQoJCSdXZWItU2VydmVyJywNCgkJJ1dlYi1OZXQtRXh0NDUnLA0KCQknV2ViLUFTUCcsDQoJCSdXZWItQXNwLU5ldDQ1JywNCgkJJ1dlYi1JU0FQSS1FeHQnLA0KCQknV2ViLUlTQVBJLUZpbHRlcicsDQoJCSdXZWItSW5jbHVkZXMnDQoJKQ0KCQ0KCSRQcmVyZXF1aXNpdGVzTGlzdCA9IEAoDQoJCSdBc3BOZXRNdmM0U2V0dXAuZXhlJywNCgkJJ1dlYkFwcGxpY2F0aW9ucy5leGUnDQoJKQ0KICAgIA0KCSRQcmVyZXF1aXNpdGVzUGF0aCA9IFtJTy5QYXRoXTo6Q29tYmluZSgkUHJlcmVxdWlzaXRlc1BhdGgsICdJSVMnKQ0KICAgIA0KCVdyaXRlLUxvZyAiVmFsaWRhdGluZyBwcmVyZXF1aXNpdGVzIGJhc2VkIG9uIHRoZSBsaXN0IC4uLiINCglmb3JlYWNoICgkRmlsZU5hbWUgaW4gJFByZXJlcXVpc2l0ZXNMaXN0KSB7DQoJCSRGaWxlUGF0aCA9IFtJTy5QYXRoXTo6Q29tYmluZSgkUHJlcmVxdWlzaXRlc1BhdGgsICRGaWxlTmFtZSkNCgkJaWYgKC1ub3QgKFRlc3QtUGF0aCAtUGF0aCAkRmlsZVBhdGggLVBhdGhUeXBlIExlYWYpKSB7DQoJCQl0aHJvdygiUHJlcmVxdWlzaXRlIGZpbGUgbm90IGZvdW5kOiAnJEZpbGVQYXRoJyIpDQoJCX0NCgl9DQoJDQoJSW1wb3J0LU1vZHVsZSBTZXJ2ZXJNYW5hZ2VyDQoJDQoJV3JpdGUtTG9nICJJbnN0YWxsaW5nIFdlYiBTZXJ2ZXIgLi4uIg0KCUluc3RhbGwtV2luZG93c0ZlYXR1cmUgJEZlYXR1cmVMaXN0IC1JbmNsdWRlTWFuYWdlbWVudFRvb2xzDQoJDQoJV3JpdGUtTG9nICJJbnN0YWxsaW5nIEFzcE5ldE12cDQgLi4uIg0KCSRFeGVjID0gRXhlYyAtRmlsZVBhdGggJChbSU8uUGF0aF06OkNvbWJpbmUoJFByZXJlcXVpc2l0ZXNQYXRoLCAnQXNwTmV0TXZjNFNldHVwLmV4ZScpKSAtQXJndW1lbnRMaXN0ICcvcScgLVBhc3NUaHJ1DQoJaWYgKCRFeGVjLkV4aXRDb2RlIC1uZSAwKSB7DQoJCXRocm93KCJJbnN0YWxsYXRpb24gb2YgJ0FzcE5ldE12YzRTZXR1cC5leGUnIGZhaWxlZC4gUHJvY2VzcyBleGl0IGNvZGUgJyQoJEV4ZWMuRXhpdENvZGUpJyIpDQoJfQ0KCQ0KCSMgRXh0cmFjdCBXZWJBcHBsaWNhdGlvbnMgZm9sZGVyIHdpdGggKi50YXJnZXQgZmlsZXMgdG8NCgkjICAgQzpcUHJvZ3JhbSBGaWxlcyAoeDg2KVxNU0J1aWxkXE1pY3Jvc29mdFxWaXN1YWxTdHVkaW9cdjEwLjANCglXcml0ZS1Mb2cgIkluc3RhbGxpbmcgV2ViQXBwbGljYXRpb24gdGFyZ2V0cyAuLi4iDQoJJFdlYkFwcGxpY2F0aW9uc1RhcmdldHNSb290ID0gJ0M6XFByb2dyYW0gRmlsZXMgKHg4NilcTVNCdWlsZFxNaWNyb3NvZnRcVmlzdWFsU3R1ZGlvXHYxMC4wJw0KCSRudWxsID0gTmV3LUl0ZW0gLVBhdGggJFdlYkFwcGxpY2F0aW9uc1RhcmdldHNSb290IC1JdGVtVHlwZSBDb250YWluZXINCgkkRXhlYyA9IEV4ZWMgLUZpbGVQYXRoICQoW0lPLlBhdGhdOjpDb21iaW5lKCRQcmVyZXF1aXNpdGVzUGF0aCwgJ1dlYkFwcGxpY2F0aW9ucy5leGUnKSkgLUFyZ3VtZW50TGlzdCBAKCItb2AiJFdlYkFwcGxpY2F0aW9uc1RhcmdldHNSb290YCIiLCAnLXknKSAtUGFzc1RocnUNCglpZiAoJEV4ZWMuRXhpdENvZGUgLW5lIDApIHsNCgkJdGhyb3coIkluc3RhbGxhdGlvbiBvZiAnV2ViQXBwbGljYXRpb25zLmV4ZScgZmFpbGVkLiBQcm9jZXNzIGV4aXQgY29kZSAnJCgkRXhlYy5FeGl0Q29kZSknIikNCgl9DQoNCglXcml0ZS1Mb2cgIjwtLSBJbnN0YWxsLVdlYlNlcnZlciINCn0NCg0K"
],
"Commands": [
{
"Name": "Import-Module",
"Arguments": {
"Name": "CoreFunctions"
}
},
{
"Name": "Copy-Prerequisites",
"Arguments": {
"Destination": "C:\\Prerequisites"
}
},
{
"Name": "Install-WebServer",
"Arguments": {
"PrerequisitesPath": "C:\\Prerequisites"
}
}
],
"RebootOnCompletion": 0
}

View File

@ -1,223 +1,223 @@
<#
.DESCRIPTION
## Failover Cluster Input Data (from the UI)
* Domain Membership
- [String] / [Select box] $DomainName - Domain name
* Domain User Credentials
- [String] $UserName - Username
- [Password string] $UserPassword - User password
* Shared Folder Information
- [String] $ShareServer - Server which will host the folder
- [String] $ShareName - Share name
- [String] $SharePath - Shared folder internal path
* Failover Cluster Members
- [String] $ClusterName - Cluster name
- [String] $ClusterIP - Static IP address that will be assigned to the cluster
- [String[]] $ClusterNodes - List of node names
## Failover Cluster creation workflow
* Create AD domain
* Join all the VMs to that domain
* Prepare nodes
- Install Failover Cluster prerequisites on all FC nodes
* Create failover cluster
- Create new cluster
- Add members
* Confugure FC quorum
- Create new folder that will be shared
- Share that folder with appropriate permissions
- Configure quorum mode
## Helpful SmbShare* Functions
* New-SmbShare
* Grant-SmbShareAccess
#>
trap {
&$TrapHandler
}
function Install-FailoverClusterPrerequisites {
#Import-Module FailoverClusters
Add-WindowsFeature Failover-Clustering, RSAT-Clustering-PowerShell
}
function New-FailoverClusterSharedFolder {
param (
[String] $ClusterName,
[String] $DomainName,
[String] $ShareServer,
[String] $SharePath = $($Env:SystemDrive + '\FCShare'),
[String] $ShareName = 'FCShare',
[String] $UserName,
[String] $UserPassword,
$Credential = $null
)
begin {
Show-InvocationInfo $MyInvocation
}
end {
Show-InvocationInfo $MyInvocation -End
}
process {
trap {
&$TrapHandler
}
Write-Log "--> New-FailoverClusterSharedFolder"
Write-Log "Creating shared folder for Failover Cluster ..."
if ($Credential -eq $null) {
$Credential = New-Credential -UserName "$DomainName\$UserName" -Password "$UserPassword"
}
if ((Test-Connection -ComputerName $ShareServer -Count 1 -Quiet) -eq $false) {
throw("Server '$ShareServer' is unreachable via ICMP.")
}
$Session = New-PSSession -ComputerName $ShareServer -Credential $Credential
Write-Log "Creating folder on '$ShareServer' ..."
Invoke-Command -Session $Session -ScriptBlock {
param (
[String] $SharePath,
[String] $ShareName,
[String] $ClusterAccount
)
Remove-SmbShare -Name $ShareName -Force -ErrorAction 'SilentlyContinue'
Remove-Item -Path $SharePath -Force -ErrorAction 'SilentlyContinue'
New-Item -Path $SharePath -ItemType Container -Force
New-SmbShare -Path $SharePath `
-Name $ShareName `
-FullAccess "$ClusterAccount", 'Everyone' `
-Description "Shared folder for Failover Cluster."
} -ArgumentList $SharePath, $ShareName, "$DomainName\$ClusterName`$"
Write-Log "Confguring Failover Cluster to use shared folder as qourum resourse ..."
$null = Set-ClusterQuorum -NodeAndFileShareMajority "\\$ShareServer\$ShareName"
Write-Log "<-- New-FailoverClusterSharedFolder"
}
}
function New-FailoverCluster {
param (
[String] $ClusterName,
[String] $StaticAddress,
[String[]] $ClusterNodes,
[String] $DomainName,
[String] $UserName,
[String] $UserPassword,
$Credential
)
begin {
Show-InvocationInfo $MyInvocation
}
end {
Show-InvocationInfo $MyInvocation -End
}
process {
trap {
&$TrapHandler
}
Write-Log "ClusterNodes: $($ClusterNodes -join ', ')"
if ($Credential -eq $null) {
$Credential = New-Credential -UserName "$DomainName\$UserName" -Password "$UserPassword"
}
Import-Module FailoverClusters
if ((Get-Cluster $ClusterName -ErrorAction SilentlyContinue) -eq $null) {
Write-Log "Creating new cluster '$ClusterName' ..."
Start-PowerShellProcess -Command @"
Import-Module FailoverClusters
New-Cluster -Name '$ClusterName' -StaticAddress '$StaticAddress'
"@ -Credential $Credential -NoBase64
Start-Sleep -Seconds 15
}
else {
Write-Log "Cluster '$ClusterName' already exists."
}
foreach ($Node in $ClusterNodes) {
Write-Log "Adding node '$Node' to the cluster '$ClusterName' ..."
if ((Get-ClusterNode $Node -ErrorAction SilentlyContinue) -eq $null) {
Write-Log "Adding node ..."
Start-PowerShellProcess -Command @"
Import-Module FailoverClusters
Add-ClusterNode -Cluster '$ClusterName' -Name '$Node'
"@ -Credential $Credential -NoBase64
}
else {
Write-Log "Node '$Node' already a part of the cluster '$ClusterName'."
}
}
}
}
<#
# Example
$DomainName = 'fc-acme.local'
$DomainUser = 'Administrator'
$DomainPassword = 'P@ssw0rd'
$ClusterName = 'fc-test'
$ClusterIP = '10.200.0.60'
$ClusterNodes = @('fc-node-01','fc-node-02','fc-node-03')
$ShareServer = 'fc-dc-01'
$ShareName = 'FCShare'
$SharePath = "C:\$ShareName"
Import-Module CoreFunctions -Force
$Creds = New-Credential `
-UserName "$DomainName\$DomainUser" `
-Password "$DomainPassword"
New-FailoverCluster `
-ClusterName $ClusterName `
-StaticAddress $ClusterIP `
-ClusterNodes $ClusterNodes `
-Credential $Creds
New-FailoverClusterSharedFolder `
-ClusterName $ClusterName `
-DomainName $DomainName `
-ShareServer $ShareServer `
-SharePath "$SharePath" `
-ShareName "$ShareName" `
-Credential $Creds
#>
<#
.DESCRIPTION
## Failover Cluster Input Data (from the UI)
* Domain Membership
- [String] / [Select box] $DomainName - Domain name
* Domain User Credentials
- [String] $UserName - Username
- [Password string] $UserPassword - User password
* Shared Folder Information
- [String] $ShareServer - Server which will host the folder
- [String] $ShareName - Share name
- [String] $SharePath - Shared folder internal path
* Failover Cluster Members
- [String] $ClusterName - Cluster name
- [String] $ClusterIP - Static IP address that will be assigned to the cluster
- [String[]] $ClusterNodes - List of node names
## Failover Cluster creation workflow
* Create AD domain
* Join all the VMs to that domain
* Prepare nodes
- Install Failover Cluster prerequisites on all FC nodes
* Create failover cluster
- Create new cluster
- Add members
* Confugure FC quorum
- Create new folder that will be shared
- Share that folder with appropriate permissions
- Configure quorum mode
## Helpful SmbShare* Functions
* New-SmbShare
* Grant-SmbShareAccess
#>
trap {
&$TrapHandler
}
function Install-FailoverClusterPrerequisites {
#Import-Module FailoverClusters
Add-WindowsFeature Failover-Clustering, RSAT-Clustering-PowerShell
}
function New-FailoverClusterSharedFolder {
param (
[String] $ClusterName,
[String] $DomainName,
[String] $ShareServer,
[String] $SharePath = $($Env:SystemDrive + '\FCShare'),
[String] $ShareName = 'FCShare',
[String] $UserName,
[String] $UserPassword,
$Credential = $null
)
begin {
Show-InvocationInfo $MyInvocation
}
end {
Show-InvocationInfo $MyInvocation -End
}
process {
trap {
&$TrapHandler
}
Write-Log "--> New-FailoverClusterSharedFolder"
Write-Log "Creating shared folder for Failover Cluster ..."
if ($Credential -eq $null) {
$Credential = New-Credential -UserName "$DomainName\$UserName" -Password "$UserPassword"
}
if ((Test-Connection -ComputerName $ShareServer -Count 1 -Quiet) -eq $false) {
throw("Server '$ShareServer' is unreachable via ICMP.")
}
$Session = New-PSSession -ComputerName $ShareServer -Credential $Credential
Write-Log "Creating folder on '$ShareServer' ..."
Invoke-Command -Session $Session -ScriptBlock {
param (
[String] $SharePath,
[String] $ShareName,
[String] $ClusterAccount
)
Remove-SmbShare -Name $ShareName -Force -ErrorAction 'SilentlyContinue'
Remove-Item -Path $SharePath -Force -ErrorAction 'SilentlyContinue'
New-Item -Path $SharePath -ItemType Container -Force
New-SmbShare -Path $SharePath `
-Name $ShareName `
-FullAccess "$ClusterAccount", 'Everyone' `
-Description "Shared folder for Failover Cluster."
} -ArgumentList $SharePath, $ShareName, "$DomainName\$ClusterName`$"
Write-Log "Confguring Failover Cluster to use shared folder as qourum resourse ..."
$null = Set-ClusterQuorum -NodeAndFileShareMajority "\\$ShareServer\$ShareName"
Write-Log "<-- New-FailoverClusterSharedFolder"
}
}
function New-FailoverCluster {
param (
[String] $ClusterName,
[String] $StaticAddress,
[String[]] $ClusterNodes,
[String] $DomainName,
[String] $UserName,
[String] $UserPassword,
$Credential
)
begin {
Show-InvocationInfo $MyInvocation
}
end {
Show-InvocationInfo $MyInvocation -End
}
process {
trap {
&$TrapHandler
}
Write-Log "ClusterNodes: $($ClusterNodes -join ', ')"
if ($Credential -eq $null) {
$Credential = New-Credential -UserName "$DomainName\$UserName" -Password "$UserPassword"
}
Import-Module FailoverClusters
if ((Get-Cluster $ClusterName -ErrorAction SilentlyContinue) -eq $null) {
Write-Log "Creating new cluster '$ClusterName' ..."
Start-PowerShellProcess -Command @"
Import-Module FailoverClusters
New-Cluster -Name '$ClusterName' -StaticAddress '$StaticAddress'
"@ -Credential $Credential -NoBase64
Start-Sleep -Seconds 15
}
else {
Write-Log "Cluster '$ClusterName' already exists."
}
foreach ($Node in $ClusterNodes) {
Write-Log "Adding node '$Node' to the cluster '$ClusterName' ..."
if ((Get-ClusterNode $Node -ErrorAction SilentlyContinue) -eq $null) {
Write-Log "Adding node ..."
Start-PowerShellProcess -Command @"
Import-Module FailoverClusters
Add-ClusterNode -Cluster '$ClusterName' -Name '$Node'
"@ -Credential $Credential -NoBase64
}
else {
Write-Log "Node '$Node' already a part of the cluster '$ClusterName'."
}
}
}
}
<#
# Example
$DomainName = 'fc-acme.local'
$DomainUser = 'Administrator'
$DomainPassword = 'P@ssw0rd'
$ClusterName = 'fc-test'
$ClusterIP = '10.200.0.60'
$ClusterNodes = @('fc-node-01','fc-node-02','fc-node-03')
$ShareServer = 'fc-dc-01'
$ShareName = 'FCShare'
$SharePath = "C:\$ShareName"
Import-Module CoreFunctions -Force
$Creds = New-Credential `
-UserName "$DomainName\$DomainUser" `
-Password "$DomainPassword"
New-FailoverCluster `
-ClusterName $ClusterName `
-StaticAddress $ClusterIP `
-ClusterNodes $ClusterNodes `
-Credential $Creds
New-FailoverClusterSharedFolder `
-ClusterName $ClusterName `
-DomainName $DomainName `
-ShareServer $ShareServer `
-SharePath "$SharePath" `
-ShareName "$ShareName" `
-Credential $Creds
#>

View File

@ -1,117 +1,117 @@
function Init-Clustering {
<#
.SYNOPSIS
Installs all the prerequisites for windows failover cluster.
.DESCRIPTION
Checks that computer is a part of Windows Domain.
Installs Failover Clustering windows feature with management tools if needed.
Restart may be required to continue installation, so check this cmdlet exit code.
If exit code is $true, a restart is required. System should be restarted and
CmdLet should be re-executed to perform all the configuration tasks left.
Is is safe to execute this CmdLet multiple times. It checks which components
are missing / unconfigured and performs only necessary steps.
#>
$ComputerSystem = Get-WmiObject Win32_ComputerSystem
if (-not $ComputerSystem.PartOfDomain) {
throw "The computer should be joined to domain first"
}
Import-Module ServerManager
$Feature = Get-WindowsFeature Failover-Clustering
if ($Feature -eq $null) {
throw "Failover-Clustering not found" # Should not happen on Win Server 2012
}
if (-not $Feature.Installed) {
Write-Host "Failover Clustering feature is not installed. Installing it using Server Manager..."
$FeatureOpResult = Add-WindowsFeature $Feature -IncludeManagementTools
if (-not $FeatureOpResult.Success) {
throw "Failed to install Failover-Clustering: " + $FeatureOpResult.ExitCode.toString()
}
if ($FeatureOpResult.RestartNeeded) {
Write-Host "Restart is required to continue..."
return $true
}
}
$Feature = Get-WindowsFeature RSAT-Clustering
if ($Feature -eq $null) {
throw "Failover Clustering Tools feature not found" # Should not happen on Win Server 2012
}
if (-not $Feature.Installed) {
Write-Host "Failover Clustering Tools feature is not installed. Installing it using Server Manager..."
$FeatureOpResult = Add-WindowsFeature $Feature
if (-not $FeatureOpResult.Success) {
throw "Failed to install RSAT-Clustering: " + $FeatureOpResult.ExitCode.toString()
}
if ($FeatureOpResult.RestartNeeded) {
Write-Host "Restart is required to continue..."
return $true
}
}
$Feature = Get-WindowsFeature RSAT-Clustering-Mgmt
if ($Feature -eq $null) {
throw "Failover Cluster Management Tools feature not found" # Should not happen on Win Server 2012
}
if (-not $Feature.Installed) {
Write-Host "Failover Cluster Management Tools feature is not installed. Installing it using Server Manager..."
$FeatureOpResult = Add-WindowsFeature $Feature
if (-not $FeatureOpResult.Success) {
throw "Failed to install RSAT-Clustering-Mgmt: " + $FeatureOpResult.ExitCode.toString()
}
if ($FeatureOpResult.RestartNeeded) {
Write-Host "Restart is required to continue..."
return $true
}
}
$Feature = Get-WindowsFeature RSAT-Clustering-PowerShell
if ($Feature -eq $null) {
throw "Failover Cluster Module for Windows PowerShell feature not found" # Should not happen on Win Server 2012
}
if (-not $Feature.Installed) {
Write-Host "Failover Cluster Module for Windows PowerShell feature is not installed. Installing it using Server Manager..."
$FeatureOpResult = Add-WindowsFeature $Feature
if (-not $FeatureOpResult.Success) {
throw "Failed to install RSAT-Clustering-PowerShell: " + $FeatureOpResult.ExitCode.toString()
}
if ($FeatureOpResult.RestartNeeded) {
Write-Host "Restart is required to continue..."
return $true
}
}
}
function New-WindowsFailoverCluster {
<#
.SYNOPSIS
Creates a Windows Failover Cluster.
.DESCRIPTION
Installs all the prerequisites and creates a new Windows Failover Cluster. Init-Clustering is executed
by this cmdlet to ensure that all the required server components are installed. A reboot mey be
required to complete installation. In case if this CmdLet returns $true, reboot the system and
re-invoke the CmdLet with the same arguments to continue installation.
.PARAMETER ClusterName
Failover Cluster Name. The installation will fail if a cluster or other object with the same name
already exists in the domain.
.PARAMETER Nodes
List of computers (fully qualified domain names are recommmeneded) to participate in the cluster.
Current user should have all the required permissions to join all the machones to the cluster.
#>
param(
[parameter(Mandatory = $true)]
[string]$ClusterName,
[parameter(Mandatory = $true)]
[array]$Nodes
)
if (Init-Clustering) {
return $true
}
Import-Module FailoverClusters
[void](Test-Cluster -Cluster $ClusterName -Node $Nodes)
[void](New-Cluster -Name $ClusterName -Node @("bravo.murano.local", "charlie.murano.local") -NoStorage)
return $false
}
function Init-Clustering {
<#
.SYNOPSIS
Installs all the prerequisites for windows failover cluster.
.DESCRIPTION
Checks that computer is a part of Windows Domain.
Installs Failover Clustering windows feature with management tools if needed.
Restart may be required to continue installation, so check this cmdlet exit code.
If exit code is $true, a restart is required. System should be restarted and
CmdLet should be re-executed to perform all the configuration tasks left.
Is is safe to execute this CmdLet multiple times. It checks which components
are missing / unconfigured and performs only necessary steps.
#>
$ComputerSystem = Get-WmiObject Win32_ComputerSystem
if (-not $ComputerSystem.PartOfDomain) {
throw "The computer should be joined to domain first"
}
Import-Module ServerManager
$Feature = Get-WindowsFeature Failover-Clustering
if ($Feature -eq $null) {
throw "Failover-Clustering not found" # Should not happen on Win Server 2012
}
if (-not $Feature.Installed) {
Write-Host "Failover Clustering feature is not installed. Installing it using Server Manager..."
$FeatureOpResult = Add-WindowsFeature $Feature -IncludeManagementTools
if (-not $FeatureOpResult.Success) {
throw "Failed to install Failover-Clustering: " + $FeatureOpResult.ExitCode.toString()
}
if ($FeatureOpResult.RestartNeeded) {
Write-Host "Restart is required to continue..."
return $true
}
}
$Feature = Get-WindowsFeature RSAT-Clustering
if ($Feature -eq $null) {
throw "Failover Clustering Tools feature not found" # Should not happen on Win Server 2012
}
if (-not $Feature.Installed) {
Write-Host "Failover Clustering Tools feature is not installed. Installing it using Server Manager..."
$FeatureOpResult = Add-WindowsFeature $Feature
if (-not $FeatureOpResult.Success) {
throw "Failed to install RSAT-Clustering: " + $FeatureOpResult.ExitCode.toString()
}
if ($FeatureOpResult.RestartNeeded) {
Write-Host "Restart is required to continue..."
return $true
}
}
$Feature = Get-WindowsFeature RSAT-Clustering-Mgmt
if ($Feature -eq $null) {
throw "Failover Cluster Management Tools feature not found" # Should not happen on Win Server 2012
}
if (-not $Feature.Installed) {
Write-Host "Failover Cluster Management Tools feature is not installed. Installing it using Server Manager..."
$FeatureOpResult = Add-WindowsFeature $Feature
if (-not $FeatureOpResult.Success) {
throw "Failed to install RSAT-Clustering-Mgmt: " + $FeatureOpResult.ExitCode.toString()
}
if ($FeatureOpResult.RestartNeeded) {
Write-Host "Restart is required to continue..."
return $true
}
}
$Feature = Get-WindowsFeature RSAT-Clustering-PowerShell
if ($Feature -eq $null) {
throw "Failover Cluster Module for Windows PowerShell feature not found" # Should not happen on Win Server 2012
}
if (-not $Feature.Installed) {
Write-Host "Failover Cluster Module for Windows PowerShell feature is not installed. Installing it using Server Manager..."
$FeatureOpResult = Add-WindowsFeature $Feature
if (-not $FeatureOpResult.Success) {
throw "Failed to install RSAT-Clustering-PowerShell: " + $FeatureOpResult.ExitCode.toString()
}
if ($FeatureOpResult.RestartNeeded) {
Write-Host "Restart is required to continue..."
return $true
}
}
}
function New-WindowsFailoverCluster {
<#
.SYNOPSIS
Creates a Windows Failover Cluster.
.DESCRIPTION
Installs all the prerequisites and creates a new Windows Failover Cluster. Init-Clustering is executed
by this cmdlet to ensure that all the required server components are installed. A reboot mey be
required to complete installation. In case if this CmdLet returns $true, reboot the system and
re-invoke the CmdLet with the same arguments to continue installation.
.PARAMETER ClusterName
Failover Cluster Name. The installation will fail if a cluster or other object with the same name
already exists in the domain.
.PARAMETER Nodes
List of computers (fully qualified domain names are recommmeneded) to participate in the cluster.
Current user should have all the required permissions to join all the machones to the cluster.
#>
param(
[parameter(Mandatory = $true)]
[string]$ClusterName,
[parameter(Mandatory = $true)]
[array]$Nodes
)
if (Init-Clustering) {
return $true
}
Import-Module FailoverClusters
[void](Test-Cluster -Cluster $ClusterName -Node $Nodes)
[void](New-Cluster -Name $ClusterName -Node @("bravo.murano.local", "charlie.murano.local") -NoStorage)
return $false
}

Some files were not shown because too many files have changed in this diff Show More