├── .gitattributes ├── .gitignore ├── Exercise1.md ├── Exercise2.md ├── Exercise2 ├── Deploy.ps1 ├── Parameters.ps1 └── Templates │ └── Webserver.template.answer ├── Exercise3.md ├── Exercise3 ├── ConfigureWebserver.ps1 ├── ConfigureWebserver.ps1.answer ├── DSC_Diagnostics.md └── PowerShellModules │ ├── cWinServer │ ├── DSCResources │ │ └── WinServerOptions │ │ │ ├── WinServerOptions.psm1 │ │ │ └── WinServerOptions.schema.mof │ └── cWinServer.psd1 │ ├── xDscDiagnostics │ ├── xDscDiagnostics.psd1 │ ├── xDscDiagnostics.psm1 │ └── xDscDiagnosticsFormat.ps1xml │ ├── xNetworking │ ├── DSCResources │ │ ├── MSFT_xDNSServerAddress │ │ │ ├── MSFT_xDNSServerAddress.psm1 │ │ │ └── MSFT_xDNSServerAddress.schema.mof │ │ ├── MSFT_xFirewall │ │ │ ├── MSFT_xFirewall.Schema.mof │ │ │ └── MSFT_xFirewall.psm1 │ │ └── MSFT_xIPAddress │ │ │ ├── MSFT_xIPAddress.psm1 │ │ │ └── MSFT_xIPAddress.schema.mof │ ├── Examples │ │ ├── Sample_xDnsServerAddress.ps1 │ │ ├── Sample_xFirewall_AddFirewallRule.ps1 │ │ ├── Sample_xFirewall_AddFirewallRuleToExistingGroup.ps1 │ │ ├── Sample_xFirewall_AddFirewallRuleToNewGroup.ps1 │ │ ├── Sample_xFirewall_DisableAccessToApplication.ps1 │ │ ├── Sample_xIPAddress_FixedValue.ps1 │ │ └── Sample_xIPAddress_Parameterized.ps1 │ ├── xNetworking.psd1 │ └── xNetworking_TechNetDocumentation.html │ ├── xPendingReboot │ ├── DSCResources │ │ └── MSFT_xPendingReboot │ │ │ ├── MSFT_xPendingReboot.psm1 │ │ │ └── MSFT_xPendingReboot.schema.mof │ ├── xPendingReboot.psd1 │ └── xPendingReboot_Documentation.html │ └── xWebAdministration │ ├── DSCResources │ ├── MSFT_xIisModule │ │ ├── MSFT_xIisModule.psm1 │ │ ├── MSFT_xIisModule.schema.mof │ │ └── xIisModuleDesigner.ps1 │ ├── MSFT_xWebAppPool │ │ ├── MSFT_xWebAppPool.psm1 │ │ └── MSFT_xWebAppPool.schema.mof │ ├── MSFT_xWebApplication │ │ ├── MSFT_xWebApplication.psm1 │ │ └── MSFT_xWebApplication.schema.mof │ ├── MSFT_xWebConfigKeyValue │ │ ├── MSFT_xWebConfigKeyValue.psm1 │ │ └── MSFT_xWebConfigKeyValue.schema.mof │ ├── MSFT_xWebVirtualDirectory │ │ ├── MSFT_xWebVirtualDirectory.psm1 │ │ └── MSFT_xWebVirtualDirectory.schema.mof │ └── MSFT_xWebsite │ │ ├── MSFT_xWebsite.psm1 │ │ └── MSFT_xWebsite.schema.mof │ ├── TechNetDocumentation_xWebAdministration.html │ └── xWebAdministration.psd1 ├── Exercise4.md ├── Exercise4 ├── Deploy.ps1 ├── Parameters.ps1 ├── PowerShellModules │ ├── cWinServer │ │ ├── DSCResources │ │ │ └── WinServerOptions │ │ │ │ ├── WinServerOptions.psm1 │ │ │ │ └── WinServerOptions.schema.mof │ │ └── cWinServer.psd1 │ ├── xDscDiagnostics │ │ ├── xDscDiagnostics.psd1 │ │ ├── xDscDiagnostics.psm1 │ │ └── xDscDiagnosticsFormat.ps1xml │ ├── xNetworking │ │ ├── DSCResources │ │ │ ├── MSFT_xDNSServerAddress │ │ │ │ ├── MSFT_xDNSServerAddress.psm1 │ │ │ │ └── MSFT_xDNSServerAddress.schema.mof │ │ │ ├── MSFT_xFirewall │ │ │ │ ├── MSFT_xFirewall.Schema.mof │ │ │ │ └── MSFT_xFirewall.psm1 │ │ │ └── MSFT_xIPAddress │ │ │ │ ├── MSFT_xIPAddress.psm1 │ │ │ │ └── MSFT_xIPAddress.schema.mof │ │ ├── Examples │ │ │ ├── Sample_xDnsServerAddress.ps1 │ │ │ ├── Sample_xFirewall_AddFirewallRule.ps1 │ │ │ ├── Sample_xFirewall_AddFirewallRuleToExistingGroup.ps1 │ │ │ ├── Sample_xFirewall_AddFirewallRuleToNewGroup.ps1 │ │ │ ├── Sample_xFirewall_DisableAccessToApplication.ps1 │ │ │ ├── Sample_xIPAddress_FixedValue.ps1 │ │ │ └── Sample_xIPAddress_Parameterized.ps1 │ │ ├── xNetworking.psd1 │ │ └── xNetworking_TechNetDocumentation.html │ ├── xPendingReboot │ │ ├── DSCResources │ │ │ └── MSFT_xPendingReboot │ │ │ │ ├── MSFT_xPendingReboot.psm1 │ │ │ │ └── MSFT_xPendingReboot.schema.mof │ │ ├── xPendingReboot.psd1 │ │ └── xPendingReboot_Documentation.html │ └── xWebAdministration │ │ ├── DSCResources │ │ ├── MSFT_xIisModule │ │ │ ├── MSFT_xIisModule.psm1 │ │ │ ├── MSFT_xIisModule.schema.mof │ │ │ └── xIisModuleDesigner.ps1 │ │ ├── MSFT_xWebAppPool │ │ │ ├── MSFT_xWebAppPool.psm1 │ │ │ └── MSFT_xWebAppPool.schema.mof │ │ ├── MSFT_xWebApplication │ │ │ ├── MSFT_xWebApplication.psm1 │ │ │ └── MSFT_xWebApplication.schema.mof │ │ ├── MSFT_xWebConfigKeyValue │ │ │ ├── MSFT_xWebConfigKeyValue.psm1 │ │ │ └── MSFT_xWebConfigKeyValue.schema.mof │ │ ├── MSFT_xWebVirtualDirectory │ │ │ ├── MSFT_xWebVirtualDirectory.psm1 │ │ │ └── MSFT_xWebVirtualDirectory.schema.mof │ │ └── MSFT_xWebsite │ │ │ ├── MSFT_xWebsite.psm1 │ │ │ └── MSFT_xWebsite.schema.mof │ │ ├── TechNetDocumentation_xWebAdministration.html │ │ └── xWebAdministration.psd1 ├── Scripts │ ├── ConfigureWebserver.ps1 │ └── Teardown.ps1 └── Templates │ ├── Webserver.template │ ├── Webserver.template.answer │ └── Zephyr.template ├── Exercise5.md ├── Exercise5 ├── Deploy.ps1 ├── Deploy.ps1.answer ├── Parameters.ps1 ├── PowerShellModules │ ├── cOctopus │ │ ├── DSCResources │ │ │ └── cTentacleAgent │ │ │ │ ├── cTentacleAgent.psm1 │ │ │ │ └── cTentacleAgent.schema.mof │ │ └── cOctopus.psd1 │ ├── cWinServer │ │ ├── DSCResources │ │ │ └── WinServerOptions │ │ │ │ ├── WinServerOptions.psm1 │ │ │ │ └── WinServerOptions.schema.mof │ │ └── cWinServer.psd1 │ ├── xDscDiagnostics │ │ ├── xDscDiagnostics.psd1 │ │ ├── xDscDiagnostics.psm1 │ │ └── xDscDiagnosticsFormat.ps1xml │ ├── xNetworking │ │ ├── DSCResources │ │ │ ├── MSFT_xDNSServerAddress │ │ │ │ ├── MSFT_xDNSServerAddress.psm1 │ │ │ │ └── MSFT_xDNSServerAddress.schema.mof │ │ │ ├── MSFT_xFirewall │ │ │ │ ├── MSFT_xFirewall.Schema.mof │ │ │ │ └── MSFT_xFirewall.psm1 │ │ │ └── MSFT_xIPAddress │ │ │ │ ├── MSFT_xIPAddress.psm1 │ │ │ │ └── MSFT_xIPAddress.schema.mof │ │ ├── Examples │ │ │ ├── Sample_xDnsServerAddress.ps1 │ │ │ ├── Sample_xFirewall_AddFirewallRule.ps1 │ │ │ ├── Sample_xFirewall_AddFirewallRuleToExistingGroup.ps1 │ │ │ ├── Sample_xFirewall_AddFirewallRuleToNewGroup.ps1 │ │ │ ├── Sample_xFirewall_DisableAccessToApplication.ps1 │ │ │ ├── Sample_xIPAddress_FixedValue.ps1 │ │ │ └── Sample_xIPAddress_Parameterized.ps1 │ │ ├── xNetworking.psd1 │ │ └── xNetworking_TechNetDocumentation.html │ ├── xPendingReboot │ │ ├── DSCResources │ │ │ └── MSFT_xPendingReboot │ │ │ │ ├── MSFT_xPendingReboot.psm1 │ │ │ │ └── MSFT_xPendingReboot.schema.mof │ │ ├── xPendingReboot.psd1 │ │ └── xPendingReboot_Documentation.html │ └── xWebAdministration │ │ ├── DSCResources │ │ ├── MSFT_xIisModule │ │ │ ├── MSFT_xIisModule.psm1 │ │ │ ├── MSFT_xIisModule.schema.mof │ │ │ └── xIisModuleDesigner.ps1 │ │ ├── MSFT_xWebAppPool │ │ │ ├── MSFT_xWebAppPool.psm1 │ │ │ └── MSFT_xWebAppPool.schema.mof │ │ ├── MSFT_xWebApplication │ │ │ ├── MSFT_xWebApplication.psm1 │ │ │ └── MSFT_xWebApplication.schema.mof │ │ ├── MSFT_xWebConfigKeyValue │ │ │ ├── MSFT_xWebConfigKeyValue.psm1 │ │ │ └── MSFT_xWebConfigKeyValue.schema.mof │ │ ├── MSFT_xWebVirtualDirectory │ │ │ ├── MSFT_xWebVirtualDirectory.psm1 │ │ │ └── MSFT_xWebVirtualDirectory.schema.mof │ │ └── MSFT_xWebsite │ │ │ ├── MSFT_xWebsite.psm1 │ │ │ └── MSFT_xWebsite.schema.mof │ │ ├── TechNetDocumentation_xWebAdministration.html │ │ └── xWebAdministration.psd1 ├── Scripts │ ├── ConfigureWebserver.ps1 │ ├── ConfigureWebserver.ps1.answer │ └── Teardown.ps1 └── Templates │ ├── Webserver.template │ └── Zephyr.template ├── README.md └── ResetCredentials.bat /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | build/ 21 | bld/ 22 | [Bb]in/ 23 | [Oo]bj/ 24 | 25 | # Visual Studo 2015 cache/options directory 26 | .vs/ 27 | 28 | # MSTest test Results 29 | [Tt]est[Rr]esult*/ 30 | [Bb]uild[Ll]og.* 31 | 32 | # NUNIT 33 | *.VisualState.xml 34 | TestResult.xml 35 | 36 | # Build Results of an ATL Project 37 | [Dd]ebugPS/ 38 | [Rr]eleasePS/ 39 | dlldata.c 40 | 41 | *_i.c 42 | *_p.c 43 | *_i.h 44 | *.ilk 45 | *.meta 46 | *.obj 47 | *.pch 48 | *.pdb 49 | *.pgc 50 | *.pgd 51 | *.rsp 52 | *.sbr 53 | *.tlb 54 | *.tli 55 | *.tlh 56 | *.tmp 57 | *.tmp_proj 58 | *.log 59 | *.vspscc 60 | *.vssscc 61 | .builds 62 | *.pidb 63 | *.svclog 64 | *.scc 65 | 66 | # Chutzpah Test files 67 | _Chutzpah* 68 | 69 | # Visual C++ cache files 70 | ipch/ 71 | *.aps 72 | *.ncb 73 | *.opensdf 74 | *.sdf 75 | *.cachefile 76 | 77 | # Visual Studio profiler 78 | *.psess 79 | *.vsp 80 | *.vspx 81 | 82 | # TFS 2012 Local Workspace 83 | $tf/ 84 | 85 | # Guidance Automation Toolkit 86 | *.gpState 87 | 88 | # ReSharper is a .NET coding add-in 89 | _ReSharper*/ 90 | *.[Rr]e[Ss]harper 91 | *.DotSettings.user 92 | 93 | # JustCode is a .NET coding addin-in 94 | .JustCode 95 | 96 | # TeamCity is a build add-in 97 | _TeamCity* 98 | 99 | # DotCover is a Code Coverage Tool 100 | *.dotCover 101 | 102 | # NCrunch 103 | _NCrunch_* 104 | .*crunch*.local.xml 105 | 106 | # MightyMoose 107 | *.mm.* 108 | AutoTest.Net/ 109 | 110 | # Web workbench (sass) 111 | .sass-cache/ 112 | 113 | # Installshield output folder 114 | [Ee]xpress/ 115 | 116 | # DocProject is a documentation generator add-in 117 | DocProject/buildhelp/ 118 | DocProject/Help/*.HxT 119 | DocProject/Help/*.HxC 120 | DocProject/Help/*.hhc 121 | DocProject/Help/*.hhk 122 | DocProject/Help/*.hhp 123 | DocProject/Help/Html2 124 | DocProject/Help/html 125 | 126 | # Click-Once directory 127 | publish/ 128 | 129 | # Publish Web Output 130 | *.[Pp]ublish.xml 131 | *.azurePubxml 132 | # TODO: Comment the next line if you want to checkin your web deploy settings 133 | # but database connection strings (with potential passwords) will be unencrypted 134 | *.pubxml 135 | *.publishproj 136 | 137 | # NuGet Packages 138 | *.nupkg 139 | # The packages folder can be ignored because of Package Restore 140 | **/packages/* 141 | # except build/, which is used as an MSBuild target. 142 | !**/packages/build/ 143 | # Uncomment if necessary however generally it will be regenerated when needed 144 | #!**/packages/repositories.config 145 | 146 | # Windows Azure Build Output 147 | csx/ 148 | *.build.csdef 149 | 150 | # Windows Store app package directory 151 | AppPackages/ 152 | 153 | # Others 154 | *.[Cc]ache 155 | ClientBin/ 156 | [Ss]tyle[Cc]op.* 157 | ~$* 158 | *~ 159 | *.dbmdl 160 | *.dbproj.schemaview 161 | *.pfx 162 | *.publishsettings 163 | node_modules/ 164 | bower_components/ 165 | 166 | # RIA/Silverlight projects 167 | Generated_Code/ 168 | 169 | # Backup & report files from converting an old project file 170 | # to a newer Visual Studio version. Backup files are not needed, 171 | # because we have git ;-) 172 | _UpgradeReport_Files/ 173 | Backup*/ 174 | UpgradeLog*.XML 175 | UpgradeLog*.htm 176 | 177 | # SQL Server files 178 | *.mdf 179 | *.ldf 180 | 181 | # Business Intelligence projects 182 | *.rdl.data 183 | *.bim.layout 184 | *.bim_*.settings 185 | 186 | # Microsoft Fakes 187 | FakesAssemblies/ 188 | 189 | # Node.js Tools for Visual Studio 190 | .ntvs_analysis.dat 191 | 192 | # Visual Studio 6 build log 193 | *.plg 194 | 195 | # Visual Studio 6 workspace options file 196 | *.opt 197 | Private/* 198 | **/Private/* 199 | -------------------------------------------------------------------------------- /Exercise1.md: -------------------------------------------------------------------------------- 1 | # Exercise 1 2 | 3 | ## Manually provisioning 4 | 5 | In this exercise we will be provisioning an EC2 instance by hand to build some familiarity with the web console, and to develop an appreciation for the level of effort involved to launch and configure an instance by hand. 6 | 7 | ## Goals 8 | 9 | * Build familiarity with the AWS Web console 10 | * Develop a healthy appreciation for manual provisioning effort 11 | * Provision a functional web-server by hand, and deploy to it with Octopus 12 | 13 | ## Instructions 14 | 15 | 1. Open the EC2 console within the AWS web console 16 | 2. Launch a "Microsoft Windows Server 2016 Base" image-based EC2 instance 17 | 3. Make it a t2.medium 18 | 4. Ensure it is on the *CloudFormawesome* VPC, in the *DMZ B* subnet 19 | 5. Ensure it is assigned a public IP address 20 | 6. Provision a 50 gigabyte *General Purpose* SSD to be used 21 | 7. Tag the instance with a key of "Name", and value of "{yourinitials}-WebServer-Manual" 22 | 8. Create a new security group named {yourinitials}-WebServer-Manual-SecurityGroup 23 | 9. Given we are going to be using the instance to host a web site, need to remote to it to configure a tentacle, and Octopus needs to talk to it, assign inbound access rules for all IP addresses to ports 80 and 3389, and for the VPC IP range to 10933 24 | 10. GO GO GO! (Review, then click Launch) 25 | 11. You will be prompted for a key pair that will be used to generate the instance's administrator password. Select the AwsDayKeyPair 26 | 12. Once launched, remote onto your instance via it's public IP address - to retrieve the password for your instance, select it in the console and click 'Connect', locate the .pem file for the AwsDayKeyPair and click 'Decrypt Password' 27 | 13. Give that this is a base windows image, we will need to add the *Web Server (IIS)* role to it in Server Management, and ensure under that that we have selected *Application Development > ASP.NET 4.6* 28 | 14. Finally, connect to Octopus (address and credentials are be provided), install a tentacle onto your machine, add your machine to the Production environment and trigger a deployment. _Use the manual tentacle registration if discovery fails in Octopus._ 29 | 15. On your webserver hit http://localhost - great success! 30 | -------------------------------------------------------------------------------- /Exercise2.md: -------------------------------------------------------------------------------- 1 | # Exercise 2 2 | 3 | ## Cloud Formation templating 4 | 5 | In this exercise we will build a cloud formation template to provision the security group and EC2 instance pair that we manually created in [Exercise 1](https://github.com/andrewabest/AWS-Workshop/blob/master/Exercise1.md) 6 | 7 | ## Goals 8 | 9 | * Gain exposure to AWS powershell API 10 | * Get hands dirty building a CloudFormation template 11 | * Launch a security group and EC2 instance via powershell - Infrastructure as code! 12 | 13 | ## Prior to starting 14 | 15 | To complete this exercise you'll need to add an appropriate set of credentials to your [SDK Credential Store](http://docs.aws.amazon.com/powershell/latest/userguide/specifying-your-aws-credentials.html) - run ResetCredentials.bat from the repository root with appropriate parameters to do this 16 | 17 | ## Instructions 18 | 19 | 1. Navigate to .\Exercise2 and open Deploy.ps1 in Powershell ISE 20 | 2. Spend a some time getting familiar with what it is doing 21 | * How does the template get from our local machine to AWS? 22 | * How do we supply parameters that our CloudFormation template requires? 23 | 3. Open .\Exercise2\Parameters.ps1. Update the ResourcePrefix parameter to your initials, and take note of the other parameters provided 24 | 4. Create an empty file named Webserver.template in .\Exercise2\Templates 25 | 5. Build your template's [Skeleton Structure](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/template-anatomy.html) 26 | 6. Define your [Security Group Template](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-security-group.html) 27 | * Refer to the [samples available](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/sample-templates-services-us-west-2.html#d0e111750) if you need a more complete sample to work from 28 | 7. Define your [EC2 Instance Template](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-instance.html) 29 | 8. Kick off .\Deploy.ps1 by F5-ing it in ISE, and open the CloudFormation section of the AWS console 30 | 9. Monitor your stack's creation by opening the 'Events' tab for a running summary of progress 31 | 10. If something fails, analyse the error. What went wrong? Double check your template, and the template documentation. Feel free to grab someone to rubber duck! 32 | 11. If it is all green, jump into the EC2 console and try to remote into your instance 33 | 12. Great success! 34 | 35 | Note: If you installed the [Visual Studio Tooling](http://blog.kloud.com.au/2015/05/18/create-aws-cloudformation-templates-with-visual-studio/) you can use an "AWS CloudFormation project" to work with your template, which will give you some intellisense out of the box. 36 | -------------------------------------------------------------------------------- /Exercise2/Deploy.ps1: -------------------------------------------------------------------------------- 1 | cls 2 | 3 | Import-Module AWSPowerShell 4 | 5 | ############################################################################################################################ 6 | # 7 | # 00 - Helper Functions 8 | # 9 | ############################################################################################################################ 10 | 11 | function GenerateConfigFileS3Key($environment, $release, $filename) 12 | { 13 | $key = $environment + "/" + $release + "/" + $filename 14 | return $key 15 | } 16 | 17 | ############################################################################################################################ 18 | # 19 | # 01 - Wrangling Octopus Variables 20 | # 21 | ############################################################################################################################ 22 | 23 | # Create a new variable scope so that we can run this script multiple times 24 | # in a single script console instance without polluting the global scope with 25 | # fake variables. 26 | & { 27 | $scriptPath = [System.IO.Path]::GetDirectoryName($myInvocation.PSCommandPath) 28 | 29 | . .\Parameters.ps1 30 | 31 | # Lower case variables sensitive to casing 32 | $Parameters['CloudFormationStackName'] = $Parameters['CloudFormationStackName'].ToLowerInvariant() 33 | $Parameters['S3BucketName'] = $Parameters['S3BucketName'].ToLowerInvariant() 34 | 35 | Write-Output $Parameters 36 | Write-Output "" 37 | 38 | ############################################################################################################################ 39 | # 40 | # 02 - Push templates to clouds 41 | # 42 | ############################################################################################################################ 43 | 44 | # Create an S3 bucket to upload our templates and scripts to. 45 | if (-Not (Get-S3Bucket -BucketName $Parameters['S3BucketName'] -Region $Parameters['AWSRegion'] -ProfileName "AWSWorkshop")) 46 | { 47 | Write-Output "Creating S3 bucket..." 48 | New-S3Bucket -BucketName $Parameters['S3BucketName'] -Region $Parameters['AWSRegion'] -ProfileName "AWSWorkshop" 49 | } 50 | 51 | # CloudFormation templates 52 | Write-Output "Uploading CloudFormation templates..." 53 | $webserverTemplateS3BucketKey = GenerateConfigFileS3Key -environment $Parameters['Environment'] -release $Parameters['Version'] -filename "Webserver.template" 54 | Write-S3Object -BucketName: $Parameters['S3BucketName'] -Key $webserverTemplateS3BucketKey -File $scriptPath\Templates\Webserver.template -Region $Parameters['AWSRegion'] -ProfileName "AWSWorkshop" 55 | 56 | ############################################################################################################################ 57 | # 58 | # 03 - GO GO GO (Create the stack) 59 | # 60 | ############################################################################################################################ 61 | 62 | $webserverTemplateUrl = "https://" + $Parameters['S3BucketName'] + ".s3.amazonaws.com/$webserverTemplateS3BucketKey" 63 | $timestamp = Get-Date -Format u 64 | 65 | $stack = $null 66 | try 67 | { 68 | $stack = Get-CFNStack -StackName $Parameters['CloudFormationStackName'] -Region $Parameters['AWSRegion'] -ProfileName "AWSWorkshop" 69 | } 70 | catch 71 | { 72 | } 73 | 74 | $stackParameters = ` 75 | @(` 76 | @{ParameterKey="VpcId"; ParameterValue=$Parameters['VpcId']},` 77 | @{ParameterKey="Version"; ParameterValue=$Parameters['Version']},` 78 | @{ParameterKey="Environment"; ParameterValue=$Parameters['Environment']},` 79 | @{ParameterKey="KeyPairName"; ParameterValue=$Parameters['KeyPairName']},` 80 | @{ParameterKey="WebserverImageId"; ParameterValue=$Parameters['WebserverImageId']},` 81 | @{ParameterKey="WebserverInstanceType"; ParameterValue=$Parameters['WebserverInstanceType']},` 82 | @{ParameterKey="WebserverSubnetId"; ParameterValue=$Parameters['WebserverSubnetId']},` 83 | @{ParameterKey="ResourcePrefix"; ParameterValue=$Parameters['ResourcePrefix']}) 84 | 85 | $stackName = $Parameters['CloudFormationStackName'] 86 | if ($stack -eq $null) 87 | { 88 | Write-Output "Creating new CFN stack $stackName" 89 | 90 | New-CFNStack -Capability "CAPABILITY_IAM" -StackName $stackName -TemplateURL $webserverTemplateUrl -Parameters $stackParameters -Region $Parameters['AWSRegion'] -ProfileName "AWSWorkshop" 91 | } 92 | else 93 | { 94 | Write-Output "Updating existing CFN stack $stackName" 95 | 96 | Update-CFNStack -Capability "CAPABILITY_IAM" -StackName $stackName -TemplateURL $webserverTemplateUrl -Parameters $stackParameters -Region $Parameters['AWSRegion'] -ProfileName "AWSWorkshop" 97 | } 98 | 99 | while($true) 100 | { 101 | $stack = Get-CFNStack -StackName $stackName -Region $Parameters['AWSRegion'] -ProfileName "AWSWorkshop" 102 | 103 | if ($stack.StackStatus -eq [Amazon.CloudFormation.StackStatus]::CREATE_COMPLETE -or $stack.StackStatus -eq [Amazon.CloudFormation.StackStatus]::UPDATE_COMPLETE) 104 | { 105 | Write-Output "Cloud formation succeeded with the following outputs..." 106 | $stack.Outputs | Format-Table | Write-Output 107 | 108 | # Note: In here, wire up external DNS etc based on stack output parameters 109 | 110 | break; 111 | } 112 | 113 | if ($stack.StackStatus -eq [Amazon.CloudFormation.StackStatus]::CREATE_FAILED -or $stack.StackStatus -eq [Amazon.CloudFormation.StackStatus]::ROLLBACK_COMPLETE -or $stack.StackStatus -eq [Amazon.CloudFormation.StackStatus]::ROLLBACK_FAILED) 114 | { 115 | Write-Output "Cloud formation failed, abandoning..." 116 | 117 | break; 118 | } 119 | 120 | Write-Output "Waiting for cloud formation $stackName to finish creation..." 121 | 122 | Start-Sleep -s 10 123 | } 124 | 125 | Write-Output "fin" 126 | } -------------------------------------------------------------------------------- /Exercise2/Parameters.ps1: -------------------------------------------------------------------------------- 1 | $Parameters = @{} 2 | 3 | # Octopus parameters 4 | $Parameters['ResourcePrefix'] = "aab"; 5 | $Parameters['Environment'] = "Production"; 6 | $Parameters['Version'] = "1.0.0-ryan0001"; 7 | 8 | # CloudFormation parameters 9 | $Parameters['AWSRegion'] = "ap-southeast-2"; 10 | $Parameters['CloudFormationStackName'] = "{0}-simple-sandbox-{1}" -f @($Parameters['ResourcePrefix'], $Parameters['Environment']); 11 | $Parameters['S3BucketName'] = "{0}-simple-sandbox-infrastructure" -f $Parameters['ResourcePrefix']; 12 | $Parameters['VpcId'] = "vpc-7ecaee1b"; 13 | 14 | # AWS parameters 15 | $Parameters['KeyPairName'] = "AwsDayKeyPair"; 16 | $Parameters['WebserverImageId'] = "ami-bf8895dc"; #WINDOWS_2016_BASE 17 | $Parameters['WebserverInstanceType'] = "t2.medium"; 18 | $Parameters['WebserverSubnetId'] = "subnet-99477cee"; # DMZ B -------------------------------------------------------------------------------- /Exercise2/Templates/Webserver.template.answer: -------------------------------------------------------------------------------- 1 | { 2 | "AWSTemplateFormatVersion": "2010-09-09", 3 | 4 | "Description": "A template to deploy a simple web server to a single subnet.", 5 | 6 | "Parameters": { 7 | "VpcId": { 8 | "Description": "The Vpc to deploy the Webserver infrastructure into.", 9 | "Type": "String" 10 | }, 11 | "Version": { 12 | "Description": "The package version that contains this CloudFormation template.", 13 | "Type": "String" 14 | }, 15 | "Environment": { 16 | "Type": "String", 17 | "Default": "Development" 18 | }, 19 | "KeyPairName": { 20 | "Description": "The EC2 key pair used to launch web instances", 21 | "Type": "AWS::EC2::KeyPair::KeyName" 22 | }, 23 | "WebserverImageId": { 24 | "Description": "The EC2 AmiId to use for web", 25 | "Type": "String" 26 | }, 27 | "WebserverInstanceType": { 28 | "Description": "The EC2 instance type to use for web", 29 | "Type": "String" 30 | }, 31 | "WebserverSubnetId": { 32 | "Description": "The PUBLIC subnet belonging to availability zone one into which the instance will be launched", 33 | "Type": "String" 34 | }, 35 | "ResourcePrefix" : { 36 | "Description": "Used to prefix a unique name to resources where applicable", 37 | "Type": "String" 38 | } 39 | }, 40 | 41 | "Resources": { 42 | "WebSecurityGroup": { 43 | "Type": "AWS::EC2::SecurityGroup", 44 | "Properties": { 45 | "GroupDescription": "Inbound Octopus, RDP and HTTP (web and healthcheck)", 46 | "VpcId": { "Ref": "VpcId" }, 47 | "SecurityGroupIngress": [ 48 | { 49 | "IpProtocol": "tcp", 50 | "FromPort": "10933", 51 | "ToPort": "10933", 52 | "CidrIp": "172.26.0.0/0" 53 | }, 54 | { 55 | "IpProtocol": "tcp", 56 | "FromPort": "80", 57 | "ToPort": "80", 58 | "CidrIp": "0.0.0.0/0" 59 | }, 60 | { 61 | "IpProtocol": "tcp", 62 | "FromPort": "3389", 63 | "ToPort": "3389", 64 | "CidrIp": "0.0.0.0/0" 65 | } 66 | ] 67 | } 68 | }, 69 | "WebServer": { 70 | "Type": "AWS::EC2::Instance", 71 | "Properties": { 72 | "ImageId": { "Ref": "WebserverImageId" }, 73 | "InstanceType": { "Ref": "WebserverInstanceType" }, 74 | "KeyName": { "Ref": "KeyPairName" }, 75 | "BlockDeviceMappings": [ 76 | { 77 | "DeviceName": "/dev/sda1", 78 | "Ebs": { 79 | "VolumeSize": "50", 80 | "VolumeType": "gp2" 81 | } 82 | } 83 | ], 84 | "NetworkInterfaces": [ { 85 | "AssociatePublicIpAddress": "true", 86 | "DeviceIndex": "0", 87 | "GroupSet": [ { "Fn::GetAtt": [ "WebSecurityGroup", "GroupId" ] } ], 88 | "SubnetId": { "Ref" : "WebserverSubnetId" } 89 | } ], 90 | "Tags": [ 91 | { 92 | "Key": "Name", 93 | "Value": { 94 | "Fn::Join": [ 95 | "", 96 | [ 97 | { 98 | "Ref": "ResourcePrefix" 99 | }, 100 | "-", 101 | { 102 | "Ref": "Environment" 103 | }, 104 | "-WebServer" 105 | ] 106 | ] 107 | } 108 | }, 109 | { 110 | "Key": "Version", 111 | "Value": { "Ref": "Version" } 112 | }, 113 | { 114 | "Key": "Environment", 115 | "Value": { "Ref": "Environment" } 116 | } 117 | ] 118 | } 119 | } 120 | } 121 | } -------------------------------------------------------------------------------- /Exercise3.md: -------------------------------------------------------------------------------- 1 | # Exercise 3 2 | 3 | ## PowerShell DSC authoring 4 | 5 | In this exercise we will build out a sample DSC template and apply it to our CloudFormation-created web servers that we created in [Exercise 2](https://github.com/andrewabest/AWS-Workshop/blob/master/Exercise2.md). 6 | 7 | We are going to configure a website to act as a basic load balancer endpoint that our server's IIS can serve up when requested over port 81 - a static index.html file will suffice. 8 | 9 | ## Goals 10 | 11 | * Use DSC resources to add a load balancer endpoint and firewall exceptions to the supplied DSC template 12 | * See what happens when a configuration fails to compile, and know how to 'fail fast' 13 | * See the output of the Local Configuration Manager when it applies a configuration 14 | * Discover how to diagnose errors that occur when applying DSC configurations 15 | * Configure a Windows server with DSC 16 | 17 | ## Instructions 18 | 19 | 1. Remote into your EC2 instance that you created with CloudFormation in [Exercise 2](https://github.com/andrewabest/AWS-Workshop/blob/master/Exercise2.md). 20 | 2. Copy the contents of .\Exercise3 onto the instance 21 | 3. Jump into PowerShell ISE on your instance and allow us to utilize our unsigned DSC resources by executing the following 22 | 23 | > Set-ExecutionPolicy Bypass 24 | 25 | 4. Open .\Exercise3\PowerShellModules, and copy all of the folders therein over to 26 | 27 | > C:\Program Files\WindowsPowerShell\Modules 28 | 29 | > NOTE: since Powershell 5, we can install these modules like so: 30 | > install-module xdscdiagnostics -Repository 'PSGallery' 31 | 32 | 5. Open .\Exercise3\DSC_Diagnostics.md and read it. Enable low level logging on your instance, and have a play with the Get and Trace cmdlets mentioned 33 | 6. Open .\Exercise3\ConfigureWebserver.ps1 - this is our DSC configuration. Take a look at its structure. Look at what it is already doing 34 | 7. Complete the [File](https://msdn.microsoft.com/en-us/PowerShell/DSC/fileResource) resource TODO 35 | 8. Complete the [xWebsite](https://github.com/PowerShell/xWebAdministration#xwebsite) resource TODO 36 | 9. Complete the [xFirewall](https://github.com/PowerShell/xNetworking#xfirewall) resource TODO 37 | 10. F5 your configuration. The machine will need to reboot a couple of times - you can see where by looking for the **xPendingReboot** resource usage 38 | 11. Monitor the EC2 console in AWS for your machine to come back online - once it is, remote back into it 39 | 12. Open the DSC_Diagnostics.md guide again and use the instructions to see what operations were executed, if they were successful or not, and what diagnostic information you are provided with 40 | 13. If there were errors, troubleshoot what they were. Pair up, rubber duck, whatever works! Once you think you have fixed the errors in your configuration again, F5 it again! 41 | 14. Rinse and repeat until you have succesfully configured your server 42 | 43 | ### Gotchas 44 | 45 | If you want to run the configuration multiple times, you will need to remove the previously generated MOF before regenerating a new one, or you will get a reasonably undecipherable error 46 | -------------------------------------------------------------------------------- /Exercise3/ConfigureWebserver.ps1: -------------------------------------------------------------------------------- 1 | Configuration ConfigureWebserver 2 | { 3 | Import-DscResource -ModuleName cWinServer 4 | Import-DscResource -ModuleName xWebAdministration 5 | Import-DscResource -ModuleName xPendingReboot 6 | Import-DscResource -ModuleName xNetworking 7 | 8 | # Localhost targets the node this script is run on 9 | Node 'localhost' 10 | { 11 | LocalConfigurationManager 12 | { 13 | RebootNodeIfNeeded = $True 14 | } 15 | 16 | WinServerOptions ServerOptions 17 | { 18 | Ensure = "Present" 19 | Name = "Set timezone and culture" 20 | Culture = "en-AU" 21 | TimeZone = "AUS Eastern Standard Time" 22 | } 23 | 24 | xPendingReboot AfterServerOptions 25 | { 26 | Name = "AfterServerOptions" 27 | DependsOn = '[WinServerOptions]ServerOptions' 28 | } 29 | 30 | $windowsFeatures = @( 31 | "Web-App-Dev", 32 | "Web-Common-Http", 33 | "Web-Health", 34 | "Web-Performance", 35 | "Web-Security", 36 | "Web-Scripting-Tools", 37 | "Web-Mgmt-Service", 38 | "Web-Mgmt-Console" 39 | ) 40 | 41 | $windowsFeatureDependOn = @(); 42 | 43 | foreach ($windowsFeature in $windowsFeatures) 44 | { 45 | WindowsFeature "IIS_$windowsFeature" 46 | { 47 | Ensure = "Present" 48 | Name = $windowsFeature 49 | IncludeAllSubFeature = $true 50 | DependsOn = "[xPendingReboot]AfterServerOptions" 51 | } 52 | 53 | $windowsFeatureDependOn += "[WindowsFeature]IIS_$windowsFeature" 54 | } 55 | 56 | <# 57 | NOTE: For new players, if you want to discover whether a reboot will be required after a given piece of DSC, search for "$global:DSCMachineStatus = 1" in the resources you have used. 58 | #> 59 | 60 | xPendingReboot AfterWindowsFeatures 61 | { 62 | Name = 'AfterWindowsFeatures' 63 | DependsOn = $windowsFeatureDependOn 64 | } 65 | 66 | # Stop & Remove the default website 67 | xWebsite DefaultSite 68 | { 69 | Ensure = "Absent" 70 | Name = "Default Web Site" 71 | State = "Stopped" 72 | PhysicalPath = "C:\inetpub\wwwroot" 73 | DependsOn = $windowsFeatureDependOn 74 | } 75 | 76 | # Remove all default Application Pools EXCEPT DEFAULT (will use this for the load balancer health check) 77 | foreach ($appPool in @("Classic .NET AppPool", ".NET v2.0", 78 | ".NET v2.0 Classic", ".NET v4.5", ".NET v4.5 Classic")) 79 | { 80 | xWebAppPool $appPool 81 | { 82 | Ensure = "Absent" 83 | Name = $appPool 84 | DependsOn = ($windowsFeatureDependOn + @("[xWebsite]DefaultSite")) 85 | } 86 | } 87 | 88 | # TODO: Use File Resource to add a load-balancer endpoint index.html 89 | 90 | # TODO: Use xWebsite Resource to set up an IIS website at the root of the load-balancer endpoint 91 | 92 | # TODO: Use xFirewall Resource to allow inbound http access on ports 80 and 81 93 | } 94 | } 95 | 96 | ConfigureWebserver 97 | 98 | Set-DscLocalConfigurationManager -Path .\ConfigureWebserver -Verbose 99 | Start-DscConfiguration -Path .\ConfigureWebserver -Verbose -Wait -Force 100 | -------------------------------------------------------------------------------- /Exercise3/ConfigureWebserver.ps1.answer: -------------------------------------------------------------------------------- 1 | Configuration ConfigureWebserver 2 | { 3 | Import-DscResource -ModuleName cWinServer 4 | Import-DscResource -ModuleName xWebAdministration 5 | Import-DscResource -ModuleName xPendingReboot 6 | Import-DscResource -ModuleName xNetworking 7 | 8 | # Localhost targets the node this script is run on 9 | Node 'localhost' 10 | { 11 | LocalConfigurationManager 12 | { 13 | RebootNodeIfNeeded = $True 14 | } 15 | 16 | WinServerOptions ServerOptions 17 | { 18 | Ensure = "Present" 19 | Name = "Set timezone and culture" 20 | Culture = "en-AU" 21 | TimeZone = "AUS Eastern Standard Time" 22 | } 23 | 24 | xPendingReboot AfterServerOptions 25 | { 26 | Name = "AfterServerOptions" 27 | DependsOn = '[WinServerOptions]ServerOptions' 28 | } 29 | 30 | $windowsFeatures = @( 31 | "Web-App-Dev", 32 | "Web-Common-Http", 33 | "Web-Health", 34 | "Web-Performance", 35 | "Web-Security", 36 | "Web-Scripting-Tools", 37 | "Web-Mgmt-Service", 38 | "Web-Mgmt-Console" 39 | ) 40 | 41 | $windowsFeatureDependOn = @(); 42 | 43 | foreach ($windowsFeature in $windowsFeatures) 44 | { 45 | WindowsFeature "IIS_$windowsFeature" 46 | { 47 | Ensure = "Present" 48 | Name = $windowsFeature 49 | IncludeAllSubFeature = $true 50 | DependsOn = "[xPendingReboot]AfterServerOptions" 51 | } 52 | 53 | $windowsFeatureDependOn += "[WindowsFeature]IIS_$windowsFeature" 54 | } 55 | 56 | <# 57 | NOTE: For new players, if you want to discover whether a reboot will be required after a given piece of DSC, search for "$global:DSCMachineStatus = 1" in the resources you have used. 58 | #> 59 | 60 | xPendingReboot AfterWindowsFeatures 61 | { 62 | Name = 'AfterWindowsFeatures' 63 | DependsOn = $windowsFeatureDependOn 64 | } 65 | 66 | # Stop & Remove the default website 67 | xWebsite DefaultSite 68 | { 69 | Ensure = "Absent" 70 | Name = "Default Web Site" 71 | State = "Stopped" 72 | PhysicalPath = "C:\inetpub\wwwroot" 73 | DependsOn = $windowsFeatureDependOn 74 | } 75 | 76 | # Remove all default Application Pools EXCEPT DEFAULT (will use this for the load balancer health check) 77 | foreach ($appPool in @("Classic .NET AppPool", ".NET v2.0", 78 | ".NET v2.0 Classic", ".NET v4.5", ".NET v4.5 Classic")) 79 | { 80 | xWebAppPool $appPool 81 | { 82 | Ensure = "Absent" 83 | Name = $appPool 84 | DependsOn = ($windowsFeatureDependOn + @("[xWebsite]DefaultSite")) 85 | } 86 | } 87 | 88 | File LoadBalancerHealthCheckEndpointContent 89 | { 90 | Ensure = "Present" 91 | DestinationPath = "C:\inetpub\wwwroot\index.html" 92 | Contents = "Hello, is it me you're looking for?" 93 | Type = "File" 94 | } 95 | 96 | xWebsite LoadBalancerHealthCheckEndpoint 97 | { 98 | Ensure = "Present" 99 | Name = "LoadBalancerHealthCheck" 100 | State = "Started" 101 | PhysicalPath = "C:\inetpub\wwwroot" 102 | BindingInfo = MSFT_xWebBindingInformation 103 | { 104 | Protocol = "HTTP" 105 | Port = 81 106 | } 107 | DependsOn = "[File]LoadBalancerHealthCheckEndpointContent" 108 | } 109 | 110 | xFirewall Firewall 111 | { 112 | Name = "Web" 113 | DisplayName = "Inbound access for web requests" 114 | Ensure = "Present" 115 | Access = "Allow" 116 | State = "Enabled" 117 | Profile = ("Domain", "Private", "Public") 118 | Direction = "InBound" 119 | RemotePort = ("Any") 120 | LocalPort = ("80", "81", "443") 121 | Protocol = "TCP" 122 | Description = "Inbound access for web requests" 123 | } 124 | } 125 | } 126 | 127 | ConfigureWebserver 128 | 129 | Set-DscLocalConfigurationManager -Path .\ConfigureWebserver -Verbose 130 | Start-DscConfiguration -Path .\ConfigureWebserver -Verbose -Wait -Force 131 | -------------------------------------------------------------------------------- /Exercise3/DSC_Diagnostics.md: -------------------------------------------------------------------------------- 1 | # DSC Diagnostics 2 | 3 | PowerShell logs all DSC related events to *[Applications and Services Logs/Microsoft/Windows/Desired State Configuration]* in the Windows Event Log. 4 | 5 | By default, **analytic** and **debug** level logging are off by default. To turn them on, we can use the [xDscDiagnostics](http://blogs.msdn.com/b/powershell/archive/2014/02/11/dsc-diagnostics-module-analyze-dsc-logs-instantly-now.aspx) module and run the following commands 6 | 7 | Update-xDscEventLogStatus -Channel Analytic -Status Enabled 8 | Update-xDscEventLogStatus -Channel Debug -Status Enabled 9 | 10 | Once we have enabled our low-level logging, we can query to see what DSC operations have been executed thus far by executing 11 | 12 | Get-xDscOperation 13 | 14 | To get detailed information on an operation, we can then go further and use 15 | 16 | Trace-xDscOperation -SequenceID 1 | Format-Table 17 | 18 | If you are particularly sadistic, and the xDscDiagnostics tools are not returning the information you want to see, you can query the event log directly using the approaches outlined [here](https://technet.microsoft.com/en-au/library/dn249926.aspx). Disclaimer: it is a horrible way to work. -------------------------------------------------------------------------------- /Exercise3/PowerShellModules/cWinServer/DSCResources/WinServerOptions/WinServerOptions.psm1: -------------------------------------------------------------------------------- 1 | function Get-TargetResource 2 | { 3 | [CmdletBinding()] 4 | [OutputType([System.Collections.Hashtable])] 5 | param 6 | ( 7 | [parameter(Mandatory = $true)] 8 | [System.String] 9 | $Name, 10 | 11 | [System.String] 12 | $Culture, 13 | 14 | [System.String] 15 | $TimeZone 16 | ) 17 | 18 | $returnValue = @{ 19 | Ensure = $Ensure 20 | Name = $Name 21 | Culture = $Culture 22 | Timezone = $Timezone 23 | } 24 | 25 | return $returnValue; 26 | } 27 | 28 | function Set-TargetResource 29 | { 30 | [CmdletBinding()] 31 | param 32 | ( 33 | [ValidateSet("Present","Absent")] 34 | [System.String] 35 | $Ensure, 36 | 37 | [parameter(Mandatory = $true)] 38 | [System.String] 39 | $Name, 40 | 41 | [System.String] 42 | $Culture, 43 | 44 | [System.String] 45 | $TimeZone 46 | ) 47 | 48 | if ($Ensure -eq "Present") 49 | { 50 | if ($Culture) 51 | { 52 | if ((Get-WinSystemLocale).Name -ne $Culture) 53 | { 54 | Write-Verbose "Setting System Locale to $Culture. Will Require reboot to take effect." 55 | Set-WinSystemLocale -SystemLocale $Culture 56 | 57 | $global:DSCMachineStatus = 1; 58 | } 59 | } 60 | 61 | if (([System.TimeZone]::CurrentTimeZone).StandardName -ne $TimeZone) 62 | { 63 | Write-Verbose "Setting System TimeZone to [$TimeZone]" 64 | & tzutil.exe /s "$TimeZone" 65 | } 66 | } 67 | } 68 | 69 | function Test-TargetResource 70 | { 71 | [CmdletBinding()] 72 | [OutputType([System.Boolean])] 73 | param 74 | ( 75 | [ValidateSet("Present","Absent")] 76 | [System.String] 77 | $Ensure, 78 | 79 | [parameter(Mandatory = $true)] 80 | [System.String] 81 | $Name, 82 | 83 | [System.String] 84 | $Culture, 85 | 86 | [System.String] 87 | $TimeZone 88 | ) 89 | 90 | if ($Ensure -eq "Present") 91 | { 92 | if ($Culture) 93 | { 94 | if ((Get-WinSystemLocale).Name -ne $Culture) 95 | { 96 | Write-Verbose "System Locale is currently $((Get-WinSystemLocale).Name) and should be $Culture" 97 | return $false; 98 | } 99 | 100 | Write-Verbose "System Locale and Culture are correct." 101 | } 102 | 103 | if ($TimeZone) 104 | { 105 | if (([System.TimeZone]::CurrentTimeZone).StandardName -ne $TimeZone) 106 | { 107 | Write-Verbose "System TimeZone is current:[$(([System.TimeZone]::CurrentTimeZone).StandardName)] and should be:[$TimeZone]" 108 | return $false; 109 | } 110 | 111 | Write-Verbose "System TimeZone is correct." 112 | } 113 | } 114 | else 115 | { 116 | Write-Verbose "Ignoring checks" 117 | } 118 | 119 | return $true; 120 | } -------------------------------------------------------------------------------- /Exercise3/PowerShellModules/cWinServer/DSCResources/WinServerOptions/WinServerOptions.schema.mof: -------------------------------------------------------------------------------- 1 | [ClassVersion("1.0.0.0"), FriendlyName("WinServerOptions")] 2 | class WinServerOptions : OMI_BaseResource 3 | { 4 | [Write, ValueMap{"Present","Absent"}, Values{"Present","Absent"}] String Ensure; 5 | [Key, Description("The name for the setup. Can just be the server name")] String Name; 6 | [Write, Description("The Windows Server culture")] String Culture; 7 | [Write, Description("The Windows Server Timezone")] String TimeZone; 8 | }; -------------------------------------------------------------------------------- /Exercise3/PowerShellModules/cWinServer/cWinServer.psd1: -------------------------------------------------------------------------------- 1 | # 2 | # Module manifest for module 'cWinServer' 3 | # 4 | # Generated by: andrewb 5 | # 6 | # Generated on: 9/06/2015 7 | @{ 8 | ModuleVersion = '1.0' 9 | GUID = '90798d5f-9f2e-4af4-b9fd-79b4f67899fb' 10 | Author = 'andrewb' 11 | CompanyName = 'Unknown' 12 | Copyright = '(c) 2015 andrewb. All rights reserved.' 13 | Description = '' 14 | PowerShellVersion = '4.0' 15 | FunctionsToExport = @('Get-TargetResource','Set-TargetResource','Test-TargetResource') 16 | } 17 | 18 | -------------------------------------------------------------------------------- /Exercise3/PowerShellModules/xDscDiagnostics/xDscDiagnostics.psd1: -------------------------------------------------------------------------------- 1 |  2 | 3 | @{ 4 | 5 | 6 | ModuleVersion = '2.0' 7 | GUID = 'ef098cb4-f7e9-4763-b636-0cd9799e1c9a' 8 | 9 | Author = 'Microsoft Corporation' 10 | CompanyName = 'Microsoft Corporation' 11 | Copyright = '(c) 2013 Microsoft Corporation. All rights reserved.' 12 | 13 | Description = 'Module to help in reading details from DSC events' 14 | 15 | PowerShellVersion = '4.0' 16 | 17 | CLRVersion = '4.0' 18 | 19 | FunctionsToExport = @("*") 20 | 21 | NestedModules = @('xDscDiagnostics.psm1') 22 | } -------------------------------------------------------------------------------- /Exercise3/PowerShellModules/xDscDiagnostics/xDscDiagnosticsFormat.ps1xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Microsoft.PowerShell.xDscDiagnostics.GroupedEvents 7 | 8 | Microsoft.PowerShell.xDscDiagnostics.GroupedEvents 9 | 10 | 11 | 12 | 13 | 14 | 14 15 | 16 | 17 | 18 | 10 19 | 20 | 21 | 22 | 21 23 | 24 | 25 | 26 | 8 27 | 28 | 29 | 30 | 37 31 | 32 | 33 | 34 | 21 35 | 36 | 37 | 38 | 39 | 40 | 41 | ComputerName 42 | 43 | 44 | SequenceId 45 | 46 | 47 | TimeCreated 48 | 49 | 50 | Result 51 | 52 | 53 | JobID 54 | 55 | 56 | AllEvents 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | Microsoft.PowerShell.xDscDiagnostics.TraceOutput 65 | 66 | Microsoft.PowerShell.xDscDiagnostics.TraceOutput 67 | 68 | 69 | 70 | 71 | 72 | 14 73 | 74 | 75 | 76 | 12 77 | 78 | 79 | 80 | 21 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | ComputerName 91 | 92 | 93 | EventType 94 | 95 | 96 | TimeCreated 97 | 98 | 99 | Message 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | -------------------------------------------------------------------------------- /Exercise3/PowerShellModules/xNetworking/DSCResources/MSFT_xDNSServerAddress/MSFT_xDNSServerAddress.psm1: -------------------------------------------------------------------------------- 1 | <####################################################################################### 2 | # xDNSServerAddress : DSC Resource that will set/test/get the current DNS Server 3 | # Address, by accepting values among those given in xDNSServerAddress.schema.mof 4 | #######################################################################################> 5 | 6 | 7 | 8 | ###################################################################################### 9 | # The Get-TargetResource cmdlet. 10 | # This function will get the present list of DNS ServerAddress DSC Resource schema variables on the system 11 | ###################################################################################### 12 | function Get-TargetResource 13 | { 14 | param 15 | ( 16 | [Parameter(Mandatory)] 17 | [ValidateNotNullOrEmpty()] 18 | [String[]]$Address, 19 | 20 | [Parameter(Mandatory)] 21 | [ValidateNotNullOrEmpty()] 22 | [String]$InterfaceAlias, 23 | 24 | [ValidateSet("IPv4", "IPv6")] 25 | [String]$AddressFamily = "IPv4" 26 | ) 27 | 28 | 29 | $returnValue = @{ 30 | Address = (Get-DnsClientServerAddress -InterfaceAlias $InterfaceAlias -AddressFamily $AddressFamily).ServerAddresses 31 | AddressFamily = $AddressFamily 32 | InterfaceAlias = $InterfaceAlias 33 | } 34 | 35 | $returnValue 36 | } 37 | 38 | ###################################################################################### 39 | # The Set-TargetResource cmdlet. 40 | # This function will set a new Server Address in the current node 41 | ###################################################################################### 42 | function Set-TargetResource 43 | { 44 | param 45 | ( 46 | #IP Address that has to be set 47 | [Parameter(Mandatory)] 48 | [ValidateNotNullOrEmpty()] 49 | [String[]]$Address, 50 | 51 | [Parameter(Mandatory)] 52 | [ValidateNotNullOrEmpty()] 53 | [String]$InterfaceAlias, 54 | 55 | [ValidateSet("IPv4", "IPv6")] 56 | [String]$AddressFamily = "IPv4" 57 | ) 58 | 59 | ValidateProperties @PSBoundParameters -Apply 60 | } 61 | 62 | ###################################################################################### 63 | # The Test-TargetResource cmdlet. 64 | # This will test if the given Server Address is among the current node's Server Address collection 65 | ###################################################################################### 66 | function Test-TargetResource 67 | { 68 | param 69 | ( 70 | [Parameter(Mandatory)] 71 | [ValidateNotNullOrEmpty()] 72 | [String[]]$Address, 73 | 74 | [Parameter(Mandatory)] 75 | [ValidateNotNullOrEmpty()] 76 | [String]$InterfaceAlias, 77 | 78 | [ValidateSet("IPv4", "IPv6")] 79 | [String]$AddressFamily = "IPv4" 80 | ) 81 | 82 | ValidateProperties @PSBoundParameters 83 | } 84 | 85 | 86 | ####################################################################################### 87 | # Helper function that validates the Server Address properties. If the switch parameter 88 | # "Apply" is set, then it will set the properties after a test 89 | ####################################################################################### 90 | function ValidateProperties 91 | { 92 | param 93 | ( 94 | [Parameter(Mandatory)] 95 | [ValidateNotNullOrEmpty()] 96 | [String[]]$Address, 97 | 98 | [Parameter(Mandatory)] 99 | [ValidateNotNullOrEmpty()] 100 | [String]$InterfaceAlias, 101 | 102 | [ValidateSet("IPv4", "IPv6")] 103 | [String]$AddressFamily, 104 | 105 | [Switch]$Apply 106 | ) 107 | $sa =$Address 108 | $sa | %{ 109 | if(!([System.Net.Ipaddress]::TryParse($_, [ref]0))) 110 | { 111 | throw "Server Address *$_* is not in the correct format. Please correct the Address in the configuration and try again" 112 | } 113 | if (([System.Net.IPAddress]$_).AddressFamily.ToString() -eq [System.Net.Sockets.AddressFamily]::InterNetwork.ToString()) 114 | { 115 | if ($AddressFamily -ne "IPv4") 116 | { 117 | throw "Server address $Address is in IPv4 format, which does not match server address family $AddressFamily. Please correct either of them in the configuration and try again" 118 | } 119 | } 120 | else 121 | { 122 | if ($AddressFamily -ne "IPv6") 123 | { 124 | throw "Server address $Address is in IPv6 format, which does not match server address family $AddressFamily. Please correct either of them in the configuration and try again" 125 | } 126 | } 127 | } 128 | try 129 | { 130 | Write-Verbose -Message "Checking the DNS Server Address ..." 131 | #Get the current IP Address based on the parameters given. 132 | $currentAddress = (Get-DnsClientServerAddress -InterfaceAlias $InterfaceAlias -AddressFamily $AddressFamily -ErrorAction Stop).ServerAddresses 133 | 134 | #Check if the Server addresses are the same as the desired addresses. 135 | if(@(Compare-Object -ReferenceObject $currentAddress -DifferenceObject $Address -SyncWindow 0).Length -gt 0) 136 | { 137 | Write-Verbose -Message "DNS Servers are not correct. Expected $Address, actual $currentAddress" 138 | if($Apply) 139 | { 140 | # Set the DNS settings as well 141 | Set-DnsClientServerAddress -InterfaceAlias $InterfaceAlias -ServerAddresses $Address 142 | Write-Verbose -Message "DNS Servers have been set correctly." 143 | } 144 | else 145 | { 146 | return $false 147 | } 148 | } 149 | else 150 | { 151 | #Test will return true in this case 152 | Write-Verbose -Message "DNS Servers are set correctly." 153 | return $true 154 | } 155 | } 156 | catch 157 | { 158 | Write-Verbose -Message $_ 159 | throw "Can not set or find valid DNS Server addresses using InterfaceAlias $InterfaceAlias and AddressFamily $AddressFamily" 160 | } 161 | } 162 | 163 | 164 | 165 | # FUNCTIONS TO BE EXPORTED 166 | Export-ModuleMember -function Get-TargetResource, Set-TargetResource, Test-TargetResource -------------------------------------------------------------------------------- /Exercise3/PowerShellModules/xNetworking/DSCResources/MSFT_xDNSServerAddress/MSFT_xDNSServerAddress.schema.mof: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewabest/AWS-Workshop/071e4b7912e2704a366be0a6294d4d3d1da95a4d/Exercise3/PowerShellModules/xNetworking/DSCResources/MSFT_xDNSServerAddress/MSFT_xDNSServerAddress.schema.mof -------------------------------------------------------------------------------- /Exercise3/PowerShellModules/xNetworking/DSCResources/MSFT_xFirewall/MSFT_xFirewall.Schema.mof: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewabest/AWS-Workshop/071e4b7912e2704a366be0a6294d4d3d1da95a4d/Exercise3/PowerShellModules/xNetworking/DSCResources/MSFT_xFirewall/MSFT_xFirewall.Schema.mof -------------------------------------------------------------------------------- /Exercise3/PowerShellModules/xNetworking/DSCResources/MSFT_xIPAddress/MSFT_xIPAddress.psm1: -------------------------------------------------------------------------------- 1 | <####################################################################################### 2 | # MSDSCPack_IPAddress : DSC Resource that will set/test/get the current IP 3 | # Address, by accepting values among those given in MSDSCPack_IPAddress.schema.mof 4 | #######################################################################################> 5 | 6 | 7 | 8 | ###################################################################################### 9 | # The Get-TargetResource cmdlet. 10 | # This function will get the present list of IP Address DSC Resource schema variables on the system 11 | ###################################################################################### 12 | function Get-TargetResource 13 | { 14 | param 15 | ( 16 | [Parameter(Mandatory)] 17 | [ValidateNotNullOrEmpty()] 18 | [String]$IPAddress, 19 | 20 | [Parameter(Mandatory)] 21 | [ValidateNotNullOrEmpty()] 22 | [String]$InterfaceAlias, 23 | 24 | [Int]$SubnetMask = 16, 25 | 26 | [ValidateNotNullOrEmpty()] 27 | [String]$DefaultGateway, 28 | 29 | [ValidateSet("IPv4", "IPv6")] 30 | [String]$AddressFamily = "IPv4" 31 | ) 32 | 33 | 34 | $returnValue = @{ 35 | IPAddress = [System.String]::Join(", ",(Get-NetIPAddress -InterfaceAlias $InterfaceAlias -AddressFamily $AddressFamily).IPAddress) 36 | SubnetMask = $SubnetMask 37 | DefaultGateway = $DefaultGateway 38 | AddressFamily = $AddressFamily 39 | InterfaceAlias=$InterfaceAlias 40 | } 41 | 42 | $returnValue 43 | } 44 | 45 | ###################################################################################### 46 | # The Set-TargetResource cmdlet. 47 | # This function will set a new IP Address in the current node 48 | ###################################################################################### 49 | function Set-TargetResource 50 | { 51 | param 52 | ( 53 | #IP Address that has to be set 54 | [Parameter(Mandatory)] 55 | [ValidateNotNullOrEmpty()] 56 | [String]$IPAddress, 57 | 58 | [Parameter(Mandatory)] 59 | [ValidateNotNullOrEmpty()] 60 | [String]$InterfaceAlias, 61 | 62 | [Int]$SubnetMask, 63 | 64 | [ValidateNotNullOrEmpty()] 65 | [String]$DefaultGateway, 66 | 67 | [ValidateSet("IPv4", "IPv6")] 68 | [String]$AddressFamily = "IPv4" 69 | ) 70 | 71 | 72 | ValidateProperties @PSBoundParameters -Apply 73 | } 74 | 75 | ###################################################################################### 76 | # The Test-TargetResource cmdlet. 77 | # This will test if the given IP Address is among the current node's IP Address collection 78 | ###################################################################################### 79 | function Test-TargetResource 80 | { 81 | param 82 | ( 83 | [Parameter(Mandatory)] 84 | [ValidateNotNullOrEmpty()] 85 | [String]$IPAddress, 86 | 87 | [Parameter(Mandatory)] 88 | [ValidateNotNullOrEmpty()] 89 | [String]$InterfaceAlias, 90 | 91 | [Int]$SubnetMask, 92 | 93 | [ValidateNotNullOrEmpty()] 94 | [String]$DefaultGateway, 95 | 96 | [ValidateSet("IPv4", "IPv6")] 97 | [String]$AddressFamily = "IPv4" 98 | ) 99 | 100 | ValidateProperties @PSBoundParameters 101 | } 102 | 103 | 104 | ####################################################################################### 105 | # Helper function that validates the IP Address properties. If the switch parameter 106 | # "Apply" is set, then it will set the properties after a test 107 | ####################################################################################### 108 | function ValidateProperties 109 | { 110 | param 111 | ( 112 | [Parameter(Mandatory)] 113 | [ValidateNotNullOrEmpty()] 114 | [String]$IPAddress, 115 | 116 | [Parameter(Mandatory)] 117 | [ValidateNotNullOrEmpty()] 118 | [String]$InterfaceAlias, 119 | 120 | [ValidateNotNullOrEmpty()] 121 | [String]$DefaultGateway, 122 | 123 | [Int]$SubnetMask = 16, 124 | 125 | [ValidateSet("IPv4", "IPv6")] 126 | [String]$AddressFamily = "IPv4", 127 | 128 | [Switch]$Apply 129 | ) 130 | $ip=$IPAddress 131 | if(!([System.Net.Ipaddress]::TryParse($ip, [ref]0))) 132 | { 133 | throw "IP Address *$IPAddress* is not in the correct format. Please correct the ipaddress in the configuration and try again" 134 | } 135 | try 136 | { 137 | Write-Verbose -Message "Checking the IPAddress ..." 138 | #Get the current IP Address based on the parameters given. 139 | $currentIP = Get-NetIPAddress -InterfaceAlias $InterfaceAlias -AddressFamily $AddressFamily -ErrorAction Stop 140 | 141 | #Test if the IP Address passed is equal to the current ip address 142 | if(!$currentIP.IPAddress.Contains($IPAddress)) 143 | { 144 | Write-Verbose -Message "IPAddress not correct. Expected $IPAddress, actual $($currentIP.IPAddress)" 145 | $Parameters = @{} 146 | 147 | #Apply is true in the case of set - target resource - in which case, it will set the new IP Address 148 | if($Apply) 149 | { 150 | Write-Verbose -Message "Setting IPAddress ..." 151 | $Parameters["IPAddress"] = $IPAddress 152 | $Parameters["PrefixLength"] = $SubnetMask 153 | $Parameters["InterfaceAlias"] = $currentIP[0].InterfaceAlias 154 | 155 | if($DefaultGateway){ $Parameters["DefaultGateWay"] = $DefaultGateway } 156 | $null = New-NetIPAddress @Parameters -ErrorAction Stop 157 | 158 | # Make the connection profile private 159 | Get-NetConnectionProfile -InterfaceAlias $InterfaceAlias | Set-NetConnectionProfile -NetworkCategory Private -ErrorAction SilentlyContinue 160 | Write-Verbose -Message "IPAddress is set to $IPAddress." 161 | } 162 | else {return $false} 163 | } 164 | else 165 | { 166 | Write-Verbose -Message "IPAddress is correct." 167 | return $true 168 | } 169 | } 170 | catch 171 | { 172 | Write-Verbose -Message $_ 173 | throw "Can not set or find valid IPAddress using InterfaceAlias $InterfaceAlias and AddressFamily $AddressFamily" 174 | } 175 | } 176 | 177 | 178 | 179 | # FUNCTIONS TO BE EXPORTED 180 | Export-ModuleMember -function Get-TargetResource, Set-TargetResource, Test-TargetResource -------------------------------------------------------------------------------- /Exercise3/PowerShellModules/xNetworking/DSCResources/MSFT_xIPAddress/MSFT_xIPAddress.schema.mof: -------------------------------------------------------------------------------- 1 | [ClassVersion("1.0.0"), FriendlyName("xIPAddress")] 2 | class MSFT_xIPAddress : OMI_BaseResource 3 | { 4 | [Key] string IPAddress; 5 | [Key] string InterfaceAlias; 6 | [write] string DefaultGateway; 7 | [Write] uint32 SubnetMask; 8 | [Write,ValueMap{"IPv4", "IPv6"},Values{"IPv4", "IPv6"}] string AddressFamily; 9 | }; 10 | -------------------------------------------------------------------------------- /Exercise3/PowerShellModules/xNetworking/Examples/Sample_xDnsServerAddress.ps1: -------------------------------------------------------------------------------- 1 | configuration Sample_xDnsServerAddress 2 | { 3 | param 4 | ( 5 | [string[]]$NodeName = 'localhost', 6 | 7 | [Parameter(Mandatory)] 8 | [string]$DnsServerAddress, 9 | 10 | [Parameter(Mandatory)] 11 | [string]$InterfaceAlias, 12 | 13 | [ValidateSet("IPv4","IPv6")] 14 | [string]$AddressFamily = 'IPv4' 15 | ) 16 | 17 | Import-DscResource -Module xNetworking 18 | 19 | Node $NodeName 20 | { 21 | xDnsServerAddress DnsServerAddress 22 | { 23 | Address = $DnsServerAddress 24 | InterfaceAlias = $InterfaceAlias 25 | AddressFamily = $AddressFamily 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /Exercise3/PowerShellModules/xNetworking/Examples/Sample_xFirewall_AddFirewallRule.ps1: -------------------------------------------------------------------------------- 1 | # DSC configuration for Firewall 2 | 3 | configuration Sample_xFirewall_AddFirewallRule 4 | { 5 | param 6 | ( 7 | [string[]]$NodeName = 'localhost' 8 | ) 9 | 10 | Import-DSCResource -ModuleName xNetworking 11 | 12 | Node $NodeName 13 | { 14 | xFirewall Firewall 15 | { 16 | Name = "NotePadFirewallRule" 17 | DisplayName = "Firewall Rule for Notepad.exe" 18 | DisplayGroup = "NotePad Firewall Rule Group" 19 | Ensure = "Present" 20 | Access = "Allow" 21 | State = "Enabled" 22 | Profile = ("Domain", "Private") 23 | Direction = "OutBound" 24 | RemotePort = ("8080", "8081") 25 | LocalPort = ("9080", "9081") 26 | Protocol = "TCP" 27 | Description = "Firewall Rule for Notepad.exe" 28 | ApplicationPath = "c:\windows\system32\notepad.exe" 29 | Service = "WinRM" 30 | } 31 | } 32 | } 33 | 34 | Sample_xFirewall_AddFirewallRule 35 | Start-DscConfiguration -Path Sample_xFirewall_AddFirewallRule -Wait -Verbose -Force -------------------------------------------------------------------------------- /Exercise3/PowerShellModules/xNetworking/Examples/Sample_xFirewall_AddFirewallRuleToExistingGroup.ps1: -------------------------------------------------------------------------------- 1 | # DSC configuration for Firewall 2 | # 3 | 4 | configuration Sample_xFirewall_AddFirewallRuleToExistingGroup 5 | { 6 | param 7 | ( 8 | [string[]]$NodeName = 'localhost' 9 | ) 10 | 11 | Import-DSCResource -ModuleName xNetworking 12 | 13 | Node $NodeName 14 | { 15 | xFirewall Firewall 16 | { 17 | Name = "MyFirewallRule" 18 | DisplayName = "My Firewall Rule" 19 | DisplayGroup = "My Firewall Rule Group" 20 | Access = "Allow" 21 | } 22 | 23 | xFirewall Firewall1 24 | { 25 | Name = "MyFirewallRule1" 26 | DisplayName = "My Firewall Rule" 27 | DisplayGroup = "My Firewall Rule Group" 28 | Ensure = "Present" 29 | Access = "Allow" 30 | State = "Enabled" 31 | Profile = ("Domain", "Private") 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /Exercise3/PowerShellModules/xNetworking/Examples/Sample_xFirewall_AddFirewallRuleToNewGroup.ps1: -------------------------------------------------------------------------------- 1 | # DSC configuration for Firewall 2 | 3 | configuration Sample_xFirewall_AddFirewallRuleToNewGroup 4 | { 5 | param 6 | ( 7 | [string[]]$NodeName = 'localhost' 8 | ) 9 | 10 | Import-DSCResource -ModuleName xNetworking 11 | 12 | Node $NodeName 13 | { 14 | xFirewall Firewall 15 | { 16 | Name = "MyAppFirewallRule" 17 | ApplicationPath = "c:\windows\system32\MyApp.exe" 18 | Access = "Allow" 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /Exercise3/PowerShellModules/xNetworking/Examples/Sample_xFirewall_DisableAccessToApplication.ps1: -------------------------------------------------------------------------------- 1 | # DSC configuration for Firewall 2 | # 3 | 4 | configuration Sample_xFirewall_AddFirewallRuleToNewGroup 5 | { 6 | param 7 | ( 8 | [string[]]$NodeName = 'localhost' 9 | ) 10 | 11 | Import-DSCResource -ModuleName xNetworking 12 | 13 | Node $NodeName 14 | { 15 | xFirewall Firewall 16 | { 17 | Name = "NotePadFirewallRule" 18 | DisplayName = "Firewall Rule for Notepad.exe" 19 | DisplayGroup = "NotePad Firewall Rule Group" 20 | Ensure = "Present" 21 | Access = "Block" 22 | Description = "Firewall Rule for Notepad.exe" 23 | ApplicationPath = "c:\windows\system32\notepad.exe" 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /Exercise3/PowerShellModules/xNetworking/Examples/Sample_xIPAddress_FixedValue.ps1: -------------------------------------------------------------------------------- 1 | configuration Sample_xIPAddress_FixedValue 2 | { 3 | param 4 | ( 5 | [string[]]$NodeName = 'localhost' 6 | ) 7 | 8 | Import-DscResource -Module xNetworking 9 | 10 | Node $NodeName 11 | { 12 | xIPAddress NewIPAddress 13 | { 14 | IPAddress = "2001:4898:200:7:6c71:a102:ebd8:f482" 15 | InterfaceAlias = "Ethernet" 16 | SubnetMask = 24 17 | AddressFamily = "IPV6" 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /Exercise3/PowerShellModules/xNetworking/Examples/Sample_xIPAddress_Parameterized.ps1: -------------------------------------------------------------------------------- 1 | configuration Sample_xIPAddress_Parameterized 2 | { 3 | param 4 | ( 5 | 6 | [string[]]$NodeName = 'localhost', 7 | 8 | [Parameter(Mandatory)] 9 | [string]$IPAddress, 10 | 11 | [Parameter(Mandatory)] 12 | [string]$InterfaceAlias, 13 | 14 | [Parameter(Mandatory)] 15 | [string]$DefaultGateway, 16 | 17 | [int]$SubnetMask = 16, 18 | 19 | [ValidateSet("IPv4","IPv6")] 20 | [string]$AddressFamily = 'IPv4' 21 | ) 22 | 23 | Import-DscResource -Module xNetworking 24 | 25 | Node $NodeName 26 | { 27 | xIPAddress NewIPAddress 28 | { 29 | IPAddress = $IPAddress 30 | InterfaceAlias = $InterfaceAlias 31 | DefaultGateway = $DefaultGateway 32 | SubnetMask = $SubnetMask 33 | AddressFamily = $AddressFamily 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /Exercise3/PowerShellModules/xNetworking/xNetworking.psd1: -------------------------------------------------------------------------------- 1 | @{ 2 | # Version number of this module. 3 | ModuleVersion = '2.1.1' 4 | 5 | # ID used to uniquely identify this module 6 | GUID = 'e6647cc3-ce9c-4c86-9eb8-2ee8919bf358' 7 | 8 | # Author of this module 9 | Author = 'Microsoft Corporation' 10 | 11 | # Company or vendor of this module 12 | CompanyName = 'Microsoft Corporation' 13 | 14 | # Copyright statement for this module 15 | Copyright = '(c) 2013 Microsoft Corporation. All rights reserved.' 16 | 17 | # Description of the functionality provided by this module 18 | Description = 'Module with DSC Resources for Networking area' 19 | 20 | # Minimum version of the Windows PowerShell engine required by this module 21 | PowerShellVersion = '4.0' 22 | 23 | # Minimum version of the common language runtime (CLR) required by this module 24 | CLRVersion = '4.0' 25 | 26 | # Functions to export from this module 27 | FunctionsToExport = '*' 28 | 29 | # Cmdlets to export from this module 30 | CmdletsToExport = '*' 31 | } -------------------------------------------------------------------------------- /Exercise3/PowerShellModules/xPendingReboot/DSCResources/MSFT_xPendingReboot/MSFT_xPendingReboot.psm1: -------------------------------------------------------------------------------- 1 | Function Get-TargetResource 2 | { 3 | [CmdletBinding()] 4 | param 5 | ( 6 | [Parameter(Mandatory=$true)] 7 | [string]$Name 8 | ) 9 | 10 | <## Remove: 11 | $ComponentBasedServicing = (Get-ItemProperty 'hklm:SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\').RebootPending -ne $null 12 | Remove - $WindowsUpdate = (Get-ItemProperty 'hklm:SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\').RebootRequired -ne $null 13 | Remove - $PendingFileRename = (Get-ItemProperty 'hklm:\SYSTEM\CurrentControlSet\Control\Session Manager\').PendingFileRenameOperations -ne $null 14 | #> 15 | 16 | ## Brian's additions:-------------------------------------------------- 17 | $ComponentBasedServicing = (Get-ChildItem 'hklm:SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\').Name.Split("\") -contains "RebootPending" 18 | $WindowsUpdate = (Get-ChildItem 'hklm:SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\').Name.Split("\") -contains "RebootRequired" 19 | $PendingFileRename = (Get-ItemProperty 'hklm:\SYSTEM\CurrentControlSet\Control\Session Manager\').PendingFileRenameOperations.Length -gt 0 20 | $ActiveComputerName = (Get-ItemProperty 'hklm:\SYSTEM\CurrentControlSet\Control\ComputerName\ActiveComputerName').ComputerName 21 | $PendingComputerName = (Get-ItemProperty 'hklm:\SYSTEM\CurrentControlSet\Control\ComputerName\ComputerName').ComputerName 22 | $PendingComputerRename = $ActiveComputerName -ne $PendingComputerName 23 | 24 | $CCMSplat = @{ 25 | NameSpace='ROOT\ccm\ClientSDK' 26 | Class='CCM_ClientUtilities' 27 | Name='DetermineIfRebootPending' 28 | ErrorAction='Stop' 29 | } 30 | 31 | Try { 32 | $CCMClientSDK = Invoke-WmiMethod @CCMSplat 33 | } Catch { 34 | Write-Warning "Unable to query CCM_ClientUtilities: $_" 35 | } 36 | 37 | $SCCMSDK = ($CCMClientSDK.ReturnValue -eq 0) -and ($CCMClientSDK.IsHardRebootPending -or $CCMClientSDK.RebootPending) 38 | ## End Brian's additions------------------------------------------------ 39 | 40 | return @{ 41 | Name = $Name 42 | ComponentBasedServicing = $ComponentBasedServicing 43 | WindowsUpdate = $WindowsUpdate 44 | PendingFileRename = $PendingFileRename 45 | PendingComputerRename = $PendingComputerRename 46 | CcmClientSDK = $SCCMSDK 47 | } 48 | } 49 | 50 | Function Set-TargetResource 51 | { 52 | [CmdletBinding()] 53 | param 54 | ( 55 | [Parameter(Mandatory=$true)] 56 | [string]$Name 57 | ) 58 | 59 | $global:DSCMachineStatus = 1 60 | } 61 | 62 | Function Test-TargetResource 63 | { 64 | [CmdletBinding()] 65 | param 66 | ( 67 | [Parameter(Mandatory=$true)] 68 | [string]$Name 69 | ) 70 | 71 | <## Remove 72 | $regRebootLocations += @{'HKLM:SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\'='RebootPending'} 73 | $regRebootLocations += @{'HKLM:SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\'='RebootRequired'} 74 | $regRebootLocations += @{'HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\'='PendingFileRenameOperations'} 75 | 76 | foreach ($reg in $regRebootLocations.keys) { 77 | if ((Get-ItemProperty $reg).($regRebootLocations[$reg]) -ne $Null) { 78 | Write-Verbose "A pending reboot was found at $reg." 79 | Write-Verbose 'Setting the DSCMachineStatus global variable to 1.' 80 | return $false} 81 | } 82 | #> 83 | 84 | ## Brian's additions:-------------------------------------------------- 85 | $ScriptBlocks += @{ComponentBasedServicing = {(Get-ChildItem 'hklm:SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\').Name.Split("\") -contains "RebootPending"}} 86 | $ScriptBlocks += @{WindowsUpdate = {(Get-ChildItem 'hklm:SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\').Name.Split("\") -contains "RebootRequired"}} 87 | $ScriptBlocks += @{PendingFileRename = {(Get-ItemProperty 'hklm:\SYSTEM\CurrentControlSet\Control\Session Manager\').PendingFileRenameOperations.Length -gt 0}} 88 | $ScriptBlocks += @{PendingComputerRename = { 89 | $ActiveComputerName = (Get-ItemProperty 'hklm:\SYSTEM\CurrentControlSet\Control\ComputerName\ActiveComputerName').ComputerName 90 | $PendingComputerName = (Get-ItemProperty 'hklm:\SYSTEM\CurrentControlSet\Control\ComputerName\ComputerName').ComputerName 91 | $ActiveComputerName -ne $PendingComputerName 92 | } 93 | } 94 | $ScriptBlocks += @{CcmClientSDK = { 95 | $CCMSplat = @{ 96 | NameSpace='ROOT\ccm\ClientSDK' 97 | Class='CCM_ClientUtilities' 98 | Name='DetermineIfRebootPending' 99 | ErrorAction='Stop' 100 | } 101 | Try { 102 | $CCMClientSDK = Invoke-WmiMethod @CCMSplat 103 | ($CCMClientSDK.ReturnValue -eq 0) -and ($CCMClientSDK.IsHardRebootPending -or $CCMClientSDK.RebootPending) 104 | } Catch { 105 | Write-Warning "Unable to query CCM_ClientUtilities: $_" 106 | } 107 | } 108 | } 109 | Foreach ($Script in $ScriptBlocks.Keys) { 110 | If (Invoke-Command $ScriptBlocks[$Script]) { 111 | Write-Verbose "A pending reboot was found for $Script." 112 | Write-Verbose 'Setting the DSCMachineStatus global variable to 1.' 113 | return $false 114 | } 115 | } 116 | ## End Brian's additions------------------------------------------------ 117 | 118 | Write-Verbose 'No pending reboots found.' 119 | return $true 120 | } 121 | 122 | Export-ModuleMember -Function *-TargetResource 123 | 124 | $regRebootLocations = $null -------------------------------------------------------------------------------- /Exercise3/PowerShellModules/xPendingReboot/DSCResources/MSFT_xPendingReboot/MSFT_xPendingReboot.schema.mof: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewabest/AWS-Workshop/071e4b7912e2704a366be0a6294d4d3d1da95a4d/Exercise3/PowerShellModules/xPendingReboot/DSCResources/MSFT_xPendingReboot/MSFT_xPendingReboot.schema.mof -------------------------------------------------------------------------------- /Exercise3/PowerShellModules/xPendingReboot/xPendingReboot.psd1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewabest/AWS-Workshop/071e4b7912e2704a366be0a6294d4d3d1da95a4d/Exercise3/PowerShellModules/xPendingReboot/xPendingReboot.psd1 -------------------------------------------------------------------------------- /Exercise3/PowerShellModules/xWebAdministration/DSCResources/MSFT_xIisModule/MSFT_xIisModule.psm1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewabest/AWS-Workshop/071e4b7912e2704a366be0a6294d4d3d1da95a4d/Exercise3/PowerShellModules/xWebAdministration/DSCResources/MSFT_xIisModule/MSFT_xIisModule.psm1 -------------------------------------------------------------------------------- /Exercise3/PowerShellModules/xWebAdministration/DSCResources/MSFT_xIisModule/MSFT_xIisModule.schema.mof: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewabest/AWS-Workshop/071e4b7912e2704a366be0a6294d4d3d1da95a4d/Exercise3/PowerShellModules/xWebAdministration/DSCResources/MSFT_xIisModule/MSFT_xIisModule.schema.mof -------------------------------------------------------------------------------- /Exercise3/PowerShellModules/xWebAdministration/DSCResources/MSFT_xIisModule/xIisModuleDesigner.ps1: -------------------------------------------------------------------------------- 1 | $diff = join-Path ${env:ProgramFiles(x86)} "Beyond compare 2\bc2.exe" 2 | $friendlyName = "xIisModule" 3 | $resourceName = "MSFT_$friendlyName" 4 | $classVersion = "1.0.0" 5 | 6 | $scriptRoot = Split-Path $MyInvocation.MyCommand.Path 7 | $originalModuleRoot = join-Path $scriptroot "..\.." 8 | $originalModuleRootPath = Resolve-Path $originalModuleRoot 9 | $moduleRoot = Join-Path $env:temp "$($originalModuleRootPath.path | split-path -Leaf)Temp" 10 | 11 | $resources = @() 12 | $schemaPath = (join-path $scriptRoot "$resourceName.schema.mof") 13 | 14 | #Key properties 15 | $resources += New-xDscResourceProperty -Name Path -Type String -Attribute Key -Description "The path to the module, usually a dll, to be added to IIS." 16 | 17 | 18 | #Required Properites 19 | $resources += New-xDscResourceProperty -Name Name -Type String -Attribute Required -Description "The logical name of the module to add to IIS." 20 | $resources += New-xDscResourceProperty -Name RequestPath -Type String -Attribute Required -Description "The allowed request Path example: *.php" 21 | $resources += New-xDscResourceProperty -Name Verb -Type String[] -Attribute Required -Description "The supported verbs for the module." 22 | 23 | #Write Properties 24 | $resources += New-xDscResourceProperty -Name SiteName -Type String -Attribute Write -Description "The IIS Site to register the module." 25 | $resources += New-xDscResourceProperty -Name Ensure -Type String -Attribute Write -Description "Should the module be present or absent." -ValidateSet @("Present","Absent") 26 | $resources += New-xDscResourceProperty -Name ModuleType -Type String -Attribute Write -Description "The type of the module." -ValidateSet @("FastCgiModule") 27 | 28 | #Read Properties 29 | $resources += New-xDscResourceProperty -Name EndPointSetup -Type Boolean -Attribute Read -Description "The End Point is setup. Such as a Fast Cgi endpoint." 30 | 31 | 32 | 33 | Write-Host updating... 34 | 35 | # Create a New template resource to a temporary folder 36 | New-xDscResource -Property $resources -ClassVersion $classVersion -Name $resourceName -Path $moduleRoot -FriendlyName $friendlyName 37 | 38 | 39 | # Use your favorite diff program to compare and merge the current resource and the existing resource 40 | 41 | if((test-Path $diff)) 42 | { 43 | &$diff $originalModuleRoot $moduleRoot 44 | } 45 | else 46 | { 47 | Write-Warning "Diff propgram not found!`r`nUse your favorite diff program to compare and merge:`r`n `t$($originalModuleRootPath.path)`r`n and:`r`n `t$moduleRoot" 48 | } 49 | 50 | -------------------------------------------------------------------------------- /Exercise3/PowerShellModules/xWebAdministration/DSCResources/MSFT_xWebAppPool/MSFT_xWebAppPool.psm1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewabest/AWS-Workshop/071e4b7912e2704a366be0a6294d4d3d1da95a4d/Exercise3/PowerShellModules/xWebAdministration/DSCResources/MSFT_xWebAppPool/MSFT_xWebAppPool.psm1 -------------------------------------------------------------------------------- /Exercise3/PowerShellModules/xWebAdministration/DSCResources/MSFT_xWebAppPool/MSFT_xWebAppPool.schema.mof: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewabest/AWS-Workshop/071e4b7912e2704a366be0a6294d4d3d1da95a4d/Exercise3/PowerShellModules/xWebAdministration/DSCResources/MSFT_xWebAppPool/MSFT_xWebAppPool.schema.mof -------------------------------------------------------------------------------- /Exercise3/PowerShellModules/xWebAdministration/DSCResources/MSFT_xWebApplication/MSFT_xWebApplication.psm1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewabest/AWS-Workshop/071e4b7912e2704a366be0a6294d4d3d1da95a4d/Exercise3/PowerShellModules/xWebAdministration/DSCResources/MSFT_xWebApplication/MSFT_xWebApplication.psm1 -------------------------------------------------------------------------------- /Exercise3/PowerShellModules/xWebAdministration/DSCResources/MSFT_xWebApplication/MSFT_xWebApplication.schema.mof: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewabest/AWS-Workshop/071e4b7912e2704a366be0a6294d4d3d1da95a4d/Exercise3/PowerShellModules/xWebAdministration/DSCResources/MSFT_xWebApplication/MSFT_xWebApplication.schema.mof -------------------------------------------------------------------------------- /Exercise3/PowerShellModules/xWebAdministration/DSCResources/MSFT_xWebConfigKeyValue/MSFT_xWebConfigKeyValue.psm1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewabest/AWS-Workshop/071e4b7912e2704a366be0a6294d4d3d1da95a4d/Exercise3/PowerShellModules/xWebAdministration/DSCResources/MSFT_xWebConfigKeyValue/MSFT_xWebConfigKeyValue.psm1 -------------------------------------------------------------------------------- /Exercise3/PowerShellModules/xWebAdministration/DSCResources/MSFT_xWebConfigKeyValue/MSFT_xWebConfigKeyValue.schema.mof: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewabest/AWS-Workshop/071e4b7912e2704a366be0a6294d4d3d1da95a4d/Exercise3/PowerShellModules/xWebAdministration/DSCResources/MSFT_xWebConfigKeyValue/MSFT_xWebConfigKeyValue.schema.mof -------------------------------------------------------------------------------- /Exercise3/PowerShellModules/xWebAdministration/DSCResources/MSFT_xWebVirtualDirectory/MSFT_xWebVirtualDirectory.psm1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewabest/AWS-Workshop/071e4b7912e2704a366be0a6294d4d3d1da95a4d/Exercise3/PowerShellModules/xWebAdministration/DSCResources/MSFT_xWebVirtualDirectory/MSFT_xWebVirtualDirectory.psm1 -------------------------------------------------------------------------------- /Exercise3/PowerShellModules/xWebAdministration/DSCResources/MSFT_xWebVirtualDirectory/MSFT_xWebVirtualDirectory.schema.mof: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewabest/AWS-Workshop/071e4b7912e2704a366be0a6294d4d3d1da95a4d/Exercise3/PowerShellModules/xWebAdministration/DSCResources/MSFT_xWebVirtualDirectory/MSFT_xWebVirtualDirectory.schema.mof -------------------------------------------------------------------------------- /Exercise3/PowerShellModules/xWebAdministration/DSCResources/MSFT_xWebsite/MSFT_xWebsite.schema.mof: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewabest/AWS-Workshop/071e4b7912e2704a366be0a6294d4d3d1da95a4d/Exercise3/PowerShellModules/xWebAdministration/DSCResources/MSFT_xWebsite/MSFT_xWebsite.schema.mof -------------------------------------------------------------------------------- /Exercise3/PowerShellModules/xWebAdministration/xWebAdministration.psd1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewabest/AWS-Workshop/071e4b7912e2704a366be0a6294d4d3d1da95a4d/Exercise3/PowerShellModules/xWebAdministration/xWebAdministration.psd1 -------------------------------------------------------------------------------- /Exercise4.md: -------------------------------------------------------------------------------- 1 | # Exercise 4 2 | 3 | ## Bootstrapping CloudFormation created instances with PowerShell DSC 4 | 5 | In this exercise we will take a fleshed out web server CloudFormation template, and wire it up so that it bootstraps our PowerShell DSC configuration script on the EC2 instances it creates for us 6 | 7 | ## Goals 8 | 9 | * Discover some of the functionality CloudFormation offers to configure provisioned instances with 10 | * Bootstrap Powershell DSC configuration on created EC2 instances by leveraging cfn-init 11 | 12 | ## Instructions 13 | 14 | 1. Read through this example of [Bootstrapping Windows Instances](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-windows-stacks-bootstrapping.html) 15 | 2. Read the documentation on the [CloudFormation::Init template](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-init.html) 16 | 3. Open .\Exercise4\Templates\Webserver.template 17 | 4. Locate the the WebServerAzOne resource definition within the webserver template 18 | 5. Follow the [Bootstrapping Windows Instances](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-windows-stacks-bootstrapping.html) example and fill out the UserData section of the template to kickstart cfn-init 19 | 6. Complete the **sources** section of the [CloudFormation::Init template](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-init.html) within WebServerAzOne to pull down 20 | * Our powershell modules from the PowerShellModulesBundleUrl template parameter to C:\Program Files\WindowsPowerShell\Modules 21 | * Our scripts from the BootstrapperScriptBundleUrl template parameter to c:\cfn\Zephyr\Scripts 22 | 7. Complete the **commands** section of the [CloudFormation::Init template](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-init.html) within WebServerAzOne to 23 | * Set the powershell execution policy to unrestricted 24 | * Invoke our ConfigureWebserver DSC configuration 25 | 8. Duplicate 5-7 on WebServerAzTwo 26 | 9. Open .\Exercise4\Parameters.ps1. Update the ResourcePrefix parameter to your initials, and take note of the other parameters provided 27 | 10. Open Deploy.ps1 locally in Powershell ISE. 28 | 11. F5!!! 29 | 12. Open the CloudFormation console in AWS and monitor your stack's creation 30 | 13. If it fails, troubleshooting time! Pick your troubleshooting buddy and get it sorted 31 | 14. If it succeeds, open up the EC2 console and remote into one of your instances 32 | 15. Open c:\cfn\log\cfn-init.log 33 | 16. Can you see your DSC output inside it? Are there any errors, or does everything look good? 34 | 35 | ### Gotcha 36 | 37 | cfn-init will consider its job done when at the point when all of its commands have succesfully completed - this is going to be at the first reboot of your DSC. This means that if subsequent parts of your DSC fail, the cloud formation init logs are not going to tell you - so you need to monitor your DSC logs to ensure it is happily configured. 38 | 39 | 17. Revisit your recently acquired DSC log analyzing skills. Has everything gone swimmingly? 40 | 18. Profit! 41 | -------------------------------------------------------------------------------- /Exercise4/Deploy.ps1: -------------------------------------------------------------------------------- 1 | cls 2 | 3 | Add-Type -Assembly "System.IO.Compression.FileSystem"; 4 | Import-Module AWSPowerShell 5 | 6 | ############################################################################################################################ 7 | # 8 | # 00 - Helper Functions 9 | # 10 | ############################################################################################################################ 11 | 12 | function GenerateConfigFileS3Key($environment, $release, $filename) 13 | { 14 | $key = $environment + "/" + $release + "/" + $filename 15 | return $key 16 | } 17 | 18 | function CompressDirectoryToArchive($directoryPath, $filePath) 19 | { 20 | if (Test-Path $filePath) 21 | { 22 | Remove-Item $filePath -Force 23 | } 24 | 25 | [System.IO.Compression.ZipFile]::CreateFromDirectory($directoryPath, $filePath); 26 | } 27 | 28 | function EnsureDirectoryExists($directoryPath) 29 | { 30 | if (-Not (Test-Path $directoryPath)) 31 | { 32 | New-Item $directoryPath -ItemType Directory 33 | } 34 | } 35 | 36 | ############################################################################################################################ 37 | # 38 | # 01 - Wrangling Octopus Variables 39 | # 40 | ############################################################################################################################ 41 | 42 | # Create a new variable scope so that we can run this script multiple times 43 | # in a single script console instance without polluting the global scope with 44 | # fake Octopus variables. 45 | & { 46 | $scriptPath = [System.IO.Path]::GetDirectoryName($myInvocation.PSCommandPath) 47 | $scriptsPath = "$scriptPath\Scripts" 48 | EnsureDirectoryExists($scriptsPath) 49 | 50 | if ($OctopusParameters -eq $null) 51 | { 52 | Write-Output "Doesn't look like we have any Octopus variables. Using development defaults." 53 | 54 | . .\Parameters.ps1 55 | } 56 | else 57 | { 58 | Write-Output "Using Octopus-provided variables..." 59 | } 60 | 61 | # Lower case variables sensitive to casing 62 | $OctopusParameters['CloudFormationStackName'] = $OctopusParameters['CloudFormationStackName'].ToLowerInvariant() 63 | $OctopusParameters['S3BucketName'] = $OctopusParameters['S3BucketName'].ToLowerInvariant() 64 | 65 | Write-Output $OctopusParameters 66 | Write-Output "" 67 | 68 | ############################################################################################################################ 69 | # 70 | # 02 - Creating cleanup scripts 71 | # 72 | ############################################################################################################################ 73 | 74 | $cleanupScript = @" 75 | ` 76 | `# TODO: Remove machines from octopus 77 | ` 78 | `# Tear down infrastructure 79 | `Remove-CFNStack -StackName "$($OctopusParameters['CloudFormationStackName'])" -Force -ProfileName "AWSWorkshop" -Region us-west-2 80 | "@ 81 | 82 | $cleanupScript | Out-File -FilePath "$scriptPath\Scripts\Cleanup.ps1" -Encoding ASCII -Force 83 | 84 | ############################################################################################################################ 85 | # 86 | # 03 - Push scripts and templates to clouds 87 | # 88 | ############################################################################################################################ 89 | 90 | # Create a directory to store our zipped powershell modules and bootstrapper scripts. 91 | $tempPath = "$scriptPath\Temp" 92 | EnsureDirectoryExists($tempPath) 93 | 94 | # Create an S3 bucket to upload our templates and scripts to. 95 | if (-Not (Get-S3Bucket -BucketName $OctopusParameters['S3BucketName'] -ProfileName "AWSWorkshop" -Region $OctopusParameters['AWSRegion'])) 96 | { 97 | Write-Output "Creating S3 bucket..." 98 | New-S3Bucket -BucketName $OctopusParameters['S3BucketName'] -ProfileName "AWSWorkshop" -Region $OctopusParameters['AWSRegion'] 99 | } 100 | 101 | # Cleanup scripts 102 | Write-Output "Uploading cleanup script..." 103 | $cleanupScriptFullPath = "$scriptPath\Scripts\Cleanup.ps1" 104 | $cleanupScriptsS3BucketKey = GenerateConfigFileS3Key -environment $OctopusParameters['Environment'] -release $OctopusParameters['Version'] -filename "Cleanup.ps1" 105 | Write-S3Object -BucketName: $OctopusParameters['S3BucketName'] -Key $cleanupScriptsS3BucketKey -File $cleanupScriptFullPath -ProfileName "AWSWorkshop" -Region $OctopusParameters['AWSRegion'] 106 | 107 | # Powershell modules 108 | $powerShellModulesFullPath = "$scriptPath\Temp\PowerShellModules.zip" 109 | CompressDirectoryToArchive -directoryPath "$scriptPath\PowerShellModules" -filePath $powerShellModulesFullPath 110 | $powerShellModulesS3BucketKey = GenerateConfigFileS3Key -environment $OctopusParameters['Environment'] -release $OctopusParameters['Version'] -filename "PowerShellModules.zip" 111 | Write-Output "Uploading powershell modules..." 112 | Write-S3Object -BucketName: $OctopusParameters['S3BucketName'] -Key $powerShellModulesS3BucketKey -File $powerShellModulesFullPath -ProfileName "AWSWorkshop" -Region $OctopusParameters['AWSRegion'] 113 | 114 | # Bootstrapper scripts 115 | $scriptsFullPath = "$scriptPath\Temp\Scripts.zip" 116 | CompressDirectoryToArchive -directoryPath "$scriptPath\Scripts" -filePath $scriptsFullPath 117 | $scriptsS3BucketKey = GenerateConfigFileS3Key -environment $OctopusParameters['Environment'] -release $OctopusParameters['Version'] -filename "Scripts.zip" 118 | Write-Output "Uploading bootstrapper scripts..." 119 | Write-S3Object -BucketName: $OctopusParameters['S3BucketName'] -Key $scriptsS3BucketKey -File $scriptsFullPath -ProfileName "AWSWorkshop" -Region $OctopusParameters['AWSRegion'] 120 | 121 | # CloudFormation templates 122 | Write-Output "Uploading CloudFormation templates..." 123 | $webserverTemplateS3BucketKey = GenerateConfigFileS3Key -environment $OctopusParameters['Environment'] -release $OctopusParameters['Version'] -filename "Webserver.template" 124 | Write-S3Object -BucketName: $OctopusParameters['S3BucketName'] -Key $webserverTemplateS3BucketKey -File $scriptPath\Templates\Webserver.template -ProfileName "AWSWorkshop" -Region $OctopusParameters['AWSRegion'] 125 | $mainTemplateS3BucketKey = GenerateConfigFileS3Key -environment $OctopusParameters['Environment'] -release $OctopusParameters['Version'] -filename "Zephyr.template" 126 | Write-S3Object -BucketName: $OctopusParameters['S3BucketName'] -Key $mainTemplateS3BucketKey -File $scriptPath\Templates\Zephyr.template -ProfileName "AWSWorkshop" -Region $OctopusParameters['AWSRegion'] 127 | 128 | # Cleanup generated scripts 129 | Remove-Item "$scriptPath\Scripts\Cleanup.ps1" -Force 130 | 131 | ############################################################################################################################ 132 | # 133 | # 04 - GO GO GO (Create the stack) 134 | # 135 | ############################################################################################################################ 136 | 137 | $powerShellModulesBundleUrl = "https://" + $OctopusParameters['S3BucketName'] + ".s3.amazonaws.com/$powerShellModulesS3BucketKey" 138 | $bootstrapperScriptBundleUrl = "https://" + $OctopusParameters['S3BucketName'] + ".s3.amazonaws.com/$scriptsS3BucketKey" 139 | $webserverTemplateUrl = "https://" + $OctopusParameters['S3BucketName'] + ".s3.amazonaws.com/$webserverTemplateS3BucketKey" 140 | $mainStackTemplateUrl = "https://" + $OctopusParameters['S3BucketName'] + ".s3.amazonaws.com/$mainTemplateS3BucketKey" 141 | $timestamp = Get-Date -Format u 142 | 143 | $stack = $null 144 | try 145 | { 146 | $stack = Get-CFNStack -StackName $OctopusParameters['CloudFormationStackName'] -ProfileName "AWSWorkshop" -Region $OctopusParameters['AWSRegion'] 147 | } 148 | catch 149 | { 150 | } 151 | 152 | $stackParameters = ` 153 | @(` 154 | @{ParameterKey="S3BucketName"; ParameterValue=$OctopusParameters['S3BucketName']},` 155 | @{ParameterKey="VpcId"; ParameterValue=$OctopusParameters['VpcId']},` 156 | @{ParameterKey="PowerShellModulesBundleUrl"; ParameterValue="$powerShellModulesBundleUrl"},` 157 | @{ParameterKey="BootstrapperScriptBundleUrl"; ParameterValue="$bootstrapperScriptBundleUrl"},` 158 | @{ParameterKey="WebserverTemplateUrl"; ParameterValue="$webserverTemplateUrl"},` 159 | @{ParameterKey="Timestamp"; ParameterValue=$timestamp},` 160 | @{ParameterKey="Version"; ParameterValue=$OctopusParameters['Version']},` 161 | @{ParameterKey="Environment"; ParameterValue=$OctopusParameters['Environment']},` 162 | @{ParameterKey="KeyPairName"; ParameterValue=$OctopusParameters['KeyPairName']},` 163 | @{ParameterKey="WebserverImageId"; ParameterValue=$OctopusParameters['WebserverImageId']},` 164 | @{ParameterKey="WebserverInstanceType"; ParameterValue=$OctopusParameters['WebserverInstanceType']},` 165 | @{ParameterKey="WebserverSubnetIdAzOne"; ParameterValue=$OctopusParameters['WebserverSubnetIdAzOne']},` 166 | @{ParameterKey="WebserverSubnetIdAzTwo"; ParameterValue=$OctopusParameters['WebserverSubnetIdAzTwo']},` 167 | @{ParameterKey="LoadBalancerSubnetIdAzOne"; ParameterValue=$OctopusParameters['LoadBalancerSubnetIdAzOne']},` 168 | @{ParameterKey="LoadBalancerSubnetIdAzTwo"; ParameterValue=$OctopusParameters['LoadBalancerSubnetIdAzTwo']},` 169 | @{ParameterKey="ResourcePrefix"; ParameterValue=$OctopusParameters['ResourcePrefix']}) 170 | 171 | $stackName = $OctopusParameters['CloudFormationStackName'] 172 | if ($stack -eq $null) 173 | { 174 | Write-Output "Creating new CFN stack $stackName" 175 | 176 | New-CFNStack -Capability "CAPABILITY_IAM" -StackName $stackName -TemplateURL $mainStackTemplateUrl -Parameters $stackParameters -ProfileName "AWSWorkshop" -Region $OctopusParameters['AWSRegion'] 177 | } 178 | else 179 | { 180 | Write-Output "Updating existing CFN stack $stackName" 181 | 182 | Update-CFNStack -Capability "CAPABILITY_IAM" -StackName $stackName -TemplateURL $mainStackTemplateUrl -Parameters $stackParameters -ProfileName "AWSWorkshop" -Region $OctopusParameters['AWSRegion'] 183 | } 184 | 185 | while($true) 186 | { 187 | $stack = Get-CFNStack -StackName $stackName -ProfileName "AWSWorkshop" -Region $OctopusParameters['AWSRegion'] 188 | 189 | if ($stack.StackStatus -eq [Amazon.CloudFormation.StackStatus]::CREATE_COMPLETE -or $stack.StackStatus -eq [Amazon.CloudFormation.StackStatus]::UPDATE_COMPLETE) 190 | { 191 | Write-Output "Cloud formation succeeded with the following outputs..." 192 | $stack.Outputs | Format-Table | Write-Output 193 | 194 | # Note: In here, wire up external DNS etc based on stack output parameters 195 | 196 | break; 197 | } 198 | 199 | if ($stack.StackStatus -eq [Amazon.CloudFormation.StackStatus]::CREATE_FAILED -or $stack.StackStatus -eq [Amazon.CloudFormation.StackStatus]::ROLLBACK_COMPLETE -or $stack.StackStatus -eq [Amazon.CloudFormation.StackStatus]::ROLLBACK_FAILED) 200 | { 201 | Write-Output "Cloud formation failed, abandoning..." 202 | 203 | break; 204 | } 205 | 206 | Write-Output "Waiting for cloud formation $stackName to finish creation..." 207 | 208 | Start-Sleep -s 10 209 | } 210 | 211 | Write-Output "fin" 212 | } -------------------------------------------------------------------------------- /Exercise4/Parameters.ps1: -------------------------------------------------------------------------------- 1 | $OctopusParameters = @{} 2 | 3 | # Octopus parameters 4 | $OctopusParameters['ResourcePrefix'] = 'aab'; 5 | $OctopusParameters['Environment'] = "Production"; 6 | $OctopusParameters['Version'] = "1.0.0-ryan0001"; 7 | 8 | # CloudFormation parameters 9 | $OctopusParameters['AWSRegion'] = "ap-southeast-2"; 10 | $OctopusParameters['CloudFormationStackName'] = "{0}-sandbox-{1}" -f @($OctopusParameters['ResourcePrefix'], $OctopusParameters['Environment']); 11 | $OctopusParameters['S3BucketName'] = "{0}-sandbox-infrastructure" -f $OctopusParameters['ResourcePrefix']; 12 | $OctopusParameters['VpcId'] = "vpc-7ecaee1b"; 13 | 14 | # AWS parameters 15 | $OctopusParameters['KeyPairName'] = "AwsDayKeyPair"; 16 | $OctopusParameters['WebserverImageId'] = "ami-bf8895dc"; #WINDOWS_2016_BASE 17 | $OctopusParameters['WebserverInstanceType'] = "t2.medium"; 18 | $OctopusParameters['WebserverSubnetIdAzOne'] = "subnet-b1afb5d4"; # Web A 19 | $OctopusParameters['WebserverSubnetIdAzTwo'] = "subnet-14787e63"; # Web B 20 | $OctopusParameters['LoadBalancerSubnetIdAzOne'] = "subnet-973728f2"; # DMZ A 21 | $OctopusParameters['LoadBalancerSubnetIdAzTwo'] = "subnet-99477cee"; # DMZ B -------------------------------------------------------------------------------- /Exercise4/PowerShellModules/cWinServer/DSCResources/WinServerOptions/WinServerOptions.psm1: -------------------------------------------------------------------------------- 1 | function Get-TargetResource 2 | { 3 | [CmdletBinding()] 4 | [OutputType([System.Collections.Hashtable])] 5 | param 6 | ( 7 | [parameter(Mandatory = $true)] 8 | [System.String] 9 | $Name, 10 | 11 | [System.String] 12 | $Culture, 13 | 14 | [System.String] 15 | $TimeZone 16 | ) 17 | 18 | $returnValue = @{ 19 | Ensure = $Ensure 20 | Name = $Name 21 | Culture = $Culture 22 | Timezone = $Timezone 23 | } 24 | 25 | return $returnValue; 26 | } 27 | 28 | function Set-TargetResource 29 | { 30 | [CmdletBinding()] 31 | param 32 | ( 33 | [ValidateSet("Present","Absent")] 34 | [System.String] 35 | $Ensure, 36 | 37 | [parameter(Mandatory = $true)] 38 | [System.String] 39 | $Name, 40 | 41 | [System.String] 42 | $Culture, 43 | 44 | [System.String] 45 | $TimeZone 46 | ) 47 | 48 | if ($Ensure -eq "Present") 49 | { 50 | if ($Culture) 51 | { 52 | if ((Get-WinSystemLocale).Name -ne $Culture) 53 | { 54 | Write-Verbose "Setting System Locale to $Culture. Will Require reboot to take effect." 55 | Set-WinSystemLocale -SystemLocale $Culture 56 | 57 | $global:DSCMachineStatus = 1; 58 | } 59 | } 60 | 61 | if (([System.TimeZone]::CurrentTimeZone).StandardName -ne $TimeZone) 62 | { 63 | Write-Verbose "Setting System TimeZone to [$TimeZone]" 64 | & tzutil.exe /s "$TimeZone" 65 | } 66 | } 67 | } 68 | 69 | function Test-TargetResource 70 | { 71 | [CmdletBinding()] 72 | [OutputType([System.Boolean])] 73 | param 74 | ( 75 | [ValidateSet("Present","Absent")] 76 | [System.String] 77 | $Ensure, 78 | 79 | [parameter(Mandatory = $true)] 80 | [System.String] 81 | $Name, 82 | 83 | [System.String] 84 | $Culture, 85 | 86 | [System.String] 87 | $TimeZone 88 | ) 89 | 90 | if ($Ensure -eq "Present") 91 | { 92 | if ($Culture) 93 | { 94 | if ((Get-WinSystemLocale).Name -ne $Culture) 95 | { 96 | Write-Verbose "System Locale is currently $((Get-WinSystemLocale).Name) and should be $Culture" 97 | return $false; 98 | } 99 | 100 | Write-Verbose "System Locale and Culture are correct." 101 | } 102 | 103 | if ($TimeZone) 104 | { 105 | if (([System.TimeZone]::CurrentTimeZone).StandardName -ne $TimeZone) 106 | { 107 | Write-Verbose "System TimeZone is current:[$(([System.TimeZone]::CurrentTimeZone).StandardName)] and should be:[$TimeZone]" 108 | return $false; 109 | } 110 | 111 | Write-Verbose "System TimeZone is correct." 112 | } 113 | } 114 | else 115 | { 116 | Write-Verbose "Ignoring checks" 117 | } 118 | 119 | return $true; 120 | } -------------------------------------------------------------------------------- /Exercise4/PowerShellModules/cWinServer/DSCResources/WinServerOptions/WinServerOptions.schema.mof: -------------------------------------------------------------------------------- 1 | [ClassVersion("1.0.0.0"), FriendlyName("WinServerOptions")] 2 | class WinServerOptions : OMI_BaseResource 3 | { 4 | [Write, ValueMap{"Present","Absent"}, Values{"Present","Absent"}] String Ensure; 5 | [Key, Description("The name for the setup. Can just be the server name")] String Name; 6 | [Write, Description("The Windows Server culture")] String Culture; 7 | [Write, Description("The Windows Server Timezone")] String TimeZone; 8 | }; -------------------------------------------------------------------------------- /Exercise4/PowerShellModules/cWinServer/cWinServer.psd1: -------------------------------------------------------------------------------- 1 | # 2 | # Module manifest for module 'cWinServer' 3 | # 4 | # Generated by: andrewb 5 | # 6 | # Generated on: 9/06/2015 7 | @{ 8 | ModuleVersion = '1.0' 9 | GUID = '90798d5f-9f2e-4af4-b9fd-79b4f67899fb' 10 | Author = 'andrewb' 11 | CompanyName = 'Unknown' 12 | Copyright = '(c) 2015 andrewb. All rights reserved.' 13 | Description = '' 14 | PowerShellVersion = '4.0' 15 | FunctionsToExport = @('Get-TargetResource','Set-TargetResource','Test-TargetResource') 16 | } 17 | 18 | -------------------------------------------------------------------------------- /Exercise4/PowerShellModules/xDscDiagnostics/xDscDiagnostics.psd1: -------------------------------------------------------------------------------- 1 |  2 | 3 | @{ 4 | 5 | 6 | ModuleVersion = '2.0' 7 | GUID = 'ef098cb4-f7e9-4763-b636-0cd9799e1c9a' 8 | 9 | Author = 'Microsoft Corporation' 10 | CompanyName = 'Microsoft Corporation' 11 | Copyright = '(c) 2013 Microsoft Corporation. All rights reserved.' 12 | 13 | Description = 'Module to help in reading details from DSC events' 14 | 15 | PowerShellVersion = '4.0' 16 | 17 | CLRVersion = '4.0' 18 | 19 | FunctionsToExport = @("*") 20 | 21 | NestedModules = @('xDscDiagnostics.psm1') 22 | } -------------------------------------------------------------------------------- /Exercise4/PowerShellModules/xDscDiagnostics/xDscDiagnosticsFormat.ps1xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Microsoft.PowerShell.xDscDiagnostics.GroupedEvents 7 | 8 | Microsoft.PowerShell.xDscDiagnostics.GroupedEvents 9 | 10 | 11 | 12 | 13 | 14 | 14 15 | 16 | 17 | 18 | 10 19 | 20 | 21 | 22 | 21 23 | 24 | 25 | 26 | 8 27 | 28 | 29 | 30 | 37 31 | 32 | 33 | 34 | 21 35 | 36 | 37 | 38 | 39 | 40 | 41 | ComputerName 42 | 43 | 44 | SequenceId 45 | 46 | 47 | TimeCreated 48 | 49 | 50 | Result 51 | 52 | 53 | JobID 54 | 55 | 56 | AllEvents 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | Microsoft.PowerShell.xDscDiagnostics.TraceOutput 65 | 66 | Microsoft.PowerShell.xDscDiagnostics.TraceOutput 67 | 68 | 69 | 70 | 71 | 72 | 14 73 | 74 | 75 | 76 | 12 77 | 78 | 79 | 80 | 21 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | ComputerName 91 | 92 | 93 | EventType 94 | 95 | 96 | TimeCreated 97 | 98 | 99 | Message 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | -------------------------------------------------------------------------------- /Exercise4/PowerShellModules/xNetworking/DSCResources/MSFT_xDNSServerAddress/MSFT_xDNSServerAddress.psm1: -------------------------------------------------------------------------------- 1 | <####################################################################################### 2 | # xDNSServerAddress : DSC Resource that will set/test/get the current DNS Server 3 | # Address, by accepting values among those given in xDNSServerAddress.schema.mof 4 | #######################################################################################> 5 | 6 | 7 | 8 | ###################################################################################### 9 | # The Get-TargetResource cmdlet. 10 | # This function will get the present list of DNS ServerAddress DSC Resource schema variables on the system 11 | ###################################################################################### 12 | function Get-TargetResource 13 | { 14 | param 15 | ( 16 | [Parameter(Mandatory)] 17 | [ValidateNotNullOrEmpty()] 18 | [String[]]$Address, 19 | 20 | [Parameter(Mandatory)] 21 | [ValidateNotNullOrEmpty()] 22 | [String]$InterfaceAlias, 23 | 24 | [ValidateSet("IPv4", "IPv6")] 25 | [String]$AddressFamily = "IPv4" 26 | ) 27 | 28 | 29 | $returnValue = @{ 30 | Address = (Get-DnsClientServerAddress -InterfaceAlias $InterfaceAlias -AddressFamily $AddressFamily).ServerAddresses 31 | AddressFamily = $AddressFamily 32 | InterfaceAlias = $InterfaceAlias 33 | } 34 | 35 | $returnValue 36 | } 37 | 38 | ###################################################################################### 39 | # The Set-TargetResource cmdlet. 40 | # This function will set a new Server Address in the current node 41 | ###################################################################################### 42 | function Set-TargetResource 43 | { 44 | param 45 | ( 46 | #IP Address that has to be set 47 | [Parameter(Mandatory)] 48 | [ValidateNotNullOrEmpty()] 49 | [String[]]$Address, 50 | 51 | [Parameter(Mandatory)] 52 | [ValidateNotNullOrEmpty()] 53 | [String]$InterfaceAlias, 54 | 55 | [ValidateSet("IPv4", "IPv6")] 56 | [String]$AddressFamily = "IPv4" 57 | ) 58 | 59 | ValidateProperties @PSBoundParameters -Apply 60 | } 61 | 62 | ###################################################################################### 63 | # The Test-TargetResource cmdlet. 64 | # This will test if the given Server Address is among the current node's Server Address collection 65 | ###################################################################################### 66 | function Test-TargetResource 67 | { 68 | param 69 | ( 70 | [Parameter(Mandatory)] 71 | [ValidateNotNullOrEmpty()] 72 | [String[]]$Address, 73 | 74 | [Parameter(Mandatory)] 75 | [ValidateNotNullOrEmpty()] 76 | [String]$InterfaceAlias, 77 | 78 | [ValidateSet("IPv4", "IPv6")] 79 | [String]$AddressFamily = "IPv4" 80 | ) 81 | 82 | ValidateProperties @PSBoundParameters 83 | } 84 | 85 | 86 | ####################################################################################### 87 | # Helper function that validates the Server Address properties. If the switch parameter 88 | # "Apply" is set, then it will set the properties after a test 89 | ####################################################################################### 90 | function ValidateProperties 91 | { 92 | param 93 | ( 94 | [Parameter(Mandatory)] 95 | [ValidateNotNullOrEmpty()] 96 | [String[]]$Address, 97 | 98 | [Parameter(Mandatory)] 99 | [ValidateNotNullOrEmpty()] 100 | [String]$InterfaceAlias, 101 | 102 | [ValidateSet("IPv4", "IPv6")] 103 | [String]$AddressFamily, 104 | 105 | [Switch]$Apply 106 | ) 107 | $sa =$Address 108 | $sa | %{ 109 | if(!([System.Net.Ipaddress]::TryParse($_, [ref]0))) 110 | { 111 | throw "Server Address *$_* is not in the correct format. Please correct the Address in the configuration and try again" 112 | } 113 | if (([System.Net.IPAddress]$_).AddressFamily.ToString() -eq [System.Net.Sockets.AddressFamily]::InterNetwork.ToString()) 114 | { 115 | if ($AddressFamily -ne "IPv4") 116 | { 117 | throw "Server address $Address is in IPv4 format, which does not match server address family $AddressFamily. Please correct either of them in the configuration and try again" 118 | } 119 | } 120 | else 121 | { 122 | if ($AddressFamily -ne "IPv6") 123 | { 124 | throw "Server address $Address is in IPv6 format, which does not match server address family $AddressFamily. Please correct either of them in the configuration and try again" 125 | } 126 | } 127 | } 128 | try 129 | { 130 | Write-Verbose -Message "Checking the DNS Server Address ..." 131 | #Get the current IP Address based on the parameters given. 132 | $currentAddress = (Get-DnsClientServerAddress -InterfaceAlias $InterfaceAlias -AddressFamily $AddressFamily -ErrorAction Stop).ServerAddresses 133 | 134 | #Check if the Server addresses are the same as the desired addresses. 135 | if(@(Compare-Object -ReferenceObject $currentAddress -DifferenceObject $Address -SyncWindow 0).Length -gt 0) 136 | { 137 | Write-Verbose -Message "DNS Servers are not correct. Expected $Address, actual $currentAddress" 138 | if($Apply) 139 | { 140 | # Set the DNS settings as well 141 | Set-DnsClientServerAddress -InterfaceAlias $InterfaceAlias -ServerAddresses $Address 142 | Write-Verbose -Message "DNS Servers have been set correctly." 143 | } 144 | else 145 | { 146 | return $false 147 | } 148 | } 149 | else 150 | { 151 | #Test will return true in this case 152 | Write-Verbose -Message "DNS Servers are set correctly." 153 | return $true 154 | } 155 | } 156 | catch 157 | { 158 | Write-Verbose -Message $_ 159 | throw "Can not set or find valid DNS Server addresses using InterfaceAlias $InterfaceAlias and AddressFamily $AddressFamily" 160 | } 161 | } 162 | 163 | 164 | 165 | # FUNCTIONS TO BE EXPORTED 166 | Export-ModuleMember -function Get-TargetResource, Set-TargetResource, Test-TargetResource -------------------------------------------------------------------------------- /Exercise4/PowerShellModules/xNetworking/DSCResources/MSFT_xDNSServerAddress/MSFT_xDNSServerAddress.schema.mof: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewabest/AWS-Workshop/071e4b7912e2704a366be0a6294d4d3d1da95a4d/Exercise4/PowerShellModules/xNetworking/DSCResources/MSFT_xDNSServerAddress/MSFT_xDNSServerAddress.schema.mof -------------------------------------------------------------------------------- /Exercise4/PowerShellModules/xNetworking/DSCResources/MSFT_xFirewall/MSFT_xFirewall.Schema.mof: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewabest/AWS-Workshop/071e4b7912e2704a366be0a6294d4d3d1da95a4d/Exercise4/PowerShellModules/xNetworking/DSCResources/MSFT_xFirewall/MSFT_xFirewall.Schema.mof -------------------------------------------------------------------------------- /Exercise4/PowerShellModules/xNetworking/DSCResources/MSFT_xIPAddress/MSFT_xIPAddress.psm1: -------------------------------------------------------------------------------- 1 | <####################################################################################### 2 | # MSDSCPack_IPAddress : DSC Resource that will set/test/get the current IP 3 | # Address, by accepting values among those given in MSDSCPack_IPAddress.schema.mof 4 | #######################################################################################> 5 | 6 | 7 | 8 | ###################################################################################### 9 | # The Get-TargetResource cmdlet. 10 | # This function will get the present list of IP Address DSC Resource schema variables on the system 11 | ###################################################################################### 12 | function Get-TargetResource 13 | { 14 | param 15 | ( 16 | [Parameter(Mandatory)] 17 | [ValidateNotNullOrEmpty()] 18 | [String]$IPAddress, 19 | 20 | [Parameter(Mandatory)] 21 | [ValidateNotNullOrEmpty()] 22 | [String]$InterfaceAlias, 23 | 24 | [Int]$SubnetMask = 16, 25 | 26 | [ValidateNotNullOrEmpty()] 27 | [String]$DefaultGateway, 28 | 29 | [ValidateSet("IPv4", "IPv6")] 30 | [String]$AddressFamily = "IPv4" 31 | ) 32 | 33 | 34 | $returnValue = @{ 35 | IPAddress = [System.String]::Join(", ",(Get-NetIPAddress -InterfaceAlias $InterfaceAlias -AddressFamily $AddressFamily).IPAddress) 36 | SubnetMask = $SubnetMask 37 | DefaultGateway = $DefaultGateway 38 | AddressFamily = $AddressFamily 39 | InterfaceAlias=$InterfaceAlias 40 | } 41 | 42 | $returnValue 43 | } 44 | 45 | ###################################################################################### 46 | # The Set-TargetResource cmdlet. 47 | # This function will set a new IP Address in the current node 48 | ###################################################################################### 49 | function Set-TargetResource 50 | { 51 | param 52 | ( 53 | #IP Address that has to be set 54 | [Parameter(Mandatory)] 55 | [ValidateNotNullOrEmpty()] 56 | [String]$IPAddress, 57 | 58 | [Parameter(Mandatory)] 59 | [ValidateNotNullOrEmpty()] 60 | [String]$InterfaceAlias, 61 | 62 | [Int]$SubnetMask, 63 | 64 | [ValidateNotNullOrEmpty()] 65 | [String]$DefaultGateway, 66 | 67 | [ValidateSet("IPv4", "IPv6")] 68 | [String]$AddressFamily = "IPv4" 69 | ) 70 | 71 | 72 | ValidateProperties @PSBoundParameters -Apply 73 | } 74 | 75 | ###################################################################################### 76 | # The Test-TargetResource cmdlet. 77 | # This will test if the given IP Address is among the current node's IP Address collection 78 | ###################################################################################### 79 | function Test-TargetResource 80 | { 81 | param 82 | ( 83 | [Parameter(Mandatory)] 84 | [ValidateNotNullOrEmpty()] 85 | [String]$IPAddress, 86 | 87 | [Parameter(Mandatory)] 88 | [ValidateNotNullOrEmpty()] 89 | [String]$InterfaceAlias, 90 | 91 | [Int]$SubnetMask, 92 | 93 | [ValidateNotNullOrEmpty()] 94 | [String]$DefaultGateway, 95 | 96 | [ValidateSet("IPv4", "IPv6")] 97 | [String]$AddressFamily = "IPv4" 98 | ) 99 | 100 | ValidateProperties @PSBoundParameters 101 | } 102 | 103 | 104 | ####################################################################################### 105 | # Helper function that validates the IP Address properties. If the switch parameter 106 | # "Apply" is set, then it will set the properties after a test 107 | ####################################################################################### 108 | function ValidateProperties 109 | { 110 | param 111 | ( 112 | [Parameter(Mandatory)] 113 | [ValidateNotNullOrEmpty()] 114 | [String]$IPAddress, 115 | 116 | [Parameter(Mandatory)] 117 | [ValidateNotNullOrEmpty()] 118 | [String]$InterfaceAlias, 119 | 120 | [ValidateNotNullOrEmpty()] 121 | [String]$DefaultGateway, 122 | 123 | [Int]$SubnetMask = 16, 124 | 125 | [ValidateSet("IPv4", "IPv6")] 126 | [String]$AddressFamily = "IPv4", 127 | 128 | [Switch]$Apply 129 | ) 130 | $ip=$IPAddress 131 | if(!([System.Net.Ipaddress]::TryParse($ip, [ref]0))) 132 | { 133 | throw "IP Address *$IPAddress* is not in the correct format. Please correct the ipaddress in the configuration and try again" 134 | } 135 | try 136 | { 137 | Write-Verbose -Message "Checking the IPAddress ..." 138 | #Get the current IP Address based on the parameters given. 139 | $currentIP = Get-NetIPAddress -InterfaceAlias $InterfaceAlias -AddressFamily $AddressFamily -ErrorAction Stop 140 | 141 | #Test if the IP Address passed is equal to the current ip address 142 | if(!$currentIP.IPAddress.Contains($IPAddress)) 143 | { 144 | Write-Verbose -Message "IPAddress not correct. Expected $IPAddress, actual $($currentIP.IPAddress)" 145 | $Parameters = @{} 146 | 147 | #Apply is true in the case of set - target resource - in which case, it will set the new IP Address 148 | if($Apply) 149 | { 150 | Write-Verbose -Message "Setting IPAddress ..." 151 | $Parameters["IPAddress"] = $IPAddress 152 | $Parameters["PrefixLength"] = $SubnetMask 153 | $Parameters["InterfaceAlias"] = $currentIP[0].InterfaceAlias 154 | 155 | if($DefaultGateway){ $Parameters["DefaultGateWay"] = $DefaultGateway } 156 | $null = New-NetIPAddress @Parameters -ErrorAction Stop 157 | 158 | # Make the connection profile private 159 | Get-NetConnectionProfile -InterfaceAlias $InterfaceAlias | Set-NetConnectionProfile -NetworkCategory Private -ErrorAction SilentlyContinue 160 | Write-Verbose -Message "IPAddress is set to $IPAddress." 161 | } 162 | else {return $false} 163 | } 164 | else 165 | { 166 | Write-Verbose -Message "IPAddress is correct." 167 | return $true 168 | } 169 | } 170 | catch 171 | { 172 | Write-Verbose -Message $_ 173 | throw "Can not set or find valid IPAddress using InterfaceAlias $InterfaceAlias and AddressFamily $AddressFamily" 174 | } 175 | } 176 | 177 | 178 | 179 | # FUNCTIONS TO BE EXPORTED 180 | Export-ModuleMember -function Get-TargetResource, Set-TargetResource, Test-TargetResource -------------------------------------------------------------------------------- /Exercise4/PowerShellModules/xNetworking/DSCResources/MSFT_xIPAddress/MSFT_xIPAddress.schema.mof: -------------------------------------------------------------------------------- 1 | [ClassVersion("1.0.0"), FriendlyName("xIPAddress")] 2 | class MSFT_xIPAddress : OMI_BaseResource 3 | { 4 | [Key] string IPAddress; 5 | [Key] string InterfaceAlias; 6 | [write] string DefaultGateway; 7 | [Write] uint32 SubnetMask; 8 | [Write,ValueMap{"IPv4", "IPv6"},Values{"IPv4", "IPv6"}] string AddressFamily; 9 | }; 10 | -------------------------------------------------------------------------------- /Exercise4/PowerShellModules/xNetworking/Examples/Sample_xDnsServerAddress.ps1: -------------------------------------------------------------------------------- 1 | configuration Sample_xDnsServerAddress 2 | { 3 | param 4 | ( 5 | [string[]]$NodeName = 'localhost', 6 | 7 | [Parameter(Mandatory)] 8 | [string]$DnsServerAddress, 9 | 10 | [Parameter(Mandatory)] 11 | [string]$InterfaceAlias, 12 | 13 | [ValidateSet("IPv4","IPv6")] 14 | [string]$AddressFamily = 'IPv4' 15 | ) 16 | 17 | Import-DscResource -Module xNetworking 18 | 19 | Node $NodeName 20 | { 21 | xDnsServerAddress DnsServerAddress 22 | { 23 | Address = $DnsServerAddress 24 | InterfaceAlias = $InterfaceAlias 25 | AddressFamily = $AddressFamily 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /Exercise4/PowerShellModules/xNetworking/Examples/Sample_xFirewall_AddFirewallRule.ps1: -------------------------------------------------------------------------------- 1 | # DSC configuration for Firewall 2 | 3 | configuration Sample_xFirewall_AddFirewallRule 4 | { 5 | param 6 | ( 7 | [string[]]$NodeName = 'localhost' 8 | ) 9 | 10 | Import-DSCResource -ModuleName xNetworking 11 | 12 | Node $NodeName 13 | { 14 | xFirewall Firewall 15 | { 16 | Name = "NotePadFirewallRule" 17 | DisplayName = "Firewall Rule for Notepad.exe" 18 | DisplayGroup = "NotePad Firewall Rule Group" 19 | Ensure = "Present" 20 | Access = "Allow" 21 | State = "Enabled" 22 | Profile = ("Domain", "Private") 23 | Direction = "OutBound" 24 | RemotePort = ("8080", "8081") 25 | LocalPort = ("9080", "9081") 26 | Protocol = "TCP" 27 | Description = "Firewall Rule for Notepad.exe" 28 | ApplicationPath = "c:\windows\system32\notepad.exe" 29 | Service = "WinRM" 30 | } 31 | } 32 | } 33 | 34 | Sample_xFirewall_AddFirewallRule 35 | Start-DscConfiguration -Path Sample_xFirewall_AddFirewallRule -Wait -Verbose -Force -------------------------------------------------------------------------------- /Exercise4/PowerShellModules/xNetworking/Examples/Sample_xFirewall_AddFirewallRuleToExistingGroup.ps1: -------------------------------------------------------------------------------- 1 | # DSC configuration for Firewall 2 | # 3 | 4 | configuration Sample_xFirewall_AddFirewallRuleToExistingGroup 5 | { 6 | param 7 | ( 8 | [string[]]$NodeName = 'localhost' 9 | ) 10 | 11 | Import-DSCResource -ModuleName xNetworking 12 | 13 | Node $NodeName 14 | { 15 | xFirewall Firewall 16 | { 17 | Name = "MyFirewallRule" 18 | DisplayName = "My Firewall Rule" 19 | DisplayGroup = "My Firewall Rule Group" 20 | Access = "Allow" 21 | } 22 | 23 | xFirewall Firewall1 24 | { 25 | Name = "MyFirewallRule1" 26 | DisplayName = "My Firewall Rule" 27 | DisplayGroup = "My Firewall Rule Group" 28 | Ensure = "Present" 29 | Access = "Allow" 30 | State = "Enabled" 31 | Profile = ("Domain", "Private") 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /Exercise4/PowerShellModules/xNetworking/Examples/Sample_xFirewall_AddFirewallRuleToNewGroup.ps1: -------------------------------------------------------------------------------- 1 | # DSC configuration for Firewall 2 | 3 | configuration Sample_xFirewall_AddFirewallRuleToNewGroup 4 | { 5 | param 6 | ( 7 | [string[]]$NodeName = 'localhost' 8 | ) 9 | 10 | Import-DSCResource -ModuleName xNetworking 11 | 12 | Node $NodeName 13 | { 14 | xFirewall Firewall 15 | { 16 | Name = "MyAppFirewallRule" 17 | ApplicationPath = "c:\windows\system32\MyApp.exe" 18 | Access = "Allow" 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /Exercise4/PowerShellModules/xNetworking/Examples/Sample_xFirewall_DisableAccessToApplication.ps1: -------------------------------------------------------------------------------- 1 | # DSC configuration for Firewall 2 | # 3 | 4 | configuration Sample_xFirewall_AddFirewallRuleToNewGroup 5 | { 6 | param 7 | ( 8 | [string[]]$NodeName = 'localhost' 9 | ) 10 | 11 | Import-DSCResource -ModuleName xNetworking 12 | 13 | Node $NodeName 14 | { 15 | xFirewall Firewall 16 | { 17 | Name = "NotePadFirewallRule" 18 | DisplayName = "Firewall Rule for Notepad.exe" 19 | DisplayGroup = "NotePad Firewall Rule Group" 20 | Ensure = "Present" 21 | Access = "Block" 22 | Description = "Firewall Rule for Notepad.exe" 23 | ApplicationPath = "c:\windows\system32\notepad.exe" 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /Exercise4/PowerShellModules/xNetworking/Examples/Sample_xIPAddress_FixedValue.ps1: -------------------------------------------------------------------------------- 1 | configuration Sample_xIPAddress_FixedValue 2 | { 3 | param 4 | ( 5 | [string[]]$NodeName = 'localhost' 6 | ) 7 | 8 | Import-DscResource -Module xNetworking 9 | 10 | Node $NodeName 11 | { 12 | xIPAddress NewIPAddress 13 | { 14 | IPAddress = "2001:4898:200:7:6c71:a102:ebd8:f482" 15 | InterfaceAlias = "Ethernet" 16 | SubnetMask = 24 17 | AddressFamily = "IPV6" 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /Exercise4/PowerShellModules/xNetworking/Examples/Sample_xIPAddress_Parameterized.ps1: -------------------------------------------------------------------------------- 1 | configuration Sample_xIPAddress_Parameterized 2 | { 3 | param 4 | ( 5 | 6 | [string[]]$NodeName = 'localhost', 7 | 8 | [Parameter(Mandatory)] 9 | [string]$IPAddress, 10 | 11 | [Parameter(Mandatory)] 12 | [string]$InterfaceAlias, 13 | 14 | [Parameter(Mandatory)] 15 | [string]$DefaultGateway, 16 | 17 | [int]$SubnetMask = 16, 18 | 19 | [ValidateSet("IPv4","IPv6")] 20 | [string]$AddressFamily = 'IPv4' 21 | ) 22 | 23 | Import-DscResource -Module xNetworking 24 | 25 | Node $NodeName 26 | { 27 | xIPAddress NewIPAddress 28 | { 29 | IPAddress = $IPAddress 30 | InterfaceAlias = $InterfaceAlias 31 | DefaultGateway = $DefaultGateway 32 | SubnetMask = $SubnetMask 33 | AddressFamily = $AddressFamily 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /Exercise4/PowerShellModules/xNetworking/xNetworking.psd1: -------------------------------------------------------------------------------- 1 | @{ 2 | # Version number of this module. 3 | ModuleVersion = '2.1.1' 4 | 5 | # ID used to uniquely identify this module 6 | GUID = 'e6647cc3-ce9c-4c86-9eb8-2ee8919bf358' 7 | 8 | # Author of this module 9 | Author = 'Microsoft Corporation' 10 | 11 | # Company or vendor of this module 12 | CompanyName = 'Microsoft Corporation' 13 | 14 | # Copyright statement for this module 15 | Copyright = '(c) 2013 Microsoft Corporation. All rights reserved.' 16 | 17 | # Description of the functionality provided by this module 18 | Description = 'Module with DSC Resources for Networking area' 19 | 20 | # Minimum version of the Windows PowerShell engine required by this module 21 | PowerShellVersion = '4.0' 22 | 23 | # Minimum version of the common language runtime (CLR) required by this module 24 | CLRVersion = '4.0' 25 | 26 | # Functions to export from this module 27 | FunctionsToExport = '*' 28 | 29 | # Cmdlets to export from this module 30 | CmdletsToExport = '*' 31 | } -------------------------------------------------------------------------------- /Exercise4/PowerShellModules/xPendingReboot/DSCResources/MSFT_xPendingReboot/MSFT_xPendingReboot.psm1: -------------------------------------------------------------------------------- 1 | Function Get-TargetResource 2 | { 3 | [CmdletBinding()] 4 | param 5 | ( 6 | [Parameter(Mandatory=$true)] 7 | [string]$Name 8 | ) 9 | 10 | <## Remove: 11 | $ComponentBasedServicing = (Get-ItemProperty 'hklm:SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\').RebootPending -ne $null 12 | Remove - $WindowsUpdate = (Get-ItemProperty 'hklm:SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\').RebootRequired -ne $null 13 | Remove - $PendingFileRename = (Get-ItemProperty 'hklm:\SYSTEM\CurrentControlSet\Control\Session Manager\').PendingFileRenameOperations -ne $null 14 | #> 15 | 16 | ## Brian's additions:-------------------------------------------------- 17 | $ComponentBasedServicing = (Get-ChildItem 'hklm:SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\').Name.Split("\") -contains "RebootPending" 18 | $WindowsUpdate = (Get-ChildItem 'hklm:SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\').Name.Split("\") -contains "RebootRequired" 19 | $PendingFileRename = (Get-ItemProperty 'hklm:\SYSTEM\CurrentControlSet\Control\Session Manager\').PendingFileRenameOperations.Length -gt 0 20 | $ActiveComputerName = (Get-ItemProperty 'hklm:\SYSTEM\CurrentControlSet\Control\ComputerName\ActiveComputerName').ComputerName 21 | $PendingComputerName = (Get-ItemProperty 'hklm:\SYSTEM\CurrentControlSet\Control\ComputerName\ComputerName').ComputerName 22 | $PendingComputerRename = $ActiveComputerName -ne $PendingComputerName 23 | 24 | $CCMSplat = @{ 25 | NameSpace='ROOT\ccm\ClientSDK' 26 | Class='CCM_ClientUtilities' 27 | Name='DetermineIfRebootPending' 28 | ErrorAction='Stop' 29 | } 30 | 31 | Try { 32 | $CCMClientSDK = Invoke-WmiMethod @CCMSplat 33 | } Catch { 34 | Write-Warning "Unable to query CCM_ClientUtilities: $_" 35 | } 36 | 37 | $SCCMSDK = ($CCMClientSDK.ReturnValue -eq 0) -and ($CCMClientSDK.IsHardRebootPending -or $CCMClientSDK.RebootPending) 38 | ## End Brian's additions------------------------------------------------ 39 | 40 | return @{ 41 | Name = $Name 42 | ComponentBasedServicing = $ComponentBasedServicing 43 | WindowsUpdate = $WindowsUpdate 44 | PendingFileRename = $PendingFileRename 45 | PendingComputerRename = $PendingComputerRename 46 | CcmClientSDK = $SCCMSDK 47 | } 48 | } 49 | 50 | Function Set-TargetResource 51 | { 52 | [CmdletBinding()] 53 | param 54 | ( 55 | [Parameter(Mandatory=$true)] 56 | [string]$Name 57 | ) 58 | 59 | $global:DSCMachineStatus = 1 60 | } 61 | 62 | Function Test-TargetResource 63 | { 64 | [CmdletBinding()] 65 | param 66 | ( 67 | [Parameter(Mandatory=$true)] 68 | [string]$Name 69 | ) 70 | 71 | <## Remove 72 | $regRebootLocations += @{'HKLM:SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\'='RebootPending'} 73 | $regRebootLocations += @{'HKLM:SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\'='RebootRequired'} 74 | $regRebootLocations += @{'HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\'='PendingFileRenameOperations'} 75 | 76 | foreach ($reg in $regRebootLocations.keys) { 77 | if ((Get-ItemProperty $reg).($regRebootLocations[$reg]) -ne $Null) { 78 | Write-Verbose "A pending reboot was found at $reg." 79 | Write-Verbose 'Setting the DSCMachineStatus global variable to 1.' 80 | return $false} 81 | } 82 | #> 83 | 84 | ## Brian's additions:-------------------------------------------------- 85 | $ScriptBlocks += @{ComponentBasedServicing = {(Get-ChildItem 'hklm:SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\').Name.Split("\") -contains "RebootPending"}} 86 | $ScriptBlocks += @{WindowsUpdate = {(Get-ChildItem 'hklm:SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\').Name.Split("\") -contains "RebootRequired"}} 87 | $ScriptBlocks += @{PendingFileRename = {(Get-ItemProperty 'hklm:\SYSTEM\CurrentControlSet\Control\Session Manager\').PendingFileRenameOperations.Length -gt 0}} 88 | $ScriptBlocks += @{PendingComputerRename = { 89 | $ActiveComputerName = (Get-ItemProperty 'hklm:\SYSTEM\CurrentControlSet\Control\ComputerName\ActiveComputerName').ComputerName 90 | $PendingComputerName = (Get-ItemProperty 'hklm:\SYSTEM\CurrentControlSet\Control\ComputerName\ComputerName').ComputerName 91 | $ActiveComputerName -ne $PendingComputerName 92 | } 93 | } 94 | $ScriptBlocks += @{CcmClientSDK = { 95 | $CCMSplat = @{ 96 | NameSpace='ROOT\ccm\ClientSDK' 97 | Class='CCM_ClientUtilities' 98 | Name='DetermineIfRebootPending' 99 | ErrorAction='Stop' 100 | } 101 | Try { 102 | $CCMClientSDK = Invoke-WmiMethod @CCMSplat 103 | ($CCMClientSDK.ReturnValue -eq 0) -and ($CCMClientSDK.IsHardRebootPending -or $CCMClientSDK.RebootPending) 104 | } Catch { 105 | Write-Warning "Unable to query CCM_ClientUtilities: $_" 106 | } 107 | } 108 | } 109 | Foreach ($Script in $ScriptBlocks.Keys) { 110 | If (Invoke-Command $ScriptBlocks[$Script]) { 111 | Write-Verbose "A pending reboot was found for $Script." 112 | Write-Verbose 'Setting the DSCMachineStatus global variable to 1.' 113 | return $false 114 | } 115 | } 116 | ## End Brian's additions------------------------------------------------ 117 | 118 | Write-Verbose 'No pending reboots found.' 119 | return $true 120 | } 121 | 122 | Export-ModuleMember -Function *-TargetResource 123 | 124 | $regRebootLocations = $null -------------------------------------------------------------------------------- /Exercise4/PowerShellModules/xPendingReboot/DSCResources/MSFT_xPendingReboot/MSFT_xPendingReboot.schema.mof: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewabest/AWS-Workshop/071e4b7912e2704a366be0a6294d4d3d1da95a4d/Exercise4/PowerShellModules/xPendingReboot/DSCResources/MSFT_xPendingReboot/MSFT_xPendingReboot.schema.mof -------------------------------------------------------------------------------- /Exercise4/PowerShellModules/xPendingReboot/xPendingReboot.psd1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewabest/AWS-Workshop/071e4b7912e2704a366be0a6294d4d3d1da95a4d/Exercise4/PowerShellModules/xPendingReboot/xPendingReboot.psd1 -------------------------------------------------------------------------------- /Exercise4/PowerShellModules/xWebAdministration/DSCResources/MSFT_xIisModule/MSFT_xIisModule.psm1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewabest/AWS-Workshop/071e4b7912e2704a366be0a6294d4d3d1da95a4d/Exercise4/PowerShellModules/xWebAdministration/DSCResources/MSFT_xIisModule/MSFT_xIisModule.psm1 -------------------------------------------------------------------------------- /Exercise4/PowerShellModules/xWebAdministration/DSCResources/MSFT_xIisModule/MSFT_xIisModule.schema.mof: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewabest/AWS-Workshop/071e4b7912e2704a366be0a6294d4d3d1da95a4d/Exercise4/PowerShellModules/xWebAdministration/DSCResources/MSFT_xIisModule/MSFT_xIisModule.schema.mof -------------------------------------------------------------------------------- /Exercise4/PowerShellModules/xWebAdministration/DSCResources/MSFT_xIisModule/xIisModuleDesigner.ps1: -------------------------------------------------------------------------------- 1 | $diff = join-Path ${env:ProgramFiles(x86)} "Beyond compare 2\bc2.exe" 2 | $friendlyName = "xIisModule" 3 | $resourceName = "MSFT_$friendlyName" 4 | $classVersion = "1.0.0" 5 | 6 | $scriptRoot = Split-Path $MyInvocation.MyCommand.Path 7 | $originalModuleRoot = join-Path $scriptroot "..\.." 8 | $originalModuleRootPath = Resolve-Path $originalModuleRoot 9 | $moduleRoot = Join-Path $env:temp "$($originalModuleRootPath.path | split-path -Leaf)Temp" 10 | 11 | $resources = @() 12 | $schemaPath = (join-path $scriptRoot "$resourceName.schema.mof") 13 | 14 | #Key properties 15 | $resources += New-xDscResourceProperty -Name Path -Type String -Attribute Key -Description "The path to the module, usually a dll, to be added to IIS." 16 | 17 | 18 | #Required Properites 19 | $resources += New-xDscResourceProperty -Name Name -Type String -Attribute Required -Description "The logical name of the module to add to IIS." 20 | $resources += New-xDscResourceProperty -Name RequestPath -Type String -Attribute Required -Description "The allowed request Path example: *.php" 21 | $resources += New-xDscResourceProperty -Name Verb -Type String[] -Attribute Required -Description "The supported verbs for the module." 22 | 23 | #Write Properties 24 | $resources += New-xDscResourceProperty -Name SiteName -Type String -Attribute Write -Description "The IIS Site to register the module." 25 | $resources += New-xDscResourceProperty -Name Ensure -Type String -Attribute Write -Description "Should the module be present or absent." -ValidateSet @("Present","Absent") 26 | $resources += New-xDscResourceProperty -Name ModuleType -Type String -Attribute Write -Description "The type of the module." -ValidateSet @("FastCgiModule") 27 | 28 | #Read Properties 29 | $resources += New-xDscResourceProperty -Name EndPointSetup -Type Boolean -Attribute Read -Description "The End Point is setup. Such as a Fast Cgi endpoint." 30 | 31 | 32 | 33 | Write-Host updating... 34 | 35 | # Create a New template resource to a temporary folder 36 | New-xDscResource -Property $resources -ClassVersion $classVersion -Name $resourceName -Path $moduleRoot -FriendlyName $friendlyName 37 | 38 | 39 | # Use your favorite diff program to compare and merge the current resource and the existing resource 40 | 41 | if((test-Path $diff)) 42 | { 43 | &$diff $originalModuleRoot $moduleRoot 44 | } 45 | else 46 | { 47 | Write-Warning "Diff propgram not found!`r`nUse your favorite diff program to compare and merge:`r`n `t$($originalModuleRootPath.path)`r`n and:`r`n `t$moduleRoot" 48 | } 49 | 50 | -------------------------------------------------------------------------------- /Exercise4/PowerShellModules/xWebAdministration/DSCResources/MSFT_xWebAppPool/MSFT_xWebAppPool.psm1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewabest/AWS-Workshop/071e4b7912e2704a366be0a6294d4d3d1da95a4d/Exercise4/PowerShellModules/xWebAdministration/DSCResources/MSFT_xWebAppPool/MSFT_xWebAppPool.psm1 -------------------------------------------------------------------------------- /Exercise4/PowerShellModules/xWebAdministration/DSCResources/MSFT_xWebAppPool/MSFT_xWebAppPool.schema.mof: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewabest/AWS-Workshop/071e4b7912e2704a366be0a6294d4d3d1da95a4d/Exercise4/PowerShellModules/xWebAdministration/DSCResources/MSFT_xWebAppPool/MSFT_xWebAppPool.schema.mof -------------------------------------------------------------------------------- /Exercise4/PowerShellModules/xWebAdministration/DSCResources/MSFT_xWebApplication/MSFT_xWebApplication.psm1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewabest/AWS-Workshop/071e4b7912e2704a366be0a6294d4d3d1da95a4d/Exercise4/PowerShellModules/xWebAdministration/DSCResources/MSFT_xWebApplication/MSFT_xWebApplication.psm1 -------------------------------------------------------------------------------- /Exercise4/PowerShellModules/xWebAdministration/DSCResources/MSFT_xWebApplication/MSFT_xWebApplication.schema.mof: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewabest/AWS-Workshop/071e4b7912e2704a366be0a6294d4d3d1da95a4d/Exercise4/PowerShellModules/xWebAdministration/DSCResources/MSFT_xWebApplication/MSFT_xWebApplication.schema.mof -------------------------------------------------------------------------------- /Exercise4/PowerShellModules/xWebAdministration/DSCResources/MSFT_xWebConfigKeyValue/MSFT_xWebConfigKeyValue.psm1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewabest/AWS-Workshop/071e4b7912e2704a366be0a6294d4d3d1da95a4d/Exercise4/PowerShellModules/xWebAdministration/DSCResources/MSFT_xWebConfigKeyValue/MSFT_xWebConfigKeyValue.psm1 -------------------------------------------------------------------------------- /Exercise4/PowerShellModules/xWebAdministration/DSCResources/MSFT_xWebConfigKeyValue/MSFT_xWebConfigKeyValue.schema.mof: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewabest/AWS-Workshop/071e4b7912e2704a366be0a6294d4d3d1da95a4d/Exercise4/PowerShellModules/xWebAdministration/DSCResources/MSFT_xWebConfigKeyValue/MSFT_xWebConfigKeyValue.schema.mof -------------------------------------------------------------------------------- /Exercise4/PowerShellModules/xWebAdministration/DSCResources/MSFT_xWebVirtualDirectory/MSFT_xWebVirtualDirectory.psm1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewabest/AWS-Workshop/071e4b7912e2704a366be0a6294d4d3d1da95a4d/Exercise4/PowerShellModules/xWebAdministration/DSCResources/MSFT_xWebVirtualDirectory/MSFT_xWebVirtualDirectory.psm1 -------------------------------------------------------------------------------- /Exercise4/PowerShellModules/xWebAdministration/DSCResources/MSFT_xWebVirtualDirectory/MSFT_xWebVirtualDirectory.schema.mof: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewabest/AWS-Workshop/071e4b7912e2704a366be0a6294d4d3d1da95a4d/Exercise4/PowerShellModules/xWebAdministration/DSCResources/MSFT_xWebVirtualDirectory/MSFT_xWebVirtualDirectory.schema.mof -------------------------------------------------------------------------------- /Exercise4/PowerShellModules/xWebAdministration/DSCResources/MSFT_xWebsite/MSFT_xWebsite.schema.mof: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewabest/AWS-Workshop/071e4b7912e2704a366be0a6294d4d3d1da95a4d/Exercise4/PowerShellModules/xWebAdministration/DSCResources/MSFT_xWebsite/MSFT_xWebsite.schema.mof -------------------------------------------------------------------------------- /Exercise4/PowerShellModules/xWebAdministration/xWebAdministration.psd1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewabest/AWS-Workshop/071e4b7912e2704a366be0a6294d4d3d1da95a4d/Exercise4/PowerShellModules/xWebAdministration/xWebAdministration.psd1 -------------------------------------------------------------------------------- /Exercise4/Scripts/ConfigureWebserver.ps1: -------------------------------------------------------------------------------- 1 | Configuration ConfigureWebserver 2 | { 3 | Import-DscResource -ModuleName cWinServer 4 | Import-DscResource -ModuleName xWebAdministration 5 | Import-DscResource -ModuleName xPendingReboot 6 | Import-DscResource -ModuleName xNetworking 7 | 8 | # Localhost targets the node this script is run on 9 | Node 'localhost' 10 | { 11 | LocalConfigurationManager 12 | { 13 | RebootNodeIfNeeded = $True 14 | } 15 | 16 | WinServerOptions ServerOptions 17 | { 18 | Ensure = "Present" 19 | Name = "Set timezone and culture" 20 | Culture = "en-AU" 21 | TimeZone = "AUS Eastern Standard Time" 22 | } 23 | 24 | xPendingReboot AfterServerOptions 25 | { 26 | Name = "AfterServerOptions" 27 | DependsOn = '[WinServerOptions]ServerOptions' 28 | } 29 | 30 | $windowsFeatures = @( 31 | "Web-App-Dev", 32 | "Web-Common-Http", 33 | "Web-Health", 34 | "Web-Performance", 35 | "Web-Security", 36 | "Web-Scripting-Tools", 37 | "Web-Mgmt-Service", 38 | "Web-Mgmt-Console" 39 | ) 40 | 41 | $windowsFeatureDependOn = @(); 42 | 43 | foreach ($windowsFeature in $windowsFeatures) 44 | { 45 | WindowsFeature "IIS_$windowsFeature" 46 | { 47 | Ensure = "Present" 48 | Name = $windowsFeature 49 | IncludeAllSubFeature = $true 50 | DependsOn = "[xPendingReboot]AfterServerOptions" 51 | } 52 | 53 | $windowsFeatureDependOn += "[WindowsFeature]IIS_$windowsFeature" 54 | } 55 | 56 | <# 57 | NOTE: For new players, if you want to discover whether a reboot will be required after a given piece of DSC, search for "$global:DSCMachineStatus = 1" in the resources you have used. 58 | #> 59 | 60 | xPendingReboot RebootAfterWindowsFeatures 61 | { 62 | Name = 'AfterWindowsFeatures' 63 | DependsOn = $windowsFeatureDependOn 64 | } 65 | 66 | # Stop & Remove the default website 67 | xWebsite DefaultSite 68 | { 69 | Ensure = "Absent" 70 | Name = "Default Web Site" 71 | State = "Stopped" 72 | PhysicalPath = "C:\inetpub\wwwroot" 73 | DependsOn = $windowsFeatureDependOn 74 | } 75 | 76 | # Remove all default Application Pools EXCEPT DEFAULT (will use this for the load balancer health check) 77 | foreach ($appPool in @("Classic .NET AppPool", ".NET v2.0", 78 | ".NET v2.0 Classic", ".NET v4.5", ".NET v4.5 Classic")) 79 | { 80 | xWebAppPool $appPool 81 | { 82 | Ensure = "Absent" 83 | Name = $appPool 84 | DependsOn = ($windowsFeatureDependOn + @("[xWebsite]DefaultSite")) 85 | } 86 | } 87 | 88 | File LoadBalancerHealthCheckEndpointContent 89 | { 90 | Ensure = "Present" 91 | DestinationPath = "C:\inetpub\wwwroot\index.html" 92 | Contents = "Hello, is it me you're looking for?" 93 | Type = "File" 94 | } 95 | 96 | xWebsite LoadBalancerHealthCheckEndpoint 97 | { 98 | Ensure = "Present" 99 | Name = "LoadBalancerHealthCheck" 100 | State = "Started" 101 | PhysicalPath = "C:\inetpub\wwwroot" 102 | BindingInfo = MSFT_xWebBindingInformation 103 | { 104 | Protocol = "HTTP" 105 | Port = 81 106 | } 107 | DependsOn = "[File]LoadBalancerHealthCheckEndpointContent" 108 | } 109 | 110 | xFirewall Firewall 111 | { 112 | Name = "Web" 113 | DisplayName = "Inbound access for web requests" 114 | Ensure = "Present" 115 | Access = "Allow" 116 | State = "Enabled" 117 | Profile = ("Domain", "Private", "Public") 118 | Direction = "InBound" 119 | RemotePort = ("Any") 120 | LocalPort = ("80", "81", "443") 121 | Protocol = "TCP" 122 | Description = "Inbound access for web requests" 123 | } 124 | } 125 | } 126 | 127 | ConfigureWebserver 128 | 129 | Set-DscLocalConfigurationManager -Path .\ConfigureWebserver -Verbose 130 | Start-DscConfiguration -Path .\ConfigureWebserver -Verbose -Wait -Force 131 | -------------------------------------------------------------------------------- /Exercise4/Scripts/Teardown.ps1: -------------------------------------------------------------------------------- 1 |  -------------------------------------------------------------------------------- /Exercise4/Templates/Zephyr.template: -------------------------------------------------------------------------------- 1 | { 2 | "AWSTemplateFormatVersion": "2010-09-09", 3 | 4 | "Description": "A template to deploy a simple fault tolerant load balanced web hosting infrastructure.", 5 | 6 | "Parameters": { 7 | "S3BucketName": { 8 | "Description": "The S3 Bucket Name used in URL's to specify authentication against.", 9 | "Type": "String" 10 | }, 11 | "VpcId": { 12 | "Description": "The Vpc to deploy the infrastructure into.", 13 | "Type": "String" 14 | }, 15 | "PowerShellModulesBundleUrl": { 16 | "Description": "The URL to a ZIP file containing any PowerShell modules required by this CloudFormation template.", 17 | "Type": "String" 18 | }, 19 | "BootstrapperScriptBundleUrl": { 20 | "Description": "The URL to a ZIP file containing the PowerShell script package to bootstrap EC2 instances in this CloudFormation template.", 21 | "Type": "String" 22 | }, 23 | "WebserverTemplateUrl": { 24 | "Description": "The URL to the CloudFormation stack template for web servers.", 25 | "Type": "String" 26 | }, 27 | "Timestamp": { 28 | "Description": "When this CloudFormation stack was last updated.", 29 | "Type": "String" 30 | }, 31 | "Version": { 32 | "Description": "The package version that contains this CloudFormation template.", 33 | "Type": "String" 34 | }, 35 | "Environment": { 36 | "Type": "String", 37 | "Default": "Development" 38 | }, 39 | "KeyPairName": { 40 | "Description": "The EC2 key pair used to launch web instances", 41 | "Type": "AWS::EC2::KeyPair::KeyName" 42 | }, 43 | "WebserverImageId": { 44 | "Description": "The EC2 AmiId to use for web", 45 | "Type": "String", 46 | "Default": "ami-f9760dc3" 47 | }, 48 | "WebserverInstanceType": { 49 | "Description": "The EC2 instance type to use for web", 50 | "Type": "String", 51 | "Default": "t2.small" 52 | }, 53 | "WebserverSubnetIdAzOne": { 54 | "Description": "The PUBLIC subnet belonging to availability zone one into which the instance will be launched", 55 | "Type": "String" 56 | }, 57 | "WebserverSubnetIdAzTwo": { 58 | "Description": "The PUBLIC subnet belonging to availability zone two into which the instance will be launched", 59 | "Type": "String" 60 | }, 61 | "LoadBalancerSubnetIdAzOne": { 62 | "Description": "The PUBLIC IG-connected subnet belonging to availability zone one that the load balancer will belong to", 63 | "Type": "String" 64 | }, 65 | "LoadBalancerSubnetIdAzTwo": { 66 | "Description": "The PUBLIC IG-connected subnet belonging to availability zone two that the load balancer will belong to", 67 | "Type": "String" 68 | }, 69 | "ResourcePrefix" : { 70 | "Description": "Used to prefix a unique name to resources where applicable", 71 | "Type": "String" 72 | } 73 | }, 74 | 75 | "Resources": { 76 | "BootstrapRole": { 77 | "Type": "AWS::IAM::Role", 78 | "Properties": { 79 | "AssumeRolePolicyDocument": { 80 | "Version": "2012-10-17", 81 | "Statement": [ 82 | { 83 | "Effect": "Allow", 84 | "Principal": { 85 | "Service": [ "ec2.amazonaws.com" ] 86 | }, 87 | "Action": [ "sts:AssumeRole" ] 88 | } 89 | ] 90 | }, 91 | "Path": "/" 92 | } 93 | }, 94 | "BootstrapRolePolicies": { 95 | "Type": "AWS::IAM::Policy", 96 | "Properties": { 97 | "PolicyName": "bootstrap", 98 | "PolicyDocument": { 99 | "Version": "2012-10-17", 100 | "Statement": [ 101 | { 102 | "Effect": "Allow", 103 | "Action": "s3:*", 104 | "Resource": [ 105 | { "Fn::Join": [ "", [ "arn:aws:s3:::", { "Ref": "S3BucketName" } ] ] }, 106 | { "Fn::Join": [ "", [ "arn:aws:s3:::", { "Ref": "S3BucketName" }, "/*" ] ] } 107 | ] 108 | } 109 | ] 110 | }, 111 | "Roles": [ 112 | { 113 | "Ref": "BootstrapRole" 114 | } 115 | ] 116 | } 117 | }, 118 | "BootstrapInstanceProfile": { 119 | "Type": "AWS::IAM::InstanceProfile", 120 | "Properties": { 121 | "Path": "/", 122 | "Roles": [ 123 | { 124 | "Ref": "BootstrapRole" 125 | } 126 | ] 127 | } 128 | }, 129 | "WebStack": { 130 | "Type": "AWS::CloudFormation::Stack", 131 | "Properties": { 132 | "Parameters": { 133 | "S3BucketName": { "Ref": "S3BucketName" }, 134 | "VpcId": { "Ref": "VpcId" }, 135 | "PowerShellModulesBundleUrl": { "Ref": "PowerShellModulesBundleUrl" }, 136 | "BootstrapperScriptBundleUrl": { "Ref": "BootstrapperScriptBundleUrl" }, 137 | "Timestamp": { "Ref": "Timestamp" }, 138 | "Version": { "Ref": "Version" }, 139 | "Environment": { "Ref": "Environment" }, 140 | "InstanceProfile": { "Ref": "BootstrapInstanceProfile" }, 141 | "BootstrapperRole": { "Ref": "BootstrapRole" }, 142 | "KeyPairName": { "Ref": "KeyPairName" }, 143 | "WebserverImageId": { "Ref": "WebserverImageId" }, 144 | "WebserverInstanceType": { "Ref": "WebserverInstanceType" }, 145 | "WebserverSubnetIdAzOne": { "Ref": "WebserverSubnetIdAzOne" }, 146 | "WebserverSubnetIdAzTwo": { "Ref": "WebserverSubnetIdAzTwo" }, 147 | "LoadBalancerSubnetIdAzOne": { "Ref": "LoadBalancerSubnetIdAzOne" }, 148 | "LoadBalancerSubnetIdAzTwo": { "Ref": "LoadBalancerSubnetIdAzTwo" }, 149 | "ResourcePrefix": { "Ref": "ResourcePrefix" } 150 | }, 151 | "TemplateURL": { "Ref": "WebserverTemplateUrl" }, 152 | "TimeoutInMinutes": 10 153 | } 154 | } 155 | }, 156 | 157 | "Outputs": { 158 | "LoadBalancerUri": { 159 | "Value": { "Fn::GetAtt": [ "WebStack", "Outputs.LoadBalancerUri" ] } 160 | } 161 | } 162 | } -------------------------------------------------------------------------------- /Exercise5.md: -------------------------------------------------------------------------------- 1 | # Exercise 5 2 | 3 | ## Deployment Magic 4 | 5 | In the final exercise, we are going to use some DSC + Octopus magic to [Automatically Deploy](https://octopus.com/docs/guides/elastic-and-transient-environments/immutable-infrastructure) to our transient infrastructure. 6 | 7 | ## Goals 8 | 9 | * Learn how we can automatically deploy our software along with our infrastructure 10 | 11 | ## Instructions 12 | 13 | 1. Open .\Exercise5\Parameters.ps1. Update the ResourcePrefix parameter to your initials, and take note of the other parameters provided 14 | 2. Open up .\Exercise5\Deploy.ps1 15 | 3. With PowerShell, write a file to scriptPath\Scripts\Variables.ps1 containing a HashTable named $BootstrapParameters that contains the values of the following parameters 16 | * OctopusServerUrl 17 | * OctopusApiKey 18 | * OctopusRole 19 | * Octopus.Environment.Name as 'Environment' 20 | 4. The astute observer would notice that this file will be scooped up into our scripts zip that we then download onto our instances during cfn-init 21 | 5. Navigate to .\Exercise5\PowerShellModules\cOctopus\DSCResources\cTentacleAgent\cTentacleAgent.psm1 and open it up in PowerShell ISE 22 | 6. Follow through **Set-TargetResource** and see how it does its thing 23 | 7. Go to Octopus, open the *CloudFormawesome* project, and navigate to its _Triggers_. Take a look at the trigger that will deploy our software when our transient infrastructure enters our environment. 24 | 8. Open up .\Exercise5\Scripts\ConfigureWebserver.ps1 25 | 9. At the top of the file, determine the execution location using 26 | 27 | [System.IO.Path]::GetDirectoryName($PSScriptRoot) 28 | 10. This will give us the root execution location - c:\cfn. Now we can dot-source our variables.ps1 file that will be downloaded onto the machine 29 | 11. Now that we have our $BootstrapParameters collection in scope, we can use the values in it to add a [cTentacleAgent resource](https://github.com/OctopusDeploy/OctopusDSC) to the end of our DSC configuration 30 | 12. Return to .\Exercise5\Deploy.ps1 and F5! 31 | 13. Monitor your stack's creation, and once your instances are available, remote in and take a look in the cfn-init log along with the DSC logs and ensure the operation was successful 32 | 14. If all went well, your machines should pop up in Octopus, and have a deployment triggered for themselves (one deployment per machine) 33 | 15. Hit your load balancer URL returned by the script! Wow! Such automated. Much website 34 | 35 | -------------------------------------------------------------------------------- /Exercise5/Parameters.ps1: -------------------------------------------------------------------------------- 1 | $OctopusParameters = @{} 2 | 3 | # Octopus parameters 4 | $OctopusParameters['ResourcePrefix'] = 'aab'; 5 | $OctopusParameters['OctopusServerUrl'] = "http://octopus.cfa.aws"; 6 | $OctopusParameters['OctopusRole'] = "web"; 7 | $OctopusParameters['OctopusApiKey'] = ""; 8 | $OctopusParameters['Octopus.Environment.Name'] = "Production"; 9 | $OctopusParameters['Octopus.Release.Number'] = "1.0.0-ryan0001"; 10 | 11 | # CloudFormation parameters 12 | $OctopusParameters['AWSRegion'] = "ap-southeast-2"; 13 | $OctopusParameters['CloudFormationStackName'] = "{0}-sandbox-{1}" -f @($OctopusParameters['ResourcePrefix'], $OctopusParameters['Octopus.Environment.Name']); 14 | $OctopusParameters['S3BucketName'] = "{0}-sandbox-infrastructure" -f $OctopusParameters['ResourcePrefix']; 15 | $OctopusParameters['VpcId'] = "vpc-7ecaee1b"; 16 | 17 | # AWS parameters 18 | $OctopusParameters['KeyPairName'] = "AwsDayKeyPair"; 19 | $OctopusParameters['WebserverImageId'] = "ami-bf8895dc"; #WINDOWS_2016_BASE 20 | $OctopusParameters['WebserverInstanceType'] = "t2.medium"; 21 | $OctopusParameters['WebserverSubnetIdAzOne'] = "subnet-b1afb5d4"; # Web A 22 | $OctopusParameters['WebserverSubnetIdAzTwo'] = "subnet-14787e63"; # Web B 23 | $OctopusParameters['LoadBalancerSubnetIdAzOne'] = "subnet-973728f2"; # DMZ A 24 | $OctopusParameters['LoadBalancerSubnetIdAzTwo'] = "subnet-99477cee"; # DMZ B -------------------------------------------------------------------------------- /Exercise5/PowerShellModules/cOctopus/DSCResources/cTentacleAgent/cTentacleAgent.schema.mof: -------------------------------------------------------------------------------- 1 | [ClassVersion("1.0.0"), FriendlyName("cTentacleAgent")] 2 | class cTentacleAgent : OMI_BaseResource 3 | { 4 | [Key] string Name; 5 | [Write, ValueMap{"Present", "Absent"}, Values{"Present", "Absent"}] string Ensure; 6 | [Write, ValueMap{"Started", "Stopped"}, Values{"Started", "Stopped"}] string State; 7 | 8 | [Write, ValueMap{"Listen", "Poll"}, Values{"Listen", "Poll"}] string CommunicationMode; 9 | [Write] string ApiKey; 10 | [Write] string OctopusServerUrl; 11 | [Write] string DisplayName; 12 | [Write] string Policy; 13 | [Write] string Environments[]; 14 | [Write] string Roles[]; 15 | [Write] string Tenants[]; 16 | [Write] string TenantTags[]; 17 | [Write] UInt32 ListenPort; 18 | [Write] UInt32 ServerPort; 19 | [Write] string DefaultApplicationDirectory; 20 | [Write] string TentacleDownloadUrl; 21 | [Write] string TentacleDownloadUrl64; 22 | [Write, ValueMap{"PublicIp", "FQDN", "ComputerName", "Custom"}, Values{"PublicIp", "FQDN", "ComputerName", "Custom"}] string PublicHostNameConfiguration; 23 | [Write] string CustomPublicHostName; 24 | [Write] string TentacleHomeDirectory; 25 | [Write] Boolean RegisterWithServer; 26 | [Write] String OctopusServerThumbprint; 27 | }; 28 | -------------------------------------------------------------------------------- /Exercise5/PowerShellModules/cOctopus/cOctopus.psd1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewabest/AWS-Workshop/071e4b7912e2704a366be0a6294d4d3d1da95a4d/Exercise5/PowerShellModules/cOctopus/cOctopus.psd1 -------------------------------------------------------------------------------- /Exercise5/PowerShellModules/cWinServer/DSCResources/WinServerOptions/WinServerOptions.psm1: -------------------------------------------------------------------------------- 1 | function Get-TargetResource 2 | { 3 | [CmdletBinding()] 4 | [OutputType([System.Collections.Hashtable])] 5 | param 6 | ( 7 | [parameter(Mandatory = $true)] 8 | [System.String] 9 | $Name, 10 | 11 | [System.String] 12 | $Culture, 13 | 14 | [System.String] 15 | $TimeZone 16 | ) 17 | 18 | $returnValue = @{ 19 | Ensure = $Ensure 20 | Name = $Name 21 | Culture = $Culture 22 | Timezone = $Timezone 23 | } 24 | 25 | return $returnValue; 26 | } 27 | 28 | function Set-TargetResource 29 | { 30 | [CmdletBinding()] 31 | param 32 | ( 33 | [ValidateSet("Present","Absent")] 34 | [System.String] 35 | $Ensure, 36 | 37 | [parameter(Mandatory = $true)] 38 | [System.String] 39 | $Name, 40 | 41 | [System.String] 42 | $Culture, 43 | 44 | [System.String] 45 | $TimeZone 46 | ) 47 | 48 | if ($Ensure -eq "Present") 49 | { 50 | if ($Culture) 51 | { 52 | if ((Get-WinSystemLocale).Name -ne $Culture) 53 | { 54 | Write-Verbose "Setting System Locale to $Culture. Will Require reboot to take effect." 55 | Set-WinSystemLocale -SystemLocale $Culture 56 | 57 | $global:DSCMachineStatus = 1; 58 | } 59 | } 60 | 61 | if (([System.TimeZone]::CurrentTimeZone).StandardName -ne $TimeZone) 62 | { 63 | Write-Verbose "Setting System TimeZone to [$TimeZone]" 64 | & tzutil.exe /s "$TimeZone" 65 | } 66 | } 67 | } 68 | 69 | function Test-TargetResource 70 | { 71 | [CmdletBinding()] 72 | [OutputType([System.Boolean])] 73 | param 74 | ( 75 | [ValidateSet("Present","Absent")] 76 | [System.String] 77 | $Ensure, 78 | 79 | [parameter(Mandatory = $true)] 80 | [System.String] 81 | $Name, 82 | 83 | [System.String] 84 | $Culture, 85 | 86 | [System.String] 87 | $TimeZone 88 | ) 89 | 90 | if ($Ensure -eq "Present") 91 | { 92 | if ($Culture) 93 | { 94 | if ((Get-WinSystemLocale).Name -ne $Culture) 95 | { 96 | Write-Verbose "System Locale is currently $((Get-WinSystemLocale).Name) and should be $Culture" 97 | return $false; 98 | } 99 | 100 | Write-Verbose "System Locale and Culture are correct." 101 | } 102 | 103 | if ($TimeZone) 104 | { 105 | if (([System.TimeZone]::CurrentTimeZone).StandardName -ne $TimeZone) 106 | { 107 | Write-Verbose "System TimeZone is current:[$(([System.TimeZone]::CurrentTimeZone).StandardName)] and should be:[$TimeZone]" 108 | return $false; 109 | } 110 | 111 | Write-Verbose "System TimeZone is correct." 112 | } 113 | } 114 | else 115 | { 116 | Write-Verbose "Ignoring checks" 117 | } 118 | 119 | return $true; 120 | } -------------------------------------------------------------------------------- /Exercise5/PowerShellModules/cWinServer/DSCResources/WinServerOptions/WinServerOptions.schema.mof: -------------------------------------------------------------------------------- 1 | [ClassVersion("1.0.0.0"), FriendlyName("WinServerOptions")] 2 | class WinServerOptions : OMI_BaseResource 3 | { 4 | [Write, ValueMap{"Present","Absent"}, Values{"Present","Absent"}] String Ensure; 5 | [Key, Description("The name for the setup. Can just be the server name")] String Name; 6 | [Write, Description("The Windows Server culture")] String Culture; 7 | [Write, Description("The Windows Server Timezone")] String TimeZone; 8 | }; -------------------------------------------------------------------------------- /Exercise5/PowerShellModules/cWinServer/cWinServer.psd1: -------------------------------------------------------------------------------- 1 | # 2 | # Module manifest for module 'cWinServer' 3 | # 4 | # Generated by: andrewb 5 | # 6 | # Generated on: 9/06/2015 7 | @{ 8 | ModuleVersion = '1.0' 9 | GUID = '90798d5f-9f2e-4af4-b9fd-79b4f67899fb' 10 | Author = 'andrewb' 11 | CompanyName = 'Unknown' 12 | Copyright = '(c) 2015 andrewb. All rights reserved.' 13 | Description = '' 14 | PowerShellVersion = '4.0' 15 | FunctionsToExport = @('Get-TargetResource','Set-TargetResource','Test-TargetResource') 16 | } 17 | 18 | -------------------------------------------------------------------------------- /Exercise5/PowerShellModules/xDscDiagnostics/xDscDiagnostics.psd1: -------------------------------------------------------------------------------- 1 |  2 | 3 | @{ 4 | 5 | 6 | ModuleVersion = '2.0' 7 | GUID = 'ef098cb4-f7e9-4763-b636-0cd9799e1c9a' 8 | 9 | Author = 'Microsoft Corporation' 10 | CompanyName = 'Microsoft Corporation' 11 | Copyright = '(c) 2013 Microsoft Corporation. All rights reserved.' 12 | 13 | Description = 'Module to help in reading details from DSC events' 14 | 15 | PowerShellVersion = '4.0' 16 | 17 | CLRVersion = '4.0' 18 | 19 | FunctionsToExport = @("*") 20 | 21 | NestedModules = @('xDscDiagnostics.psm1') 22 | } -------------------------------------------------------------------------------- /Exercise5/PowerShellModules/xDscDiagnostics/xDscDiagnosticsFormat.ps1xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Microsoft.PowerShell.xDscDiagnostics.GroupedEvents 7 | 8 | Microsoft.PowerShell.xDscDiagnostics.GroupedEvents 9 | 10 | 11 | 12 | 13 | 14 | 14 15 | 16 | 17 | 18 | 10 19 | 20 | 21 | 22 | 21 23 | 24 | 25 | 26 | 8 27 | 28 | 29 | 30 | 37 31 | 32 | 33 | 34 | 21 35 | 36 | 37 | 38 | 39 | 40 | 41 | ComputerName 42 | 43 | 44 | SequenceId 45 | 46 | 47 | TimeCreated 48 | 49 | 50 | Result 51 | 52 | 53 | JobID 54 | 55 | 56 | AllEvents 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | Microsoft.PowerShell.xDscDiagnostics.TraceOutput 65 | 66 | Microsoft.PowerShell.xDscDiagnostics.TraceOutput 67 | 68 | 69 | 70 | 71 | 72 | 14 73 | 74 | 75 | 76 | 12 77 | 78 | 79 | 80 | 21 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | ComputerName 91 | 92 | 93 | EventType 94 | 95 | 96 | TimeCreated 97 | 98 | 99 | Message 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | -------------------------------------------------------------------------------- /Exercise5/PowerShellModules/xNetworking/DSCResources/MSFT_xDNSServerAddress/MSFT_xDNSServerAddress.psm1: -------------------------------------------------------------------------------- 1 | <####################################################################################### 2 | # xDNSServerAddress : DSC Resource that will set/test/get the current DNS Server 3 | # Address, by accepting values among those given in xDNSServerAddress.schema.mof 4 | #######################################################################################> 5 | 6 | 7 | 8 | ###################################################################################### 9 | # The Get-TargetResource cmdlet. 10 | # This function will get the present list of DNS ServerAddress DSC Resource schema variables on the system 11 | ###################################################################################### 12 | function Get-TargetResource 13 | { 14 | param 15 | ( 16 | [Parameter(Mandatory)] 17 | [ValidateNotNullOrEmpty()] 18 | [String[]]$Address, 19 | 20 | [Parameter(Mandatory)] 21 | [ValidateNotNullOrEmpty()] 22 | [String]$InterfaceAlias, 23 | 24 | [ValidateSet("IPv4", "IPv6")] 25 | [String]$AddressFamily = "IPv4" 26 | ) 27 | 28 | 29 | $returnValue = @{ 30 | Address = (Get-DnsClientServerAddress -InterfaceAlias $InterfaceAlias -AddressFamily $AddressFamily).ServerAddresses 31 | AddressFamily = $AddressFamily 32 | InterfaceAlias = $InterfaceAlias 33 | } 34 | 35 | $returnValue 36 | } 37 | 38 | ###################################################################################### 39 | # The Set-TargetResource cmdlet. 40 | # This function will set a new Server Address in the current node 41 | ###################################################################################### 42 | function Set-TargetResource 43 | { 44 | param 45 | ( 46 | #IP Address that has to be set 47 | [Parameter(Mandatory)] 48 | [ValidateNotNullOrEmpty()] 49 | [String[]]$Address, 50 | 51 | [Parameter(Mandatory)] 52 | [ValidateNotNullOrEmpty()] 53 | [String]$InterfaceAlias, 54 | 55 | [ValidateSet("IPv4", "IPv6")] 56 | [String]$AddressFamily = "IPv4" 57 | ) 58 | 59 | ValidateProperties @PSBoundParameters -Apply 60 | } 61 | 62 | ###################################################################################### 63 | # The Test-TargetResource cmdlet. 64 | # This will test if the given Server Address is among the current node's Server Address collection 65 | ###################################################################################### 66 | function Test-TargetResource 67 | { 68 | param 69 | ( 70 | [Parameter(Mandatory)] 71 | [ValidateNotNullOrEmpty()] 72 | [String[]]$Address, 73 | 74 | [Parameter(Mandatory)] 75 | [ValidateNotNullOrEmpty()] 76 | [String]$InterfaceAlias, 77 | 78 | [ValidateSet("IPv4", "IPv6")] 79 | [String]$AddressFamily = "IPv4" 80 | ) 81 | 82 | ValidateProperties @PSBoundParameters 83 | } 84 | 85 | 86 | ####################################################################################### 87 | # Helper function that validates the Server Address properties. If the switch parameter 88 | # "Apply" is set, then it will set the properties after a test 89 | ####################################################################################### 90 | function ValidateProperties 91 | { 92 | param 93 | ( 94 | [Parameter(Mandatory)] 95 | [ValidateNotNullOrEmpty()] 96 | [String[]]$Address, 97 | 98 | [Parameter(Mandatory)] 99 | [ValidateNotNullOrEmpty()] 100 | [String]$InterfaceAlias, 101 | 102 | [ValidateSet("IPv4", "IPv6")] 103 | [String]$AddressFamily, 104 | 105 | [Switch]$Apply 106 | ) 107 | $sa =$Address 108 | $sa | %{ 109 | if(!([System.Net.Ipaddress]::TryParse($_, [ref]0))) 110 | { 111 | throw "Server Address *$_* is not in the correct format. Please correct the Address in the configuration and try again" 112 | } 113 | if (([System.Net.IPAddress]$_).AddressFamily.ToString() -eq [System.Net.Sockets.AddressFamily]::InterNetwork.ToString()) 114 | { 115 | if ($AddressFamily -ne "IPv4") 116 | { 117 | throw "Server address $Address is in IPv4 format, which does not match server address family $AddressFamily. Please correct either of them in the configuration and try again" 118 | } 119 | } 120 | else 121 | { 122 | if ($AddressFamily -ne "IPv6") 123 | { 124 | throw "Server address $Address is in IPv6 format, which does not match server address family $AddressFamily. Please correct either of them in the configuration and try again" 125 | } 126 | } 127 | } 128 | try 129 | { 130 | Write-Verbose -Message "Checking the DNS Server Address ..." 131 | #Get the current IP Address based on the parameters given. 132 | $currentAddress = (Get-DnsClientServerAddress -InterfaceAlias $InterfaceAlias -AddressFamily $AddressFamily -ErrorAction Stop).ServerAddresses 133 | 134 | #Check if the Server addresses are the same as the desired addresses. 135 | if(@(Compare-Object -ReferenceObject $currentAddress -DifferenceObject $Address -SyncWindow 0).Length -gt 0) 136 | { 137 | Write-Verbose -Message "DNS Servers are not correct. Expected $Address, actual $currentAddress" 138 | if($Apply) 139 | { 140 | # Set the DNS settings as well 141 | Set-DnsClientServerAddress -InterfaceAlias $InterfaceAlias -ServerAddresses $Address 142 | Write-Verbose -Message "DNS Servers have been set correctly." 143 | } 144 | else 145 | { 146 | return $false 147 | } 148 | } 149 | else 150 | { 151 | #Test will return true in this case 152 | Write-Verbose -Message "DNS Servers are set correctly." 153 | return $true 154 | } 155 | } 156 | catch 157 | { 158 | Write-Verbose -Message $_ 159 | throw "Can not set or find valid DNS Server addresses using InterfaceAlias $InterfaceAlias and AddressFamily $AddressFamily" 160 | } 161 | } 162 | 163 | 164 | 165 | # FUNCTIONS TO BE EXPORTED 166 | Export-ModuleMember -function Get-TargetResource, Set-TargetResource, Test-TargetResource -------------------------------------------------------------------------------- /Exercise5/PowerShellModules/xNetworking/DSCResources/MSFT_xDNSServerAddress/MSFT_xDNSServerAddress.schema.mof: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewabest/AWS-Workshop/071e4b7912e2704a366be0a6294d4d3d1da95a4d/Exercise5/PowerShellModules/xNetworking/DSCResources/MSFT_xDNSServerAddress/MSFT_xDNSServerAddress.schema.mof -------------------------------------------------------------------------------- /Exercise5/PowerShellModules/xNetworking/DSCResources/MSFT_xFirewall/MSFT_xFirewall.Schema.mof: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewabest/AWS-Workshop/071e4b7912e2704a366be0a6294d4d3d1da95a4d/Exercise5/PowerShellModules/xNetworking/DSCResources/MSFT_xFirewall/MSFT_xFirewall.Schema.mof -------------------------------------------------------------------------------- /Exercise5/PowerShellModules/xNetworking/DSCResources/MSFT_xIPAddress/MSFT_xIPAddress.psm1: -------------------------------------------------------------------------------- 1 | <####################################################################################### 2 | # MSDSCPack_IPAddress : DSC Resource that will set/test/get the current IP 3 | # Address, by accepting values among those given in MSDSCPack_IPAddress.schema.mof 4 | #######################################################################################> 5 | 6 | 7 | 8 | ###################################################################################### 9 | # The Get-TargetResource cmdlet. 10 | # This function will get the present list of IP Address DSC Resource schema variables on the system 11 | ###################################################################################### 12 | function Get-TargetResource 13 | { 14 | param 15 | ( 16 | [Parameter(Mandatory)] 17 | [ValidateNotNullOrEmpty()] 18 | [String]$IPAddress, 19 | 20 | [Parameter(Mandatory)] 21 | [ValidateNotNullOrEmpty()] 22 | [String]$InterfaceAlias, 23 | 24 | [Int]$SubnetMask = 16, 25 | 26 | [ValidateNotNullOrEmpty()] 27 | [String]$DefaultGateway, 28 | 29 | [ValidateSet("IPv4", "IPv6")] 30 | [String]$AddressFamily = "IPv4" 31 | ) 32 | 33 | 34 | $returnValue = @{ 35 | IPAddress = [System.String]::Join(", ",(Get-NetIPAddress -InterfaceAlias $InterfaceAlias -AddressFamily $AddressFamily).IPAddress) 36 | SubnetMask = $SubnetMask 37 | DefaultGateway = $DefaultGateway 38 | AddressFamily = $AddressFamily 39 | InterfaceAlias=$InterfaceAlias 40 | } 41 | 42 | $returnValue 43 | } 44 | 45 | ###################################################################################### 46 | # The Set-TargetResource cmdlet. 47 | # This function will set a new IP Address in the current node 48 | ###################################################################################### 49 | function Set-TargetResource 50 | { 51 | param 52 | ( 53 | #IP Address that has to be set 54 | [Parameter(Mandatory)] 55 | [ValidateNotNullOrEmpty()] 56 | [String]$IPAddress, 57 | 58 | [Parameter(Mandatory)] 59 | [ValidateNotNullOrEmpty()] 60 | [String]$InterfaceAlias, 61 | 62 | [Int]$SubnetMask, 63 | 64 | [ValidateNotNullOrEmpty()] 65 | [String]$DefaultGateway, 66 | 67 | [ValidateSet("IPv4", "IPv6")] 68 | [String]$AddressFamily = "IPv4" 69 | ) 70 | 71 | 72 | ValidateProperties @PSBoundParameters -Apply 73 | } 74 | 75 | ###################################################################################### 76 | # The Test-TargetResource cmdlet. 77 | # This will test if the given IP Address is among the current node's IP Address collection 78 | ###################################################################################### 79 | function Test-TargetResource 80 | { 81 | param 82 | ( 83 | [Parameter(Mandatory)] 84 | [ValidateNotNullOrEmpty()] 85 | [String]$IPAddress, 86 | 87 | [Parameter(Mandatory)] 88 | [ValidateNotNullOrEmpty()] 89 | [String]$InterfaceAlias, 90 | 91 | [Int]$SubnetMask, 92 | 93 | [ValidateNotNullOrEmpty()] 94 | [String]$DefaultGateway, 95 | 96 | [ValidateSet("IPv4", "IPv6")] 97 | [String]$AddressFamily = "IPv4" 98 | ) 99 | 100 | ValidateProperties @PSBoundParameters 101 | } 102 | 103 | 104 | ####################################################################################### 105 | # Helper function that validates the IP Address properties. If the switch parameter 106 | # "Apply" is set, then it will set the properties after a test 107 | ####################################################################################### 108 | function ValidateProperties 109 | { 110 | param 111 | ( 112 | [Parameter(Mandatory)] 113 | [ValidateNotNullOrEmpty()] 114 | [String]$IPAddress, 115 | 116 | [Parameter(Mandatory)] 117 | [ValidateNotNullOrEmpty()] 118 | [String]$InterfaceAlias, 119 | 120 | [ValidateNotNullOrEmpty()] 121 | [String]$DefaultGateway, 122 | 123 | [Int]$SubnetMask = 16, 124 | 125 | [ValidateSet("IPv4", "IPv6")] 126 | [String]$AddressFamily = "IPv4", 127 | 128 | [Switch]$Apply 129 | ) 130 | $ip=$IPAddress 131 | if(!([System.Net.Ipaddress]::TryParse($ip, [ref]0))) 132 | { 133 | throw "IP Address *$IPAddress* is not in the correct format. Please correct the ipaddress in the configuration and try again" 134 | } 135 | try 136 | { 137 | Write-Verbose -Message "Checking the IPAddress ..." 138 | #Get the current IP Address based on the parameters given. 139 | $currentIP = Get-NetIPAddress -InterfaceAlias $InterfaceAlias -AddressFamily $AddressFamily -ErrorAction Stop 140 | 141 | #Test if the IP Address passed is equal to the current ip address 142 | if(!$currentIP.IPAddress.Contains($IPAddress)) 143 | { 144 | Write-Verbose -Message "IPAddress not correct. Expected $IPAddress, actual $($currentIP.IPAddress)" 145 | $Parameters = @{} 146 | 147 | #Apply is true in the case of set - target resource - in which case, it will set the new IP Address 148 | if($Apply) 149 | { 150 | Write-Verbose -Message "Setting IPAddress ..." 151 | $Parameters["IPAddress"] = $IPAddress 152 | $Parameters["PrefixLength"] = $SubnetMask 153 | $Parameters["InterfaceAlias"] = $currentIP[0].InterfaceAlias 154 | 155 | if($DefaultGateway){ $Parameters["DefaultGateWay"] = $DefaultGateway } 156 | $null = New-NetIPAddress @Parameters -ErrorAction Stop 157 | 158 | # Make the connection profile private 159 | Get-NetConnectionProfile -InterfaceAlias $InterfaceAlias | Set-NetConnectionProfile -NetworkCategory Private -ErrorAction SilentlyContinue 160 | Write-Verbose -Message "IPAddress is set to $IPAddress." 161 | } 162 | else {return $false} 163 | } 164 | else 165 | { 166 | Write-Verbose -Message "IPAddress is correct." 167 | return $true 168 | } 169 | } 170 | catch 171 | { 172 | Write-Verbose -Message $_ 173 | throw "Can not set or find valid IPAddress using InterfaceAlias $InterfaceAlias and AddressFamily $AddressFamily" 174 | } 175 | } 176 | 177 | 178 | 179 | # FUNCTIONS TO BE EXPORTED 180 | Export-ModuleMember -function Get-TargetResource, Set-TargetResource, Test-TargetResource -------------------------------------------------------------------------------- /Exercise5/PowerShellModules/xNetworking/DSCResources/MSFT_xIPAddress/MSFT_xIPAddress.schema.mof: -------------------------------------------------------------------------------- 1 | [ClassVersion("1.0.0"), FriendlyName("xIPAddress")] 2 | class MSFT_xIPAddress : OMI_BaseResource 3 | { 4 | [Key] string IPAddress; 5 | [Key] string InterfaceAlias; 6 | [write] string DefaultGateway; 7 | [Write] uint32 SubnetMask; 8 | [Write,ValueMap{"IPv4", "IPv6"},Values{"IPv4", "IPv6"}] string AddressFamily; 9 | }; 10 | -------------------------------------------------------------------------------- /Exercise5/PowerShellModules/xNetworking/Examples/Sample_xDnsServerAddress.ps1: -------------------------------------------------------------------------------- 1 | configuration Sample_xDnsServerAddress 2 | { 3 | param 4 | ( 5 | [string[]]$NodeName = 'localhost', 6 | 7 | [Parameter(Mandatory)] 8 | [string]$DnsServerAddress, 9 | 10 | [Parameter(Mandatory)] 11 | [string]$InterfaceAlias, 12 | 13 | [ValidateSet("IPv4","IPv6")] 14 | [string]$AddressFamily = 'IPv4' 15 | ) 16 | 17 | Import-DscResource -Module xNetworking 18 | 19 | Node $NodeName 20 | { 21 | xDnsServerAddress DnsServerAddress 22 | { 23 | Address = $DnsServerAddress 24 | InterfaceAlias = $InterfaceAlias 25 | AddressFamily = $AddressFamily 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /Exercise5/PowerShellModules/xNetworking/Examples/Sample_xFirewall_AddFirewallRule.ps1: -------------------------------------------------------------------------------- 1 | # DSC configuration for Firewall 2 | 3 | configuration Sample_xFirewall_AddFirewallRule 4 | { 5 | param 6 | ( 7 | [string[]]$NodeName = 'localhost' 8 | ) 9 | 10 | Import-DSCResource -ModuleName xNetworking 11 | 12 | Node $NodeName 13 | { 14 | xFirewall Firewall 15 | { 16 | Name = "NotePadFirewallRule" 17 | DisplayName = "Firewall Rule for Notepad.exe" 18 | DisplayGroup = "NotePad Firewall Rule Group" 19 | Ensure = "Present" 20 | Access = "Allow" 21 | State = "Enabled" 22 | Profile = ("Domain", "Private") 23 | Direction = "OutBound" 24 | RemotePort = ("8080", "8081") 25 | LocalPort = ("9080", "9081") 26 | Protocol = "TCP" 27 | Description = "Firewall Rule for Notepad.exe" 28 | ApplicationPath = "c:\windows\system32\notepad.exe" 29 | Service = "WinRM" 30 | } 31 | } 32 | } 33 | 34 | Sample_xFirewall_AddFirewallRule 35 | Start-DscConfiguration -Path Sample_xFirewall_AddFirewallRule -Wait -Verbose -Force -------------------------------------------------------------------------------- /Exercise5/PowerShellModules/xNetworking/Examples/Sample_xFirewall_AddFirewallRuleToExistingGroup.ps1: -------------------------------------------------------------------------------- 1 | # DSC configuration for Firewall 2 | # 3 | 4 | configuration Sample_xFirewall_AddFirewallRuleToExistingGroup 5 | { 6 | param 7 | ( 8 | [string[]]$NodeName = 'localhost' 9 | ) 10 | 11 | Import-DSCResource -ModuleName xNetworking 12 | 13 | Node $NodeName 14 | { 15 | xFirewall Firewall 16 | { 17 | Name = "MyFirewallRule" 18 | DisplayName = "My Firewall Rule" 19 | DisplayGroup = "My Firewall Rule Group" 20 | Access = "Allow" 21 | } 22 | 23 | xFirewall Firewall1 24 | { 25 | Name = "MyFirewallRule1" 26 | DisplayName = "My Firewall Rule" 27 | DisplayGroup = "My Firewall Rule Group" 28 | Ensure = "Present" 29 | Access = "Allow" 30 | State = "Enabled" 31 | Profile = ("Domain", "Private") 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /Exercise5/PowerShellModules/xNetworking/Examples/Sample_xFirewall_AddFirewallRuleToNewGroup.ps1: -------------------------------------------------------------------------------- 1 | # DSC configuration for Firewall 2 | 3 | configuration Sample_xFirewall_AddFirewallRuleToNewGroup 4 | { 5 | param 6 | ( 7 | [string[]]$NodeName = 'localhost' 8 | ) 9 | 10 | Import-DSCResource -ModuleName xNetworking 11 | 12 | Node $NodeName 13 | { 14 | xFirewall Firewall 15 | { 16 | Name = "MyAppFirewallRule" 17 | ApplicationPath = "c:\windows\system32\MyApp.exe" 18 | Access = "Allow" 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /Exercise5/PowerShellModules/xNetworking/Examples/Sample_xFirewall_DisableAccessToApplication.ps1: -------------------------------------------------------------------------------- 1 | # DSC configuration for Firewall 2 | # 3 | 4 | configuration Sample_xFirewall_AddFirewallRuleToNewGroup 5 | { 6 | param 7 | ( 8 | [string[]]$NodeName = 'localhost' 9 | ) 10 | 11 | Import-DSCResource -ModuleName xNetworking 12 | 13 | Node $NodeName 14 | { 15 | xFirewall Firewall 16 | { 17 | Name = "NotePadFirewallRule" 18 | DisplayName = "Firewall Rule for Notepad.exe" 19 | DisplayGroup = "NotePad Firewall Rule Group" 20 | Ensure = "Present" 21 | Access = "Block" 22 | Description = "Firewall Rule for Notepad.exe" 23 | ApplicationPath = "c:\windows\system32\notepad.exe" 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /Exercise5/PowerShellModules/xNetworking/Examples/Sample_xIPAddress_FixedValue.ps1: -------------------------------------------------------------------------------- 1 | configuration Sample_xIPAddress_FixedValue 2 | { 3 | param 4 | ( 5 | [string[]]$NodeName = 'localhost' 6 | ) 7 | 8 | Import-DscResource -Module xNetworking 9 | 10 | Node $NodeName 11 | { 12 | xIPAddress NewIPAddress 13 | { 14 | IPAddress = "2001:4898:200:7:6c71:a102:ebd8:f482" 15 | InterfaceAlias = "Ethernet" 16 | SubnetMask = 24 17 | AddressFamily = "IPV6" 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /Exercise5/PowerShellModules/xNetworking/Examples/Sample_xIPAddress_Parameterized.ps1: -------------------------------------------------------------------------------- 1 | configuration Sample_xIPAddress_Parameterized 2 | { 3 | param 4 | ( 5 | 6 | [string[]]$NodeName = 'localhost', 7 | 8 | [Parameter(Mandatory)] 9 | [string]$IPAddress, 10 | 11 | [Parameter(Mandatory)] 12 | [string]$InterfaceAlias, 13 | 14 | [Parameter(Mandatory)] 15 | [string]$DefaultGateway, 16 | 17 | [int]$SubnetMask = 16, 18 | 19 | [ValidateSet("IPv4","IPv6")] 20 | [string]$AddressFamily = 'IPv4' 21 | ) 22 | 23 | Import-DscResource -Module xNetworking 24 | 25 | Node $NodeName 26 | { 27 | xIPAddress NewIPAddress 28 | { 29 | IPAddress = $IPAddress 30 | InterfaceAlias = $InterfaceAlias 31 | DefaultGateway = $DefaultGateway 32 | SubnetMask = $SubnetMask 33 | AddressFamily = $AddressFamily 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /Exercise5/PowerShellModules/xNetworking/xNetworking.psd1: -------------------------------------------------------------------------------- 1 | @{ 2 | # Version number of this module. 3 | ModuleVersion = '2.1.1' 4 | 5 | # ID used to uniquely identify this module 6 | GUID = 'e6647cc3-ce9c-4c86-9eb8-2ee8919bf358' 7 | 8 | # Author of this module 9 | Author = 'Microsoft Corporation' 10 | 11 | # Company or vendor of this module 12 | CompanyName = 'Microsoft Corporation' 13 | 14 | # Copyright statement for this module 15 | Copyright = '(c) 2013 Microsoft Corporation. All rights reserved.' 16 | 17 | # Description of the functionality provided by this module 18 | Description = 'Module with DSC Resources for Networking area' 19 | 20 | # Minimum version of the Windows PowerShell engine required by this module 21 | PowerShellVersion = '4.0' 22 | 23 | # Minimum version of the common language runtime (CLR) required by this module 24 | CLRVersion = '4.0' 25 | 26 | # Functions to export from this module 27 | FunctionsToExport = '*' 28 | 29 | # Cmdlets to export from this module 30 | CmdletsToExport = '*' 31 | } -------------------------------------------------------------------------------- /Exercise5/PowerShellModules/xPendingReboot/DSCResources/MSFT_xPendingReboot/MSFT_xPendingReboot.psm1: -------------------------------------------------------------------------------- 1 | Function Get-TargetResource 2 | { 3 | [CmdletBinding()] 4 | param 5 | ( 6 | [Parameter(Mandatory=$true)] 7 | [string]$Name 8 | ) 9 | 10 | <## Remove: 11 | $ComponentBasedServicing = (Get-ItemProperty 'hklm:SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\').RebootPending -ne $null 12 | Remove - $WindowsUpdate = (Get-ItemProperty 'hklm:SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\').RebootRequired -ne $null 13 | Remove - $PendingFileRename = (Get-ItemProperty 'hklm:\SYSTEM\CurrentControlSet\Control\Session Manager\').PendingFileRenameOperations -ne $null 14 | #> 15 | 16 | ## Brian's additions:-------------------------------------------------- 17 | $ComponentBasedServicing = (Get-ChildItem 'hklm:SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\').Name.Split("\") -contains "RebootPending" 18 | $WindowsUpdate = (Get-ChildItem 'hklm:SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\').Name.Split("\") -contains "RebootRequired" 19 | $PendingFileRename = (Get-ItemProperty 'hklm:\SYSTEM\CurrentControlSet\Control\Session Manager\').PendingFileRenameOperations.Length -gt 0 20 | $ActiveComputerName = (Get-ItemProperty 'hklm:\SYSTEM\CurrentControlSet\Control\ComputerName\ActiveComputerName').ComputerName 21 | $PendingComputerName = (Get-ItemProperty 'hklm:\SYSTEM\CurrentControlSet\Control\ComputerName\ComputerName').ComputerName 22 | $PendingComputerRename = $ActiveComputerName -ne $PendingComputerName 23 | 24 | $CCMSplat = @{ 25 | NameSpace='ROOT\ccm\ClientSDK' 26 | Class='CCM_ClientUtilities' 27 | Name='DetermineIfRebootPending' 28 | ErrorAction='Stop' 29 | } 30 | 31 | Try { 32 | $CCMClientSDK = Invoke-WmiMethod @CCMSplat 33 | } Catch { 34 | Write-Warning "Unable to query CCM_ClientUtilities: $_" 35 | } 36 | 37 | $SCCMSDK = ($CCMClientSDK.ReturnValue -eq 0) -and ($CCMClientSDK.IsHardRebootPending -or $CCMClientSDK.RebootPending) 38 | ## End Brian's additions------------------------------------------------ 39 | 40 | return @{ 41 | Name = $Name 42 | ComponentBasedServicing = $ComponentBasedServicing 43 | WindowsUpdate = $WindowsUpdate 44 | PendingFileRename = $PendingFileRename 45 | PendingComputerRename = $PendingComputerRename 46 | CcmClientSDK = $SCCMSDK 47 | } 48 | } 49 | 50 | Function Set-TargetResource 51 | { 52 | [CmdletBinding()] 53 | param 54 | ( 55 | [Parameter(Mandatory=$true)] 56 | [string]$Name 57 | ) 58 | 59 | $global:DSCMachineStatus = 1 60 | } 61 | 62 | Function Test-TargetResource 63 | { 64 | [CmdletBinding()] 65 | param 66 | ( 67 | [Parameter(Mandatory=$true)] 68 | [string]$Name 69 | ) 70 | 71 | <## Remove 72 | $regRebootLocations += @{'HKLM:SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\'='RebootPending'} 73 | $regRebootLocations += @{'HKLM:SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\'='RebootRequired'} 74 | $regRebootLocations += @{'HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\'='PendingFileRenameOperations'} 75 | 76 | foreach ($reg in $regRebootLocations.keys) { 77 | if ((Get-ItemProperty $reg).($regRebootLocations[$reg]) -ne $Null) { 78 | Write-Verbose "A pending reboot was found at $reg." 79 | Write-Verbose 'Setting the DSCMachineStatus global variable to 1.' 80 | return $false} 81 | } 82 | #> 83 | 84 | ## Brian's additions:-------------------------------------------------- 85 | $ScriptBlocks += @{ComponentBasedServicing = {(Get-ChildItem 'hklm:SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\').Name.Split("\") -contains "RebootPending"}} 86 | $ScriptBlocks += @{WindowsUpdate = {(Get-ChildItem 'hklm:SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\').Name.Split("\") -contains "RebootRequired"}} 87 | $ScriptBlocks += @{PendingFileRename = {(Get-ItemProperty 'hklm:\SYSTEM\CurrentControlSet\Control\Session Manager\').PendingFileRenameOperations.Length -gt 0}} 88 | $ScriptBlocks += @{PendingComputerRename = { 89 | $ActiveComputerName = (Get-ItemProperty 'hklm:\SYSTEM\CurrentControlSet\Control\ComputerName\ActiveComputerName').ComputerName 90 | $PendingComputerName = (Get-ItemProperty 'hklm:\SYSTEM\CurrentControlSet\Control\ComputerName\ComputerName').ComputerName 91 | $ActiveComputerName -ne $PendingComputerName 92 | } 93 | } 94 | $ScriptBlocks += @{CcmClientSDK = { 95 | $CCMSplat = @{ 96 | NameSpace='ROOT\ccm\ClientSDK' 97 | Class='CCM_ClientUtilities' 98 | Name='DetermineIfRebootPending' 99 | ErrorAction='Stop' 100 | } 101 | Try { 102 | $CCMClientSDK = Invoke-WmiMethod @CCMSplat 103 | ($CCMClientSDK.ReturnValue -eq 0) -and ($CCMClientSDK.IsHardRebootPending -or $CCMClientSDK.RebootPending) 104 | } Catch { 105 | Write-Warning "Unable to query CCM_ClientUtilities: $_" 106 | } 107 | } 108 | } 109 | Foreach ($Script in $ScriptBlocks.Keys) { 110 | If (Invoke-Command $ScriptBlocks[$Script]) { 111 | Write-Verbose "A pending reboot was found for $Script." 112 | Write-Verbose 'Setting the DSCMachineStatus global variable to 1.' 113 | return $false 114 | } 115 | } 116 | ## End Brian's additions------------------------------------------------ 117 | 118 | Write-Verbose 'No pending reboots found.' 119 | return $true 120 | } 121 | 122 | Export-ModuleMember -Function *-TargetResource 123 | 124 | $regRebootLocations = $null -------------------------------------------------------------------------------- /Exercise5/PowerShellModules/xPendingReboot/DSCResources/MSFT_xPendingReboot/MSFT_xPendingReboot.schema.mof: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewabest/AWS-Workshop/071e4b7912e2704a366be0a6294d4d3d1da95a4d/Exercise5/PowerShellModules/xPendingReboot/DSCResources/MSFT_xPendingReboot/MSFT_xPendingReboot.schema.mof -------------------------------------------------------------------------------- /Exercise5/PowerShellModules/xPendingReboot/xPendingReboot.psd1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewabest/AWS-Workshop/071e4b7912e2704a366be0a6294d4d3d1da95a4d/Exercise5/PowerShellModules/xPendingReboot/xPendingReboot.psd1 -------------------------------------------------------------------------------- /Exercise5/PowerShellModules/xWebAdministration/DSCResources/MSFT_xIisModule/MSFT_xIisModule.psm1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewabest/AWS-Workshop/071e4b7912e2704a366be0a6294d4d3d1da95a4d/Exercise5/PowerShellModules/xWebAdministration/DSCResources/MSFT_xIisModule/MSFT_xIisModule.psm1 -------------------------------------------------------------------------------- /Exercise5/PowerShellModules/xWebAdministration/DSCResources/MSFT_xIisModule/MSFT_xIisModule.schema.mof: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewabest/AWS-Workshop/071e4b7912e2704a366be0a6294d4d3d1da95a4d/Exercise5/PowerShellModules/xWebAdministration/DSCResources/MSFT_xIisModule/MSFT_xIisModule.schema.mof -------------------------------------------------------------------------------- /Exercise5/PowerShellModules/xWebAdministration/DSCResources/MSFT_xIisModule/xIisModuleDesigner.ps1: -------------------------------------------------------------------------------- 1 | $diff = join-Path ${env:ProgramFiles(x86)} "Beyond compare 2\bc2.exe" 2 | $friendlyName = "xIisModule" 3 | $resourceName = "MSFT_$friendlyName" 4 | $classVersion = "1.0.0" 5 | 6 | $scriptRoot = Split-Path $MyInvocation.MyCommand.Path 7 | $originalModuleRoot = join-Path $scriptroot "..\.." 8 | $originalModuleRootPath = Resolve-Path $originalModuleRoot 9 | $moduleRoot = Join-Path $env:temp "$($originalModuleRootPath.path | split-path -Leaf)Temp" 10 | 11 | $resources = @() 12 | $schemaPath = (join-path $scriptRoot "$resourceName.schema.mof") 13 | 14 | #Key properties 15 | $resources += New-xDscResourceProperty -Name Path -Type String -Attribute Key -Description "The path to the module, usually a dll, to be added to IIS." 16 | 17 | 18 | #Required Properites 19 | $resources += New-xDscResourceProperty -Name Name -Type String -Attribute Required -Description "The logical name of the module to add to IIS." 20 | $resources += New-xDscResourceProperty -Name RequestPath -Type String -Attribute Required -Description "The allowed request Path example: *.php" 21 | $resources += New-xDscResourceProperty -Name Verb -Type String[] -Attribute Required -Description "The supported verbs for the module." 22 | 23 | #Write Properties 24 | $resources += New-xDscResourceProperty -Name SiteName -Type String -Attribute Write -Description "The IIS Site to register the module." 25 | $resources += New-xDscResourceProperty -Name Ensure -Type String -Attribute Write -Description "Should the module be present or absent." -ValidateSet @("Present","Absent") 26 | $resources += New-xDscResourceProperty -Name ModuleType -Type String -Attribute Write -Description "The type of the module." -ValidateSet @("FastCgiModule") 27 | 28 | #Read Properties 29 | $resources += New-xDscResourceProperty -Name EndPointSetup -Type Boolean -Attribute Read -Description "The End Point is setup. Such as a Fast Cgi endpoint." 30 | 31 | 32 | 33 | Write-Host updating... 34 | 35 | # Create a New template resource to a temporary folder 36 | New-xDscResource -Property $resources -ClassVersion $classVersion -Name $resourceName -Path $moduleRoot -FriendlyName $friendlyName 37 | 38 | 39 | # Use your favorite diff program to compare and merge the current resource and the existing resource 40 | 41 | if((test-Path $diff)) 42 | { 43 | &$diff $originalModuleRoot $moduleRoot 44 | } 45 | else 46 | { 47 | Write-Warning "Diff propgram not found!`r`nUse your favorite diff program to compare and merge:`r`n `t$($originalModuleRootPath.path)`r`n and:`r`n `t$moduleRoot" 48 | } 49 | 50 | -------------------------------------------------------------------------------- /Exercise5/PowerShellModules/xWebAdministration/DSCResources/MSFT_xWebAppPool/MSFT_xWebAppPool.psm1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewabest/AWS-Workshop/071e4b7912e2704a366be0a6294d4d3d1da95a4d/Exercise5/PowerShellModules/xWebAdministration/DSCResources/MSFT_xWebAppPool/MSFT_xWebAppPool.psm1 -------------------------------------------------------------------------------- /Exercise5/PowerShellModules/xWebAdministration/DSCResources/MSFT_xWebAppPool/MSFT_xWebAppPool.schema.mof: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewabest/AWS-Workshop/071e4b7912e2704a366be0a6294d4d3d1da95a4d/Exercise5/PowerShellModules/xWebAdministration/DSCResources/MSFT_xWebAppPool/MSFT_xWebAppPool.schema.mof -------------------------------------------------------------------------------- /Exercise5/PowerShellModules/xWebAdministration/DSCResources/MSFT_xWebApplication/MSFT_xWebApplication.psm1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewabest/AWS-Workshop/071e4b7912e2704a366be0a6294d4d3d1da95a4d/Exercise5/PowerShellModules/xWebAdministration/DSCResources/MSFT_xWebApplication/MSFT_xWebApplication.psm1 -------------------------------------------------------------------------------- /Exercise5/PowerShellModules/xWebAdministration/DSCResources/MSFT_xWebApplication/MSFT_xWebApplication.schema.mof: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewabest/AWS-Workshop/071e4b7912e2704a366be0a6294d4d3d1da95a4d/Exercise5/PowerShellModules/xWebAdministration/DSCResources/MSFT_xWebApplication/MSFT_xWebApplication.schema.mof -------------------------------------------------------------------------------- /Exercise5/PowerShellModules/xWebAdministration/DSCResources/MSFT_xWebConfigKeyValue/MSFT_xWebConfigKeyValue.psm1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewabest/AWS-Workshop/071e4b7912e2704a366be0a6294d4d3d1da95a4d/Exercise5/PowerShellModules/xWebAdministration/DSCResources/MSFT_xWebConfigKeyValue/MSFT_xWebConfigKeyValue.psm1 -------------------------------------------------------------------------------- /Exercise5/PowerShellModules/xWebAdministration/DSCResources/MSFT_xWebConfigKeyValue/MSFT_xWebConfigKeyValue.schema.mof: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewabest/AWS-Workshop/071e4b7912e2704a366be0a6294d4d3d1da95a4d/Exercise5/PowerShellModules/xWebAdministration/DSCResources/MSFT_xWebConfigKeyValue/MSFT_xWebConfigKeyValue.schema.mof -------------------------------------------------------------------------------- /Exercise5/PowerShellModules/xWebAdministration/DSCResources/MSFT_xWebVirtualDirectory/MSFT_xWebVirtualDirectory.psm1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewabest/AWS-Workshop/071e4b7912e2704a366be0a6294d4d3d1da95a4d/Exercise5/PowerShellModules/xWebAdministration/DSCResources/MSFT_xWebVirtualDirectory/MSFT_xWebVirtualDirectory.psm1 -------------------------------------------------------------------------------- /Exercise5/PowerShellModules/xWebAdministration/DSCResources/MSFT_xWebVirtualDirectory/MSFT_xWebVirtualDirectory.schema.mof: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewabest/AWS-Workshop/071e4b7912e2704a366be0a6294d4d3d1da95a4d/Exercise5/PowerShellModules/xWebAdministration/DSCResources/MSFT_xWebVirtualDirectory/MSFT_xWebVirtualDirectory.schema.mof -------------------------------------------------------------------------------- /Exercise5/PowerShellModules/xWebAdministration/DSCResources/MSFT_xWebsite/MSFT_xWebsite.schema.mof: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewabest/AWS-Workshop/071e4b7912e2704a366be0a6294d4d3d1da95a4d/Exercise5/PowerShellModules/xWebAdministration/DSCResources/MSFT_xWebsite/MSFT_xWebsite.schema.mof -------------------------------------------------------------------------------- /Exercise5/PowerShellModules/xWebAdministration/xWebAdministration.psd1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewabest/AWS-Workshop/071e4b7912e2704a366be0a6294d4d3d1da95a4d/Exercise5/PowerShellModules/xWebAdministration/xWebAdministration.psd1 -------------------------------------------------------------------------------- /Exercise5/Scripts/ConfigureWebserver.ps1: -------------------------------------------------------------------------------- 1 | # TODO: Dot-source our variables.ps1 2 | 3 | Configuration ConfigureWebserver 4 | { 5 | Import-DscResource -ModuleName cWinServer 6 | Import-DscResource -ModuleName xWebAdministration 7 | Import-DscResource -ModuleName xPendingReboot 8 | Import-DscResource -ModuleName xNetworking 9 | 10 | # Localhost targets the node this script is run on 11 | Node 'localhost' 12 | { 13 | LocalConfigurationManager 14 | { 15 | RebootNodeIfNeeded = $True 16 | } 17 | 18 | WinServerOptions ServerOptions 19 | { 20 | Ensure = "Present" 21 | Name = "Set timezone and culture" 22 | Culture = "en-AU" 23 | TimeZone = "AUS Eastern Standard Time" 24 | } 25 | 26 | xPendingReboot AfterServerOptions 27 | { 28 | Name = "AfterServerOptions" 29 | DependsOn = '[WinServerOptions]ServerOptions' 30 | } 31 | 32 | $windowsFeatures = @( 33 | "Web-App-Dev", 34 | "Web-Common-Http", 35 | "Web-Health", 36 | "Web-Performance", 37 | "Web-Security", 38 | "Web-Scripting-Tools", 39 | "Web-Mgmt-Service", 40 | "Web-Mgmt-Console" 41 | ) 42 | 43 | $windowsFeatureDependOn = @(); 44 | 45 | foreach ($windowsFeature in $windowsFeatures) 46 | { 47 | WindowsFeature "IIS_$windowsFeature" 48 | { 49 | Ensure = "Present" 50 | Name = $windowsFeature 51 | IncludeAllSubFeature = $true 52 | DependsOn = "[xPendingReboot]AfterServerOptions" 53 | } 54 | 55 | $windowsFeatureDependOn += "[WindowsFeature]IIS_$windowsFeature" 56 | } 57 | 58 | <# 59 | NOTE: For new players, if you want to discover whether a reboot will be required after a given piece of DSC, search for "$global:DSCMachineStatus = 1" in the resources you have used. 60 | #> 61 | 62 | xPendingReboot RebootAfterWindowsFeatures 63 | { 64 | Name = 'AfterWindowsFeatures' 65 | DependsOn = $windowsFeatureDependOn 66 | } 67 | 68 | # Stop & Remove the default website 69 | xWebsite DefaultSite 70 | { 71 | Ensure = "Absent" 72 | Name = "Default Web Site" 73 | State = "Stopped" 74 | PhysicalPath = "C:\inetpub\wwwroot" 75 | DependsOn = $windowsFeatureDependOn 76 | } 77 | 78 | # Remove all default Application Pools EXCEPT DEFAULT (will use this for the load balancer health check) 79 | foreach ($appPool in @("Classic .NET AppPool", ".NET v2.0", 80 | ".NET v2.0 Classic", ".NET v4.5", ".NET v4.5 Classic")) 81 | { 82 | xWebAppPool $appPool 83 | { 84 | Ensure = "Absent" 85 | Name = $appPool 86 | DependsOn = ($windowsFeatureDependOn + @("[xWebsite]DefaultSite")) 87 | } 88 | } 89 | 90 | File LoadBalancerHealthCheckEndpointContent 91 | { 92 | Ensure = "Present" 93 | DestinationPath = "C:\inetpub\wwwroot\index.html" 94 | Contents = "Hello, is it me you're looking for?" 95 | Type = "File" 96 | } 97 | 98 | xWebsite LoadBalancerHealthCheckEndpoint 99 | { 100 | Ensure = "Present" 101 | Name = "LoadBalancerHealthCheck" 102 | State = "Started" 103 | PhysicalPath = "C:\inetpub\wwwroot" 104 | BindingInfo = MSFT_xWebBindingInformation 105 | { 106 | Protocol = "HTTP" 107 | Port = 81 108 | } 109 | DependsOn = "[File]LoadBalancerHealthCheckEndpointContent" 110 | } 111 | 112 | xFirewall Firewall 113 | { 114 | Name = "Web" 115 | DisplayName = "Inbound access for web requests" 116 | Ensure = "Present" 117 | Access = "Allow" 118 | State = "Enabled" 119 | Profile = ("Domain", "Private", "Public") 120 | Direction = "InBound" 121 | RemotePort = ("Any") 122 | LocalPort = ("80", "81", "443") 123 | Protocol = "TCP" 124 | Description = "Inbound access for web requests" 125 | } 126 | 127 | # TODO: Add cTentacleAgent resource 128 | } 129 | } 130 | 131 | ConfigureWebserver 132 | 133 | Set-DscLocalConfigurationManager -Path .\ConfigureWebserver -Verbose 134 | Start-DscConfiguration -Path .\ConfigureWebserver -Verbose -Wait -Force 135 | -------------------------------------------------------------------------------- /Exercise5/Scripts/ConfigureWebserver.ps1.answer: -------------------------------------------------------------------------------- 1 | # We don't get executed from our own directory so we need to find out where our scripts have 2 | # been dropped and execute everything from there. 3 | $scriptPath = [System.IO.Path]::GetDirectoryName($PSScriptRoot) 4 | Write-Host "Executing scripts from $scriptPath" 5 | 6 | . $scriptPath\Scripts\Variables.ps1 7 | 8 | Configuration ConfigureWebserver 9 | { 10 | Import-DscResource -ModuleName cWinServer 11 | Import-DscResource -ModuleName cOctopus 12 | Import-DscResource -ModuleName xWebAdministration 13 | Import-DscResource -ModuleName xPendingReboot 14 | Import-DscResource -ModuleName xNetworking 15 | 16 | # Localhost targets the node this script is run on 17 | Node 'localhost' 18 | { 19 | LocalConfigurationManager 20 | { 21 | RebootNodeIfNeeded = $True 22 | } 23 | 24 | WinServerOptions ServerOptions 25 | { 26 | Ensure = "Present" 27 | Name = "Set timezone and culture" 28 | Culture = "en-AU" 29 | TimeZone = "AUS Eastern Standard Time" 30 | } 31 | 32 | xPendingReboot AfterServerOptions 33 | { 34 | Name = "AfterServerOptions" 35 | DependsOn = '[WinServerOptions]ServerOptions' 36 | } 37 | 38 | $windowsFeatures = @( 39 | "Web-App-Dev", 40 | "Web-Common-Http", 41 | "Web-Health", 42 | "Web-Performance", 43 | "Web-Security", 44 | "Web-Scripting-Tools", 45 | "Web-Mgmt-Service", 46 | "Web-Mgmt-Console" 47 | ) 48 | 49 | $windowsFeatureDependOn = @(); 50 | 51 | foreach ($windowsFeature in $windowsFeatures) 52 | { 53 | WindowsFeature "IIS_$windowsFeature" 54 | { 55 | Ensure = "Present" 56 | Name = $windowsFeature 57 | IncludeAllSubFeature = $true 58 | DependsOn = "[xPendingReboot]AfterServerOptions" 59 | } 60 | 61 | $windowsFeatureDependOn += "[WindowsFeature]IIS_$windowsFeature" 62 | } 63 | 64 | <# 65 | NOTE: For new players, if you want to discover whether a reboot will be required after a given piece of DSC, search for "$global:DSCMachineStatus = 1" in the resources you have used. 66 | #> 67 | 68 | xPendingReboot RebootAfterWindowsFeatures 69 | { 70 | Name = 'AfterWindowsFeatures' 71 | DependsOn = $windowsFeatureDependOn 72 | } 73 | 74 | # Stop & Remove the default website 75 | xWebsite DefaultSite 76 | { 77 | Ensure = "Absent" 78 | Name = "Default Web Site" 79 | State = "Stopped" 80 | PhysicalPath = "C:\inetpub\wwwroot" 81 | DependsOn = $windowsFeatureDependOn 82 | } 83 | 84 | # Remove all default Application Pools EXCEPT DEFAULT (will use this for the load balancer health check) 85 | foreach ($appPool in @("Classic .NET AppPool", ".NET v2.0", 86 | ".NET v2.0 Classic", ".NET v4.5", ".NET v4.5 Classic")) 87 | { 88 | xWebAppPool $appPool 89 | { 90 | Ensure = "Absent" 91 | Name = $appPool 92 | DependsOn = ($windowsFeatureDependOn + @("[xWebsite]DefaultSite")) 93 | } 94 | } 95 | 96 | File LoadBalancerHealthCheckEndpointContent 97 | { 98 | Ensure = "Present" 99 | DestinationPath = "C:\inetpub\wwwroot\index.html" 100 | Contents = "Hello, is it me you're looking for?" 101 | Type = "File" 102 | } 103 | 104 | xWebsite LoadBalancerHealthCheckEndpoint 105 | { 106 | Ensure = "Present" 107 | Name = "LoadBalancerHealthCheck" 108 | State = "Started" 109 | PhysicalPath = "C:\inetpub\wwwroot" 110 | BindingInfo = MSFT_xWebBindingInformation 111 | { 112 | Protocol = "HTTP" 113 | Port = 81 114 | } 115 | DependsOn = "[File]LoadBalancerHealthCheckEndpointContent" 116 | } 117 | 118 | xFirewall Firewall 119 | { 120 | Name = "Web" 121 | DisplayName = "Inbound access for web requests" 122 | Ensure = "Present" 123 | Access = "Allow" 124 | State = "Enabled" 125 | Profile = ("Domain", "Private", "Public") 126 | Direction = "InBound" 127 | RemotePort = ("Any") 128 | LocalPort = ("80", "81", "443") 129 | Protocol = "TCP" 130 | Description = "Inbound access for web requests" 131 | } 132 | 133 | cTentacleAgent OctopusTentacle 134 | { 135 | Ensure = "Present" 136 | State = "Started" 137 | Name = "Tentacle" 138 | 139 | # Registration - all parameters required 140 | ApiKey = $BootstrapParameters['OctopusApiKey'] 141 | OctopusServerUrl = $BootstrapParameters['OctopusServerUrl'] 142 | Environments = $BootstrapParameters['Environment'] 143 | Roles = $BootstrapParameters['OctopusRole'] 144 | 145 | # Optional settings 146 | ListenPort = 10933; 147 | DefaultApplicationDirectory = "C:\Octopus\Applications" 148 | DependsOn = "[xWebsite]LoadBalancerHealthCheckEndpoint" 149 | } 150 | } 151 | } 152 | 153 | ConfigureWebserver 154 | 155 | Set-DscLocalConfigurationManager -Path .\ConfigureWebserver -Verbose 156 | Start-DscConfiguration -Path .\ConfigureWebserver -Verbose -Wait -Force 157 | -------------------------------------------------------------------------------- /Exercise5/Scripts/Teardown.ps1: -------------------------------------------------------------------------------- 1 |  -------------------------------------------------------------------------------- /Exercise5/Templates/Zephyr.template: -------------------------------------------------------------------------------- 1 | { 2 | "AWSTemplateFormatVersion": "2010-09-09", 3 | 4 | "Description": "A template to deploy a simple fault tolerant load balanced web hosting infrastructure.", 5 | 6 | "Parameters": { 7 | "S3BucketName": { 8 | "Description": "The S3 Bucket Name used in URL's to specify authentication against.", 9 | "Type": "String" 10 | }, 11 | "VpcId": { 12 | "Description": "The Vpc to deploy the infrastructure into.", 13 | "Type": "String" 14 | }, 15 | "PowerShellModulesBundleUrl": { 16 | "Description": "The URL to a ZIP file containing any PowerShell modules required by this CloudFormation template.", 17 | "Type": "String" 18 | }, 19 | "BootstrapperScriptBundleUrl": { 20 | "Description": "The URL to a ZIP file containing the PowerShell script package to bootstrap EC2 instances in this CloudFormation template.", 21 | "Type": "String" 22 | }, 23 | "WebserverTemplateUrl": { 24 | "Description": "The URL to the CloudFormation stack template for web servers.", 25 | "Type": "String" 26 | }, 27 | "Timestamp": { 28 | "Description": "When this CloudFormation stack was last updated.", 29 | "Type": "String" 30 | }, 31 | "Version": { 32 | "Description": "The package version that contains this CloudFormation template.", 33 | "Type": "String" 34 | }, 35 | "Environment": { 36 | "Type": "String", 37 | "Default": "Development" 38 | }, 39 | "KeyPairName": { 40 | "Description": "The EC2 key pair used to launch web instances", 41 | "Type": "AWS::EC2::KeyPair::KeyName" 42 | }, 43 | "WebserverImageId": { 44 | "Description": "The EC2 AmiId to use for web", 45 | "Type": "String", 46 | "Default": "ami-f9760dc3" 47 | }, 48 | "WebserverInstanceType": { 49 | "Description": "The EC2 instance type to use for web", 50 | "Type": "String", 51 | "Default": "t2.small" 52 | }, 53 | "WebserverSubnetIdAzOne": { 54 | "Description": "The PUBLIC subnet belonging to availability zone one into which the instance will be launched", 55 | "Type": "String" 56 | }, 57 | "WebserverSubnetIdAzTwo": { 58 | "Description": "The PUBLIC subnet belonging to availability zone two into which the instance will be launched", 59 | "Type": "String" 60 | }, 61 | "LoadBalancerSubnetIdAzOne": { 62 | "Description": "The PUBLIC IG-connected subnet belonging to availability zone one that the load balancer will belong to", 63 | "Type": "String" 64 | }, 65 | "LoadBalancerSubnetIdAzTwo": { 66 | "Description": "The PUBLIC IG-connected subnet belonging to availability zone two that the load balancer will belong to", 67 | "Type": "String" 68 | }, 69 | "ResourcePrefix" : { 70 | "Description": "Used to prefix a unique name to resources where applicable", 71 | "Type": "String" 72 | } 73 | }, 74 | 75 | "Resources": { 76 | "BootstrapRole": { 77 | "Type": "AWS::IAM::Role", 78 | "Properties": { 79 | "AssumeRolePolicyDocument": { 80 | "Version": "2012-10-17", 81 | "Statement": [ 82 | { 83 | "Effect": "Allow", 84 | "Principal": { 85 | "Service": [ "ec2.amazonaws.com" ] 86 | }, 87 | "Action": [ "sts:AssumeRole" ] 88 | } 89 | ] 90 | }, 91 | "Path": "/" 92 | } 93 | }, 94 | "BootstrapRolePolicies": { 95 | "Type": "AWS::IAM::Policy", 96 | "Properties": { 97 | "PolicyName": "bootstrap", 98 | "PolicyDocument": { 99 | "Version": "2012-10-17", 100 | "Statement": [ 101 | { 102 | "Effect": "Allow", 103 | "Action": "s3:*", 104 | "Resource": [ 105 | { "Fn::Join": [ "", [ "arn:aws:s3:::", { "Ref": "S3BucketName" } ] ] }, 106 | { "Fn::Join": [ "", [ "arn:aws:s3:::", { "Ref": "S3BucketName" }, "/*" ] ] } 107 | ] 108 | } 109 | ] 110 | }, 111 | "Roles": [ 112 | { 113 | "Ref": "BootstrapRole" 114 | } 115 | ] 116 | } 117 | }, 118 | "BootstrapInstanceProfile": { 119 | "Type": "AWS::IAM::InstanceProfile", 120 | "Properties": { 121 | "Path": "/", 122 | "Roles": [ 123 | { 124 | "Ref": "BootstrapRole" 125 | } 126 | ] 127 | } 128 | }, 129 | "WebStack": { 130 | "Type": "AWS::CloudFormation::Stack", 131 | "Properties": { 132 | "Parameters": { 133 | "S3BucketName": { "Ref": "S3BucketName" }, 134 | "VpcId": { "Ref": "VpcId" }, 135 | "PowerShellModulesBundleUrl": { "Ref": "PowerShellModulesBundleUrl" }, 136 | "BootstrapperScriptBundleUrl": { "Ref": "BootstrapperScriptBundleUrl" }, 137 | "Timestamp": { "Ref": "Timestamp" }, 138 | "Version": { "Ref": "Version" }, 139 | "Environment": { "Ref": "Environment" }, 140 | "InstanceProfile": { "Ref": "BootstrapInstanceProfile" }, 141 | "BootstrapperRole": { "Ref": "BootstrapRole" }, 142 | "KeyPairName": { "Ref": "KeyPairName" }, 143 | "WebserverImageId": { "Ref": "WebserverImageId" }, 144 | "WebserverInstanceType": { "Ref": "WebserverInstanceType" }, 145 | "WebserverSubnetIdAzOne": { "Ref": "WebserverSubnetIdAzOne" }, 146 | "WebserverSubnetIdAzTwo": { "Ref": "WebserverSubnetIdAzTwo" }, 147 | "LoadBalancerSubnetIdAzOne": { "Ref": "LoadBalancerSubnetIdAzOne" }, 148 | "LoadBalancerSubnetIdAzTwo": { "Ref": "LoadBalancerSubnetIdAzTwo" }, 149 | "ResourcePrefix": { "Ref": "ResourcePrefix" } 150 | }, 151 | "TemplateURL": { "Ref": "WebserverTemplateUrl" }, 152 | "TimeoutInMinutes": 10 153 | } 154 | } 155 | }, 156 | 157 | "Outputs": { 158 | "LoadBalancerUri": { 159 | "Value": { "Fn::GetAtt": [ "WebStack", "Outputs.LoadBalancerUri" ] } 160 | } 161 | } 162 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AWS-Workshop 2 | Workshop content for automated delivery in AWS for .NET 3 | 4 | ## Prerequisites 5 | 6 | You will need to have installed [The AWS.NET SDK](https://aws.amazon.com/sdk-for-net/). You could optionally install The [AWS VS Tooling](http://aws.amazon.com/visualstudio/) instead which includes the SDK, and also gives you intellisense for CloudFormation templates. 7 | 8 | The samples within assume you are using the [AWS SDK Credential Store](http://docs.aws.amazon.com/powershell/latest/userguide/specifying-your-aws-credentials.html). You will need to store an appropriate set of credentials under the "AWSWorkshop" profile to execute the samples. *ResetCredentials.bat* will help accomplish this. 9 | 10 | ## Itinerary 11 | 12 | * Working securely in AWS 13 | * [AWS a-b-c's](https://speakerdeck.com/andrewabest/aws-a-b-cs) 14 | * [Exercise One - DIY](https://github.com/andrewabest/AWS-Workshop/blob/master/Exercise1.md) 15 | * CloudFormation Introduction ([supplementary information](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-whatis-howdoesitwork.html)) 16 | * [Exercise Two - CloudFormation](https://github.com/andrewabest/AWS-Workshop/blob/master/Exercise2.md) 17 | * Question Time 18 | * [DSC a-b-c's](https://speakerdeck.com/andrewabest/dsc-a-b-cs) 19 | * [Exercise Three - DSC DIY](https://github.com/andrewabest/AWS-Workshop/blob/master/Exercise3.md) 20 | * Question Time 21 | * [Exercise Four - CloudFormation + DSC](https://github.com/andrewabest/AWS-Workshop/blob/master/Exercise4.md) 22 | * [Exercise Five - CloudFormation + DSC + Octopus (Form like Voltron)](https://github.com/andrewabest/AWS-Workshop/blob/master/Exercise5.md) 23 | * Discussion time - Automating infrastructure 24 | 25 | ### Disclaimer 26 | 27 | What is presented here is 101 level infrastructure automation, and is not intended as a production solution. Most production rollouts in AWS will involve a significantly more complex setup to enforce appropriate security and scalability - for a reference architecture, see [Amazon's examples](http://docs.aws.amazon.com/AmazonVPC/latest/UserGuide/VPC_Scenario3.html). 28 | -------------------------------------------------------------------------------- /ResetCredentials.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | IF '%~1' == '' ECHO "Missing 'AccessKey' arg" 4 | IF '%~1' == '' GOTO ERROR 5 | 6 | IF '%~2' == '' ECHO "Missing 'SecretKey' arg" 7 | IF '%~2' == '' GOTO ERROR 8 | 9 | powershell.exe -ExecutionPolicy Bypass -Command "Set-AWSCredentials -AccessKey %~1 -SecretKey %~2 -StoreAs AWSWorkshop" 10 | 11 | exit /b 0 12 | 13 | goto end 14 | 15 | :error 16 | 17 | echo !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 18 | echo !!! Stopping due to error !!! 19 | echo !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 20 | 21 | exit /b 1 22 | 23 | goto end 24 | 25 | :end 26 | exit /b --------------------------------------------------------------------------------