Added base64 encryption of the script files. Now script files are stored

separately from templates in the ./scripts/ directory.

test_windows_agent.py updated.

Formatting in windows_agent.py fixed.

Tracing and error capturing added to Set-LocalUserPassword.

Function Set-LocalUserPassword removed as it is implemented by workflow
means.

Scripts now stored in one common folder.
Scripts updated from murano-deployment.
Templates updated to reflect new script names.

Workflow template can reference multiple script files. These script
files will be concatinated and encrypted with base64.

Change-Id: Icb3532d2fb724bbb711c06086cb906bde22a380f

Fixed flake8 reported issues.

Change-Id: Icb3532d2fb724bbb711c06086cb906bde22a380f

Fixed test failure after reformatting.

Change-Id: Icb3532d2fb724bbb711c06086cb906bde22a380f

Fixed issues with test. Revert back path selection for scripts folder.
It is reasonable to have an ability to use own folder for custom
workflows so script path is relative to template location.

Change-Id: Icb3532d2fb724bbb711c06086cb906bde22a380f
This commit is contained in:
Georgy Okrokvertskhov 2013-08-10 00:22:58 -07:00
parent 8f7b38049a
commit 30b9bed2fc
37 changed files with 3940 additions and 118 deletions

View File

@ -1,6 +1,6 @@
{
"Scripts": [
"ZnVuY3Rpb24gR2V0LURuc0xpc3RlbmluZ0lwQWRkcmVzcyB7DQogICAgSW1wb3J0LU1vZHVsZSBEbnNTZXJ2ZXINCiAgICAoR2V0LUROU1NlcnZlciAtQ29tcHV0ZXJOYW1lIGxvY2FsaG9zdCkuU2VydmVyU2V0dGluZy5MaXN0ZW5pbmdJcEFkZHJlc3MgfA0KICAgICAgICBXaGVyZS1PYmplY3QgeyAkXyAtbWF0Y2ggIlxkezEsM31cLlxkezEsM31cLlxkezEsM31cLlxkezEsM30iIH0NCn0NCg=="
"Get-DnsListeningIpAddress.ps1"
],
"Commands": [
{

View File

@ -1,21 +1,16 @@
{
"Scripts": [
"RnVuY3Rpb24gU2V0LUxvY2FsVXNlclBhc3N3b3JkIHsKICAgIHBhcmFtICgKICAgICAgICBbU3RyaW5nXSAkVXNlck5hbWUsCiAgICAgICAgW1N0cmluZ10gJFBhc3N3b3JkLAogICAgICAgIFtTd2l0Y2hdICRGb3JjZQogICAgKQogICAgCiAgICB0cmFwIHsgU3RvcC1FeGVjdXRpb24gJF8gfQogICAgCiAgICBpZiAoKEdldC1XbWlPYmplY3QgV2luMzJfVXNlckFjY291bnQgLUZpbHRlciAiTG9jYWxBY2NvdW50ID0gJ1RydWUnIEFORCBOYW1lPSckVXNlck5hbWUnIikgLWVxICRudWxsKSB7CiAgICAgICAgdGhyb3cgIlVuYWJsZSB0byBmaW5kIGxvY2FsIHVzZXIgYWNjb3VudCAnJFVzZXJOYW1lJyIKICAgIH0KICAgIAogICAgaWYgKCRGb3JjZSkgewogICAgICAgIFdyaXRlLUxvZyAiQ2hhbmdpbmcgcGFzc3dvcmQgZm9yIHVzZXIgJyRVc2VyTmFtZScgdG8gJyoqKioqJyIgIyA6KQogICAgICAgIChbQURTSV0gIldpbk5UOi8vLi8kVXNlck5hbWUiKS5TZXRQYXNzd29yZCgkUGFzc3dvcmQpCiAgICB9CiAgICBlbHNlIHsKICAgICAgICBXcml0ZS1Mb2dXYXJuaW5nICJZb3UgYXJlIHRyeWluZyB0byBjaGFuZ2UgcGFzc3dvcmQgZm9yIHVzZXIgJyRVc2VyTmFtZScuIFRvIGRvIHRoaXMgcGxlYXNlIHJ1biB0aGUgY29tbWFuZCBhZ2FpbiB3aXRoIC1Gb3JjZSBwYXJhbWV0ZXIuIgogICAgICAgICRVc2VyQWNjb3VudAogICAgfQp9CgoKCkZ1bmN0aW9uIEluc3RhbGwtUm9sZVByaW1hcnlEb21haW5Db250cm9sbGVyCnsKPCMKLlNZTk9QU0lTCkNvbmZpZ3VyZSBub2RlJ3MgbmV0d29yayBhZGFwdGVycy4KQ3JlYXRlIGZpcnN0IGRvbWFpbiBjb250cm9sbGVyIGluIHRoZSBmb3Jlc3QuCgouRVhBTVBMRQpQUz4gSW5zdGFsbC1Sb2xlUHJpbWFyeURvbWFpbkNvbnRyb2xsZXIgLURvbWFpbk5hbWUgYWNtZS5sb2NhbCAtU2FmZU1vZGVQYXNzd29yZCAiUEBzc3cwcmQiCgpJbnN0YWxsIEROUyBhbmQgQUREUywgY3JlYXRlIGZvcmVzdCBhbmQgZG9tYWluICdhY21lLmxvY2FsJy4KU2V0IERDIHJlY292ZXJ5IG1vZGUgcGFzc3dvcmQgdG8gJ1BAc3N3MHJkJy4KIz4KCQoJcGFyYW0KCSgKCQlbU3RyaW5nXQoJCSMgTmV3IGRvbWFpbiBuYW1lLgoJCSREb21haW5OYW1lLAoJCQoJCVtTdHJpbmddCgkJIyBEb21haW4gY29udHJvbGxlciByZWNvdmVyeSBtb2RlIHBhc3N3b3JkLgoJCSRTYWZlTW9kZVBhc3N3b3JkCgkpCgoJdHJhcCB7IFN0b3AtRXhlY3V0aW9uICRfIH0KCiAgICAgICAgIyBBZGQgcmVxdWlyZWQgd2luZG93cyBmZWF0dXJlcwoJQWRkLVdpbmRvd3NGZWF0dXJlV3JhcHBlciBgCgkJLU5hbWUgIkROUyIsIkFELURvbWFpbi1TZXJ2aWNlcyIsIlJTQVQtREZTLU1nbXQtQ29uIiBgCgkJLUluY2x1ZGVNYW5hZ2VtZW50VG9vbHMgYAogICAgICAgIC1Ob3RpZnlSZXN0YXJ0CgoKCVdyaXRlLUxvZyAiQ3JlYXRpbmcgZmlyc3QgZG9tYWluIGNvbnRyb2xsZXIgLi4uIgoJCQoJJFNNQVAgPSBDb252ZXJ0VG8tU2VjdXJlU3RyaW5nIC1TdHJpbmcgJFNhZmVNb2RlUGFzc3dvcmQgLUFzUGxhaW5UZXh0IC1Gb3JjZQoJCQoJSW5zdGFsbC1BRERTRm9yZXN0IGAKCQktRG9tYWluTmFtZSAkRG9tYWluTmFtZSBgCgkJLVNhZmVNb2RlQWRtaW5pc3RyYXRvclBhc3N3b3JkICRTTUFQIGAKCQktRG9tYWluTW9kZSBEZWZhdWx0IGAKCQktRm9yZXN0TW9kZSBEZWZhdWx0IGAKCQktTm9SZWJvb3RPbkNvbXBsZXRpb24gYAoJCS1Gb3JjZSBgCgkJLUVycm9yQWN0aW9uIFN0b3AgfCBPdXQtTnVsbAoKCVdyaXRlLUxvZyAiV2FpdGluZyBmb3IgcmVib290IC4uLiIJCQojCVN0b3AtRXhlY3V0aW9uIC1FeGl0Q29kZSAzMDEwIC1FeGl0U3RyaW5nICJDb21wdXRlciBtdXN0IGJlIHJlc3RhcnRlZCB0byBmaW5pc2ggZG9tYWluIGNvbnRyb2xsZXIgcHJvbW90aW9uLiIKIwlXcml0ZS1Mb2cgIlJlc3RhcmluZyBjb21wdXRlciAuLi4iCiMJUmVzdGFydC1Db21wdXRlciAtRm9yY2UKfQo="
"ImportCoreFunctions.ps1",
"Install-RolePrimaryDomainController.ps1"
],
"Commands": [
{
"Name": "Import-Module",
"Arguments": {
"Name": "CoreFunctions"
}
},
{
"Name": "Install-RolePrimaryDomainController",
"Arguments": {
"DomainName": "$domain",
"SafeModePassword": "$recoveryPassword"
}
}
{
"Name": "Install-RolePrimaryDomainController",
"Arguments": {
"DomainName": "$domain",
"SafeModePassword": "$recoveryPassword"
}
}
],
"RebootOnCompletion": 1
}

View File

@ -1,14 +1,9 @@
{
"Scripts": [
"RnVuY3Rpb24gSW5zdGFsbC1Sb2xlU2Vjb25kYXJ5RG9tYWluQ29udHJvbGxlcg0Kew0KPCMNCi5TWU5PUFNJUw0KSW5zdGFsbCBhZGRpdGlvbmFsIChzZWNvbmRhcnkpIGRvbWFpbiBjb250cm9sbGVyLg0KDQojPg0KCXBhcmFtDQoJKA0KCQlbU3RyaW5nXQ0KCQkjIERvbWFpbiBuYW1lIHRvIGpvaW4gdG8uDQoJCSREb21haW5OYW1lLA0KCQkNCgkJW1N0cmluZ10NCgkJIyBEb21haW4gdXNlciB3aG8gaXMgYWxsb3dlZCB0byBqb2luIGNvbXB1dGVyIHRvIGRvbWFpbi4NCgkJJFVzZXJOYW1lLA0KCQkNCgkJW1N0cmluZ10NCgkJIyBVc2VyJ3MgcGFzc3dvcmQuDQoJCSRQYXNzd29yZCwNCgkJDQoJCVtTdHJpbmddDQoJCSMgRG9tYWluIGNvbnRyb2xsZXIgcmVjb3ZlcnkgbW9kZSBwYXNzd29yZC4NCgkJJFNhZmVNb2RlUGFzc3dvcmQNCgkpDQoNCgl0cmFwIHsgU3RvcC1FeGVjdXRpb24gJF8gfQ0KCQ0KCSRDcmVkZW50aWFsID0gTmV3LUNyZWRlbnRpYWwgLVVzZXJOYW1lICIkRG9tYWluTmFtZVwkVXNlck5hbWUiIC1QYXNzd29yZCAkUGFzc3dvcmQNCgkJDQoJIyBBZGQgcmVxdWlyZWQgd2luZG93cyBmZWF0dXJlcw0KCUFkZC1XaW5kb3dzRmVhdHVyZVdyYXBwZXIgYA0KCQktTmFtZSAiRE5TIiwiQUQtRG9tYWluLVNlcnZpY2VzIiwiUlNBVC1ERlMtTWdtdC1Db24iIGANCgkJLUluY2x1ZGVNYW5hZ2VtZW50VG9vbHMgYA0KICAgICAgICAgICAgICAgIC1Ob3RpZnlSZXN0YXJ0DQoJCQ0KCQ0KICAgICAgICBXcml0ZS1Mb2cgIkFkZGluZyBzZWNvbmRhcnkgZG9tYWluIGNvbnRyb2xsZXIgLi4uIg0KICAgIA0KCSRTTUFQID0gQ29udmVydFRvLVNlY3VyZVN0cmluZyAtU3RyaW5nICRTYWZlTW9kZVBhc3N3b3JkIC1Bc1BsYWluVGV4dCAtRm9yY2UNCg0KCUluc3RhbGwtQUREU0RvbWFpbkNvbnRyb2xsZXIgYA0KCQktRG9tYWluTmFtZSAkRG9tYWluTmFtZSBgDQoJCS1TYWZlTW9kZUFkbWluaXN0cmF0b3JQYXNzd29yZCAkU01BUCBgDQoJCS1DcmVkZW50aWFsICRDcmVkZW50aWFsIGANCgkJLU5vUmVib290T25Db21wbGV0aW9uIGANCgkJLUZvcmNlIGANCgkJLUVycm9yQWN0aW9uIFN0b3AgfCBPdXQtTnVsbA0KDQoJV3JpdGUtTG9nICJXYWl0aW5nIGZvciByZXN0YXJ0IC4uLiINCiMJU3RvcC1FeGVjdXRpb24gLUV4aXRDb2RlIDMwMTAgLUV4aXRTdHJpbmcgIkNvbXB1dGVyIG11c3QgYmUgcmVzdGFydGVkIHRvIGZpbmlzaCBkb21haW4gY29udHJvbGxlciBwcm9tb3Rpb24uIg0KIwlXcml0ZS1Mb2cgIlJlc3RhcnRpbmcgY29tcHV0ZXIgLi4uIg0KIwlSZXN0YXJ0LUNvbXB1dGVyIC1Gb3JjZQ0KfQ0K"
"ImportCoreFunctions.ps1",
"Install-RoleSecondaryDomainController.ps1"
],
"Commands": [
{
"Name": "Import-Module",
"Arguments": {
"Name": "CoreFunctions"
}
},
{
"Name": "Install-RoleSecondaryDomainController",
"Arguments": {

File diff suppressed because one or more lines are too long

View File

@ -1,14 +1,10 @@
{
"Scripts": [
"ZnVuY3Rpb24gQ29weS1QcmVyZXF1aXNpdGVzIHsNCglwYXJhbSAoDQoJCVtTdHJpbmddICRQYXRoID0gJycsDQoJCVtTdHJpbmddICREZXN0aW5hdGlvbiA9ICcnDQoJKQ0KDQoJV3JpdGUtTG9nICItLT4gQ29weS1QcmVyZXF1aXNpdGVzIg0KDQogICAgaWYgKCREZXN0aW5hdGlvbiAtZXEgJycpIHsNCiAgICAgICAgdGhyb3coIkNvcHktUHJlcmVxdWlzaXRlczogRGVzdGluYXRpb24gcGF0aCBub3Qgc3BlY2lmaWVkISIpDQogICAgfQ0KDQogICAgaWYgKCRQYXRoIC1lcSAnJykgew0KICAgICAgICAkUGF0aCA9IFtFbnZpcm9ubWVudF06OkdldEVudmlyb25tZW50VmFyaWFibGUoJ011cmFub0ZpbGVTaGFyZScpDQogICAgICAgIGlmICgkUGF0aCAtZXEgJG51bGwpIHsNCiAgICAgICAgICAgIHRocm93KCJDb3B5LVByZXJlcXVpc2l0ZXM6IFVuYWJsZSB0byBkZXRlcm1pbmUgc291cmNlIHBhdGggZm9yIHByZXJlcXVpc2l0ZXMuIikNCiAgICAgICAgfQ0KICAgIH0NCg0KCVdyaXRlLUxvZyAiQ3JlYXRpbmcgbmV3IFBTRHJpdmUgLi4uIg0KCU5ldy1QU0RyaXZlIC1OYW1lICdQJyAtUFNQcm92aWRlciAnRmlsZVN5c3RlbScgLVJvb3QgJFBhdGggfCBPdXQtTnVsbA0KCVdyaXRlLUxvZyAiQ3JlYXRpbmcgZGVzdGluYXRpb24gZm9sZGVyIC4uLiINCglOZXctSXRlbSAtUGF0aCAkRGVzdGluYXRpb24gLUl0ZW1UeXBlIENvbnRhaW5lciAtRm9yY2UgfCBPdXQtTnVsbA0KCVdyaXRlLUxvZyAiQ29weWluZyBpdGVtcyAuLi4iDQoJQ29weS1JdGVtIC1QYXRoICdQOlxQcmVyZXF1aXNpdGVzXElJUycgLURlc3RpbmF0aW9uICREZXN0aW5hdGlvbiAtUmVjdXJzZSAtRm9yY2UgfCBPdXQtTnVsbA0KCVdyaXRlLUxvZyAiUmVtb3ZpbmcgUFNEcml2ZSAuLi4iDQoJUmVtb3ZlLVBTRHJpdmUgLU5hbWUgJ1AnIC1QU1Byb3ZpZGVyICdGaWxlU3lzdGVtJyAtRm9yY2UgfCBPdXQtTnVsbA0KCQ0KCVdyaXRlLUxvZyAiPC0tIENvcHktUHJlcmVxdWlzaXRlcyINCn0NCg0KDQoNCmZ1bmN0aW9uIEluc3RhbGwtV2ViU2VydmVyIHsNCglwYXJhbSAoDQoJCVtTdHJpbmddICRQcmVyZXF1aXNpdGVzUGF0aA0KCSkNCgkNCglXcml0ZS1Mb2cgIi0tPiBJbnN0YWxsLVdlYlNlcnZlciINCg0KCSRGZWF0dXJlTGlzdCA9IEAoDQoJCSdXZWItU2VydmVyJywNCgkJJ1dlYi1OZXQtRXh0NDUnLA0KCQknV2ViLUFTUCcsDQoJCSdXZWItQXNwLU5ldDQ1JywNCgkJJ1dlYi1JU0FQSS1FeHQnLA0KCQknV2ViLUlTQVBJLUZpbHRlcicsDQoJCSdXZWItSW5jbHVkZXMnDQoJKQ0KCQ0KCSRQcmVyZXF1aXNpdGVzTGlzdCA9IEAoDQoJCSdBc3BOZXRNdmM0U2V0dXAuZXhlJywNCgkJJ1dlYkFwcGxpY2F0aW9ucy5leGUnDQoJKQ0KICAgIA0KCSRQcmVyZXF1aXNpdGVzUGF0aCA9IFtJTy5QYXRoXTo6Q29tYmluZSgkUHJlcmVxdWlzaXRlc1BhdGgsICdJSVMnKQ0KICAgIA0KCVdyaXRlLUxvZyAiVmFsaWRhdGluZyBwcmVyZXF1aXNpdGVzIGJhc2VkIG9uIHRoZSBsaXN0IC4uLiINCglmb3JlYWNoICgkRmlsZU5hbWUgaW4gJFByZXJlcXVpc2l0ZXNMaXN0KSB7DQoJCSRGaWxlUGF0aCA9IFtJTy5QYXRoXTo6Q29tYmluZSgkUHJlcmVxdWlzaXRlc1BhdGgsICRGaWxlTmFtZSkNCgkJaWYgKC1ub3QgKFRlc3QtUGF0aCAtUGF0aCAkRmlsZVBhdGggLVBhdGhUeXBlIExlYWYpKSB7DQoJCQl0aHJvdygiUHJlcmVxdWlzaXRlIGZpbGUgbm90IGZvdW5kOiAnJEZpbGVQYXRoJyIpDQoJCX0NCgl9DQoJDQoJSW1wb3J0LU1vZHVsZSBTZXJ2ZXJNYW5hZ2VyDQoJDQoJV3JpdGUtTG9nICJJbnN0YWxsaW5nIFdlYiBTZXJ2ZXIgLi4uIg0KCUluc3RhbGwtV2luZG93c0ZlYXR1cmUgJEZlYXR1cmVMaXN0IC1JbmNsdWRlTWFuYWdlbWVudFRvb2xzDQoJDQoJV3JpdGUtTG9nICJJbnN0YWxsaW5nIEFzcE5ldE12cDQgLi4uIg0KCSRFeGVjID0gRXhlYyAtRmlsZVBhdGggJChbSU8uUGF0aF06OkNvbWJpbmUoJFByZXJlcXVpc2l0ZXNQYXRoLCAnQXNwTmV0TXZjNFNldHVwLmV4ZScpKSAtQXJndW1lbnRMaXN0ICcvcScgLVBhc3NUaHJ1DQoJaWYgKCRFeGVjLkV4aXRDb2RlIC1uZSAwKSB7DQoJCXRocm93KCJJbnN0YWxsYXRpb24gb2YgJ0FzcE5ldE12YzRTZXR1cC5leGUnIGZhaWxlZC4gUHJvY2VzcyBleGl0IGNvZGUgJyQoJEV4ZWMuRXhpdENvZGUpJyIpDQoJfQ0KCQ0KCSMgRXh0cmFjdCBXZWJBcHBsaWNhdGlvbnMgZm9sZGVyIHdpdGggKi50YXJnZXQgZmlsZXMgdG8NCgkjICAgQzpcUHJvZ3JhbSBGaWxlcyAoeDg2KVxNU0J1aWxkXE1pY3Jvc29mdFxWaXN1YWxTdHVkaW9cdjEwLjANCglXcml0ZS1Mb2cgIkluc3RhbGxpbmcgV2ViQXBwbGljYXRpb24gdGFyZ2V0cyAuLi4iDQoJJFdlYkFwcGxpY2F0aW9uc1RhcmdldHNSb290ID0gJ0M6XFByb2dyYW0gRmlsZXMgKHg4NilcTVNCdWlsZFxNaWNyb3NvZnRcVmlzdWFsU3R1ZGlvXHYxMC4wJw0KCSRudWxsID0gTmV3LUl0ZW0gLVBhdGggJFdlYkFwcGxpY2F0aW9uc1RhcmdldHNSb290IC1JdGVtVHlwZSBDb250YWluZXINCgkkRXhlYyA9IEV4ZWMgLUZpbGVQYXRoICQoW0lPLlBhdGhdOjpDb21iaW5lKCRQcmVyZXF1aXNpdGVzUGF0aCwgJ1dlYkFwcGxpY2F0aW9ucy5leGUnKSkgLUFyZ3VtZW50TGlzdCBAKCItb2AiJFdlYkFwcGxpY2F0aW9uc1RhcmdldHNSb290YCIiLCAnLXknKSAtUGFzc1RocnUNCglpZiAoJEV4ZWMuRXhpdENvZGUgLW5lIDApIHsNCgkJdGhyb3coIkluc3RhbGxhdGlvbiBvZiAnV2ViQXBwbGljYXRpb25zLmV4ZScgZmFpbGVkLiBQcm9jZXNzIGV4aXQgY29kZSAnJCgkRXhlYy5FeGl0Q29kZSknIikNCgl9DQoNCglXcml0ZS1Mb2cgIjwtLSBJbnN0YWxsLVdlYlNlcnZlciINCn0NCg0K"
"ImportCoreFunctions.ps1",
"CopyPrerequisites.ps1",
"InstallIIS.ps1"
],
"Commands": [
{
"Name": "Import-Module",
"Arguments": {
"Name": "CoreFunctions"
}
},
{
"Name": "Copy-Prerequisites",
"Arguments": {

File diff suppressed because one or more lines are too long

View File

@ -1,11 +1,9 @@
{
"Scripts": [
"ImportCoreFunctions.ps1",
"Join-Domain.ps1"
],
"Commands": [
{
"Name": "Import-Module",
"Arguments": {
"Name": "CoreFunctions"
}
},
{
"Name": "Set-NetworkAdapterConfiguration",
"Arguments": {
@ -23,8 +21,5 @@
}
}
],
"RebootOnCompletion": 1,
"Scripts": [
"RnVuY3Rpb24gSm9pbi1Eb21haW4gewo8IwouU1lOT1BTSVMKRXhlY3V0ZXMgIkpvaW4gZG9tYWluIiBhY3Rpb24uCgpSZXF1aXJlcyAnQ29yZUZ1bmN0aW9ucycgbW9kdWxlLgojPgoJcGFyYW0gKAoJCVtTdHJpbmddICREb21haW5OYW1lID0gJycsCgkJW1N0cmluZ10gJFVzZXJOYW1lID0gJycsCgkJW1N0cmluZ10gJFBhc3N3b3JkID0gJycsCgkJW1N0cmluZ10gJE9VUGF0aCA9ICcnLAogICAgICAgIFtTd2l0Y2hdICRBbGxvd1Jlc3RhcnQKCSkKCQoJaWYgKCRVc2VyTmFtZSAtZXEgJycpIHsKCQkkVXNlck5hbWUgPSAnQWRtaW5pc3RyYXRvcicKCX0KCgkkQ3JlZGVudGlhbCA9IE5ldy1DcmVkZW50aWFsIC1Vc2VyTmFtZSAiJERvbWFpbk5hbWVcJFVzZXJOYW1lIiAtUGFzc3dvcmQgJFBhc3N3b3JkCgoJaWYgKFRlc3QtQ29tcHV0ZXJOYW1lIC1Eb21haW5OYW1lICREb21haW5OYW1lKSB7CiAgICAgICAgV3JpdGUtTG9nV2FybmluZyAiQ29tcHV0ZXIgYWxyZWFkeSBqb2luZWQgdG8gZG9tYWluICckRG9tYWluTmFtZSciCgl9CgllbHNlIHsKCQlXcml0ZS1Mb2cgIkpvaW5pbmcgY29tcHV0ZXIgdG8gZG9tYWluICckRG9tYWluTmFtZScgLi4uIgoJCQoJCWlmICgkT1VQYXRoIC1lcSAnJykgewoJCQlBZGQtQ29tcHV0ZXIgLURvbWFpbk5hbWUgJERvbWFpbk5hbWUgLUNyZWRlbnRpYWwgJENyZWRlbnRpYWwgLUZvcmNlIC1FcnJvckFjdGlvbiBTdG9wCgkJfQoJCWVsc2UgewoJCQlBZGQtQ29tcHV0ZXIgLURvbWFpbk5hbWUgJERvbWFpbk5hbWUgLUNyZWRlbnRpYWwgJENyZWRlbnRpYWwgLU9VUGF0aCAkT1VQYXRoIC1Gb3JjZSAtRXJyb3JBY3Rpb24gU3RvcAoJCX0KCQkKICAgICAgICBpZiAoJEFsbG93UmVzdGFydCkgewogICAgICAgICAgICBXcml0ZS1Mb2cgIlJlc3RhcnRpbmcgY29tcHV0ZXIgLi4uIgogICAgICAgICAgICBSZXN0YXJ0LUNvbXB1dGVyIC1Gb3JjZQogICAgICAgIH0KICAgICAgICBlbHNlIHsKICAgICAgICAgICAgV3JpdGUtTG9nICJQbGVhc2UgcmVzdGFydCB0aGUgY29tcHV0ZXIgbm93LiIKICAgICAgICB9Cgl9Cn0K"
]
"RebootOnCompletion": 1
}

View File

@ -1,5 +1,5 @@
{
"Scripts": [],
"Commands": [],
"RebootOnCompletion": 0,
"Scripts": []
}

View File

@ -1,14 +1,9 @@
{
"Scripts": [
"RnVuY3Rpb24gU2V0LUxvY2FsVXNlclBhc3N3b3JkIHsNCiAgICBwYXJhbSAoDQogICAgICAgIFtTdHJpbmddICRVc2VyTmFtZSwNCiAgICAgICAgW1N0cmluZ10gJFBhc3N3b3JkLA0KICAgICAgICBbU3dpdGNoXSAkRm9yY2UNCiAgICApDQogICAgDQogICAgdHJhcCB7IFN0b3AtRXhlY3V0aW9uICRfIH0NCiAgICANCiAgICBpZiAoKEdldC1XbWlPYmplY3QgV2luMzJfVXNlckFjY291bnQgLUZpbHRlciAiTG9jYWxBY2NvdW50ID0gJ1RydWUnIEFORCBOYW1lPSckVXNlck5hbWUnIikgLWVxICRudWxsKSB7DQogICAgICAgIHRocm93ICJVbmFibGUgdG8gZmluZCBsb2NhbCB1c2VyIGFjY291bnQgJyRVc2VyTmFtZSciDQogICAgfQ0KICAgIA0KICAgIGlmICgkRm9yY2UpIHsNCiAgICAgICAgV3JpdGUtTG9nICJDaGFuZ2luZyBwYXNzd29yZCBmb3IgdXNlciAnJFVzZXJOYW1lJyB0byAnKioqKionIiAjIDopDQogICAgICAgIChbQURTSV0gIldpbk5UOi8vLi8kVXNlck5hbWUiKS5TZXRQYXNzd29yZCgkUGFzc3dvcmQpDQogICAgfQ0KICAgIGVsc2Ugew0KICAgICAgICBXcml0ZS1Mb2dXYXJuaW5nICJZb3UgYXJlIHRyeWluZyB0byBjaGFuZ2UgcGFzc3dvcmQgZm9yIHVzZXIgJyRVc2VyTmFtZScuIFRvIGRvIHRoaXMgcGxlYXNlIHJ1biB0aGUgY29tbWFuZCBhZ2FpbiB3aXRoIC1Gb3JjZSBwYXJhbWV0ZXIuIg0KICAgICAgICAkVXNlckFjY291bnQNCiAgICB9DQp9DQoNCg0KDQpGdW5jdGlvbiBJbnN0YWxsLVJvbGVQcmltYXJ5RG9tYWluQ29udHJvbGxlcg0Kew0KPCMNCi5TWU5PUFNJUw0KQ29uZmlndXJlIG5vZGUncyBuZXR3b3JrIGFkYXB0ZXJzLg0KQ3JlYXRlIGZpcnN0IGRvbWFpbiBjb250cm9sbGVyIGluIHRoZSBmb3Jlc3QuDQoNCi5FWEFNUExFDQpQUz4gSW5zdGFsbC1Sb2xlUHJpbWFyeURvbWFpbkNvbnRyb2xsZXIgLURvbWFpbk5hbWUgYWNtZS5sb2NhbCAtU2FmZU1vZGVQYXNzd29yZCAiUEBzc3cwcmQiDQoNCkluc3RhbGwgRE5TIGFuZCBBRERTLCBjcmVhdGUgZm9yZXN0IGFuZCBkb21haW4gJ2FjbWUubG9jYWwnLg0KU2V0IERDIHJlY292ZXJ5IG1vZGUgcGFzc3dvcmQgdG8gJ1BAc3N3MHJkJy4NCiM+DQoJDQoJcGFyYW0NCgkoDQoJCVtTdHJpbmddDQoJCSMgTmV3IGRvbWFpbiBuYW1lLg0KCQkkRG9tYWluTmFtZSwNCgkJDQoJCVtTdHJpbmddDQoJCSMgRG9tYWluIGNvbnRyb2xsZXIgcmVjb3ZlcnkgbW9kZSBwYXNzd29yZC4NCgkJJFNhZmVNb2RlUGFzc3dvcmQNCgkpDQoNCgl0cmFwIHsgU3RvcC1FeGVjdXRpb24gJF8gfQ0KDQogICAgICAgICMgQWRkIHJlcXVpcmVkIHdpbmRvd3MgZmVhdHVyZXMNCglBZGQtV2luZG93c0ZlYXR1cmVXcmFwcGVyIGANCgkJLU5hbWUgIkROUyIsIkFELURvbWFpbi1TZXJ2aWNlcyIsIlJTQVQtREZTLU1nbXQtQ29uIiBgDQoJCS1JbmNsdWRlTWFuYWdlbWVudFRvb2xzIGANCiAgICAgICAgLU5vdGlmeVJlc3RhcnQNCg0KDQoJV3JpdGUtTG9nICJDcmVhdGluZyBmaXJzdCBkb21haW4gY29udHJvbGxlciAuLi4iDQoJCQ0KCSRTTUFQID0gQ29udmVydFRvLVNlY3VyZVN0cmluZyAtU3RyaW5nICRTYWZlTW9kZVBhc3N3b3JkIC1Bc1BsYWluVGV4dCAtRm9yY2UNCgkJDQoJSW5zdGFsbC1BRERTRm9yZXN0IGANCgkJLURvbWFpbk5hbWUgJERvbWFpbk5hbWUgYA0KCQktU2FmZU1vZGVBZG1pbmlzdHJhdG9yUGFzc3dvcmQgJFNNQVAgYA0KCQktRG9tYWluTW9kZSBEZWZhdWx0IGANCgkJLUZvcmVzdE1vZGUgRGVmYXVsdCBgDQoJCS1Ob1JlYm9vdE9uQ29tcGxldGlvbiBgDQoJCS1Gb3JjZSBgDQoJCS1FcnJvckFjdGlvbiBTdG9wIHwgT3V0LU51bGwNCg0KCVdyaXRlLUhvc3QgIldhaXRpbmcgZm9yIHJlYm9vdCAuLi4iCQkNCiMJU3RvcC1FeGVjdXRpb24gLUV4aXRDb2RlIDMwMTAgLUV4aXRTdHJpbmcgIkNvbXB1dGVyIG11c3QgYmUgcmVzdGFydGVkIHRvIGZpbmlzaCBkb21haW4gY29udHJvbGxlciBwcm9tb3Rpb24uIg0KIwlXcml0ZS1Mb2cgIlJlc3RhcmluZyBjb21wdXRlciAuLi4iDQojCVJlc3RhcnQtQ29tcHV0ZXIgLUZvcmNlDQp9DQo="
"ImportCoreFunctions.ps1",
"Set-LocalUserPasswordPassword.ps1"
],
"Commands": [
{
"Name": "Import-Module",
"Arguments": {
"Name": "CoreFunctions"
}
},
{
"Name": "Set-LocalUserPassword",
"Arguments": {

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,50 @@
trap {
&$TrapHandler
}
Function Copy-Prerequisites {
param (
[String] $Path = '',
[String] $Destination = ''
)
begin {
Show-InvocationInfo $MyInvocation
}
end {
Show-InvocationInfo $MyInvocation -End
}
process {
trap {
&$TrapHandler
}
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"
}
}

View File

@ -0,0 +1,148 @@
trap {
&$TrapHandler
}
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 = ""
)
begin {
Show-InvocationInfo $MyInvocation
}
end {
Show-InvocationInfo $MyInvocation -End
}
process {
trap {
&$TrapHandler
}
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())
)
begin {
Show-InvocationInfo $MyInvocation
}
end {
Show-InvocationInfo $MyInvocation -End
}
process {
trap {
&$TrapHandler
}
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

@ -0,0 +1,61 @@
trap {
&$TrapHandler
}
function Export-Function {
param (
[String[]] $Name,
[Parameter(ValueFromPipeline=$true)]
[String] $Path = [IO.Path]::GetTempFileName(),
[Switch] $All
)
if ([IO.Path]::GetExtension($Path) -ne 'ps1') {
$null = Rename-Item -Path $Path -NewName "$Path.ps1" -Force
$Path = "$Path.ps1"
}
$SystemFunctions = @(
'A:', 'B:', 'C:', 'D:', 'E:', 'F:', 'G:', 'H:', 'I:', 'J:',
'K:', 'L:', 'M:', 'N:', 'O:', 'P:', 'Q:', 'R:', 'S:', 'T:',
'U:', 'V:', 'W:', 'X:', 'Y:', 'Z:',
'cd..', 'cd\', 'help', 'mkdir', 'more', 'oss', 'prompt',
'Clear-Host', 'Get-Verb', 'Pause', 'TabExpansion2'
)
if ($All) {
Get-ChildItem Function: |
Where-Object {$_.ModuleName -eq ''} |
Where-Object {$SystemFunctions -notcontains $_.Name} |
ForEach-Object {
Add-Content -Path $Path -Value @"
function $($_.Name) {
$($_.ScriptBlock)
}
"@
}
}
else {
foreach ($FunctionName in $Name) {
$FunctionObject = Get-ChildItem "Function:\$FunctionName"
if ($FunctionObject -ne $null) {
Add-Content -Path $Path -Value @"
function $FunctionName {
$($FunctionObject.ScriptBlock)
}
"@
}
}
}
return $Path
}

View File

@ -0,0 +1,239 @@
<#
.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"
}
foreach ($Node in $ClusterNodes) {
Write-LogDebug "Installing Failover Cluster modules on '$Node' ..."
$null = Invoke-Command `
-ComputerName $Node `
-Credential $Credential `
-ScriptBlock {
Add-WindowsFeature Failover-Clustering, RSAT-Clustering-PowerShell
}
}
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
#>
New-Cluster -Name "$ClusterName" -StaticAddress "$StaticAddress"
Start-Sleep -Seconds 30
}
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
#>
Add-ClusterNode -Cluster "$ClusterName" -Name "$Node"
}
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

@ -0,0 +1,7 @@
function Get-DnsListeningIpAddress {
Import-Module DnsServer
(Get-DNSServer -ComputerName localhost).ServerSetting.ListeningIpAddress |
Where-Object { $_ -match "\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}" }
}

View File

@ -0,0 +1,65 @@
Import-Module CoreFunctions -Force
function Show-InvocationInfo {
param (
$Invocation,
[Switch] $End
)
if ($End) {
Write-LogDebug "</function name='$($Invocation.MyCommand.Name)'>"
}
else {
Write-LogDebug "<function name='$($Invocation.MyCommand.Name)'>"
Write-LogDebug "<param>"
foreach ($Parameter in $Invocation.MyCommand.Parameters) {
foreach ($Key in $Parameter.Keys) {
$Type = $Parameter[$Key].ParameterType.FullName
foreach ($Value in $Invocation.BoundParameters[$Key]) {
Write-LogDebug "[$Type] $Key = '$Value'"
}
}
}
Write-LogDebug "</param>"
}
}
$TrapHandler = {
Write-LogError @("<exception>", $_) -EntireObject
Write-LogError "</exception>"
break
}
trap {
&$TrapHandler
}
$ErrorActionPreference = 'Stop'
<#
# Usage example for Show-InvocationInfo
function MyFunction {
param (
[String] $Value1,
[String] $Value2,
[Int] $Int1
)
begin {
Show-InvocationInfo $MyInvocation
}
end {
Show-InvocationInfo $MyInvocation -End
}
process {
trap {
&$TrapHandler
}
# Main code here
}
}
#>

View File

@ -0,0 +1,43 @@
trap {
&$TrapHandler
}
Function Install-RolePrimaryDomainController {
param (
[String] $DomainName,
[String] $SafeModePassword
)
begin {
Show-InvocationInfo $MyInvocation
}
end {
Show-InvocationInfo $MyInvocation -End
}
process {
trap {
&$TrapHandler
}
Add-WindowsFeatureWrapper `
-Name "DNS","AD-Domain-Services","RSAT-DFS-Mgmt-Con" `
-IncludeManagementTools `
-NotifyRestart
Write-Log "Creating first domain controller ..."
$SMAP = ConvertTo-SecureString -String $SafeModePassword -AsPlainText -Force
$null = Install-ADDSForest `
-DomainName $DomainName `
-SafeModeAdministratorPassword $SMAP `
-DomainMode Default `
-ForestMode Default `
-NoRebootOnCompletion `
-Force
Write-Log "Waiting 60 seconds for reboot ..."
Start-Sleep -Seconds 60
}
}

View File

@ -0,0 +1,69 @@

trap {
&$TrapHandler
}
Function Install-RoleSecondaryDomainController
{
<#
.SYNOPSIS
Install additional (secondary) domain controller.
#>
param
(
[String]
# Domain name to join to.
$DomainName,
[String]
# Domain user who is allowed to join computer to domain.
$UserName,
[String]
# User's password.
$Password,
[String]
# Domain controller recovery mode password.
$SafeModePassword
)
begin {
Show-InvocationInfo $MyInvocation
}
end {
Show-InvocationInfo $MyInvocation -End
}
process {
trap {
&$TrapHandler
}
$Credential = New-Credential -UserName "$DomainName\$UserName" -Password $Password
# Add required windows features
Add-WindowsFeatureWrapper `
-Name "DNS","AD-Domain-Services","RSAT-DFS-Mgmt-Con" `
-IncludeManagementTools `
-NotifyRestart
Write-Log "Adding secondary domain controller ..."
$SMAP = ConvertTo-SecureString -String $SafeModePassword -AsPlainText -Force
Install-ADDSDomainController `
-DomainName $DomainName `
-SafeModeAdministratorPassword $SMAP `
-Credential $Credential `
-NoRebootOnCompletion `
-Force `
-ErrorAction Stop | Out-Null
Write-Log "Waiting for restart ..."
# Stop-Execution -ExitCode 3010 -ExitString "Computer must be restarted to finish domain controller promotion."
# Write-Log "Restarting computer ..."
# Restart-Computer -Force
}
}

View File

@ -0,0 +1,84 @@
trap {
&$TrapHandler
}
Function ConvertTo-Boolean {
param (
$InputObject,
[Boolean] $Default = $false
)
try {
[System.Convert]::ToBoolean($InputObject)
}
catch {
$Default
}
}
Function Show-Environment {
foreach ($item in (Get-ChildItem Env:)) {
Write-Log ("'{0}' --> '{1}'" -f $item.Name, $item.Value)
}
}
Function Install-SqlServer {
param (
[String] $SetupRoot = '',
[String] $SAPassword = '',
[String] $MuranoFileShare = '',
[Switch] $MixedModeAuth = $false,
[Switch] $UpdateEnabled = $false
)
begin {
Show-InvocationInfo $MyInvocation
}
end {
Show-InvocationInfo $MyInvocation -End
}
process {
trap {
&$TrapHandler
}
if ($SetupRoot -eq '') {
if ($MuranoFileShare -eq '') {
$MuranoFileShare = [Environment]::GetEnvironmentVariable('MuranoFileShare')
if ($MuranoFileShare -eq '') {
throw("Unable to find MuranoFileShare path.")
}
}
$SetupRoot = [IO.Path]::Combine($MuranoFileShare, 'Prerequisites\SQL Server\2012')
}
#$MixedModeAuthSwitch = ConvertTo-Boolean $MixedModeAuth
$ExtraOptions = @{}
if ($MixedModeAuth -eq $true) {
$ExtraOptions += @{'SECURITYMODE' = 'SQL'}
if ($SAPassword -eq '') {
throw("SAPassword must be set when MixedModeAuth is requisted!")
}
}
if ($SAPassword -ne '') {
$ExtraOptions += @{'SAPWD' = $SAPassword}
}
if (-not $UpdateEnabled) {
$ExtraOptions += @{'UpdateEnabled' = $false}
}
Show-Environment
New-SqlServer -SetupRoot $SetupRoot -ExtraOptions $ExtraOptions
}
}

View File

@ -0,0 +1,72 @@
trap {
&$TrapHandler
}
Function Install-WebServer {
param (
[String] $PrerequisitesPath
)
begin {
Show-InvocationInfo $MyInvocation
}
end {
Show-InvocationInfo $MyInvocation -End
}
process {
trap {
&$TrapHandler
}
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

@ -0,0 +1,65 @@
trap {
&$TrapHandler
}
Function Join-Domain {
<#
.SYNOPSIS
Executes "Join domain" action.
Requires 'CoreFunctions' module.
#>
param (
[String] $DomainName = '',
[String] $UserName = '',
[String] $Password = '',
[String] $OUPath = '',
[Switch] $AllowRestart
)
begin {
Show-InvocationInfo $MyInvocation
}
end {
Show-InvocationInfo $MyInvocation -End
}
process {
trap {
&$TrapHandler
}
if ($UserName -eq '') {
$UserName = 'Administrator'
}
$Credential = New-Credential -UserName "$DomainName\$UserName" -Password $Password
if (Test-ComputerName -DomainName $DomainName -ErrorAction 'SilentlyContinue') {
Write-LogWarning "Computer already joined to domain '$DomainName'"
}
else {
Write-Log "Joining computer to domain '$DomainName' ..."
if ($OUPath -eq '') {
Add-Computer -DomainName $DomainName -Credential $Credential -Force
}
else {
Add-Computer -DomainName $DomainName -Credential $Credential -OUPath $OUPath -Force
}
Write-Log "Waiting 30 seconds to restart ..."
Start-Sleep -Seconds 30
<#
if ($AllowRestart) {
Write-Log "Restarting computer ..."
Restart-Computer -Force
}
else {
Write-Log "Please restart the computer now."
}
#>
}
}
}

View File

@ -0,0 +1,64 @@
trap {
&$TrapHandler
}
function New-SqlServerSystemAccount {
param (
# (REQUIRED) Domain Name
[Parameter(Mandatory=$true)]
[String] $DomainName,
# (REQUIRED) User name who has permissions to create and modify userPassword
# Usually this is the domain administrator '$domainName\Administrator' account
[Parameter(Mandatory=$true)]
[String] $UserName,
# (REQUIRED) Password for that user
[Parameter(Mandatory=$true)]
[String] $UserPassword,
# (REQUIRED) User name for a new account that will be used to run SQL Server
[Parameter(Mandatory=$true)]
[String] $SQLServiceUserName,
# (REQUIRED) Password for that user
[Parameter(Mandatory=$true)]
[String] $SQLServiceUserPassword,
[String] $PrimaryNode = ' '
)
begin {
Show-InvocationInfo $MyInvocation
}
end {
Show-InvocationInfo $MyInvocation -End
}
process {
trap {
&$TrapHandler
}
if ($PrimaryNode.ToLower() -ne ($Env:ComputerName).ToLower()) {
Write-Log "THis function runs on AOAG primary node only."
Write-Log "Exiting."
return
}
Write-Log "Installing 'RSAT-AD-PowerShell' ... "
Add-WindowsFeature RSAT-AD-PowerShell
Import-Module ActiveDirectory
$Creds = New-Credential -UserName "$DomainName\$UserName" -Password "$UserPassword"
Write-Log "Adding new user ..."
$null = New-ADUser `
-Name $SQLServiceUserName `
-AccountPassword $(ConvertTo-SecureString -String $SQLServiceUserPassword -AsPlainText -Force) `
-Credential $Creds `
-ErrorAction 'Stop'
}
}

View File

@ -0,0 +1,280 @@
function New-Option ([string]$Name, [switch]$Switch, [switch]$Boolean, [switch]$String, [switch]$List, $Constraints=$null) {
<#
.SYNOPSIS
Creates Option object
.DESCRIPTION
Option object is a virtual object represtnting typed command line option. These objects encapsulate escaping and
validation matters.
One and only one of the switches 'Switch', 'Boolean', 'String' or 'List' should be provided.
.PARAMETER Name
Option name as it appears in the command line.
.PARAMETER Switch
Use this switch to create valueless option (a switch).
.PARAMETER Boolean
Use this switch to create boolean option. Its value is always converted to "1" or "0"
.PARAMETER String
Use this switch to create string option. Its value will be properly quoted if necessary.
.PARAMETER List
Use this switch to create option with list value. Values will be put into command line using valid value delemiter (a comma)
.PARAMETER Constraints
When this parameter is specified, option values are limited to options from that list.
#>
$Option = New-Object -TypeName PSObject
# Fields
$Option | Add-Member NoteProperty Type -value $null
$Option | Add-Member NoteProperty Name -value $null
$Option | Add-Member NoteProperty AllowedValues -value $null
# Init
$Option | Add-Member ScriptMethod __init__ {
param([string]$Name, $Switch, $Boolean, $String, $List)
$this.Name = $Name
# With respect for our developers we do not check for double type selected
if ($Switch) {
AugmentOptionSwitch($this)
} elseif ($Boolean) {
AugmentOptionBoolean($this)
} elseif ($String) {
AugmentOptionString($this)
} elseif ($List) {
AugmentOptionList($this)
} else {
throw "Switch, Boolean, String or List option type must be provided for option '$Name'"
}
}
$Option | Add-Member ScriptMethod __post_init__ {
param($Constraints=$null)
if ($Constraints -ne $null) {
$this.AllowedValues = @()
$this.AllowedValues = $this.AllowedValues + $Constraints
} else {
$Constraints = $null
}
}
# Methods
$Option | Add-Member -Force ScriptMethod Validate {
if ($this.AllowedValues -ne $null) {
if (-not($this.AllowedValues -contains $this.Value)) {
$Cts = $this.AllowedValues -join ','
throw "Option '$($this.Name)' may have values ($Cts) but not '$($this.Value)'"
}
}
}
$Option | Add-Member -Force ScriptMethod ToString {
return "/$($this.Name)"
}
# invoke constructor
$Option.__init__($Name, $Switch, $Boolean, $String, $List)
$Option.__post_init__($Constraints)
return $Option
}
function AugmentOptionSwitch($Option) {
}
function AugmentOptionBoolean($Option) {
# Fields
$Option | Add-Member NoteProperty Value -value $false
# Methods
$Option | Add-Member -Force ScriptMethod ToString {
if ($this.Value) {
return "/$($this.Name)=1"
} else {
return "/$($this.Name)=0"
}
}
}
function AugmentOptionString($Option) {
# Fields
$Option | Add-Member NoteProperty Value -value ""
# Methods
$Option | Add-Member -Force ScriptMethod ToString {
$v = "$($this.Value)"
if ($v -match '.* .*') {
# TODO: Escape double quote characters if possible
return "/$($this.Name)=`"$v`""
} else {
return "/$($this.Name)=$v"
}
}
}
function AugmentOptionList($Option) {
# Fields
$Option | Add-Member NoteProperty Value -value @()
# Methods
$Option | Add-Member -Force ScriptMethod Validate {
if ($this.AllowedValues -ne $null) {
foreach ($V in $this.Value) {
if (-not($this.AllowedValues -contains $V)) {
$Cts = $this.AllowedValues -join ','
throw "Option '$($this.Name)' may have values ($Cts) but not '$V'"
}
}
}
}
$Option | Add-Member -Force ScriptMethod ToString {
return "/$($this.Name)=$($this.Value -join ',')"
}
}
function New-OptionParser() {
<#
.SYNOPSIS
Creates OptionParser object.
.DESCRIPTION
OptionParser object leverages Option objects capabilities and builds valid command line using specified options.
An application may also be invoked with OptionParser.
#>
$OptionParser = New-Object -TypeName PSObject
# Fields
$OptionParser | Add-Member NoteProperty Options -value @{}
$OptionParser | Add-Member NoteProperty Defaults -value @{}
$OptionParser | Add-Member NoteProperty RequiredOptions -value @()
# Methods
$OptionParser | Add-Member ScriptMethod AddOption {
<#
.SYNOPSIS
Adds supported option into OptionParser.
.DESCRIPTION
OptionParser does not allow using unrecognized options. Use this method to fill OptionParser with recognized options
.PARAMETER Option
Option object
.PARAMETER Required
Required option switch
.PARAMETER Default
Option default value
#>
param($Option, [bool]$Required=$false, $Default=$null)
$this.Options.Add($Option.Name, $Option)
if ($Required) {
$this.RequiredOptions = $this.RequiredOptions + $Option.Name
if ($Option | Get-Member "Value") {
if ($Default) {
$this.Defaults.Add($Option.Name, $Default)
}
} else {
$this.Defaults.Add($Option.Name, $null)
}
}
}
$OptionParser | Add-Member ScriptMethod Parse {
<#
.SYNOPSIS
Parses supplied options and returns command line parameters array.
.DESCRIPTION
This method verifies that only supported options are provided, all mandatory options are in place,
all option meet constraints if any. Unspecified options with default values are added to command line.
So, mandatory option with default value never causes exception.
.PARAMETER Options
A hash map of options to parse. Option names should be mapped to corresponding values.
#>
param([hashtable]$Options)
$CommandLine = @()
foreach ($RequiredOptionName in $this.RequiredOptions) {
if (-not $Options.ContainsKey($RequiredOptionName)) {
$Default = $this.Defaults.Get_Item($RequiredOptionName)
if ($this.Defaults.ContainsKey($RequiredOptionName)) {
$Options.Add($RequiredOptionName, $this.Defaults.Get_Item($RequiredOptionName))
} else {
throw "Required option '$RequiredOptionName' is missing"
}
}
}
foreach ($OptionName in $($Options.keys)) {
$Option = $this.Options.Get_Item($OptionName)
if ($Option -eq $null) {
throw "Option '$OptionName' is not allowed"
}
if ($Option | Get-Member "Value") {
$Option.Value = $Options.Get_Item($OptionName)
}
$Option.Validate()
$CommandLine = $CommandLine + $Option.ToString()
}
return $CommandLine
}
$OptionParser | Add-Member ScriptMethod ExecuteBinary {
param($Binary, [hashtable]$Options = @{}, $CommandLineSuffix = @())
<#
.SYNOPSIS
Executes binary with a command line constructed from provided options. An arbitrary suffix may be
appended to the command line.
.DESCRIPTION
This method uses OptionParser.Parse method to construct command line. If there a command line suffix
was supplied, it is appended to the end of command line. Normally command line suffix should contain
leading space character.
Method waits for executable process to complete and returns its exit code.
.PARAMETER Binary
Full or relative path to the executable to run.
.PARAMETER Options
A hash map of options to pass to the executable.
.PARAMETER CommandLineSuffix
Arbitrary command line suffix. Normally it shoud have leading space character.
#>
$Binary = Get-Item $Binary
$CommandLine = $this.Parse($Options)
if ($CommandLineSuffix) {
$CommandLine = $CommandLine + $CommandLineSuffix
}
Write-Log "Executing: $($Binary.FullName) $($CommandLine -join ' ')"
$process = [System.Diagnostics.Process]::Start($Binary, $CommandLine)
$process.WaitForExit()
$process.Refresh()
return $process.ExitCode
}
return $OptionParser
}

View File

@ -0,0 +1,538 @@
trap {
&$TrapHandler
}
function Install-SqlServerPowerShellModule {
param (
[String] $SetupRoot = ''
)
begin {
Show-InvocationInfo $MyInvocation
}
end {
Show-InvocationInfo $MyInvocation -End
}
process {
trap {
&$TrapHandler
}
if ((Get-Module SQLPS -ListAvailable) -ne $null) {
Write-Log "Module SQLSP already installed."
return
}
if ($MuranoFileShare -eq '') {
$MuranoFileShare = [String]([Environment]::GetEnvironmentVariable('MuranoFileShare'))
if ($MuranoFileShare -eq '') {
throw "Unable to find MuranoFileShare path."
}
}
Write-LogDebug "MuranoFileShare = '$MuranoFileShare'"
if ($SetupRoot -eq '') {
$SetupRoot = [IO.Path]::Combine("$MuranoFileShare", 'Prerequisites\SQL Server\Tools')
}
Write-LogDebug "SetupRoot = '$SetupRoot'"
$FileList = @(
'SQLSysClrTypes.msi',
'SharedManagementObjects.msi',
'PowerShellTools.msi'
)
foreach ($MsiFile in $FileList) {
Write-Log "Trying to install '$MsiFile' ..."
$MsiPath = Join-Path $SetupRoot $MsiFile
if ([IO.File]::Exists($MsiPath)) {
Write-Log "Starting msiexe ..."
$Result = Exec -FilePath "msiexec.exe" -ArgumentList @('/i', "`"$MsiPath`"", '/quiet') -PassThru
if ($Result.ExitCode -ne 0) {
throw "Installation of MSI package '$MsiPath' failed with error code '$($Result.ExitCode)'"
}
}
else {
Write-Log "File '$MsiPath' not found."
}
}
}
}
function Install-SqlServerForAOAG {
param (
# Path to folder where msi files for additional SQL features are located
[String] $SetupRoot = '',
# Path to folder where msi files for additional SQLPS module are located
[String] $SqlpsSetupRoot = '',
[String] $MuranoFileShare = '',
# (REQUIRED) Domain name
[String] $SQLServiceUserDomain = 'fc-acme.local',
# (REQUIRED) User name for the account which will be used by SQL service
[String] $SQLServiceUserName = 'Administrator',
# (REQUIRED) Password for that user
[String] $SQLServiceUserPassword = 'P@ssw0rd',
[Switch] $UpdateEnabled
)
begin {
Show-InvocationInfo $MyInvocation
}
end {
Show-InvocationInfo $MyInvocation -End
}
process {
trap {
&$TrapHandler
}
if ($MuranoFileShare -eq '') {
$MuranoFileShare = [String]([Environment]::GetEnvironmentVariable('MuranoFileShare'))
if ($MuranoFileShare -eq '') {
throw "Unable to find MuranoFileShare path."
}
}
Write-LogDebug "MuranoFileShare = '$MuranoFileShare'"
if ($SetupRoot -eq '') {
$SetupRoot = [IO.Path]::Combine("$MuranoFileShare", 'Prerequisites\SQL Server\2012')
}
Write-LogDebug "SetupRoot = '$SetupRoot'"
$ExtraOptions = @{}
if ($UpdateEnabled) {
$ExtraOptions += @{'UpdateEnabled' = $true}
}
else {
$ExtraOptions += @{'UpdateEnabled' = $false}
}
$null = New-SQLServerForAOAG `
-SetupRoot $SetupRoot `
-SQLSvcUsrDomain $SQLServiceUserDomain `
-SQLSvcUsrName $SQLServiceUserName `
-SQLSvcUsrPassword $SQLServiceUserPassword `
-ExtraOptions $ExtraOptions
}
}
function Initialize-AlwaysOnAvailabilityGroup {
param (
[String] $DomainName,
[String] $DomainAdminAccountName,
[String] $DomainAdminAccountPassword,
[String] $SqlServiceAccountName,
[String] $PrimaryNode,
[String] $ShareName = 'SharedWorkDir'
)
begin {
Show-InvocationInfo $MyInvocation
}
end {
Show-InvocationInfo $MyInvocation -End
}
process {
trap {
&$TrapHandler
}
$ShareNetworkPath = '\\' + $PrimaryNode + '\' + $ShareName
$DomainAdminAccountCreds = New-Credential `
-UserName "$DomainName\$DomainAdminAccountName" `
-Password "$DomainAdminAccountPassword"
$FunctionsFile = Export-Function 'Get-NextFreePort', 'Initialize-AlwaysOn'
$null = Start-PowerShellProcess @"
trap {
`$_
exit 1
}
Import-Module CoreFunctions
Write-Log "Importing functions file '$FunctionsFile' ..."
. "$FunctionsFile"
Write-Log "Starting 'Initialize-AlwaysOn' ..."
`$XmlFile = [IO.Path]::Combine("$ShareNetworkPath", "`$(`$Env:ComputerName).xml")
Write-Log "Output XML file is '`$XmlFile'"
Initialize-AlwaysOn | Export-CliXml -Path `$XmlFile
"@ -Credential $DomainAdminAccountCreds -NoBase64
}
}
function New-SharedFolderForAOAG {
param (
# (OPTIONAL)
[String] $SharePath = [IO.Path]::Combine($Env:SystemDrive + '\', 'SharedWorkDir'),
# (OPTIONAL)
[String] $ShareName = 'SharedWorkDir',
[String] $PrimaryNode = ' '
)
begin {
Show-InvocationInfo $MyInvocation
}
end {
Show-InvocationInfo $MyInvocation -End
}
process {
trap {
&$TrapHandler
}
if ($PrimaryNode.ToLower() -ne ($Env:ComputerName).ToLower()) {
Write-Log "This script runs on primary node only."
Write-Log "Exiting script."
return
}
if ($ShareName -eq '') {
$ShareName = [IO.Path]::GetFileNameWithoutExtension($SharePath)
}
Write-LogDebug "SharePath = '$SharePath'"
Write-LogDebug "ShareName = '$ShareName'"
try {
Write-LogDebug "Trying to remove share '$ShareName'"
$null = Get-SmbShare -Name $ShareName -ErrorAction 'Stop'
$null = Remove-SmbShare -Name $ShareName -Force
write-Log "Share '$ShareName' removed."
}
catch {
Write-LogWarning "Share '$ShareName' not exists or cannot be deleted."
}
try {
Write-LogDebug "Trying to remove folder '$SharePath"
$null = Get-Item -Path $SharePath -ErrorAction 'Stop'
$null = Remove-Item -Path $SharePath -Recurse -Force
Write-Log "Folder '$SharePath' removed."
}
catch {
Write-LogWarning "Folder '$SharePath' not exists or cannot be deleted."
}
$null = New-Item -Path $SharePath -ItemType Container -Force
$null = New-SmbShare -Path $SharePath `
-Name $ShareName `
-FullAccess "Everyone" `
-Description "Shared folder for AlwaysOn Availability Group setup."
return '\\' + $Env:ComputerName + '\' + $ShareName
}
}
function New-DatabaseForAOAG {
param (
[String] $DatabaseName,
[String] $DomainName,
[String] $UserName,
[String] $UserPassword
)
$Creds = New-Credential -UserName "$DomainName\$UserName" -Password "$UserPassword"
$FunctionsFile = Export-Function 'Invoke-SQLText', 'ConvertTo-SQLName', 'ConvertTo-SQLString', 'New-SQLDatabase'
Start-PowerShellProcess @"
trap {
`$_
exit 1
}
Import-Module CoreFunctions
Write-Log "Importing functions from file '$FunctionsFile' ..."
. "$FunctionsFile"
Write-Log "Starting 'New-SQLDatabase' ..."
New-SQLDatabase $DatabaseName
"@ -Credential $Creds -NoBase64
}
function Initialize-AOAGPrimaryReplica {
param (
# (OPTIONAL) Name of the new Availability Group. If not specified then default name will be used.
[String] $GroupName = 'MuranoAG',
# (REQUIRED) Nodes that will be configured as replica partners.
#[Parameter(Mandatory=$true)]
[String[]] $NodeList,
# (REQUIRED) Node name that will be primary for selected Availability Group
#[Parameter(Mandatory=$true)]
[String] $PrimaryNode,
# (REQUIRED) Database list that will be added to the Availability Group
#[Parameter(Mandatory=$true)]
[String[]] $DatabaseList,
# (REQUIRED) Listener name that will be used by clients to connect to databases in that AG
#[Parameter(Mandatory=$true)]
[String] $ListenerName = 'MuranoAG_Listener',
# (REQUIRED) IP address of the listener
#[Parameter(Mandatory=$true)]
[String] $ListenerIP,
[String] $ListenerIPMask = '255.255.255.0',
[String] $ListenerPort = '5023',
# Sync Mode Node List
[String[]] $SyncModeNodeList,
[String] $SharedWorkDir = 'SharedWorkDir',
[String] $CliXmlFile = '',
[String] $DomainName,
[String] $UserName,
[String] $UserPassword
)
begin {
Show-InvocationInfo $MyInvocation
}
end {
Show-InvocationInfo $MyInvocation -End
}
process {
trap {
&$TrapHandler
}
Write-Log "Primary node: '$($PrimaryNode.ToLower())'"
Write-Log "Current node: '$(($Env:ComputerName).ToLower())'"
if ($PrimaryNode.ToLower() -ne $($Env:ComputerName).ToLower()) {
Write-Log "This function works on PrimaryNode only."
Write-Log "Exiting."
return
}
if ($CliXmlFile -eq '') {
$ReplicaDefinitionList = @()
foreach ($Node in $NodeList) {
try {
$NodeEndpointPort = Import-CliXml -Path "\\$PrimaryNode\SharedWorkDir\$Node.xml"
}
catch {
Write-Log "Using default endpoint port 5022"
$NodeEndpointPort = 5022
}
$ReplicaDefinition = @{
"SERVER_INSTANCE" = "$Node";
"ENDPOINT_URL" = "TCP://${Node}:${NodeEndpointPort}";
"AVAILABILITY_MODE" = "ASYNCHRONOUS_COMMIT";
"FAILOVER_MODE"="MANUAL";
}
if ($SyncModeNodeList -contains $Node) {
Write-Log "$Node is in SyncModeNodeList"
$ReplicaDefinition['AVAILABILITY_MODE'] = "SYNCHRONOUS_COMMIT"
$ReplicaDefinition['FAILOVER_MODE'] = "AUTOMATIC"
}
else {
Write-Log "$Node is NOT in SyncModeNodeList"
}
$ReplicaDefinitionList += @($ReplicaDefinition)
}
$Preferences = @{}
$ListenerDefinition = @{
"NAME"=$ListenerName;
"PORT" = "$ListenerPort";
"STATIC" = "$ListenerIP/$ListenerIPMask"
}
$Parameters = @{
'WorkDir' = "\\$PrimaryNode\$SharedWorkDir";
'Name' = $GroupName;
'DatabaseNames' = $DatabaseList;
'ReplicaDefs' = $ReplicaDefinitionList;
'Preferences' = $Preferences;
'ListenerDef' = $ListenerDefinition;
}
$null = Remove-Item -Path "\\$PrimaryNode\SharedWorkDir\*" -Force
$CliXmlFile = [IO.Path]::GetTempFileName()
Write-LogDebug "CliXml file: '$CliXmlFile'"
$null = Export-CliXml -Path $CliXmlFile -InputObject $Parameters -Depth 10
$null = Initialize-AOAGPrimaryReplica `
-CliXmlFile $CliXmlFile `
-DomainName $DomainName `
-UserName $UserName `
-UserPassword $UserPassword `
-PrimaryNode $PrimaryNode
Write-LogDebug "Inner 'Initialize-AOAGPrimaryReplica' call completed."
}
else {
$Creds = New-Credential -UserName "$DomainName\$UserName" -Password "$UserPassword"
$FunctionsFile = Export-Function -All
$null = Start-PowerShellProcess @"
trap {
`$_
exit 1
}
Import-Module CoreFunctions
Write-Log "Importing functions from '$FunctionsFile' ..."
. "$FunctionsFile"
Write-Log "Importing CliXml parameters file ..."
`$Parameters = Import-CliXml -Path $CliXmlFile
Write-Log "Starting 'New-AlwaysOnAvailabilityGroup' ..."
New-AlwaysOnAvailabilityGroup ``
-WorkDir `$Parameters['WorkDir'] ``
-Name `$Parameters['Name'] ``
-DatabaseNames `$Parameters['DatabaseNames'] ``
-ReplicaDefs `$Parameters['ReplicaDefs'] ``
-Preferences `$Parameters['Preferences'] ``
-ListenerDef `$Parameters['ListenerDef']
"@ -Credential $Creds -NoBase64
}
}
}
function Initialize-AOAGSecondaryReplica {
param (
# (REQUIRED) Nodes that will be configured as replica partners.
[Parameter(Mandatory=$true)]
[String[]] $NodeList,
# (REQUIRED) Node name that will be primary for selected Availability Group
[Parameter(Mandatory=$true)]
[String] $PrimaryNode,
[String] $SharedWorkDir = 'SharedWorkDir',
[String] $DomainName,
[String] $UserName,
[String] $UserPassword
)
begin {
Show-InvocationInfo $MyInvocation
}
end {
Show-InvocationInfo $MyInvocation -End
}
process {
trap {
&$TrapHandler
}
if ($PrimaryNode.ToLower() -eq ($Env:ComputerName).ToLower()) {
Write-Log "This function works on any SecondaryNode only."
Write-Log "Exiting."
return
}
$Creds = New-Credential -UserName "$DomainName\$UserName" -Password "$UserPassword"
$FunctionsFile = Export-Function -All
$null = Start-PowerShellProcess @"
trap {
$_
exit 1
}
Import-Module CoreFunctions
Write-Log "Importing functions from '$FunctionsFile' ..."
. "$FunctionsFile"
Write-Log "Starting 'New-AlwaysOnAvailabilityGroupReplica' ..."
New-AlwaysOnAvailabilityGroupReplica -WorkDir "\\$PrimaryNode\$SharedWorkDir"
"@ -Credential $Creds -NoBase64
}
}
function Disable-Firewall {
begin {
Show-InvocationInfo $MyInvocation
}
end {
Show-InvocationInfo $MyInvocation -End
}
process {
trap {
&$TrapHandler
}
netsh advfirewall set allprofiles state off
}
}
function Enable-Firewall {
begin {
Show-InvocationInfo $MyInvocation
}
end {
Show-InvocationInfo $MyInvocation -End
}
process {
trap {
&$TrapHandler
}
netsh advfirewall set allprofiles state on
}
}
function Enable-TrustedHosts {
begin {
Show-InvocationInfo $MyInvocation
}
end {
Show-InvocationInfo $MyInvocation -End
}
process {
trap {
&$TrapHandler
}
Set-Item WSMan:\localhost\Client\TrustedHosts -Value '*' -Force
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,367 @@
function New-OptionParserInstall {
<#
.SYNOPSIS
Creates an option parser for MS SQL Server 2012 setup "INSTALL" action.
.DESCRIPTION
Use this cmdlet to create an option parser for MS SQL Server 2012 setup "INSTALL" action.
All documented option are supported. See the following link for details:
http://msdn.microsoft.com/en-us/library/ms144259.aspx
#>
$OptionParser = New-OptionParser
$IsPartOfDomain = (Get-WmiObject Win32_ComputerSystem).PartOfDomain
$OptionParser.AddOption((New-Option "ACTION" -String -Constraints "INSTALL"), $true, "INSTALL")
$OptionParser.AddOption((New-Option "IACCEPTSQLSERVERLICENSETERMS" -Switch), $true)
$OptionParser.AddOption((New-Option "ENU" -Switch))
#$OptionParser.AddOption((New-Option "UpdateEnabled" -Switch))
$OptionParser.AddOption((New-Option "UpdateEnabled" -Boolean))
$OptionParser.AddOption((New-Option "UpdateSource" -String))
$OptionParser.AddOption((New-Option "CONFIGURATIONFILE" -String))
$OptionParser.AddOption((New-Option "ERRORREPORTING" -Boolean))
$OptionParser.AddOption((New-Option "FEATURES" -List -Constraints ("SQL","SQLEngine","Replication","FullText","DQ","AS","RS","DQC","IS","MDS","Tools","BC","BOL","BIDS","Conn","SSMS","ADV_SSMS","DREPLAY_CTLR","DREPLAY_CLT","SNAC_SDK","SDK","LocalDB")))
$OptionParser.AddOption((New-Option "ROLE" -String -Constraints ("SPI_AS_ExistingFarm", "SPI_AS_NewFarm", "AllFeatures_WithDefaults")))
$OptionParser.AddOption((New-Option "INDICATEPROGRESS" -Switch))
$OptionParser.AddOption((New-Option "INSTALLSHAREDDIR" -String))
$OptionParser.AddOption((New-Option "INSTALLSHAREDWOWDIR" -String))
$OptionParser.AddOption((New-Option "INSTANCEDIR" -String))
$OptionParser.AddOption((New-Option "INSTANCEID" -String))
$OptionParser.AddOption((New-Option "INSTANCENAME" -String), $true, "MSSQLSERVER")
$OptionParser.AddOption((New-Option "PID" -String))
$OptionParser.AddOption((New-Option "Q" -Switch))
$OptionParser.AddOption((New-Option "QS" -Switch))
$OptionParser.AddOption((New-Option "UIMODE" -String -Constraints ("Normal", "AutoAdvance")))
$OptionParser.AddOption((New-Option "SQMREPORTING" -Boolean))
$OptionParser.AddOption((New-Option "HIDECONSOLE" -Switch))
$OptionParser.AddOption((New-Option "AGTSVCACCOUNT" -String), $true, "NT AUTHORITY\Network Service")
$OptionParser.AddOption((New-Option "AGTSVCPASSWORD" -String))
$OptionParser.AddOption((New-Option "AGTSVCSTARTUPTYPE" -String -Constraints ("Manual", "Automatic", "Disabled")))
$OptionParser.AddOption((New-Option "ASBACKUPDIR" -String))
$OptionParser.AddOption((New-Option "ASCOLLATION" -String))
$OptionParser.AddOption((New-Option "ASCONFIGDIR" -String))
$OptionParser.AddOption((New-Option "ASDATADIR" -String))
$OptionParser.AddOption((New-Option "ASLOGDIR" -String))
$OptionParser.AddOption((New-Option "ASSERVERMODE" -String -Constraints ("MULTIDIMENSIONAL", "POWERPIVOT", "TABULAR")))
$OptionParser.AddOption((New-Option "ASSVCACCOUNT" -String), $true, "NT AUTHORITY\Network Service")
$OptionParser.AddOption((New-Option "ASSVCPASSWORD" -String))
$OptionParser.AddOption((New-Option "ASSVCSTARTUPTYPE" -String -Constraints ("Manual", "Automatic", "Disabled")))
#$OptionParser.AddOption((New-Option "ASSYSADMINACCOUNTS" -String), $true, "$ENV:USERDOMAIN\$ENV:USERNAME")
if ($IsPartOfDomain) {
$OptionParser.AddOption((New-Option "ASSYSADMINACCOUNTS" -String), $true, "$Env:USERDOMAIN\Administrator")
}
else {
$OptionParser.AddOption((New-Option "ASSYSADMINACCOUNTS" -String), $true, "$Env:COMPUTERNAME\Administrator")
}
$OptionParser.AddOption((New-Option "ASTEMPDIR" -String))
$OptionParser.AddOption((New-Option "ASPROVIDERMSOLAP" -Boolean))
$OptionParser.AddOption((New-Option "FARMACCOUNT" -String))
$OptionParser.AddOption((New-Option "FARMPASSWORD" -String))
$OptionParser.AddOption((New-Option "PASSPHRASE" -String))
$OptionParser.AddOption((New-Option "FARMADMINIPORT" -String))
$OptionParser.AddOption((New-Option "BROWSERSVCSTARTUPTYPE" -String -Constraints ("Manual", "Automatic", "Disabled")))
$OptionParser.AddOption((New-Option "ENABLERANU" -Switch))
$OptionParser.AddOption((New-Option "INSTALLSQLDATADIR" -String))
$OptionParser.AddOption((New-Option "SAPWD" -String))
$OptionParser.AddOption((New-Option "SECURITYMODE" -String -Constrainrs ("SQL")))
$OptionParser.AddOption((New-Option "SQLBACKUPDIR" -String))
$OptionParser.AddOption((New-Option "SQLCOLLATION" -String))
$OptionParser.AddOption((New-Option "ADDCURRENTUSERASSQLADMIN" -Switch))
$OptionParser.AddOption((New-Option "SQLSVCACCOUNT" -String), $true, "NT AUTHORITY\Network Service")
$OptionParser.AddOption((New-Option "SQLSVCPASSWORD" -String))
$OptionParser.AddOption((New-Option "SQLSVCSTARTUPTYPE" -String -Constraints ("Manual", "Automatic", "Disabled")))
#$OptionParser.AddOption((New-Option "SQLSYSADMINACCOUNTS" -String), $true, "$ENV:USERDOMAIN\$ENV:USERNAME")
if ($IsPartOfDomain) {
$OptionParser.AddOption((New-Option "SQLSYSADMINACCOUNTS" -String), $true, "$ENV:USERDOMAIN\Administrator")
}
else {
$OptionParser.AddOption((New-Option "SQLSYSADMINACCOUNTS" -String), $true, "$ENV:COMPUTERNAME\Administrator")
}
$OptionParser.AddOption((New-Option "SQLTEMPDBDIR" -String))
$OptionParser.AddOption((New-Option "SQLTEMPDBLOGDIR" -String))
$OptionParser.AddOption((New-Option "SQLUSERDBDIR" -String))
$OptionParser.AddOption((New-Option "SQLUSERDBLOGDIR" -String))
$OptionParser.AddOption((New-Option "FILESTREAMLEVEL" -String -Constraints ("0", "1", "2", "3")))
$OptionParser.AddOption((New-Option "FILESTREAMSHARENAME" -String))
$OptionParser.AddOption((New-Option "FTSVCACCOUNT" -String))
$OptionParser.AddOption((New-Option "FTSVCPASSWORD" -String))
$OptionParser.AddOption((New-Option "ISSVCACCOUNT" -String), $true, "NT AUTHORITY\Network Service")
$OptionParser.AddOption((New-Option "ISSVCPASSWORD" -String))
$OptionParser.AddOption((New-Option "ISSVCStartupType" -String -Constraints ("Manual", "Automatic", "Disabled")))
$OptionParser.AddOption((New-Option "NPENABLED" -Boolean))
$OptionParser.AddOption((New-Option "TCPENABLED" -Boolean))
$OptionParser.AddOption((New-Option "RSINSTALLMODE" -String -Constraints ("SharePointFilesOnlyMode", "DefaultNativeMode", "FilesOnlyMode")))
$OptionParser.AddOption((New-Option "RSSVCACCOUNT" -String), $true, "NT AUTHORITY\Network Service")
$OptionParser.AddOption((New-Option "RSSVCPASSWORD" -String))
$OptionParser.AddOption((New-Option "RSSVCStartupType" -String -Constraints ("Manual", "Automatic", "Disabled")))
return $OptionParser
}
function New-OptionParserPrepareImage {
<#
.SYNOPSIS
Creates an option parser for MS SQL Server 2012 setup "PrepareImage" action.
.DESCRIPTION
Use this cmdlet to create an option parser for MS SQL Server 2012 setup "PrepareImage" action.
Note that for installer version of MS SQL Server prior to 2012 SP1 Cumulative Update 2 only the
following features are supported: SQLEngine, Replication, FullText, RS
All documented option are supported. See the following link for details:
http://msdn.microsoft.com/en-us/library/ms144259.aspx
#>
$OptionParser = New-OptionParser
$OptionParser.AddOption((New-Option "ACTION" -String -Constraints "PrepareImage"), $true, "PrepareImage")
$OptionParser.AddOption((New-Option "IACCEPTSQLSERVERLICENSETERMS" -Switch), $true)
$OptionParser.AddOption((New-Option "ENU" -Switch))
$OptionParser.AddOption((New-Option "UpdateEnabled" -Switch))
$OptionParser.AddOption((New-Option "UpdateSource" -String))
$OptionParser.AddOption((New-Option "CONFIGURATIONFILE" -String))
# $OptionParser.AddOption((New-Option "FEATURES" -List -Constraints ("SQLEngine","Replication","FullText","RS")))
$OptionParser.AddOption((New-Option "FEATURES" -List -Constraints ("SQL","SQLEngine","Replication","FullText","DQ","AS","RS","DQC","IS","MDS","Tools","BC","BOL","BIDS","Conn","SSMS","ADV_SSMS","DREPLAY_CTLR","DREPLAY_CLT","SNAC_SDK","SDK","LocalDB")))
$OptionParser.AddOption((New-Option "HIDECONSOLE" -Switch))
$OptionParser.AddOption((New-Option "INDICATEPROGRESS" -Switch))
$OptionParser.AddOption((New-Option "INSTALLSHAREDDIR" -String))
$OptionParser.AddOption((New-Option "INSTANCEDIR" -String))
$OptionParser.AddOption((New-Option "INSTANCEID" -String), $true, "MSSQLSERVER")
$OptionParser.AddOption((New-Option "Q" -Switch))
$OptionParser.AddOption((New-Option "QS" -Switch))
return $OptionParser
}
function New-OptionParserPrepareImageSP1U2 {
<#
.SYNOPSIS
Creates an option parser for MS SQL Server 2012 setup "PrepareImage" action.
.DESCRIPTION
Use this cmdlet to create an option parser for MS SQL Server 2012 setup "PrepareImage" action.
This cmdlet should be used only for MS SQL Server 2012 SP1 Cimilative Update 2 or later.
Note that for installer version of MS SQL Server prior to 2012 SP1 Cimilative Update 2 only the
following features are supported: SQLEngine, Replication, FullText, RS
All documented option are supported. See the following link for details:
http://msdn.microsoft.com/en-us/library/ms144259.aspx
#>
$OptionParser = New-OptionParser
$OptionParser.AddOption((New-Option "ACTION" -String -Constraints "PrepareImage"), $true, "PrepareImage")
$OptionParser.AddOption((New-Option "IACCEPTSQLSERVERLICENSETERMS" -Switch), $true)
$OptionParser.AddOption((New-Option "ENU" -Switch))
$OptionParser.AddOption((New-Option "UpdateEnabled" -Switch))
$OptionParser.AddOption((New-Option "UpdateSource" -String))
$OptionParser.AddOption((New-Option "CONFIGURATIONFILE" -String))
$OptionParser.AddOption((New-Option "FEATURES" -List -Constraints ("SQL","SQLEngine","Replication","FullText","DQ","AS","RS","DQC","IS","MDS","Tools","BC","BOL","BIDS","Conn","SSMS","ADV_SSMS","SNAC_SDK","SDK","LocalDB")))
$OptionParser.AddOption((New-Option "HIDECONSOLE" -Switch))
$OptionParser.AddOption((New-Option "INDICATEPROGRESS" -Switch))
$OptionParser.AddOption((New-Option "INSTALLSHAREDDIR" -String))
$OptionParser.AddOption((New-Option "INSTANCEDIR" -String))
$OptionParser.AddOption((New-Option "INSTANCEID" -String), $true, "MSSQLSERVER")
$OptionParser.AddOption((New-Option "Q" -Switch))
$OptionParser.AddOption((New-Option "QS" -Switch))
return $OptionParser
}
function New-OptionParserCompleteImage {
<#
.SYNOPSIS
Creates an option parser for MS SQL Server 2012 setup "CompleteImage" action.
.DESCRIPTION
Use this cmdlet to create an option parser for MS SQL Server 2012 setup "CompleteImage" action.
Note that INSTANCEID parameter value MUST be the same as specified on "PrepareImage" phase.
All documented option are supported. See the following link for details:
http://msdn.microsoft.com/en-us/library/ms144259.aspx
#>
$OptionParser = New-OptionParser
$OptionParser.AddOption((New-Option "ACTION" -String -Constraints "CompleteImage"), $true, "CompleteImage")
$OptionParser.AddOption((New-Option "IACCEPTSQLSERVERLICENSETERMS" -Switch), $true)
$OptionParser.AddOption((New-Option "ENU" -Switch))
$OptionParser.AddOption((New-Option "CONFIGURATIONFILE" -String))
$OptionParser.AddOption((New-Option "ERRORREPORTING" -Boolean))
$OptionParser.AddOption((New-Option "INDICATEPROGRESS" -Switch))
$OptionParser.AddOption((New-Option "INSTANCEID" -String), $true, "MSSQLSERVER")
$OptionParser.AddOption((New-Option "INSTANCENAME" -String), $true, "MSSQLSERVER")
$OptionParser.AddOption((New-Option "PID" -String))
$OptionParser.AddOption((New-Option "Q" -Switch))
$OptionParser.AddOption((New-Option "QS" -Switch))
$OptionParser.AddOption((New-Option "SQMREPORTING" -Boolean))
$OptionParser.AddOption((New-Option "HIDECONSOLE" -Switch))
$OptionParser.AddOption((New-Option "AGTSVCACCOUNT" -String), $true, "NT AUTHORITY\Network Service")
$OptionParser.AddOption((New-Option "AGTSVCPASSWORD" -String))
$OptionParser.AddOption((New-Option "AGTSVCSTARTUPTYPE" -String -Constraints ("Manual", "Automatic", "Disabled")))
$OptionParser.AddOption((New-Option "BROWSERSVCSTARTUPTYPE" -String -Constraints ("Manual", "Automatic", "Disabled")))
$OptionParser.AddOption((New-Option "ENABLERANU" -Switch))
$OptionParser.AddOption((New-Option "INSTALLSQLDATADIR" -String))
$OptionParser.AddOption((New-Option "SAPWD" -String))
$OptionParser.AddOption((New-Option "SECURITYMODE" -String -Constrainrs ("SQL")))
$OptionParser.AddOption((New-Option "SQLBACKUPDIR" -String))
$OptionParser.AddOption((New-Option "SQLCOLLATION" -String))
$OptionParser.AddOption((New-Option "SQLSVCACCOUNT" -String), $true, "NT AUTHORITY\Network Service")
$OptionParser.AddOption((New-Option "SQLSVCPASSWORD" -String))
$OptionParser.AddOption((New-Option "SQLSVCSTARTUPTYPE" -String -Constraints ("Manual", "Automatic", "Disabled")))
$OptionParser.AddOption((New-Option "SQLSYSADMINACCOUNTS" -String), $true, "$ENV:USERDOMAIN\$ENV:USERNAME")
$OptionParser.AddOption((New-Option "SQLTEMPDBDIR" -String))
$OptionParser.AddOption((New-Option "SQLTEMPDBLOGDIR" -String))
$OptionParser.AddOption((New-Option "SQLUSERDBDIR" -String))
$OptionParser.AddOption((New-Option "SQLUSERDBLOGDIR" -String))
$OptionParser.AddOption((New-Option "FILESTREAMLEVEL" -String -Constraints ("0", "1", "2", "3")))
$OptionParser.AddOption((New-Option "FILESTREAMSHARENAME" -String))
$OptionParser.AddOption((New-Option "FTSVCACCOUNT" -String))
$OptionParser.AddOption((New-Option "FTSVCPASSWORD" -String))
$OptionParser.AddOption((New-Option "NPENABLED" -Boolean))
$OptionParser.AddOption((New-Option "TCPENABLED" -Boolean))
$OptionParser.AddOption((New-Option "RSINSTALLMODE" -String -Constraints ("SharePointFilesOnlyMode", "DefaultNativeMode", "FilesOnlyMode")))
$OptionParser.AddOption((New-Option "RSSVCACCOUNT" -String), $true, "NT AUTHORITY\Network Service")
$OptionParser.AddOption((New-Option "RSSVCPASSWORD" -String))
$OptionParser.AddOption((New-Option "RSSVCStartupType" -String -Constraints ("Manual", "Automatic", "Disabled")))
return $OptionParser
}
function New-OptionParserCompleteImageSP1U2 {
<#
.SYNOPSIS
Creates an option parser for MS SQL Server 2012 setup "CompleteImage" action.
.DESCRIPTION
Use this cmdlet to create an option parser for MS SQL Server 2012 setup "CompleteImage" action.
This cmdlet should be used only for MS SQL Server 2012 SP1 Cimilative Update 2 or later.
All documented option are supported. See the following link for details:
http://msdn.microsoft.com/en-us/library/ms144259.aspx
#>
$OptionParser = New-OptionParser
$OptionParser.AddOption((New-Option "ACTION" -String -Constraints "CompleteImage"), $true, "CompleteImage")
$OptionParser.AddOption((New-Option "IACCEPTSQLSERVERLICENSETERMS" -Switch), $true)
$OptionParser.AddOption((New-Option "ENU" -Switch))
$OptionParser.AddOption((New-Option "CONFIGURATIONFILE" -String))
$OptionParser.AddOption((New-Option "ERRORREPORTING" -Boolean))
$OptionParser.AddOption((New-Option "INDICATEPROGRESS" -Switch))
$OptionParser.AddOption((New-Option "INSTANCEID" -String))
$OptionParser.AddOption((New-Option "INSTANCENAME" -String))
$OptionParser.AddOption((New-Option "PID" -String))
$OptionParser.AddOption((New-Option "Q" -Switch))
$OptionParser.AddOption((New-Option "QS" -Switch))
$OptionParser.AddOption((New-Option "SQMREPORTING" -Boolean))
$OptionParser.AddOption((New-Option "HIDECONSOLE" -Switch))
$OptionParser.AddOption((New-Option "AGTSVCACCOUNT" -String), $true, "NT AUTHORITY\Network Service")
$OptionParser.AddOption((New-Option "AGTSVCPASSWORD" -String))
$OptionParser.AddOption((New-Option "AGTSVCSTARTUPTYPE" -String -Constraints ("Manual", "Automatic", "Disabled")))
$OptionParser.AddOption((New-Option "BROWSERSVCSTARTUPTYPE" -String -Constraints ("Manual", "Automatic", "Disabled")))
$OptionParser.AddOption((New-Option "ENABLERANU" -Switch))
$OptionParser.AddOption((New-Option "INSTALLSQLDATADIR" -String))
$OptionParser.AddOption((New-Option "SAPWD" -String))
$OptionParser.AddOption((New-Option "SECURITYMODE" -String -Constrainrs ("SQL")))
$OptionParser.AddOption((New-Option "SQLBACKUPDIR" -String))
$OptionParser.AddOption((New-Option "SQLCOLLATION" -String))
$OptionParser.AddOption((New-Option "SQLSVCACCOUNT" -String), $true, "NT AUTHORITY\Network Service")
$OptionParser.AddOption((New-Option "SQLSVCPASSWORD" -String))
$OptionParser.AddOption((New-Option "SQLSVCSTARTUPTYPE" -String -Constraints ("Manual", "Automatic", "Disabled")))
$OptionParser.AddOption((New-Option "SQLSYSADMINACCOUNTS" -String), $true, "$ENV:USERDOMAIN\$ENV:USERNAME")
$OptionParser.AddOption((New-Option "SQLTEMPDBDIR" -String))
$OptionParser.AddOption((New-Option "SQLTEMPDBLOGDIR" -String))
$OptionParser.AddOption((New-Option "SQLUSERDBDIR" -String))
$OptionParser.AddOption((New-Option "SQLUSERDBLOGDIR" -String))
$OptionParser.AddOption((New-Option "FILESTREAMLEVEL" -String -Constraints ("0", "1", "2", "3")))
$OptionParser.AddOption((New-Option "FILESTREAMSHARENAME" -String))
$OptionParser.AddOption((New-Option "FTSVCACCOUNT" -String))
$OptionParser.AddOption((New-Option "FTSVCPASSWORD" -String))
$OptionParser.AddOption((New-Option "NPENABLED" -Boolean))
$OptionParser.AddOption((New-Option "TCPENABLED" -Boolean))
$OptionParser.AddOption((New-Option "RSINSTALLMODE" -String -Constraints ("SharePointFilesOnlyMode", "DefaultNativeMode", "FilesOnlyMode")))
$OptionParser.AddOption((New-Option "RSSVCACCOUNT" -String), $true, "NT AUTHORITY\Network Service")
$OptionParser.AddOption((New-Option "RSSVCPASSWORD" -String))
$OptionParser.AddOption((New-Option "RSSVCStartupType" -String -Constraints ("Manual", "Automatic", "Disabled")))
return $OptionParser
}
function New-OptionParserUpgrade {
# ToDo: Implement
throw "Not yet implemented"
}
function New-OptionParserEditionUpgrade {
# ToDo: Implement
throw "Not yet implemented"
}
function New-OptionParserRepair {
# ToDo: Implement
throw "Not yet implemented"
}
function New-OptionParserRebuilddatabase {
# ToDo: Implement
throw "Not yet implemented"
}
function New-OptionParserUninstall {
<#
.SYNOPSIS
Creates an option parser for MS SQL Server 2012 setup "INSTALL" action.
.DESCRIPTION
Use this cmdlet to create an option parser for MS SQL Server 2012 setup "INSTALL" action.
All documented option are supported. See the following link for details:
http://msdn.microsoft.com/en-us/library/ms144259.aspx
#>
$OptionParser = New-OptionParser
$OptionParser.AddOption((New-Option "ACTION" -String -Constraints "UNINSTALL"), $true, "UNINSTALL")
$OptionParser.AddOption((New-Option "CONFIGURATIONFILE" -String))
$OptionParser.AddOption((New-Option "FEATURES" -List -Constraints ("SQL","SQLEngine","Replication","FullText","DQ","AS","RS","DQC","IS","MDS","Tools","BC","BOL","BIDS","Conn","SSMS","ADV_SSMS","DREPLAY_CTLR","DREPLAY_CLT","SNAC_SDK","SDK","LocalDB")), $true)
$OptionParser.AddOption((New-Option "INDICATEPROGRESS" -Switch))
$OptionParser.AddOption((New-Option "INSTANCENAME" -String), $true, "MSSQLSERVER")
$OptionParser.AddOption((New-Option "Q" -Switch))
$OptionParser.AddOption((New-Option "HIDECONSOLE" -Switch))
return $OptionParser
}
function New-OptionParserInstallFailoverCluster {
# ToDo: Implement
throw "Not yet implemented"
}
function New-OptionParserPrepareFailoverCluster {
# ToDo: Implement
throw "Not yet implemented"
}
function New-OptionParserCompleteFailoverCluster {
# ToDo: Implement
throw "Not yet implemented"
}
function New-OptionParserUpgrade {
# ToDo: Implement
throw "Not yet implemented"
}
function New-OptionParserAddNode {
# ToDo: Implement
throw "Not yet implemented"
}
function New-OptionParserRemoveNode {
# ToDo: Implement
throw "Not yet implemented"
}

View File

@ -0,0 +1,37 @@
trap {
&$TrapHandler
}
Function Set-LocalUserPassword {
param (
[String] $UserName,
[String] $Password,
[Switch] $Force
)
begin {
Show-InvocationInfo $MyInvocation
}
end {
Show-InvocationInfo $MyInvocation -End
}
process {
trap {
&$TrapHandler
}
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 '*****'" # :)
$null = ([ADSI] "WinNT://./$UserName").SetPassword($Password)
}
else {
Write-LogWarning "You are trying to change password for user '$UserName'. To do this please run the command again with -Force parameter."
}
}
}

View File

@ -0,0 +1,151 @@
trap {
&$TrapHandler
}
function Select-CliXmlBlock {
param (
[String] $Path,
[String] $OutFile = [IO.Path]::GetTempFileName()
)
$TagFound = $false
Get-Content $Path |
ForEach-Object {
if ($_ -eq '#< CLIXML') {
$TagFound = $true
}
if ($TagFound) {
Add-Content -Path $OutFile -Value $_
}
}
$OutFile
}
function Start-PowerShellProcess {
param (
[String] $Command,
$Credential = $null,
[Switch] $IgnoreStdErr,
[Switch] $NoBase64
)
begin {
Show-InvocationInfo $MyInvocation
}
end {
Show-InvocationInfo $MyInvocation -End
}
process {
trap {
&$TrapHandler
}
$StdOut = [IO.Path]::GetTempFileName()
$StdErr = [IO.Path]::GetTempFileName()
$ArgumentList = @('-OutputFormat', 'XML')
if ($NoBase64) {
$TmpScript = [IO.Path]::GetTempFileName()
Rename-Item -Path "$TmpScript" -NewName "$TmpScript.ps1" -Force
$TmpScript = "$TmpScript.ps1"
Write-LogDebug $TmpScript
$Command | Out-File $TmpScript
$ArgumentList += @('-File', "$TmpScript")
}
else {
$Bytes = [Text.Encoding]::Unicode.GetBytes($Command)
$EncodedCommand = [Convert]::ToBase64String($Bytes)
Write-LogDebug $EncodedCommand
$ArgumentList += @('-EncodedCommand', $EncodedCommand)
}
Write-LogDebug $ArgumentList
Write-Log "Starting external PowerShell process ..."
if ($Credential -eq $null) {
$Process = Start-Process -FilePath 'powershell.exe' `
-ArgumentList @($ArgumentList) `
-RedirectStandardOutput $StdOut `
-RedirectStandardError $StdErr `
-NoNewWindow `
-Wait `
-PassThru
}
else {
$Process = Start-Process -FilePath 'powershell.exe' `
-ArgumentList @($ArgumentList) `
-RedirectStandardOutput $StdOut `
-RedirectStandardError $StdErr `
-Credential $Credential `
-NoNewWindow `
-Wait `
-PassThru
}
Write-Log "External PowerShell process exited with exit code '$($Process.ExitCode)'."
#if ($ArgumentList -contains '-File') {
# Remove-Item -Path $TmpScript -Force
#}
$ErrorActionPreferenceSaved = $ErrorActionPreference
$ErrorActionPreference = 'SilentlyContinue'
Write-LogDebug "StdOut file is '$StdOut'"
Write-LogDebug "StdErr file is '$StdErr'"
if ((Get-Item $StdOut).Length -gt 0) {
try {
Write-LogDebug "Loading StdOut from '$StdOut'"
$TmpFile = Select-CliXmlBlock $StdOut
$StdOutObject = Import-Clixml $TmpFile
Write-LogDebug "<StdOut>"
Write-LogDebug ($StdOutObject)
Write-LogDebug "</StdOut>"
$StdOutObject
#Remove-Item -Path $TmpFile -Force
}
catch {
Write-LogDebug "An error occured while loading StdOut from '$TmpFile'"
}
}
if ((Get-Item $StdErr).Length -gt 0) {
try {
Write-LogDebug "Loading StdErr ..."
$TmpFile = Select-CliXmlBlock $StdErr
$StdErrObject = Import-Clixml $TmpFile
Write-LogDebug "<StdErr>"
Write-LogDebug ($StdErrObject)
Write-LogDebug "</StdErr>"
if (-not $IgnoreStdErr) {
$StdErrObject
}
#Remove-Item -Path $TmpFile -Force
}
catch {
Write-LogDebug "An error occured while loading StdErr from '$TmpFile'"
}
}
$ErrorActionPreference = $ErrorActionPreferenceSaved
if ($Process.ExitCode -ne 0) {
throw("External PowerShell process exited with code '$($Process.ExitCode)'")
}
#Remove-Item $StdOut -Force
#Remove-Item $StdErr -Force
}
}

View File

@ -0,0 +1,60 @@
trap {
&$TrapHandler
}
function Update-ServiceConfig {
param (
[String] $Name,
[String] $RunAsUser = '',
[String] $DomainName = '.',
[String] $Password = '',
[Switch] $RunAsLocalService
)
begin {
Show-InvocationInfo $MyInvocation
}
end {
Show-InvocationInfo $MyInvocation -End
}
process {
trap {
&$TrapHandler
}
$ArgumentList = @('config', "`"$Name`"")
if ($RunAsLocalService) {
$ArgumentList += @("obj=", "`"NT AUTHORITY\LocalService`"")
}
elseif ($RunAsUser -ne '') {
$ArgumentList += @("obj=", "`"$DomainName\$RunAsUser`"", "password=", "`"$Password`"")
}
$Process = Exec 'sc.exe' $ArgumentList -PassThru -RedirectStreams
if ($Process.ExitCode -ne 0) {
throw "Command 'sc.exe' returned exit code '$($Process.ExitCode)'"
}
$NtRights = "C:\Murano\Tools\ntrights.exe"
if (-not ([IO.File]::Exists($NtRights))) {
throw "File '$NtRights' not found."
}
$Process = Exec $NtRights @('-u', "$DomainName\$RunAsUser", '+r', 'SeServiceLogonRight') -RedirectStreams -PassThru
if ($Process.ExitCode -ne 0) {
throw "Command '$NtRights' returned exit code '$($Process.ExitCode)'"
}
$Process = Exec $NtRights @('-u', "$DomainName\$RunAsUser", '+r', 'SeBatchLogonRight') -RedirectStreams -PassThru
if ($Process.ExitCode -ne 0) {
throw "Command '$NtRights' returned exit code '$($Process.ExitCode)'"
}
}
}

View File

@ -1,5 +1,6 @@
import json
import uuid
import os
from muranoconductor.openstack.common import log as logging
from muranocommon.messaging import Message
@ -20,11 +21,14 @@ class WindowsAgentExecutor(CommandBase):
def execute(self, template, mappings, unit, service, callback,
timeout=None):
with open('data/templates/agent/%s.template' % template) as t_file:
template_path = 'data/templates/agent/%s.template' % template
with open(template_path) as t_file:
template_data = t_file.read()
json_template = json.loads(template_data)
json_template = self.encode_scripts(json_template, template_path)
template_data = muranoconductor.helpers.transform_json(
json.loads(template_data), mappings)
json_template, mappings)
msg_id = str(uuid.uuid4()).lower()
queue = ('%s-%s-%s' % (self._stack, service, unit)).lower()
@ -42,6 +46,19 @@ class WindowsAgentExecutor(CommandBase):
log.info('Sending RMQ message {0} to {1} with id {2}'.format(
template_data, queue, msg_id))
def encode_scripts(self, json_data, template_path):
scripts_folder = ''.join([os.path.dirname(template_path), "/scripts/"])
script_files = json_data.get("Scripts", [])
scripts = []
for script in script_files:
script_path = os.path.join(scripts_folder, script)
log.debug('Loading script "{0}"'.format(script_path))
with open(script_path) as script_file:
script_data = script_file.read()
scripts.append(script_data.encode('base64'))
json_data["Scripts"] = scripts
return json_data
def has_pending_commands(self):
return len(self._pending_list) > 0

View File

@ -0,0 +1,63 @@
# Copyright (c) 2013 Mirantis Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import unittest
import mock
import mockfs
import json
from muranoconductor.commands.windows_agent import WindowsAgentExecutor
class TestWindowsAgent(unittest.TestCase):
def setUp(self):
self.mfs = mockfs.replace_builtins()
self.template = {
"Scripts": [
"Get-DnsListeningIpAddress.ps1",
"Join-Domain.ps1"
],
"Commands": [
{
"Name": "Get-DnsListeningIpAddress",
"Arguments": {}
}],
"RebootOnCompletion": 0
}
self.mfs.add_entries({
'./data/templates/agent/test.template':
json.dumps(self.template),
'./data/templates/agent/scripts/Get-DnsListeningIpAddress.ps1':
'function GetDNSip(){\ntest\n}\n',
'./data/templates/agent/scripts/Join-Domain.ps1':
'function JoinDomain(){\ntest\n}\n',
})
self.template_path = './data/templates/agent/test.template'
def test_script_encode(self):
stack = mock.MagicMock()
rmqclient = mock.MagicMock()
reporter = mock.MagicMock()
rmqclient.declare = mock.Mock()
executor = WindowsAgentExecutor(stack, rmqclient, reporter)
result = executor.encode_scripts(self.template, self.template_path)
encoded = [
'ZnVuY3Rpb24gR2V0RE5TaXAoKXsKdGVzdAp9Cg==\n',
'ZnVuY3Rpb24gSm9pbkRvbWFpbigpewp0ZXN0Cn0K\n'
]
self.assertEqual(result['Scripts'], encoded,
'Encoded script is incorrect')