├── .gitignore
├── Advanced-HttpsPull.ps1
├── CompanyConfig.ps1
├── ConfigLocalGroup.ps1
├── DSClogs.ps1
├── Demo-Composite.ps1
├── DemoList.ps1
├── FeaturesConfiguration.ps1
├── Memberconfig.ps1
├── PullClientLCM.ps1
├── PushMoftoPull.ps1
├── README.md
├── ResetDSC.ps1
├── SamplePullConfig.ps1
├── ServiceConfiguration.ps1
├── companyConfig
├── DSCResources
│ └── company
│ │ ├── company.psd1
│ │ └── company.schema.psm1
└── companyConfig.psd1
├── demo-named.ps1
└── demo-partial.ps1
/.gitignore:
--------------------------------------------------------------------------------
1 | scratch*
2 | dev*
3 | ~*
4 | *.bak
5 | SRV*
6 | CMSPassword.txt
7 | *(from*
--------------------------------------------------------------------------------
/Advanced-HttpsPull.ps1:
--------------------------------------------------------------------------------
1 |
2 | #region define the configuration
3 |
4 | Configuration HTTPSPullserver {
5 | # Import the module that defines custom resources
6 | Import-DscResource -Module PSDesiredStateConfiguration,
7 | @{ModuleName='xPSDesiredStateConfiguration';RequiredVersion='5.0.0.0'}
8 |
9 | # Dynamically find the applicable nodes from configuration data
10 | Node $AllNodes.where{$_.Role -eq 'Web'}.NodeName {
11 |
12 | <#
13 | Install the IIS role - you might want to install the features
14 | manually to control Security
15 | #>
16 |
17 | # WindowsFeature IIS {
18 | #
19 | # Ensure = "Present"
20 | # Name = "Web-Server"
21 | # }
22 |
23 | # # Make sure the following defaults cannot be removed:
24 |
25 | WindowsFeature DefaultDoc {
26 |
27 | Ensure = "Present"
28 | Name = "Web-Default-Doc"
29 |
30 | }
31 |
32 | WindowsFeature HTTPErrors {
33 |
34 | Ensure = "Present"
35 | Name = "Web-HTTP-Errors"
36 |
37 | }
38 |
39 | WindowsFeature HTTPLogging {
40 |
41 | Ensure = "Present"
42 | Name = "Web-HTTP-Logging"
43 |
44 | }
45 |
46 | WindowsFeature StaticContent {
47 |
48 | Ensure = "Present"
49 | Name = "Web-Static-Content"
50 |
51 | }
52 |
53 | WindowsFeature RequestFiltering {
54 |
55 | Ensure = "Present"
56 | Name = "Web-Filtering"
57 |
58 | }
59 |
60 | # # Install additional IIS components to support the Web Application
61 |
62 | WindowsFeature NetExtens4 {
63 |
64 | Ensure = "Present"
65 | Name = "Web-Net-Ext45"
66 |
67 | }
68 |
69 | WindowsFeature AspNet45 {
70 |
71 | Ensure = "Present"
72 | Name = "Web-Asp-Net45"
73 |
74 | }
75 |
76 | WindowsFeature ISAPIExt {
77 |
78 | Ensure = "Present"
79 | Name = "Web-ISAPI-Ext"
80 |
81 | }
82 |
83 | WindowsFeature ISAPIFilter {
84 |
85 | Ensure = "Present"
86 | Name = "Web-ISAPI-filter"
87 |
88 | }
89 |
90 |
91 | WindowsFeature DirectoryBrowsing {
92 |
93 | Ensure = "Present"
94 | Name = "Web-Dir-Browsing"
95 |
96 | }
97 |
98 |
99 | WindowsFeature StaticCompression {
100 |
101 | Ensure = "Present"
102 | Name = "Web-Stat-Compression"
103 |
104 | }
105 |
106 | # I don't want these Additional settings for Web-Server to ever be enabled:
107 | # This list is shortened for demo purposes. I include eveything that should not be installed
108 |
109 | WindowsFeature ASP {
110 |
111 | Ensure = "Absent"
112 | Name = "Web-ASP"
113 |
114 | }
115 |
116 | WindowsFeature CGI {
117 |
118 | Ensure = "Absent"
119 | Name = "Web-CGI"
120 |
121 | }
122 |
123 | WindowsFeature IPDomainRestrictions {
124 |
125 | Ensure = "Absent"
126 | Name = "Web-IP-Security"
127 |
128 | }
129 |
130 | # !!!!! # GUI Remote Management of IIS requires the following: - people always forget this until too late
131 |
132 | WindowsFeature Management {
133 |
134 | Name = 'Web-Mgmt-Service'
135 | Ensure = 'Present'
136 | }
137 |
138 | Registry RemoteManagement { # Can set other custom settings inside this reg key
139 |
140 | Key = 'HKLM:\SOFTWARE\Microsoft\WebManagement\Server'
141 | ValueName = 'EnableRemoteManagement'
142 | ValueType = 'Dword'
143 | ValueData = '1'
144 | DependsOn = @('[WindowsFeature]Management')
145 | }
146 |
147 | Service StartWMSVC {
148 |
149 | Name = 'WMSVC'
150 | StartupType = 'Automatic'
151 | State = 'Running'
152 | DependsOn = '[Registry]RemoteManagement'
153 |
154 | }
155 |
156 | } #End Node Role Web
157 |
158 | ###############################################################################
159 |
160 | Node $AllNodes.where{$_.Role -eq 'PullServer'}.NodeName {
161 |
162 | # # This installs both, WebServer and the DSC Service for a pull server
163 | # # You could do everything manually
164 |
165 | WindowsFeature DSCServiceFeature {
166 |
167 | Ensure = "Present"
168 | Name = "DSC-Service"
169 | }
170 |
171 | xDscWebService PSDSCPullServer {
172 |
173 | Ensure = "Present"
174 | EndpointName = $Node.PullServerEndPointName
175 | Port = $Node.PullServerPort # <----------------------- Why this port?
176 | PhysicalPath = $Node.PullserverPhysicalPath
177 | CertificateThumbPrint = $Node.PullServerThumbprint # <---- Certificate Thumbprint
178 | ModulePath = $Node.PullServerModulePath
179 | ConfigurationPath = $Node.PullserverConfigurationPath
180 | State = "Started"
181 | UseSecurityBestPractices = $True
182 | DependsOn = "[WindowsFeature]DSCServiceFeature"
183 | }
184 |
185 |
186 | } # End Node PullServer
187 |
188 | } # End Config
189 |
190 | #endregion
191 |
192 | #region create configuration data
193 | $Thumbprint = Invoke-Command -Computername SRV2 -scriptblock {
194 | Get-Childitem Cert:\LocalMachine\My |
195 | Where-Object {$_.Subject -match "^CN=DSC"} |
196 | Select-Object -ExpandProperty ThumbPrint
197 | }
198 |
199 | $ConfigData=@{
200 | # Node specific data
201 | AllNodes = @(
202 |
203 | # All Servers need following identical information
204 | @{
205 | NodeName = '*'
206 | # PSDscAllowPlainTextPassword = $true;
207 | # PSDscAllowDomainUser = $true
208 |
209 | },
210 |
211 | # Unique Data for each Role
212 | @{
213 | NodeName = 'srv2.company.pri'
214 | Role = @('Web', 'PullServer')
215 |
216 | PullServerEndPointName = 'PSDSCPullServer'
217 | PullserverPort = 8080 #< - ask me why I use this port
218 | PullserverPhysicalPath = "$env:SystemDrive\inetpub\wwwroot\PSDSCPullServer"
219 | PullserverModulePath = "$env:PROGRAMFILES\WindowsPowerShell\DscService\Modules"
220 | PullServerConfigurationPath = "$env:PROGRAMFILES\WindowsPowerShell\DscService\Configuration"
221 | PullServerThumbPrint = $thumbprint
222 |
223 | }
224 |
225 |
226 | );
227 | }
228 |
229 | #endregion
230 |
231 | #region create the config
232 |
233 | HTTPSPullserver -ConfigurationData $ConfigData -OutputPath c:\DSC\Pull
234 |
235 | #endregion
236 |
237 | #region deploy
238 | #make sure resources are deployed to the server
239 |
240 | invoke-command { get-module xpsdesiredstate* -list } -comp srv2
241 |
242 | Start-DscConfiguration -Wait -Verbose -Path c:\dsc\pull
243 |
244 | #endregion
--------------------------------------------------------------------------------
/CompanyConfig.ps1:
--------------------------------------------------------------------------------
1 | #requires -version 5.0
2 |
3 | #configuration that will become a composite resource
4 |
5 | Configuration Company {
6 |
7 | Param(
8 | [ValidateNotNullorEmpty()]
9 | [string]$InterfaceAlias = 'Ethernet',
10 | [Parameter(Mandatory)]
11 | [ValidateNotNullorEmpty()]
12 | [string]$DomainName
13 | )
14 |
15 |
16 | Import-DscResource -ModuleName PSDesiredStateConfiguration,
17 | @{ModuleName = 'xSMBShare';RequiredVersion='2.0.0.0'},
18 | @{ModuleName = 'xWinEventLog';RequiredVersion = '1.1.0.0'},
19 | @{ModuleName = 'xTimeZone';RequiredVersion = '1.6.0.0'},
20 | @{ModuleName = 'xNetworking';RequiredVersion = '5.2.0.0'}
21 |
22 | #NO NODE <---------- Look Mom!
23 |
24 | File Work {
25 | DestinationPath = 'C:\Work'
26 | Type = 'Directory'
27 | Ensure = 'Present'
28 | }
29 |
30 | Service RemoteReg {
31 | Name = 'RemoteRegistry'
32 | State = 'Running'
33 | StartupType = 'Automatic'
34 | Ensure = 'Present'
35 | }
36 |
37 | WindowsFeature Backup {
38 | Name = 'Windows-Server-Backup'
39 | Ensure = 'Present'
40 | IncludeAllSubFeature = $True
41 | }
42 |
43 | xSMBShare WorkShare {
44 | DependsOn = '[File]Work'
45 | Name = 'Work$'
46 | Path = 'C:\work'
47 | FullAccess = "$DomainName\Domain Admins"
48 | FolderEnumerationMode = 'AccessBased'
49 | Ensure = 'Present'
50 | }
51 |
52 | xTimeZone TZ {
53 | IsSingleInstance = 'Yes'
54 | TimeZone = "Central Standard Time"
55 | }
56 |
57 | xWinEventLog Security {
58 | LogName = 'Security'
59 | MaximumSizeInBytes = 256MB
60 | IsEnabled = $True
61 | LogMode = 'AutoBackup'
62 |
63 | }
64 |
65 | xFirewall vmpingFWRule {
66 | Name = 'vm-monitoring-icmpv4'
67 | Action = 'Allow'
68 | Direction = 'Inbound'
69 | Enabled = $True
70 | Ensure = 'Present'
71 | InterfaceAlias = $InterfaceAlias
72 | }
73 |
74 | xFirewall SMB {
75 | Name = 'FPS-SMB-In-TCP'
76 | Action = 'Allow'
77 | Direction = 'Inbound'
78 | Enabled = $True
79 | Ensure = 'Present'
80 | InterfaceAlias = $InterfaceAlias
81 | }
82 |
83 | xFirewall RemoteEvtLogFWRule1 {
84 | Name = "RemoteEventLogSvc-In-TCP"
85 | Action = "Allow"
86 | Direction = 'Inbound'
87 | Enabled = $True
88 | Ensure = 'Present'
89 | InterfaceAlias = $InterfaceAlias
90 | }
91 |
92 | xFirewall RemoteEvtLogFWRule2 {
93 | Name = "RemoteEventLogSvc-NP-In-TCP"
94 | Action = "Allow"
95 | Direction = 'Inbound'
96 | Enabled = $True
97 | Ensure = 'Present'
98 | InterfaceAlias = $InterfaceAlias
99 | }
100 |
101 | xFirewall RemoteEvtLogFWRule3 {
102 | Name = "RemoteEventLogSvc-RPCSS-In-TCP"
103 | Action = "Allow"
104 | Direction = 'Inbound'
105 | Enabled = $True
106 | Ensure = 'Present'
107 | InterfaceAlias = $InterfaceAlias
108 | }
109 |
110 |
111 | #Enable DSC Analytic logs
112 |
113 | Script DSCAnalyticLog {
114 |
115 | DependsOn = '[xFirewall]RemoteEvtLogFWRule3'
116 | TestScript = {
117 | $status = wevtutil get-log "Microsoft-Windows-Dsc/Analytic"
118 | if ($status -contains "enabled: true") {return $True} else {return $False}
119 | }
120 | SetScript = {
121 | wevtutil.exe set-log "Microsoft-Windows-Dsc/Analytic" /q:true /e:true
122 | }
123 | getScript = {
124 | $Result = wevtutil get-log "Microsoft-Windows-Dsc/Analytic"
125 | return @{Result = $Result}
126 | }
127 | }
128 |
129 |
130 | } #end configuration
--------------------------------------------------------------------------------
/ConfigLocalGroup.ps1:
--------------------------------------------------------------------------------
1 | #requires -version 5.0
2 |
3 | #create a new local
4 |
5 | configuration LocalGroup {
6 |
7 | Param()
8 |
9 | Import-DscResource -ModuleName PSDesiredStateConfiguration
10 |
11 | Node $Allnodes.NodeName {
12 |
13 | Group Localadmin {
14 | GroupName = "Administrators"
15 | Ensure = 'Present'
16 | MembersToInclude = @("company\aprils","company\help desk")
17 | psdscrunasCredential = $node.credential
18 | }
19 |
20 | LocalConfigurationManager {
21 | ActionAfterReboot = 'ContinueConfiguration'
22 | RebootNodeIfNeeded = $True
23 | ConfigurationMode = 'ApplyAndMonitor'
24 | CertificateID = $node.thumbprint #<--- LCM need to know what certificate to use
25 | RefreshMode = 'Push'
26 | }
27 |
28 | } #node
29 |
30 | }
31 |
32 | #run this script to define the configuration
--------------------------------------------------------------------------------
/DSClogs.ps1:
--------------------------------------------------------------------------------
1 | Show-EventLog -ComputerName SRV3
2 |
3 | #region Using Eventlogs
4 |
5 | Get-WinEvent -ListLog *dsc*,*desired* -ComputerName SRV3 |
6 | Format-List
7 |
8 | $paramHash = @{
9 | LogName = "Microsoft-Windows-DSC/Operational"
10 | ComputerName = "SRV3"
11 | MaxEvents = 25
12 | }
13 |
14 | Get-WinEvent @paramHash | Out-GridView
15 |
16 | #add filtering
17 | #construct a hash table for the -FilterHashTable parameter in Get-WinEvent
18 | $start = (Get-Date).AddDays(-1)
19 | $filter= @{
20 | Logname= "Microsoft-Windows-DSC/Operational"
21 | Level=2,3
22 | StartTime= $start
23 | }
24 |
25 | #get all errors and warnings in the last 14 days
26 | Get-WinEvent -FilterHashtable $filter -Computer SRV3 |
27 | Out-GridView -Title "DSC Events"
28 |
29 | #or use XML
30 | #errors and warnings in the last 7 days
31 | $xml=@"
32 |
33 |
34 |
38 |
39 |
40 | "@
41 |
42 | Get-WinEvent -FilterXml $xml -ComputerName SRV1 |
43 | Out-GridView
44 |
45 | #Tip: use EventViewer to build XML
46 |
47 | #enable Analytic and Debug logs
48 | #must be run locally on the server
49 | invoke-command {
50 | Wevtutil.exe set-log "Microsoft-Windows-Dsc/Analytic" /q:true /e:true
51 | Wevtutil.exe set-log "Microsoft-Windows-Dsc/Debug" /q:true /e:true
52 | } -computername SRV3
53 |
54 | <# disable
55 |
56 | invoke-command {
57 | Wevtutil.exe set-log "Microsoft-Windows-Dsc/Analytic" /q:true /e:false
58 | Wevtutil.exe set-log "Microsoft-Windows-Dsc/Debug" /q:true /e:false
59 | } -computername SRV3
60 |
61 | #>
62 |
63 | Get-WinEvent -ListLog "Microsoft-Windows-dsc/Analytic" -ComputerName SRV3
64 |
65 | #but this is a special type of log
66 | Get-WinEvent "Microsoft-Windows-dsc/Analytic" -ComputerName SRV3 -MaxEvents 25 | Out-GridView
67 |
68 | #nothing new will show up until after the log is enabled
69 | Update-DscConfiguration -ComputerName srv3 -Wait -Verbose
70 | Test-DscConfiguration -ComputerName srv3
71 |
72 | Get-WinEvent "Microsoft-Windows-dsc/Analytic" -ComputerName SRV3 -MaxEvents 25 -Oldest |
73 | Out-GridView
74 |
75 | #events grouped by job
76 | Get-DscConfiguration -CimSession SRV3
77 |
78 | $DscEvents = Get-WinEvent "Microsoft-windows-dsc/operational" -ComputerName SRV3
79 | $DscEvents += Get-WinEvent "Microsoft-Windows-Dsc/Analytic","Microsoft-Windows-Dsc/Debug" -Oldest -ComputerName SRV3
80 | $DscEvents.count
81 |
82 | #job ID
83 | $DscEvents[0].Properties[0].value
84 | #group by job Id
85 | $DSCGrouped = $DscEvents | group {$_.Properties[0].value} | sort name
86 |
87 | $DSCGrouped
88 |
89 | #sample data
90 | ($DSCGrouped[0..10]) |
91 | Format-Table -GroupBy Name -Property @{Name="Time";
92 | Expression={$_.Group.timecreated}},
93 | @{Name="Message";Expression={$_.Group.Message}},
94 | @{Name="Log";Expression={$_.group.containerLog}} -Wrap
95 |
96 | #get today's events from all logs
97 | $DscEvents.where({$_.timecreated -ge (Get-Date).Date}) |
98 | sort TimeCreated |
99 | Select TimeCreated,Message |
100 | Out-GridView
101 |
102 | #find non Information events
103 | $DscEvents.where({$_.leveldisplayname -ne 'Information'})
104 |
105 | #create a grouped hashtable based on entry type (LevelDisplayName)
106 | $DSCLevels = $DscEvents |
107 | Group LevelDisplayname -AsHashTable
108 | $DSCLevels
109 |
110 | #display sample of entries for Error
111 | $DSCLevels.error[0..10]
112 |
113 | #view errors
114 | $DSCLevels.error | Sort TimeCreated -descending |
115 | Select TimeCreated,Message |
116 | Out-GridView
117 |
118 | #endregion
119 |
120 | cls
121 |
--------------------------------------------------------------------------------
/Demo-Composite.ps1:
--------------------------------------------------------------------------------
1 | #Demo using composite resource
2 |
3 | Configuration MyComposite {
4 |
5 | Param([string]$Computername)
6 |
7 | Import-DscResource -ModuleName CompanyConfig
8 |
9 | Node $Computername {
10 |
11 | #vvv this is the composite resource vvvv
12 | Company Core {
13 | DomainName = "Company.pri"
14 | InterfaceAlias = "Ethernet"
15 | }
16 | #^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
17 |
18 | service Wuauserv {
19 | Name = "Wuauserv"
20 | Ensure = 'Present'
21 | State = 'Running'
22 | StartupType = 'Automatic'
23 | }
24 |
25 | WindowsFeature Containers {
26 | Name = 'Containers'
27 | Ensure = 'Present'
28 | IncludeAllSubFeature = $True
29 | DependsOn = "[Company]Core"
30 |
31 | }
32 |
33 | LocalConfigurationManager {
34 | RebootNodeIfNeeded = $True
35 | ActionAfterReboot = 'ContinueConfiguration'
36 | AllowModuleOverwrite = $True
37 | ConfigurationMode = 'ApplyAndAutoCorrect'
38 |
39 | } #LCM
40 |
41 | } #node
42 | } #configuration
43 |
44 |
45 | MyComposite -computername SRV1 -OutputPath c:\DSC\Composite
--------------------------------------------------------------------------------
/DemoList.ps1:
--------------------------------------------------------------------------------
1 | #requires -version 5.0
2 |
3 | Return "This is a demo script, Jeff! (you goober)."
4 | <#
5 |
6 | DSC Review
7 | passwords and credentials
8 | Using a secure pull server
9 | Using Partial Configurations
10 | Using Composite Configurations
11 | Using Named Configurations
12 | Reporting and Troubleshooting
13 |
14 | #>
15 |
16 | #region member configuration
17 |
18 | psedit .\Memberconfig.ps1
19 |
20 | $s = New-PSSession SRV1,SRV2
21 | #copy Resources
22 | $needed = 'xWinEventLog','xTimeZone','xNetworking','xSMBShare'
23 |
24 | foreach ($item in $s) {
25 | Split-Path (get-module $needed -ListAvailable ).ModuleBase |
26 | Copy-Item -recurse -Destination 'C:\Program Files\WindowsPowerShell\Modules' -force -Tosession $item
27 | }
28 | #verify
29 | Invoke-command { Get-module $using:needed -list } -session $s
30 |
31 | #push the LCM
32 | Set-DscLocalConfigurationManager -Path C:\dsc\Member -force -Verbose
33 | Get-DscLocalConfigurationManager -CimSession SRV1
34 | Get-DscLocalConfigurationManager -CimSession SRV2
35 |
36 | #push the configs one at a time for the sake of demonstration
37 | psedit C:\dsc\Member\SRV1.mof
38 | cls
39 | Start-DscConfiguration -Path C:\dsc\Member -ComputerName SRV1 -Force -Wait -Verbose
40 | cls
41 | Start-DscConfiguration -Path C:\dsc\Member -ComputerName SRV2 -Force -Wait -Verbose
42 |
43 | #may need to give configuration time to converge and complete
44 | Test-DscConfiguration -ComputerName SRV1,SRV2 -Verbose -Detailed
45 |
46 | #endregion
47 |
48 | #region encrypt a credential password locally
49 |
50 | Get-command -noun CMSMessage
51 | dir Cert:\CurrentUser\my -DocumentEncryptionCert
52 |
53 | #be careful about quoting
54 | $certreq = @'
55 | [Version]
56 | Signature = "$Windows NT$"
57 |
58 | [Strings]
59 | szOID_ENHANCED_KEY_USAGE = "2.5.29.37"
60 | szOID_DOCUMENT_ENCRYPTION = "1.3.6.1.4.1.311.80.1"
61 |
62 | [NewRequest]
63 | Subject = "cn=administrators@company.pri"
64 | MachineKeySet = false
65 | KeyLength = 2048
66 | KeySpec = AT_KEYEXCHANGE
67 | HashAlgorithm = Sha1
68 | Exportable = true
69 | RequestType = Cert
70 | KeyUsage = "CERT_KEY_ENCIPHERMENT_KEY_USAGE | CERT_DATA_ENCIPHERMENT_KEY_USAGE"
71 | ValidityPeriod = "Years"
72 | ValidityPeriodUnits = "1000"
73 |
74 | [Extensions]
75 | %szOID_ENHANCED_KEY_USAGE% = "{text}%szOID_DOCUMENT_ENCRYPTION%"
76 | '@
77 |
78 | Set-Content -Value $certreq -Path C:\mycert.inf
79 | dir C:\mycert.inf
80 |
81 | #add it
82 | certreq -new C:\mycert.inf C:\mycert.cer
83 |
84 | dir Cert:\CurrentUser\my -DocumentEncryptionCert
85 |
86 | $plainPass = "P@ssw0rd"
87 |
88 | help Protect-CmsMessage -param To
89 | Protect-CMSMessage -Content $plainPass -OutFile .\CMSPassword.txt -to cn=administrators@company.pri
90 |
91 | get-content .\CMSPassword.txt
92 |
93 | get-content .\cmspassword.txt | Unprotect-CmsMessage
94 |
95 | $securePass = ConvertTo-SecureString -String $(get-content .\cmspassword.txt | Unprotect-CmsMessage) -AsPlainText -force
96 | $Cred = New-Object PSCredential "company\administrator",$securePass
97 |
98 | #prove it
99 | $cred
100 | $cred.GetNetworkCredential().Password
101 |
102 | #endregion
103 |
104 | #region encrypting passwords the right way
105 |
106 | <#
107 | Note - WMF 5 now requires an additional Enhanced Key Usage of Document Encryption.
108 |
109 | The error message will contain the following:
110 | Encryption certificates must contain the Data Encipherment or Key Encipherment key usage, and include the
111 | Document Encryption Enhanced Key Usage (1.3.6.1.4.1.311.80.1).
112 |
113 | This means that after adding the template, you will need to perform
114 | the following to add the new requirements.
115 | 1. Open MMC
116 | 2. Add Certificate Templates - pointed to ADCS
117 | 3. Open the properties of the Workstation Authentication certificate
118 | 4. Select Extensions tab
119 | 5. Edit the Application Policies and add Document Encyption
120 |
121 | # Now, on the TARGET node, get the new certificate if not using autoenrollment
122 | Invoke-Command -computername s2 {Get-Certificate -template 'workstation' -url https://dc.company.pri/ADPolicyProvider_CEP_Kerberos/service.svc/cep -CertStoreLocation Cert:\LocalMachine\My\ -Verbose}
123 | #>
124 |
125 | #request the certificate
126 |
127 | <# to do this remotely might require CredSSP or AD Delegation
128 |
129 | $server = Get-ADComputer DOM1
130 | $client = Get-ADComputer SRV3
131 | Set-ADComputer -Identity $Server -PrincipalsAllowedToDelegateToAccount $client
132 | #verify
133 | Get-ADComputer -Identity $Server -Properties PrincipalsAllowedToDelegateToAccount
134 |
135 | #need to purge tickets due to 15min SPN negative cache
136 | Invoke-Command -ComputerName $Server.Name -ScriptBlock {
137 | klist purge -li 0x3e7
138 | }
139 | #>
140 |
141 | #I created my own certificate template - you can deploy however you want
142 | Invoke-Command -computername SRV1 {
143 | Get-Certificate -template 'CompanyComputer' -url https://DOM1.company.pri/ADPolicyProvider_CEP_Kerberos/service.svc/CEP -CertStoreLocation Cert:\LocalMachine\My\ -Verbose
144 | }
145 |
146 |
147 | #get certificate and thumbprint
148 | $cert = Invoke-Command {
149 | #get server authentication certs that have not expired
150 | dir Cert:\LocalMachine\my |
151 | where {$_.EnhancedKeyUsageList.FriendlyName -contains "Document Encryption" -AND $_.notAfter -gt (Get-Date) -AND $_.Subject -eq "CN=SRV1.company.pri" } |
152 | Sort NotAfter -Descending | select -first 1
153 | } -computername SRV1 -ErrorAction Stop
154 |
155 | $cert
156 | #mkdir C:\Certs
157 | Export-Certificate -Cert $cert -FilePath C:\Certs\SRV1.cer -Force
158 |
159 | psedit .\ConfigLocalGroup.ps1
160 |
161 | $DomainCredential = Get-Credential company\administrator
162 |
163 | #add cert thumbprint to encrypt credentials
164 | $ConfigData = @{
165 | AllNodes = @(
166 | @{
167 | NodeName = "SRV1"
168 | Credential = $DomainCredential
169 | Thumbprint = $cert.thumbprint
170 | CertificateFile = 'C:\Certs\SRV1.cer'
171 | psDSCAllowDomainUser = $True
172 | }
173 | )
174 | }
175 |
176 | LocalGroup -ConfigurationData $ConfigData -OutputPath C:\dsc\localGroup
177 |
178 | #view the encrypted password in the MOF
179 | psedit C:\dsc\localGroup\SRV1.mof
180 |
181 | <#
182 | instance of MSFT_Credential as $MSFT_Credential1ref
183 | {
184 | Password = "-----BEGIN CMS-----\nMIIB4wYJKoZIhvcNAQcDoIIB1DCCAdACAQAxggGLMIIBhwIBADBvMFgxFTATBgoJkiaJk/IsZAEZ\nFgVsb2NhbDEcMBoGCgmSJomT8ixkARkWDEdMT0JPTUFOVElDUzEhMB8GA1UEAxMYR0xPQk9NQU5U\nSUNTLUNISS1EQzA0LUNBAhMdAAAAtjP8M3EFNZNQAAAAAAC2MA0GCSqGSIb3DQEBBzAABIIBAEdv\nLXcX8fjklAfsxDAY9RLSz7Ad814NbJ5leUq+g38oYHYAq82DxwEhAYdod1lOHRYacIZCN/UvTSvf\nbvq0+AKQM6NZ/Ya5cg1aROBe4aJnnnQlaIspsRWPrejZDNG9DAmzVldERo6je0ZjJVinGplOMUwr\nX4ArmLhNlw7vzjll+Lpyw6ubMCN4hHltHD5U5z7VkGlyjUd1aApIv8cn1FeBI8BIgbEnOLGC3lBv\n+O8hY731tvEnYwd0WLrGnCGVkByOAYwRwIUT+ad/xfUWudkucyY/ktQ5fciqFVcaWOo64qoO4R9n\nGcVOFGWD8huw+NoDDqx0iu6iEbdT7KOBkgswPAYJKoZIhvcNAQcBMB0GCWCGSAFlAwQBKgQQXUjO\nVq5lwicyWWpYMnCHDIAQ4HcMIXywBYvHJoVGQXftmQ==\n-----END CMS-----";
185 | UserName = "company\\administrator";
186 |
187 | };
188 |
189 | instance of MSFT_GroupResource as $MSFT_GroupResource1ref
190 | {
191 | ResourceID = "[Group]Localadmin";
192 | Members = {
193 | "company\\help desk"
194 | };
195 | Credential = $MSFT_Credential1ref;
196 | SourceInfo = "C:\\users\\jeff.company\\Documents\\Magic Briefcase\\presentations\\ITDevConnections2016\\DSCWorkshop\\demos\\ConfigLocalGroup.ps1::11::1::Group";
197 | GroupName = "Administrators";
198 | ModuleName = "PSDesiredStateConfiguration";
199 | #>
200 | #before
201 | invoke-command { net localgroup administrators} -computer SRV1
202 |
203 | #push the meta config
204 | Set-DscLocalConfigurationManager -Path C:\dsc\localGroup -Verbose
205 |
206 | #check the new cert id
207 | Get-DscLocalConfigurationManager -CimSession SRV1
208 |
209 | Start-DscConfiguration -Path C:\dsc\localGroup -Verbose -wait -force
210 |
211 | invoke-command { net localgroup administrators} -computer SRV1
212 |
213 |
214 | #endregion
215 |
216 | #region setup a secure pull server
217 |
218 | #setup a DNS record and associated certificate
219 | Resolve-DnsName srv2.company.pri | Tee-object -Variable A
220 |
221 | # DNS for Pull server
222 | $paramHash = @{
223 | ComputerName = 'DOM1'
224 | name = 'DSC'
225 | ZoneName = 'company.pri'
226 | IPv4Address = $A.IP4Address
227 | }
228 |
229 | Add-DnsServerResourceRecordA @paramHash
230 |
231 | Resolve-DnsName dsc.company.pri
232 |
233 | # Enter you target web server
234 | $ComputerName = 'SRV2'
235 |
236 | #this might require CredSSP or Kerberos delegation
237 |
238 | Invoke-Command -computername $ComputerName -scriptblock {
239 | $params = @{
240 | template = 'WebServer2'
241 | url = 'https://DOM1.company.pri/ADPolicyProvider_CEP_Kerberos/service.svc/CEP'
242 | DnsName = "dsc.company.pri"
243 | CertStoreLocation = 'Cert:\LocalMachine\My\'
244 | SubjectName = 'CN=dsc.company.pri,OU=Servers,DC=Company,DC=Pri'
245 | Verbose = $True
246 | }
247 | Get-Certificate @params
248 | }
249 |
250 | # Can Export to PFX if needed on other web servers for high availability - Get-Help *pfx*
251 |
252 | Invoke-command -ComputerName $computername -ScriptBlock {
253 | dir Cert:\LocalMachine\My\
254 | }
255 |
256 | psedit .\Advanced-HttpsPull.ps1
257 |
258 | enter-pssession srv2
259 | get-website
260 | exit
261 |
262 | #endregion
263 |
264 | #region pull configuration
265 |
266 | #current status
267 | Get-DscLocalConfigurationManager -CimSession SRV3
268 | #clear DSC config for the sake of the demo
269 | Remove-DscConfigurationDocument -Stage Current -CimSession srv3
270 |
271 | Get-DscConfiguration -CimSession SRV3
272 |
273 | psedit .\PullClientLCM.ps1
274 |
275 | Set-DscLocalConfigurationManager -Path C:\dsc\lcmpull -ComputerName SRV3 -Verbose
276 | Get-DscLocalConfigurationManager -CimSession SRV3
277 |
278 | psedit .\SamplePullConfig.ps1
279 |
280 | #need to rename config with guid and copy to pull server
281 | $configid = (Get-DscLocalConfigurationManager -CimSession SRV3).ConfigurationID
282 |
283 | rename-item C:\dsc\DemoPullConfig\SRV3.mof C:\dsc\DemoPullConfig\$configid.mof
284 | #it needs a checksum
285 | New-DscChecksum -Path C:\dsc\DemoPullConfig\$configid.mof
286 |
287 | dir C:\dsc\DemoPullConfig
288 |
289 | #copy the mof and checksum to the pull server
290 | $s = new-pssession SRV2
291 |
292 | dir C:\dsc\DemoPullConfig -file |
293 | copy -Destination "C:\program files\windowspowershell\dscservice\configuration" -ToSession $s
294 |
295 | Invoke-Command { dir "C:\program files\windowspowershell\dscservice\configuration" } -session $s
296 |
297 | #also need to copy resources to pull server
298 | #need to restructure folder before zipping
299 | #https://docs.microsoft.com/en-us/powershell/dsc/pullserver
300 |
301 | invoke-item 'C:\Program Files\WindowsPowerShell\Modules\xTimeZone\'
302 |
303 | $dest = "C:\DSCResources"
304 | if (-not (Test-path $dest)) { mkdir $dest}
305 |
306 | Get-DscResource |
307 | where path -match "^c:\\Program Files\\WindowsPowerShell\\Modules" |
308 | Select -ExpandProperty Module |
309 | Select Name,Version,ModuleBase -unique |
310 | foreach {
311 | $out = "{0}_{1}.zip" -f $_.Name,$_.Version
312 | $zip = Join-Path -path $dest -ChildPath $out
313 | write-host "Creating $out" -ForegroundColor green
314 | dir $_.modulebase | Compress-Archive -DestinationPath $zip -CompressionLevel Fastest -Force
315 | #give file a chance to close
316 | start-sleep -Seconds 1
317 | If (Test-Path $zip) {
318 | Try {
319 | New-DSCCheckSum -Path $zip -ErrorAction Stop -Force
320 | }
321 | Catch {
322 | Write-Warning "Failed to create checksum for $zip"
323 | }
324 | }
325 | else {
326 | Write-Warning "Failed to find $zip"
327 | }
328 |
329 | }
330 |
331 | dir $dest
332 |
333 | #copy over remoting
334 | $target = "C:\Program Files\WindowsPowerShell\DSCService\Modules"
335 | dir $dest | foreach {
336 | $_ | Copy-item -Destination $target -ToSession $s -Force
337 | }
338 |
339 | Invoke-command { dir $using:target} -session $s
340 |
341 | remove-pssession $s
342 |
343 | #clear DSCResource files
344 | Invoke-Command {
345 | dir 'C:\Program Files\WindowsPowerShell\Modules\x*' |
346 | del -Recurse -Force
347 | } -comp SRV3
348 |
349 | Invoke-command { Get-DscResource } -comp srv3
350 |
351 | #force the member server to update
352 | cls
353 | Update-DscConfiguration -Wait -computerName SRV3 -Verbose
354 |
355 | Get-DscConfiguration -CimSession srv3
356 | get-smbshare -CimSession srv3
357 |
358 | #endregion
359 |
360 | #region v5 changes
361 | #these commands don't seem to do much remotely
362 |
363 | help Publish-ModuleToPullServer -full
364 |
365 | help Publish-MOFToPullServer -full
366 |
367 | #endregion
368 |
369 | #region composite resources
370 |
371 | # https://msdn.microsoft.com/en-us/powershell/dsc/authoringresourcecomposite
372 |
373 | psedit .\companyConfig.ps1
374 |
375 | #need this file structure
376 | # \DSCResources\
377 | # mkdir companyConfig\DSCResources\company
378 |
379 | #save as companyConfig.schema.psm1
380 | copy .\companyConfig.ps1 -Destination .\companyConfig\DSCResources\company\company.schema.psm1 -PassThru
381 |
382 | #need manifests
383 | New-ModuleManifest -Path .\companyConfig\companyConfig.psd1
384 | New-ModuleManifest -Path .\companyConfig\DSCResources\company\company.psd1 -RootModule company.schema.psm1
385 |
386 | cls
387 | dir .\companyConfig -Recurse
388 |
389 | psedit .\companyConfig\companyConfig.psd1
390 |
391 | #copy to PSModulePath
392 | copy .\companyConfig -Destination 'C:\Program Files\WindowsPowerShell\Modules' -PassThru -Recurse -Container -Force
393 |
394 | Get-DscResource company
395 | Get-DscResource company -Syntax
396 |
397 | psedit .\Demo-Composite.ps1
398 | psedit C:\dsc\Composite\SRV1.mof
399 |
400 | #deploy to pull server
401 | $guid = (New-Guid).guid
402 | LCMPull -computername SRV1 -guid $guid -output c:\dsc\lcmpull
403 | Set-DscLocalConfigurationManager -Path C:\dsc\lcmpull -ComputerName SRV1 -force
404 |
405 | psedit .\pushMoftoPull.ps1
406 |
407 | dir C:\dsc\Composite\*.mof | Push-MofToPullServer -Verbose
408 |
409 | #clear current MOFs for demo
410 | Remove-DscConfigurationDocument -Stage Pending -CimSession SRV1
411 | Remove-DscConfigurationDocument -Stage current -CimSession SRV1
412 | cls
413 | Update-DscConfiguration -Wait -computerName SRV1 -Verbose
414 |
415 | #check later after reboot and configuration has finished
416 | Get-DscConfiguration -CimSession srv1
417 |
418 | #endregion
419 |
420 | #region named configurations
421 | # https://docs.microsoft.com/en-us/powershell/dsc/pullclientconfignames
422 | psedit .\demo-named.ps1
423 |
424 | #endregion
425 |
426 | #region partial configurations
427 |
428 | #is this a technical solution for a business process problem?
429 |
430 | psedit .\demo-partial.ps1
431 |
432 | #endregion
433 |
434 | #region troubleshooting
435 |
436 | #database viewer http://www.nirsoft.net/utils/ese_database_view.html
437 | esedatabaseview
438 |
439 | help Get-DscConfigurationStatus
440 | Get-DscConfigurationStatus -CimSession srv1
441 | Get-DscConfigurationStatus -CimSession srv3 | fl
442 |
443 | Test-DscConfiguration -CimSession srv3 -Detailed
444 |
445 | #event logs
446 | psedit .\DSClogs.ps1
447 |
448 | #reporting
449 | #https://docs.microsoft.com/en-us/powershell/dsc/reportserver
450 | function Get-DSCReport {
451 | [cmdletbinding()]
452 | param(
453 | [Parameter(Position=0,Mandatory)]
454 | [string]$Computername,
455 | [string]$serviceURL = "https://DSC.company.pri:8080/PSDSCPullServer.svc"
456 | )
457 |
458 | $AgentId = (Get-DscLocalConfigurationManager -CimSession $Computername).AgentID
459 | $requestUri = "$serviceURL/Nodes(AgentId= '$AgentId')/Reports"
460 | $params = @{
461 | Uri = $requestUri
462 | ContentType = "application/json;odata=minimalmetadata;streaming=true;charset=utf-8"
463 | UseBasicParsing = $True
464 | Headers = @{Accept = "application/json";ProtocolVersion = "2.0"}
465 | ErrorAction = "Stop"
466 | }
467 | Try {
468 | Write-Verbose "Querying $requestUri"
469 | $request = Invoke-RestMethod @params
470 | #$object = ConvertFrom-Json $request.content
471 | $request.value
472 | }
473 | Catch {
474 | Throw $_
475 | }
476 | }
477 |
478 | #may need to do this to handle SSL connection
479 | # $AllProtocols = [System.Net.SecurityProtocolType]'Ssl3,Tls,Tls11,Tls12'
480 | # [System.Net.ServicePointManager]::SecurityProtocol = $AllProtocols
481 |
482 | $r = Get-DSCReport -Computername srv1 -Verbose
483 | $r.count
484 | $r[0]
485 | $r[0].StatusData | ConvertFrom-Json
486 | ($r[0].StatusData | ConvertFrom-Json).ResourcesInDesiredState
487 |
488 | $r | Select JobID,@{N="Start";E={$_.StartTime -as [datetime]}},
489 | @{N="Finish";E={$_.EndTime -as [datetime]}},OperationType,RefreshMode,Status |
490 | Out-Gridview
491 |
492 | #endregion
--------------------------------------------------------------------------------
/FeaturesConfiguration.ps1:
--------------------------------------------------------------------------------
1 | #requires -version 5.0
2 |
3 | Configuration FeaturesConfiguration {
4 |
5 | Param([string[]]$Computername)
6 |
7 | Import-DscResource -ModuleName 'PSDesiredStateConfiguration'
8 |
9 | Node $Computername {
10 |
11 | WindowsFeature InternalDB {
12 | Name = 'Windows-Internal-Database'
13 | Ensure = 'Present'
14 | IncludeAllSubFeature = $True
15 |
16 | }
17 |
18 | WindowsFeature Defender {
19 | Name = 'Windows-Defender'
20 | Ensure = 'Present'
21 | }
22 |
23 | WindowsFeature TelnetClient {
24 | Name = 'Telnet-Client'
25 | Ensure = 'Present'
26 | }
27 |
28 | WindowsFeature PowerShell2 {
29 | Name = 'PowerShell-V2'
30 | Ensure = 'Absent'
31 | }
32 |
33 | WindowsFeature Wins {
34 | Name = 'Wins'
35 | Ensure = 'Absent'
36 | }
37 |
38 | WindowsFeature SNMP {
39 | Name = 'SNMP-Service'
40 | Ensure = 'Present'
41 | IncludeAllSubFeature = $True
42 | }
43 | } #node
44 |
45 | } #config
46 |
47 | FeaturesConfiguration -Computername SRV3 -OutputPath C:\dsc\PartialDemo\FeaturesConfiguration
--------------------------------------------------------------------------------
/Memberconfig.ps1:
--------------------------------------------------------------------------------
1 | #requires -version 5.0
2 |
3 | Configuration Member {
4 |
5 | Param()
6 |
7 | Import-DscResource -ModuleName PSDesiredStateConfiguration,
8 | @{ModuleName = 'xSMBShare';RequiredVersion = '2.0.0.0'},
9 | @{ModuleName = 'xWinEventLog';RequiredVersion = '1.1.0.0'},
10 | @{ModuleName = 'xTimeZone';RequiredVersion = '1.6.0.0'},
11 | @{ModuleName = 'xNetworking';RequiredVersion = '5.2.0.0'}
12 |
13 | Node $AllNodes.NodeName {
14 |
15 | File Work {
16 | DestinationPath = 'C:\Work'
17 | Type = 'Directory'
18 | Ensure = 'Present'
19 | }
20 |
21 | Service RemoteReg {
22 | Name = 'RemoteRegistry'
23 | State = 'Running'
24 | StartupType = 'Automatic'
25 | Ensure = 'Present'
26 | }
27 |
28 | WindowsFeature Backup {
29 | Name = 'Windows-Server-Backup'
30 | Ensure = 'Present'
31 | IncludeAllSubFeature = $True
32 | }
33 |
34 | xSMBShare WorkShare {
35 | DependsOn = '[File]Work'
36 | Name = 'Work$'
37 | Path = 'C:\work'
38 | FullAccess = 'Company\domain admins'
39 | NoAccess = 'Company\Domain Users'
40 | Ensure = 'Present'
41 | }
42 |
43 | xTimeZone TZ {
44 | IsSingleInstance = 'Yes'
45 | TimeZone = "Central Standard Time"
46 | }
47 |
48 | xWinEventLog Security {
49 | LogName = 'Security'
50 | MaximumSizeInBytes = 256MB
51 | IsEnabled = $True
52 | LogMode = 'AutoBackup'
53 |
54 | }
55 |
56 | xFirewall vmpingFWRule {
57 | Name = 'vm-monitoring-icmpv4'
58 | Action = 'Allow'
59 | Direction = 'Inbound'
60 | Enabled = $True
61 | Ensure = 'Present'
62 | InterfaceAlias = $Node.InterfaceAlias
63 | }
64 |
65 | xFirewall SMB {
66 | Name = 'FPS-SMB-In-TCP'
67 | Action = 'Allow'
68 | Direction = 'Inbound'
69 | Enabled = $True
70 | Ensure = 'Present'
71 | InterfaceAlias = $Node.InterfaceAlias
72 | }
73 |
74 | xFirewall RemoteEvtLogFWRule1 {
75 | Name = "RemoteEventLogSvc-In-TCP"
76 | Action = "Allow"
77 | Direction = 'Inbound'
78 | Enabled = $True
79 | Ensure = 'Present'
80 | InterfaceAlias = $Node.InterfaceAlias
81 | }
82 |
83 | xFirewall RemoteEvtLogFWRule2 {
84 | Name = "RemoteEventLogSvc-NP-In-TCP"
85 | Action = "Allow"
86 | Direction = 'Inbound'
87 | Enabled = $True
88 | Ensure = 'Present'
89 | InterfaceAlias = $Node.InterfaceAlias
90 | }
91 |
92 | xFirewall RemoteEvtLogFWRule3 {
93 | Name = "RemoteEventLogSvc-RPCSS-In-TCP"
94 | Action = "Allow"
95 | Direction = 'Inbound'
96 | Enabled = $True
97 | Ensure = 'Present'
98 | InterfaceAlias = $Node.InterfaceAlias
99 | }
100 |
101 |
102 | #Enable DSC Analytic logs
103 |
104 | Script DSCAnalyticLog {
105 |
106 | DependsOn = '[xFirewall]RemoteEvtLogFWRule3'
107 | TestScript = {
108 | $status = wevtutil get-log "Microsoft-Windows-Dsc/Analytic"
109 | if ($status -contains "enabled: true") {return $True} else {return $False}
110 | }
111 | SetScript = {
112 | wevtutil.exe set-log "Microsoft-Windows-Dsc/Analytic" /q:true /e:true
113 | }
114 | getScript = {
115 | $Result = wevtutil get-log "Microsoft-Windows-Dsc/Analytic"
116 | return @{Result = $Result}
117 | }
118 | }
119 |
120 |
121 | LocalConfigurationManager {
122 | RebootNodeIfNeeded = $True
123 | ActionAfterReboot = 'ContinueConfiguration'
124 | AllowModuleOverwrite = $True
125 | ConfigurationMode = 'ApplyAndAutoCorrect'
126 |
127 | } #LCM
128 |
129 | } #node
130 |
131 | Node $allnodes.Where({$_.roles -eq 'File'}).Nodename {
132 |
133 | WindowsFeature FileServices {
134 | Name = "FileAndStorage-Services"
135 | Ensure = "Present"
136 | IncludeAllSubFeature = $True
137 | }
138 |
139 | File Public {
140 | Ensure = 'Present'
141 | DestinationPath = 'C:\Public'
142 | Type = 'Directory'
143 | }
144 |
145 | File Sales {
146 | Ensure = 'Present'
147 | DestinationPath = 'C:\Sales'
148 | Type = 'Directory'
149 | }
150 |
151 | xSmbShare Public {
152 | Name = "Public"
153 | Path = "C:\Public"
154 | Ensure = 'Present'
155 | Description = "Public folder share"
156 | DependsOn = "[file]Public"
157 | fullAccess = "$($Node.Domain)\Domain Admins"
158 | ChangeAccess = "$($Node.Domain)\Domain Users"
159 | }
160 |
161 | xSmbShare Sales {
162 | Name = "Sales"
163 | Path = "C:\Sales"
164 | Ensure = 'Present'
165 | Description = "Sales department share"
166 | DependsOn = "[file]Sales"
167 | FullAccess = "$($Node.Domain)\Domain Admins"
168 | ChangeAccess = "$($Node.domain)\Sales"
169 | ReadAccess = "$($Node.Domain)\Domain Users"
170 | }
171 | } #file
172 |
173 | Node $allnodes.Where({$_.roles -eq 'Web'}).Nodename {
174 |
175 | WindowsFeature Web {
176 | Name = "Web-WebServer"
177 | Ensure = "Present"
178 | IncludeAllSubFeature = $True
179 | }
180 | WindowsFeature OData {
181 | Name = "ManagementOData"
182 | Ensure = "Present"
183 | }
184 |
185 | WindowsFeature PSWA {
186 | name = 'WindowsPowerShellWebAccess'
187 | Ensure = 'Present'
188 | DependsOn = "[WindowsFeature]Web"
189 |
190 | }
191 | } #Web
192 |
193 | } #configuration
194 |
195 | $ConfigData = @{
196 | AllNodes = @(
197 | @{
198 | NodeName = '*'
199 | InterfaceAlias = 'Ethernet'
200 | Domain = 'Company'
201 | },
202 | @{NodeName = 'SRV1';Roles='File'},
203 | @{NodeName = 'SRV2';Roles='Web'}
204 | )}
205 |
206 | #run it
207 | member -ConfigurationData $ConfigData -OutputPath c:\DSC\Member
208 |
209 |
210 |
211 |
--------------------------------------------------------------------------------
/PullClientLCM.ps1:
--------------------------------------------------------------------------------
1 | #requires -version 5.0
2 |
3 | [dsclocalconfigurationmanager()]
4 | Configuration LCMPull {
5 |
6 | Param([string]$Computername,[string]$guid)
7 |
8 | Node $Computername {
9 |
10 | ConfigurationRepositoryWeb Pull {
11 | ServerURL = "https://dsc.company.pri:8080/PSDSCPullServer.svc"
12 | AllowUnsecureConnection = $False
13 | #CertificateID = "A GUID that represents the certificate used to authenticate to the server."
14 | #RegistrationKey = shared secret for named configurations
15 | #ConfigurationNames = An array of names of configurations to be pulled by the target node.
16 | }
17 |
18 | ResourceRepositoryWeb Pull {
19 | ServerURL = "https://dsc.company.pri:8080/PSDSCPullServer.svc"
20 | AllowUnsecureConnection = $False
21 | }
22 |
23 | ReportServerWeb Pull {
24 | ServerURL = "https://dsc.company.pri:8080/PSDSCPullServer.svc"
25 | AllowUnsecureConnection = $false
26 | }
27 |
28 | Settings {
29 | RebootNodeIfNeeded = $True
30 | ConfigurationMode = 'ApplyAndAutoCorrect'
31 | RefreshMode = 'Pull'
32 | ActionAfterReboot = 'ContinueConfiguration'
33 | ConfigurationID = $GUID
34 | AllowModuleOverwrite = $true
35 | }
36 |
37 |
38 | } #node
39 |
40 |
41 | } #config
42 |
43 | $guid = (New-Guid).guid
44 |
45 | LCMPull -computername SRV3 -guid $guid -output c:\dsc\lcmpull
--------------------------------------------------------------------------------
/PushMoftoPull.ps1:
--------------------------------------------------------------------------------
1 | #requires -version 5.1
2 |
3 | Function Push-MofToPullServer {
4 | [cmdletbinding()]
5 | Param(
6 | [Parameter(Mandatory,Position=0,ValueFromPipelineByPropertyName)]
7 | [ValidatePattern({\.mof$})]
8 | [string]$FullName,
9 | #the name of your pull server
10 | [string]$PullServer = "SRV2"
11 | )
12 |
13 | Begin {
14 | Write-Verbose "Creating a PSSession to $Pullserver"
15 | $sess = New-PSSession -ComputerName $PullServer
16 | }
17 |
18 | Process {
19 | Write-Verbose "Processing $fullname"
20 | $filename = Split-path $fullname -Leaf
21 | $computername = $filename.split(".")[0]
22 | Write-Verbose "Getting configuration ID from $computername"
23 | $configid = (Get-DscLocalConfigurationManager -CimSession $computername).ConfigurationID
24 | if ($configid) {
25 | $new = $fullname.replace($Computername,$configID)
26 | Write-Verbose "Renaming to $new"
27 | rename-item $fullname $new -Force
28 | Write-Verbose "Adding a checksum"
29 | New-DscChecksum -Path $new -force
30 |
31 | Write-Verbose "copy the mof and checksum to the pull server"
32 | write-verbose $new
33 | Copy-Item -Path $new -Destination "C:\program files\windowspowershell\dscservice\configuration" -ToSession $sess
34 | write-verbose "$new.checksum"
35 | Copy-Item -Path "$new.checksum" -Destination "C:\program files\windowspowershell\dscservice\configuration" -ToSession $sess
36 | }
37 | else {
38 | Write-Warning "$Computername does not appear to be configured for pull"
39 | }
40 | }
41 |
42 | End {
43 | Write-Verbose "Removing PSSession"
44 | $sess| Remove-PSsession
45 | }
46 |
47 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Advanced DSC Workshop
2 |
3 | The files in this repository are my demonstration and example files for my Advanced DSC Workshop. Nothing here should be considered production ready. The material is for educational purposes only.
4 |
5 | Content is subject to change depending on whatever conference I might be using this material.
6 |
7 | *Last updated 12 November 2017*
--------------------------------------------------------------------------------
/ResetDSC.ps1:
--------------------------------------------------------------------------------
1 | #reset DSC
2 |
3 | [cmdletbinding()]
4 | Param(
5 | [Parameter(Mandatory,Position=0)]
6 | [string[]]$Computername
7 |
8 | )
9 |
10 | [DSCLocalConfigurationManager()]
11 | configuration StandardLCM {
12 | Param([string[]]$Computername)
13 |
14 | Node $Computername {
15 |
16 | Settings {
17 | RebootNodeIfNeeded = $True
18 | ConfigurationMode = 'ApplyAndMonitor'
19 | AllowModuleOverwrite = $True
20 | RefreshMode = 'Push'
21 | }
22 |
23 | } #node
24 | } #config
25 |
26 | StandardLCM -computername $computername -output c:\dsc\standard
27 |
28 | Write-Host "Setting LCM back to default" -ForegroundColor Cyan
29 | Set-DscLocalConfigurationManager -Path C:\dsc\standard -Verbose
30 |
31 | Write-Host "Removing DSC documents" -ForegroundColor cyan
32 | Remove-DscConfigurationDocument -Stage Pending -CimSession $Computername
33 | Remove-DscConfigurationDocument -Stage Current -CimSession $Computername
34 |
--------------------------------------------------------------------------------
/SamplePullConfig.ps1:
--------------------------------------------------------------------------------
1 | #requires -version 4.0
2 |
3 | Configuration DemoPullConfig {
4 |
5 | Param([string[]]$Computername)
6 |
7 | Import-DscResource -moduleName PSDesiredStateConfiguration,
8 | @{ModuleName='xNetworking';RequiredVersion = '5.2.0.0'},
9 | @{ModuleName='xTimeZone';RequiredVersion = '1.6.0.0'},
10 | @{ModuleName='xSMBShare';RequiredVersion = '2.0.0.0'}
11 |
12 | Node $Computername {
13 |
14 | xTimeZone Eastern {
15 | TimeZone = "Central Standard Time"
16 | IsSingleInstance = "Yes"
17 |
18 | } #end xTimeZone
19 |
20 | File Stuff {
21 | DestinationPath = "C:\Stuff"
22 | Ensure = "Present"
23 | Force = $True
24 | Type = "Directory"
25 |
26 | } #end File resource
27 |
28 | xSMBShare Stuff {
29 | Name = "Stuff$"
30 | Path = "c:\stuff"
31 | Description = "company stuff"
32 | Ensure = 'Present'
33 | FolderEnumerationMode = 'AccessBased'
34 | FullAccess = "company\domain admins"
35 | DependsOn = "[file]Stuff"
36 | }
37 |
38 | xDnsServerAddress CompanyDNS {
39 | Address = "192.168.3.10","8.8.8.8"
40 | InterfaceAlias = "Ethernet"
41 | AddressFamily = "IPv4"
42 |
43 | } #end DNSServer resource
44 |
45 | WindowsFeature SNMP {
46 | Name = "SNMP-Service"
47 | Ensure = 'Present'
48 | IncludeAllSubFeature = $True
49 | }
50 |
51 |
52 | } #end node
53 |
54 | } #close configuration
55 |
56 |
57 | DemoPullConfig -Computername SRV3 -OutputPath c:\dsc\DemoPullConfig
--------------------------------------------------------------------------------
/ServiceConfiguration.ps1:
--------------------------------------------------------------------------------
1 | #requires -version 5.0
2 |
3 | Configuration ServiceConfiguration {
4 | Param([string[]]$Computername)
5 |
6 | Import-DscResource -ModuleName 'PSDesiredStateConfiguration'
7 | Node $Computername {
8 |
9 | Service RemoteRegistry {
10 | Name = 'RemoteRegistry'
11 | State = 'Running'
12 | StartupType = 'Automatic'
13 | }
14 | Service Defender {
15 | Name = 'WinDefend'
16 | State = 'Running'
17 | StartupType = 'Automatic'
18 | }
19 |
20 | Service Bits {
21 | Name = 'Bits'
22 | StartupType = 'Manual'
23 | }
24 |
25 | Service Spooler {
26 | Name = 'Spooler'
27 | State = 'Stopped'
28 | StartupType = 'Disabled'
29 | }
30 |
31 | Service SharedAccess {
32 | Name = 'SharedAccess'
33 | State = 'Stopped'
34 | StartupType = 'Disabled'
35 | }
36 |
37 | } #node
38 |
39 |
40 | }
41 |
42 | ServiceConfiguration -Computername SRV3 -OutputPath C:\dsc\PartialDemo\ServiceConfiguration
43 |
--------------------------------------------------------------------------------
/companyConfig/DSCResources/company/company.psd1:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jdhitsolutions/AdvancedDSCWorkshop/a1d3970fe2ca36d671777d28c154d518a32689e2/companyConfig/DSCResources/company/company.psd1
--------------------------------------------------------------------------------
/companyConfig/DSCResources/company/company.schema.psm1:
--------------------------------------------------------------------------------
1 | #requires -version 5.0
2 |
3 | #configuration that will become a composite resource
4 |
5 | Configuration Company {
6 |
7 | Param(
8 | [ValidateNotNullorEmpty()]
9 | [string]$InterfaceAlias = 'Ethernet',
10 | [Parameter(Mandatory)]
11 | [ValidateNotNullorEmpty()]
12 | [string]$DomainName
13 | )
14 |
15 |
16 | Import-DscResource -ModuleName PSDesiredStateConfiguration,
17 | @{ModuleName = 'xSMBShare';RequiredVersion='2.0.0.0'},
18 | @{ModuleName = 'xWinEventLog';RequiredVersion = '1.1.0.0'},
19 | @{ModuleName = 'xTimeZone';RequiredVersion = '1.6.0.0'},
20 | @{ModuleName = 'xNetworking';RequiredVersion = '5.2.0.0'}
21 |
22 | #NO NODE
23 |
24 | File Work {
25 | DestinationPath = 'C:\Work'
26 | Type = 'Directory'
27 | Ensure = 'Present'
28 | }
29 |
30 | Service RemoteReg {
31 | Name = 'RemoteRegistry'
32 | State = 'Running'
33 | StartupType = 'Automatic'
34 | Ensure = 'Present'
35 | }
36 |
37 | WindowsFeature Backup {
38 | Name = 'Windows-Server-Backup'
39 | Ensure = 'Present'
40 | IncludeAllSubFeature = $True
41 | }
42 |
43 | xSMBShare WorkShare {
44 | DependsOn = '[File]Work'
45 | Name = 'Work$'
46 | Path = 'C:\work'
47 | FullAccess = "$DomainName\Domain Admins"
48 | NoAccess = "$DomainName\Domain Users"
49 | Ensure = 'Present'
50 | }
51 |
52 | xTimeZone TZ {
53 | IsSingleInstance = 'Yes'
54 | TimeZone = "Central Standard Time"
55 | }
56 |
57 | xWinEventLog Security {
58 | LogName = 'Security'
59 | MaximumSizeInBytes = 256MB
60 | IsEnabled = $True
61 | LogMode = 'AutoBackup'
62 |
63 | }
64 |
65 | xFirewall vmpingFWRule {
66 | Name = 'vm-monitoring-icmpv4'
67 | Action = 'Allow'
68 | Direction = 'Inbound'
69 | Enabled = $True
70 | Ensure = 'Present'
71 | InterfaceAlias = $InterfaceAlias
72 | }
73 |
74 | xFirewall SMB {
75 | Name = 'FPS-SMB-In-TCP'
76 | Action = 'Allow'
77 | Direction = 'Inbound'
78 | Enabled = $True
79 | Ensure = 'Present'
80 | InterfaceAlias = $InterfaceAlias
81 | }
82 |
83 | xFirewall RemoteEvtLogFWRule1 {
84 | Name = "RemoteEventLogSvc-In-TCP"
85 | Action = "Allow"
86 | Direction = 'Inbound'
87 | Enabled = $True
88 | Ensure = 'Present'
89 | InterfaceAlias = $InterfaceAlias
90 | }
91 |
92 | xFirewall RemoteEvtLogFWRule2 {
93 | Name = "RemoteEventLogSvc-NP-In-TCP"
94 | Action = "Allow"
95 | Direction = 'Inbound'
96 | Enabled = $True
97 | Ensure = 'Present'
98 | InterfaceAlias = $InterfaceAlias
99 | }
100 |
101 | xFirewall RemoteEvtLogFWRule3 {
102 | Name = "RemoteEventLogSvc-RPCSS-In-TCP"
103 | Action = "Allow"
104 | Direction = 'Inbound'
105 | Enabled = $True
106 | Ensure = 'Present'
107 | InterfaceAlias = $InterfaceAlias
108 | }
109 |
110 |
111 | #Enable DSC Analytic logs
112 |
113 | Script DSCAnalyticLog {
114 |
115 | DependsOn = '[xFirewall]RemoteEvtLogFWRule3'
116 | TestScript = {
117 | $status = wevtutil get-log "Microsoft-Windows-Dsc/Analytic"
118 | if ($status -contains "enabled: true") {return $True} else {return $False}
119 | }
120 | SetScript = {
121 | wevtutil.exe set-log "Microsoft-Windows-Dsc/Analytic" /q:true /e:true
122 | }
123 | getScript = {
124 | $Result = wevtutil get-log "Microsoft-Windows-Dsc/Analytic"
125 | return @{Result = $Result}
126 | }
127 | }
128 |
129 |
130 | } #end configuration
--------------------------------------------------------------------------------
/companyConfig/companyConfig.psd1:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jdhitsolutions/AdvancedDSCWorkshop/a1d3970fe2ca36d671777d28c154d518a32689e2/companyConfig/companyConfig.psd1
--------------------------------------------------------------------------------
/demo-named.ps1:
--------------------------------------------------------------------------------
1 |
2 | Return "This is a walkthrough demo. Pay attention!"
3 |
4 | #region configuration
5 |
6 | Configuration NamedConfig {
7 |
8 | Param([string[]]$Computername)
9 |
10 | Import-DscResource -moduleName PSDesiredStateConfiguration,
11 | @{ModuleName="xWinEventLog";Moduleversion="1.1.0.0"}
12 |
13 | Node $Computername {
14 |
15 | File FileData {
16 | DestinationPath = "C:\Files"
17 | Ensure = "Present"
18 | Force = $True
19 | Type = "Directory"
20 |
21 | } #end File resource
22 |
23 | File Test {
24 | DestinationPath = "C:\files\Data.txt"
25 | Contents = "Lorem Ipsum Factum. Hinky Dinky Doo."
26 | DependsOn = "[file]FileData"
27 | Ensure = "Present"
28 | Type = "File"
29 | }
30 |
31 | xWinEventLog Security {
32 | LogName = "Security"
33 | IsEnabled = $True
34 | LogMode = "Retain"
35 | MaximumSizeInBytes = 1GB
36 |
37 | }
38 |
39 | Registry CompanyReg {
40 | Key = "HKey_Local_Machine\Software\CompanyData"
41 | Ensure = "present"
42 | valueName = "R-Record"
43 | ValueData = "AQ-12-CK-5684"
44 | ValueType = 'String'
45 | }
46 |
47 | Service RemoteRegistry {
48 | Name = "RemoteRegistry"
49 | Ensure = "Present"
50 | StartupType = "Disabled"
51 | State = "Stopped"
52 | }
53 |
54 | WindowsFeature InternalDB {
55 | Name = "Windows-Internal-Database"
56 | Ensure = "Present"
57 | IncludeAllSubFeature = $True
58 | }
59 |
60 | } #end node
61 |
62 | } #close configuration
63 |
64 | $computer = "SRV1"
65 |
66 | NamedConfig -computername $Computername -outputpath C:\DSC\DemoNamed
67 |
68 | #rename the mof
69 | # delete existing Named entries
70 | # dir C:\dsc\DemoNamed\named* | del
71 | rename-item C:\dsc\DemoNamed\SRV1.mof -NewName "Named.mof" -force
72 |
73 | #checksum it
74 | New-DscChecksum -Path C:\dsc\DemoNamed\named.mof -OutPath C:\dsc\DemoNamed
75 |
76 | dir c:\dsc\DemoNamed
77 |
78 | #copy to pull server
79 | $pull = "srv2"
80 | $sess = New-PSSession -ComputerName $pull
81 |
82 | #if necessary
83 | # icm {dir "C:\Program Files\WindowsPowerShell\DscService\Configuration\Named*"| del} -session $sess
84 |
85 | $paramHash = @{
86 | Path = "c:\dsc\DemoNamed\Named*"
Destination = "C:\Program Files\WindowsPowerShell\DscService\Configuration"
Force = $True
ToSession = $Sess
}
87 |
88 | Copy-Item @paramHash
89 | #verify
90 | invoke-command { dir $using:paramhash.destination} -session $sess
91 |
92 | #endregion
93 |
94 | #region LCM
95 |
96 | #need some sort of shared secret. A GUID is probably best
97 | $myRegKey = (new-guid).guid #Get-Random -min 100000 -Maximum 250000
98 | $myRegKey
99 |
100 | #need to copy the key to the pull server
101 |
102 | Set-Content -Path c:\DSC\RegistrationKeys.txt -Value $myRegKey
103 | cat C:\DSC\RegistrationKeys.txt
104 | $paramhash.Destination = "c:\Program Files\WindowsPowerShell\DscService"
105 | $paramhash.Path = "C:\DSC\RegistrationKeys.txt"
106 | Copy-item @paramhash
107 |
108 | invoke-command -scriptblock { dir $using:paramhash.Destination } -session $sess
109 |
110 | #define a new LCM configuration
111 | [DSCLocalConfigurationManager()]
112 | Configuration DEMO_LCM_ConfigName {
113 | param
114 | (
115 | [Parameter(Mandatory)]
116 | [string[]]$ComputerName,
117 |
118 | #[Parameter(Mandatory=$true)]
119 | #[string]$guid, <------------------------Don't need this anymore
120 |
121 | [Parameter(Mandatory)]
122 | [string]$RegistrationKey,
123 |
124 | [Parameter(Mandatory)]
125 | [string]$ThumbPrint #<---------- still need this
126 |
127 | )
128 | Node $ComputerName {
129 |
130 | Settings {
131 |
132 | AllowModuleOverwrite = $True
133 | ConfigurationMode = 'ApplyAndAutoCorrect'
134 | RefreshMode = 'Pull'
135 | ConfigurationID = "" # Setting to blank - but can leave a guid in - won't matter
136 | }
137 |
138 | ConfigurationRepositoryWeb DSCHTTPS {
139 | ServerURL = 'https://DSC.company.pri:8080/PSDSCPullServer.svc'
140 | CertificateID = $Thumbprint
141 | AllowUnsecureConnection = $False
142 | RegistrationKey = "$RegistrationKey" # <----------- We Need this
143 | ConfigurationNames = @("Named") # <----------- The names of your configuration
144 | <#
145 | Note: If you specify more than one value in the ConfigurationNames,
146 | you must also specify PartialConfiguration blocks in your configuration.
147 | #>
148 | }
149 | ReportServerWeb CompanyPullSrv {
150 | ServerURL = 'https://DSC.company.pri:8080/PSDSCPullServer.svc'
151 | }
152 | }
153 | }
154 |
155 | $Thumbprint = Invoke-Command -Computername 'srv2' -scriptblock {
156 | Get-Childitem Cert:\LocalMachine\My | Where-Object {$_.Subject -match "^CN=DSC"} |
157 | Select-Object -ExpandProperty ThumbPrint
158 | }
159 |
160 | $computer = "SRV1"
161 |
162 | # Create the Computer.Meta.Mof in folder
163 | DEMO_LCM_ConfigName -ComputerName $computer -Thumbprint $Thumbprint -registrationKey $myRegKey -OutputPath C:\dsc\DemoNamed
164 |
165 | psedit C:\dsc\DemoNamed\SRV1.meta.mof
166 |
167 | #set the server
168 |
169 | #may need to reset it
170 | # .\ResetDSC.ps1 -Computername srv1 -Verbose
171 | # Get-DscLocalConfigurationManager -cimsession $computer
172 |
173 | Set-DscLocalConfigurationManager -cimsession $computer -Path c:\dsc\DemoNamed -verbose
174 |
175 | #endregion
176 |
177 | #region Use it
178 |
179 | Get-DSCLocalConfigurationmanager -CimSession $computer
180 | Get-DSCLocalConfigurationmanager -CimSession $computer |
181 | Select -ExpandProperty ConfigurationDownLoadManagers
182 |
183 | Update-DscConfiguration -Wait -Verbose -CimSession $computer
184 |
185 | Get-DscConfiguration -CimSession $computer
186 |
187 | dir \\$computer\c$\files
188 | get-windowsfeature -ComputerName SRV1 -Name windows-internal-database
189 | cls
190 |
191 | #endregion
192 |
193 | #clean up and reset
194 |
195 | dir C:\dsc\DemoNamed | del
196 | icm {dir "C:\Program Files\WindowsPowerShell\DscService\Configuration\named*" | del} -session $sess
197 | icm {dir "C:\Program Files\WindowsPowerShell\DscService\registrationkeys.txt" | del} -session $sess
198 |
199 | remove-pssession $sess
--------------------------------------------------------------------------------
/demo-partial.ps1:
--------------------------------------------------------------------------------
1 | #requires -version 5.0
2 |
3 | #read more: https://msdn.microsoft.com/en-us/powershell/dsc/partialconfigs
4 |
5 | #configure the LCM to accept partial configurations
6 |
7 | Return "This is a demo file you silly human."
8 |
9 | #region the configurations
10 |
11 | psedit .\ServiceConfiguration.ps1
12 | psedit .\FeaturesConfiguration.ps1
13 |
14 | #endregion
15 |
16 | #region the LCM config needed to enable partials
17 |
18 | [DSCLocalConfigurationManager()]
19 | configuration PartialConfig {
20 | Param([string[]]$Computername)
21 |
22 | Node $Computername {
23 |
24 | PartialConfiguration ServiceConfiguration #<-- Name must match eventual configuration
25 | {
26 | Description = 'Configuration to configure services.'
27 | RefreshMode = 'Push'
28 | }
29 | PartialConfiguration FeaturesConfiguration #<-- Name must match eventual configuration
30 | {
31 | Description = 'Configuration for Windows Features'
32 | RefreshMode = 'Push'
33 | }
34 |
35 | Settings {
36 | RebootNodeIfNeeded = $True
37 | ConfigurationMode = 'ApplyAndAutoCorrect'
38 | AllowModuleOverwrite = $True
39 | }
40 |
41 | } #node
42 | } #config
43 |
44 | PartialConfig -Computername SRV3 -OutputPath c:\DSC\PartialDemo
45 |
46 | psedit C:\dsc\PartialDemo\SRV3.meta.mof
47 | #endregion
48 |
49 | #region deploy
50 | #wipe current config
51 | Remove-DscConfigurationDocument -Stage Current -CimSession SRV3
52 | #current LCM
53 | Get-DscLocalConfigurationManager -cimsession SRV3
54 |
55 | #push new LCM config
56 | Set-DscLocalConfigurationManager -Path C:\dsc\PartialDemo -Verbose
57 |
58 | $lcm = Get-DscLocalConfigurationManager -cimsession SRV3
59 | $lcm.PartialConfigurations
60 |
61 | #publish partial configs with Publish-DSCConfiguration
62 | Get-DscConfiguration -CimSession SRV3
63 |
64 | #enable a feature to be removed
65 | Add-WindowsFeature -Name Wins -ComputerName SRV3
66 |
67 | Publish-DscConfiguration -Path C:\dsc\PartialDemo\FeaturesConfiguration -Verbose
68 | Publish-DscConfiguration -Path C:\dsc\PartialDemo\ServiceConfiguration -Verbose
69 |
70 | #endregion
71 |
72 | #region apply with Start-DSCConfiguration and -UseExisting
73 | Start-DscConfiguration -ComputerName SRV3 -Wait -UseExisting -Verbose
74 |
75 | #wait for server to reboot if necessary
76 |
77 | Get-windowsfeature -ComputerName SRV3 | where installed
78 | Test-DscConfiguration -ComputerName SRV3 -Detailed
79 |
80 | get-service remoteregistry,windefend,bits,spooler -com srv3 |
81 | Select name,displayname,status,StartType,machinename | format-table
82 |
83 | #endregion
--------------------------------------------------------------------------------