├── .gitignore
├── .vscode
└── settings.json
├── CMHyperHydrate.psd1
├── CMHyperHydrate.psm1
├── Certificates
├── Create-ConfigMgrCertTemplates.ps1
└── Generate-CACertTemplateConfigs.ps1
├── Create-ModuleManifest.ps1
├── Create-NewLab.ps1
├── LICENSE
├── NewEnv.ASDLabTP1.json
├── NewEnv.Template.json
├── Private
├── Invoke-LabCommand.ps1
├── New-LabCMSQLSettingsINI.ps1
├── New-LabUnattendXML.ps1
└── Test-LabConnection.ps1
├── Public
├── Add-LabAdditionalApps.ps1
├── Add-LabRoleCA.ps1
├── Add-LabRoleCM.ps1
├── Add-LabRoleDC.ps1
├── Add-LabRoleRRAS.ps1
├── Add-LabRoleSQL.ps1
├── Get-LabConfig.ps1
├── Join-LabDomain.ps1
├── New-LabEnv.ps1
├── New-LabRefVHDX.ps1
├── New-LabSwitch.ps1
├── New-LabVM.ps1
├── Update-LabRRAS.ps1
├── UpgradeCM
└── Write-LogEntry.ps1
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | NewEnv.CMCB_CPC.json
2 | TestFiles/
3 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "markdownlint.config": {
3 | "MD028": false,
4 | "MD025": {
5 | "front_matter_title": ""
6 | }
7 | }
8 | }
--------------------------------------------------------------------------------
/CMHyperHydrate.psd1:
--------------------------------------------------------------------------------
1 | #
2 | # Module manifest for module 'CMHyperHydrate'
3 | #
4 | # Generated by: Adam Gross (@AdamGrossTX) & Steven Hosking (@OnPremCloudGuy)
5 | #
6 | # Generated on: 9/11/2021
7 | #
8 |
9 | @{
10 |
11 | # Script module or binary module file associated with this manifest.
12 | RootModule = 'CMHyperHydrate.psm1'
13 |
14 | # Version number of this module.
15 | ModuleVersion = '2.0'
16 |
17 | # Supported PSEditions
18 | # CompatiblePSEditions = @()
19 |
20 | # ID used to uniquely identify this module
21 | GUID = 'd80ae962-a46c-4181-9568-dbeb12a9f9fe'
22 |
23 | # Author of this module
24 | Author = 'Adam Gross (@AdamGrossTX) & Steven Hosking (@OnPremCloudGuy)'
25 |
26 | # Company or vendor of this module
27 | CompanyName = 'Unknown'
28 |
29 | # Copyright statement for this module
30 | Copyright = '(c) Adam Gross (@AdamGrossTX) & Steven Hosking (@OnPremCloudGuy). All rights reserved.'
31 |
32 | # Description of the functionality provided by this module
33 | # Description = ''
34 |
35 | # Minimum version of the PowerShell engine required by this module
36 | # PowerShellVersion = ''
37 |
38 | # Name of the PowerShell host required by this module
39 | # PowerShellHostName = ''
40 |
41 | # Minimum version of the PowerShell host required by this module
42 | # PowerShellHostVersion = ''
43 |
44 | # Minimum version of Microsoft .NET Framework required by this module. This prerequisite is valid for the PowerShell Desktop edition only.
45 | # DotNetFrameworkVersion = ''
46 |
47 | # Minimum version of the common language runtime (CLR) required by this module. This prerequisite is valid for the PowerShell Desktop edition only.
48 | # ClrVersion = ''
49 |
50 | # Processor architecture (None, X86, Amd64) required by this module
51 | # ProcessorArchitecture = ''
52 |
53 | # Modules that must be imported into the global environment prior to importing this module
54 | # RequiredModules = @()
55 |
56 | # Assemblies that must be loaded prior to importing this module
57 | # RequiredAssemblies = @()
58 |
59 | # Script files (.ps1) that are run in the caller's environment prior to importing this module.
60 | # ScriptsToProcess = @()
61 |
62 | # Type files (.ps1xml) to be loaded when importing this module
63 | # TypesToProcess = @()
64 |
65 | # Format files (.ps1xml) to be loaded when importing this module
66 | # FormatsToProcess = @()
67 |
68 | # Modules to import as nested modules of the module specified in RootModule/ModuleToProcess
69 | # NestedModules = @()
70 |
71 | # Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export.
72 | FunctionsToExport = @()
73 |
74 | # Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export.
75 | CmdletsToExport = @()
76 |
77 | # Variables to export from this module
78 | # VariablesToExport = @()
79 |
80 | # Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export.
81 | AliasesToExport = @()
82 |
83 | # DSC resources to export from this module
84 | # DscResourcesToExport = @()
85 |
86 | # List of all modules packaged with this module
87 | # ModuleList = @()
88 |
89 | # List of all files packaged with this module
90 | # FileList = @()
91 |
92 | # Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell.
93 | PrivateData = @{
94 |
95 | PSData = @{
96 |
97 | # Tags applied to this module. These help with module discovery in online galleries.
98 | # Tags = @()
99 |
100 | # A URL to the license for this module.
101 | # LicenseUri = ''
102 |
103 | # A URL to the main website for this project.
104 | # ProjectUri = ''
105 |
106 | # A URL to an icon representing this module.
107 | # IconUri = ''
108 |
109 | # ReleaseNotes of this module
110 | # ReleaseNotes = ''
111 |
112 | # Prerelease string of this module
113 | # Prerelease = ''
114 |
115 | # Flag to indicate whether the module requires explicit user acceptance for install/update/save
116 | # RequireLicenseAcceptance = $false
117 |
118 | # External dependent modules of this module
119 | # ExternalModuleDependencies = @()
120 |
121 | } # End of PSData hashtable
122 |
123 | } # End of PrivateData hashtable
124 |
125 | # HelpInfo URI of this module
126 | # HelpInfoURI = ''
127 |
128 | # Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix.
129 | # DefaultCommandPrefix = ''
130 |
131 | }
132 |
133 |
--------------------------------------------------------------------------------
/CMHyperHydrate.psm1:
--------------------------------------------------------------------------------
1 | #Imports all PS1 files from the Public and Private folders to create the module.
2 |
3 | $Public = @( Get-ChildItem -Path .\Public\*.ps1 -Recurse )
4 | $Private = @( Get-ChildItem -Path .\Private\*.ps1 -Recurse)
5 | foreach ($import in @($Public + $Private)) {
6 | . $import.fullname
7 | }
--------------------------------------------------------------------------------
/Certificates/Create-ConfigMgrCertTemplates.ps1:
--------------------------------------------------------------------------------
1 |
2 | #https://github.com/PowerShell/CertificateDsc/issues/54
3 | $Main = {
4 | foreach ($Template in $Configs) {
5 | Write-Host $Template.displayName
6 | Create-PKICertTemplate -TemplateDisplayName $Template.DisplayName -PKIConfig $Template.Config -SecurityConfig $Template.Security
7 | }
8 | }
9 |
10 | $Configs = @(
11 | @{
12 | "DisplayName" = "Domain Controller Authentication (KDC)"
13 | "Config" = [hashtable]@{
14 | "flags" = "131168"
15 | "pKIDefaultKeySpec" = "1"
16 | "pKIKeyUsage" = [Byte[]]( "160","0" )
17 | "pKIMaxIssuingDepth" = "0"
18 | "pKICriticalExtensions" = @( "2.5.29.15","2.5.29.17" )
19 | "pKIExpirationPeriod" = ([Byte[]](0,64,57,135,46,225,254,255))
20 | "pKIOverlapPeriod" = ([Byte[]](0,128,166,10,255,222,255,255))
21 | "pKIExtendedKeyUsage" = @( "1.3.6.1.5.5.7.3.2","1.3.6.1.5.5.7.3.1","1.3.6.1.4.1.311.20.2.2","1.3.6.1.5.2.3.5" )
22 | "msPKI-RA-Signature" = "0"
23 | "msPKI-Enrollment-Flag" = "32"
24 | "msPKI-Private-Key-Flag" = "67436544"
25 | "msPKI-Certificate-Name-Flag" = "138412032"
26 | "msPKI-Minimal-Key-Size" = "2048"
27 | "msPKI-Template-Schema-Version" = "4"
28 | "msPKI-Template-Minor-Revision" = "3"
29 | "msPKI-Cert-Template-OID" = "1.3.6.1.4.1.311.21.8.9297300.10481922.2378919.4036973.687234.60.15267975.11339196"
30 | "msPKI-Supersede-Templates" = @( "KerberosAuthentication","DomainControllerAuthentication","DomainController" )
31 | "msPKI-Certificate-Application-Policy" = @( "1.3.6.1.5.5.7.3.2","1.3.6.1.5.5.7.3.1","1.3.6.1.4.1.311.20.2.2","1.3.6.1.5.2.3.5" )
32 | "msPKI-RA-Application-Policies" = "msPKI-Asymmetric-Algorithm``PZPWSTR``RSA``msPKI-Hash-Algorithm``PZPWSTR``SHA256``msPKI-Key-Usage``DWORD``16777215``msPKI-Symmetric-Algorithm``PZPWSTR``3DES``msPKI-Symmetric-Key-Length``DWORD``168``"
33 | }
34 | "Security" = @(
35 | @{
36 | "IdentityReference" = "NT AUTHORITY\Authenticated Users"
37 | "ActiveDirectoryRights" = "GenericRead"
38 | "AccessControlType" = "Allow"
39 | "ObjectType" = "00000000-0000-0000-0000-000000000000"
40 | "InheritanceType" = "None"
41 | "InheritedObjectType" = "00000000-0000-0000-0000-000000000000"
42 | },
43 | @{
44 | "IdentityReference" = "CPDesk\Domain Admins"
45 | "ActiveDirectoryRights" = "CreateChild, DeleteChild, Self, WriteProperty, DeleteTree, Delete, GenericRead, WriteDacl, WriteOwner"
46 | "AccessControlType" = "Allow"
47 | "ObjectType" = "00000000-0000-0000-0000-000000000000"
48 | "InheritanceType" = "None"
49 | "InheritedObjectType" = "00000000-0000-0000-0000-000000000000"
50 | },
51 | @{
52 | "IdentityReference" = "CPDesk\Enterprise Admins"
53 | "ActiveDirectoryRights" = "CreateChild, DeleteChild, Self, WriteProperty, DeleteTree, Delete, GenericRead, WriteDacl, WriteOwner"
54 | "AccessControlType" = "Allow"
55 | "ObjectType" = "00000000-0000-0000-0000-000000000000"
56 | "InheritanceType" = "None"
57 | "InheritedObjectType" = "00000000-0000-0000-0000-000000000000"
58 | },
59 | @{
60 | "IdentityReference" = "CPDesk\Desktop Admins"
61 | "ActiveDirectoryRights" = "CreateChild, DeleteChild, Self, WriteProperty, DeleteTree, Delete, GenericRead, WriteDacl, WriteOwner"
62 | "AccessControlType" = "Allow"
63 | "ObjectType" = "00000000-0000-0000-0000-000000000000"
64 | "InheritanceType" = "None"
65 | "InheritedObjectType" = "00000000-0000-0000-0000-000000000000"
66 | },
67 | @{
68 | "IdentityReference" = "NT AUTHORITY\ENTERPRISE DOMAIN CONTROLLERS"
69 | "ActiveDirectoryRights" = "ReadProperty, WriteProperty, ExtendedRight"
70 | "AccessControlType" = "Allow"
71 | "ObjectType" = "0e10c968-78fb-11d2-90d4-00c04f79dc55"
72 | "InheritanceType" = "None"
73 | "InheritedObjectType" = "00000000-0000-0000-0000-000000000000"
74 | },
75 | @{
76 | "IdentityReference" = "NT AUTHORITY\ENTERPRISE DOMAIN CONTROLLERS"
77 | "ActiveDirectoryRights" = "ReadProperty, WriteProperty, ExtendedRight"
78 | "AccessControlType" = "Allow"
79 | "ObjectType" = "a05b8cc2-17bc-4802-a710-e7c15ab866a2"
80 | "InheritanceType" = "None"
81 | "InheritedObjectType" = "00000000-0000-0000-0000-000000000000"
82 | },
83 | @{
84 | "IdentityReference" = "CPDesk\Enterprise Read-only Domain Controllers"
85 | "ActiveDirectoryRights" = "ReadProperty, ExtendedRight"
86 | "AccessControlType" = "Allow"
87 | "ObjectType" = "a05b8cc2-17bc-4802-a710-e7c15ab866a2"
88 | "InheritanceType" = "None"
89 | "InheritedObjectType" = "00000000-0000-0000-0000-000000000000"
90 | },
91 | @{
92 | "IdentityReference" = "CPDesk\Enterprise Read-only Domain Controllers"
93 | "ActiveDirectoryRights" = "ReadProperty, ExtendedRight"
94 | "AccessControlType" = "Allow"
95 | "ObjectType" = "0e10c968-78fb-11d2-90d4-00c04f79dc55"
96 | "InheritanceType" = "None"
97 | "InheritedObjectType" = "00000000-0000-0000-0000-000000000000"
98 | },
99 | @{
100 | "IdentityReference" = "CPDesk\Domain Admins"
101 | "ActiveDirectoryRights" = "ReadProperty, WriteProperty, ExtendedRight"
102 | "AccessControlType" = "Allow"
103 | "ObjectType" = "0e10c968-78fb-11d2-90d4-00c04f79dc55"
104 | "InheritanceType" = "None"
105 | "InheritedObjectType" = "00000000-0000-0000-0000-000000000000"
106 | },
107 | @{
108 | "IdentityReference" = "CPDesk\Domain Controllers"
109 | "ActiveDirectoryRights" = "ReadProperty, WriteProperty, ExtendedRight"
110 | "AccessControlType" = "Allow"
111 | "ObjectType" = "a05b8cc2-17bc-4802-a710-e7c15ab866a2"
112 | "InheritanceType" = "None"
113 | "InheritedObjectType" = "00000000-0000-0000-0000-000000000000"
114 | },
115 | @{
116 | "IdentityReference" = "CPDesk\Domain Controllers"
117 | "ActiveDirectoryRights" = "ReadProperty, WriteProperty, ExtendedRight"
118 | "AccessControlType" = "Allow"
119 | "ObjectType" = "0e10c968-78fb-11d2-90d4-00c04f79dc55"
120 | "InheritanceType" = "None"
121 | "InheritedObjectType" = "00000000-0000-0000-0000-000000000000"
122 | },
123 | @{
124 | "IdentityReference" = "CPDesk\Enterprise Admins"
125 | "ActiveDirectoryRights" = "ReadProperty, WriteProperty, ExtendedRight"
126 | "AccessControlType" = "Allow"
127 | "ObjectType" = "0e10c968-78fb-11d2-90d4-00c04f79dc55"
128 | "InheritanceType" = "None"
129 | "InheritedObjectType" = "00000000-0000-0000-0000-000000000000"
130 | }
131 | )
132 | }
133 | )
134 |
135 |
136 |
137 | function Create-PKICertTemplate {
138 | param (
139 | [Parameter()]
140 | [ValidateNotNullOrEmpty()]
141 | [string]
142 | $TemplateDisplayName,
143 |
144 | [Parameter()]
145 | [ValidateNotNullOrEmpty()]
146 | [hashtable]
147 | $PKIConfig,
148 |
149 | [Parameter()]
150 | [ValidateNotNullOrEmpty()]
151 | $SecurityConfig
152 |
153 | )
154 |
155 | $CN = $TemplateDisplayName.Replace(" ","")
156 | $PKIConfig.revision = "100"
157 |
158 | $ConfigContext = ([ADSI]"LDAP://RootDSE").ConfigurationNamingContext
159 | $ADSI = [ADSI]"LDAP://CN=Certificate Templates,CN=Public Key Services,CN=Services,$($ConfigContext)"
160 |
161 | $Template = [ADSI]"LDAP://CN=$($CN),CN=Certificate Templates,CN=Public Key Services,CN=Services,$($ConfigContext)"
162 | if ([string]::IsNullOrEmpty($Template.Name)){
163 | # create if not exists
164 | $Template = $ADSI.Create("pKICertificateTemplate", "CN=$($CN)")
165 | }
166 |
167 | $Template.Put("displayName", $TemplateDisplayName)
168 | $Template.SetInfo()
169 |
170 | foreach ($key in $PKIConfig.Keys){
171 | $Template.Put($key, $PKIConfig[$key])
172 | }
173 |
174 | $Template.InvokeSet("pKIKeyUsage", $PKIConfig.pKIKeyUsage)
175 | $Template.SetInfo()
176 |
177 | #ResetPerms
178 | $Template.ObjectSecurity.Access | foreach-Object {$Template.ObjectSecurity.RemoveAccessRule(($_))}
179 | #Where-Object InheritanceFlags -ne "ContainerInherit" |
180 | foreach ($Permission in $SecurityConfig) {
181 | $ID = $Permission.IdentityReference.Split("\")
182 | $ACC = [System.Security.Principal.NTAccount]::new($ID[0], $ID[1])
183 | $IdentityReference = $ACC.Translate([System.Security.Principal.SecurityIdentifier])
184 | $Rule = [System.DirectoryServices.ActiveDirectoryAccessRule]::New($IdentityReference,$Permission.ActiveDirectoryRights,$Permission.AccessControlType,$Permission.ObjectType,$Permission.InheritanceType,$Permission.InheritedObjectType)
185 |
186 | $Template.ObjectSecurity.AddAccessRule($Rule)
187 | $Template.commitchanges()
188 | }
189 |
190 |
191 | #Allow Computers to Enroll
192 |
193 | #$DomainName = Get-WMIObject Win32_NTDomain | Select -ExpandProperty DomainName
194 | #$Template.ObjectSecurity.GetAccessRules($true, $true, [System.Security.Principal.NTAccount])
195 | #$ADObj = New-Object System.Security.Principal.NTAccount("$env\Domain Controllers")
196 | #$Identity = $ADObj.Translate([System.Security.Principal.SecurityIdentifier])
197 | #$ADRights = [System.DirectoryServices.ActiveDirectoryRights]::ReadProperty -bor [System.DirectoryServices.ActiveDirectoryRights]::WriteProperty -bor [System.DirectoryServices.ActiveDirectoryRights]::ExtendedRight
198 | #$Type = "Allow"
199 | #$ACE = New-Object System.DirectoryServices.ActiveDirectoryAccessRule($identity, $adRights, $type)
200 | #$Template.psbase.ObjectSecurity.SetAccessRule($ACE)
201 | #$Template.psbase.commitchanges()
202 | #$P = Start-Process "C:\Windows\System32\certtmpl.msc" -PassThru
203 | #Start-Sleep 2
204 | #$P | Stop-Process
205 | ##Add-CATemplate -name "$TemplateDisplayName" -ErrorAction SilentlyContinue -Force
206 |
207 |
208 | #$ACC = [System.Security.Principal.NTAccount]::new($DomainName, "Domain Computers")
209 | #$Identity = $ACC.Translate([System.Security.Principal.SecurityIdentifier])
210 | #$EnrollObjectType = [Guid]::Parse("0e10c968-78fb-11d2-90d4-00c04f79dc55")
211 | #$ADRights = [System.DirectoryServices.ActiveDirectoryRights]::ReadProperty -bor [System.DirectoryServices.ActiveDirectoryRights]::WriteProperty -bor [System.DirectoryServices.ActiveDirectoryRights]::ExtendedRight
212 | #$Type = [System.Security.AccessControl.AccessControlType]::Allow
213 | #$Rule = [System.DirectoryServices.ActiveDirectoryAccessRule]::New($Identity, $ADRights, $Type, $EnrollObjectType)
214 | #$Template.ObjectSecurity.AddAccessRule($Rule)
215 | #$Template.commitchanges()
216 | }
217 |
218 | & $Main
219 |
--------------------------------------------------------------------------------
/Certificates/Generate-CACertTemplateConfigs.ps1:
--------------------------------------------------------------------------------
1 |
2 | $TargetDomain = "ASD"
3 |
4 | #Need to add logic to manage which servers or groups need perms
5 | $SourceTemplates = @(
6 | "DomainControllerAuthentication(KDC)",
7 | "ConfigMgrWebServerCertificate",
8 | "ConfigMgrDistributionPointCertificate",
9 | "ConfigMgrClientCertificate"
10 | )
11 | Start-Transcript .\settings.txt -Force | Out-Null;
12 | Write-Host ""`$Configs" = @("
13 | foreach ($SourceTemplateCN in $SourceTemplates) {
14 | $ConfigContext = ([ADSI]"LDAP://RootDSE").ConfigurationNamingContext
15 | $ADSI = [ADSI]"LDAP://CN=Certificate Templates,CN=Public Key Services,CN=Services,$ConfigContext"
16 | $Template = [ADSI]"LDAP://CN=$SourceTemplateCN,CN=Certificate Templates,CN=Public Key Services,CN=Services,$ConfigContext"
17 | $PropertyList = $Template.Properties.PropertyNames | Where-Object {$_.StartsWith("pKI") -or $_.StartsWith("flags") -or $_.StartsWith("msPKI-")}
18 |
19 | Write-Host " @{"
20 | Write-Host " ""DisplayName"" = ""$($Template.displayName.ToString()) - Test"""
21 | Write-Host " ""Config"" = [hashtable]@{"
22 | foreach ($Property in $PropertyList) {
23 | $Value = $Template.psbase.Properties.Item($Property).Value
24 | if ($Property -eq "pKIExpirationPeriod" -or $Property -eq "pKIOverlapPeriod") {
25 | $b = $Value -join ','
26 | Write-Host " ""$Property"" = ([Byte[]]($b))"
27 |
28 | }
29 | elseif ($Value -is [byte[]]) {
30 | $b = '"{0}"' -f ($Value -join '","')
31 | Write-Host " ""$Property"" = [Byte[]]("$($b.ToString())")"
32 | }
33 | elseif ($Value -is [Object[]]) {
34 | $b = '"{0}"' -f ($Value -join '","')
35 | Write-Host " ""$Property"" = @("$($b.ToString())")"
36 | }
37 | elseif ($Value -match '`') {
38 | $NewVal = $Value.Replace('`','``')
39 | Write-Host " ""$Property"" = ""$($NewVal.ToString())"""
40 | }
41 | else {
42 | Write-Host " ""$Property"" = ""$($Value.ToString())"""
43 | }
44 | }
45 | Write-Host " }"
46 |
47 | #GetPermissions
48 | $TemplateSecurityConfig = $Template.ObjectSecurity.Access | Select-Object IdentityReference,ActiveDirectoryRights,AccessControlType,ObjectType,InheritanceType,InheritedObjectType
49 |
50 | Write-Host " ""Security"" = @("
51 | $Count = 0
52 | foreach ($Config in $TemplateSecurityConfig) {
53 | $Count++
54 | Write-Host " @{"
55 | foreach ($Prop in $Config.PSObject.Properties) {
56 | $Value = $Prop.Value
57 | if ($Prop.Name.ToString() -Match "IdentityReference" -and $Value -notmatch 'NT AUTHORITY') {
58 | $Value = "{0}\{1}" -f $TargetDomain,($Value.ToString().Split("\"))[1]
59 | }
60 | Write-Host " ""$($Prop.Name.ToString())"" = ""$($Value.ToString())"""
61 | }
62 | if ($Count -eq $TemplateSecurityConfig.Count) {
63 | Write-Host " }"
64 | }
65 | else {
66 | Write-Host " },"
67 | }
68 | }
69 | Write-Host " )"
70 | Write-Host " }"
71 | }
72 |
73 | Write-Host ")"
74 |
75 |
76 | Stop-Transcript
--------------------------------------------------------------------------------
/Create-ModuleManifest.ps1:
--------------------------------------------------------------------------------
1 | $Manifest = @{
2 | Path = '.\CMHyperHydrate.psd1'
3 | RootModule = 'CMHyperHydrate.psm1'
4 | Author = 'Adam Gross (@AdamGrossTX) & Steven Hosking (@OnPremCloudGuy)'
5 | CompanyName = 'A Square Dozen'
6 | ModuleVersion = '2.0'
7 | functionsToExport = @()
8 | CmdletsToExport = @()
9 | VariablesToExport = @()
10 | AliasesToExport = @()
11 | DscResourcesToExport = @()
12 | }
13 |
14 | New-ModuleManifest @Manifest
--------------------------------------------------------------------------------
/Create-NewLab.ps1:
--------------------------------------------------------------------------------
1 |
2 | Import-Module "$($PSScriptRoot)\CMHyperHydrate.psm1" -Force
3 |
4 | $ConfigFileName = "$($PSScriptRoot)\NewEnv.ASDLabTP1.json"
5 |
6 | New-LabEnv -ConfigFileName $ConfigFileName -verbose
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Adam Gross
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/NewEnv.ASDLabTP1.json:
--------------------------------------------------------------------------------
1 | {
2 | "ENVToBuild" : "ASDLabTP1",
3 | "LabPath" : "D:\\Labs",
4 | "SourcePath" : "C:\\Labs",
5 | "PathSQL" : "\\Media\\ISO\\SQL",
6 | "PathSvr" : "\\Media\\ISO\\Server",
7 | "PathWin10" : "\\Media\\ISO\\Windows10",
8 | "PathADK" : "\\Media\\ADK",
9 | "PathADKWinPE" : "\\Media\\ADKWinPE",
10 | "PathConfigMgrTP" : "\\Media\\ConfigMgrTP",
11 | "PathConfigMgrCB" : "\\Media\\ConfigMgrCB",
12 | "PathPackages" : "\\Media\\Packages",
13 | "PathDrivers" : "\\Media\\Drivers",
14 | "PathRefImage" : "\\ReferenceImage",
15 | "VMDataPath" : "\\Data",
16 | "VMLogPath" : "\\Data\\Logs",
17 | "VMScriptPath" : "\\Data\\Scripts",
18 | "ServerRef" : [
19 | {
20 | "RefID" : "2019",
21 | "RefName" : "Windows Server 2019",
22 | "RefVHDXName" : "Server2019Ref.vhdx",
23 | "RefIndex" : "2",
24 | "RefSrcType" : "ISO",
25 | "RefHVDSize" : "25gb",
26 | "RefFeature" : "NetFx3"
27 | }
28 | ],
29 | "ENVConfig" : [
30 | {
31 | "Env" : "ASDLabTP1",
32 | "EnvSwitchName" : "ASDLabTP1",
33 | "EnvNetBios" : "ASD",
34 | "EnvFQDN" : "ASD.lab",
35 | "EnvIPSubnet" : "172.100.10.",
36 | "EnvAdminName" : "Administrator",
37 | "EnvAdminPW" : "P@ssw0rd",
38 | "EnvTimeZone" : "Central Standard Time",
39 | "InputLocale" : "0409:00000409",
40 | "SystemLocale" : "en-us",
41 | "UILanguage" : "en-us",
42 | "UILanguageFB" : "en-us",
43 | "UserLocale" : "en-us",
44 | "VLANID" : "4",
45 | "RRASName" : "ASDLabTP1-RRAS",
46 | "InternetSwitchName" : "LAB - Realtek USB",
47 | "ServerVMList": [
48 | {
49 | "VMID" : "VM1",
50 | "VMName" : "RRAS",
51 | "VMOS" : "Server",
52 | "VMRoles" : "RRAS",
53 | "VMHDDSize" : "25gb",
54 | "VMIPLastOctet" : "1",
55 | "EnableSnapShot": "1",
56 | "StartupMemory" : "4gb",
57 | "ProcessorCount" : "1",
58 | "Generation" : "2",
59 | "AutoStartup" : "1"
60 | },
61 | {
62 | "VMID" : "VM2",
63 | "VMName" : "DC01",
64 | "VMOS" : "Server",
65 | "VMRoles" : "DC,CA",
66 | "VMHDDSize" : "25gb",
67 | "VMIPLastOctet" : "12",
68 | "EnableSnapShot": "1",
69 | "StartupMemory" : "4gb",
70 | "ProcessorCount" : "1",
71 | "Generation" : "2",
72 | "AutoStartup" : "1"
73 | },
74 | {
75 | "VMID" : "VM3",
76 | "VMName" : "CM01",
77 | "VMOS" : "Server",
78 | "VMRoles" : "SQL,ADK,PE,CM",
79 | "VMHDDSize" : "150gb",
80 | "VMIPLastOctet" : "13",
81 | "CMSiteCode" : "PS1",
82 | "CMVersion" : "TP",
83 | "CMPreReqPreDL" : "1",
84 | "CMPreReqPath" : "1",
85 | "EnableSnapShot": "1",
86 | "StartupMemory" : "16gb",
87 | "ProcessorCount" : "4",
88 | "Generation" : "2",
89 | "AutoStartup" : "1",
90 | "AddWSUS" : "0"
91 | }
92 |
93 | ]
94 | }
95 | ]
96 | }
--------------------------------------------------------------------------------
/NewEnv.Template.json:
--------------------------------------------------------------------------------
1 | {
2 | "ENVToBuild" : "ASDLab1",
3 | "LabPath" : "D:\\Labs",
4 | "SourcePath" : "C:\\Labs",
5 | "PathSQL" : "\\Media\\ISO\\SQL",
6 | "PathSvr" : "\\Media\\ISO\\Server",
7 | "PathWin10" : "\\Media\\ISO\\Windows10",
8 | "PathADK" : "\\Media\\ADK",
9 | "PathADKWinPE" : "\\Media\\ADKWinPE",
10 | "PathConfigMgrTP" : "\\Media\\ConfigMgrTP",
11 | "PathConfigMgrCB" : "\\Media\\ConfigMgrCB",
12 | "PathPackages" : "\\Media\\Packages",
13 | "PathDrivers" : "\\Media\\Drivers",
14 | "PathRefImage" : "\\ReferenceImage",
15 | "VMDataPath" : "\\Data",
16 | "VMLogPath" : "\\Data\\Logs",
17 | "VMScriptPath" : "\\Data\\Scripts",
18 | "ServerRef" : [
19 | {
20 | "RefID" : "2019",
21 | "RefName" : "Windows Server 2019",
22 | "RefVHDXName" : "Server2019Ref.vhdx",
23 | "RefIndex" : "2",
24 | "RefSrcType" : "ISO",
25 | "RefHVDSize" : "25gb",
26 | "RefHFeature" : "NetFx3",
27 | "RefPackage" : "",
28 | "RefDriver" : ""
29 | }
30 | ],
31 | "ENVConfig" : [
32 | {
33 | "Env" : "ASDLab1",
34 | "EnvSwitchName" : "ASDLab1",
35 | "EnvNetBios" : "ASD",
36 | "EnvFQDN" : "ASD.lab",
37 | "EnvIPSubnet" : "172.90.10.",
38 | "EnvAdminName" : "Administrator",
39 | "EnvAdminPW" : "P@ssw0rd",
40 | "EnvTimeZone" : "Central Standard Time",
41 | "InputLocale" : "0409:00000409",
42 | "SystemLocale" : "en-us",
43 | "UILanguage" : "en-us",
44 | "UILanguageFB" : "en-us",
45 | "UserLocale" : "en-us",
46 | "VLANID" : "4",
47 | "RRASName" : "ASDLab1-RRAS",
48 | "InternetSwitchName" : "LAB - Realtek USB",
49 | "ServerVMList": [
50 | {
51 | "VMID" : "VM1",
52 | "VMName" : "RRAS",
53 | "VMOS" : "Server",
54 | "VMRoles" : "RRAS",
55 | "VMHDDSize" : "25gb",
56 | "VMIPLastOctet" : "1",
57 | "EnableSnapShot": "1",
58 | "StartupMemory" : "4gb",
59 | "ProcessorCount" : "1",
60 | "Generation" : "2",
61 | "AutoStartup" : "1"
62 | },
63 | {
64 | "VMID" : "VM2",
65 | "VMName" : "DC01",
66 | "VMOS" : "Server",
67 | "VMRoles" : "DC",
68 | "VMHDDSize" : "25gb",
69 | "VMIPLastOctet" : "10",
70 | "EnableSnapShot": "1",
71 | "StartupMemory" : "4gb",
72 | "ProcessorCount" : "1",
73 | "Generation" : "2",
74 | "AutoStartup" : "1"
75 | },
76 | {
77 | "VMID" : "VM3",
78 | "VMName" : "CA01",
79 | "VMOS" : "Server",
80 | "VMRoles" : "CA",
81 | "VMHDDSize" : "25gb",
82 | "VMIPLastOctet" : "11",
83 | "EnableSnapShot": "1",
84 | "StartupMemory" : "4gb",
85 | "ProcessorCount" : "1",
86 | "Generation" : "2",
87 | "AutoStartup" : "1"
88 | },
89 | {
90 | "VMID" : "VM4",
91 | "VMName" : "CM01",
92 | "VMOS" : "Server",
93 | "VMRoles" : "SQL,ADK,PE,CM",
94 | "VMHDDSize" : "150gb",
95 | "VMIPLastOctet" : "12",
96 | "CMSiteCode" : "PS1",
97 | "CMVersion" : "Prod",
98 | "CMPreReqPreDL" : "1",
99 | "CMPreReqPath" : "1",
100 | "EnableSnapShot": "1",
101 | "StartupMemory" : "16gb",
102 | "ProcessorCount" : "4",
103 | "Generation" : "2",
104 | "AutoStartup" : "1",
105 | "AddWSUS" : "0"
106 | }
107 | ]
108 | }
109 | ]
110 | }
--------------------------------------------------------------------------------
/Private/Invoke-LabCommand.ps1:
--------------------------------------------------------------------------------
1 | function Invoke-LabCommand {
2 | [cmdletbinding()]
3 | param (
4 |
5 | [Parameter()]
6 | [string]
7 | $MessageText,
8 |
9 | [Parameter()]
10 | [scriptblock]
11 | $ScriptBlock,
12 |
13 | [Parameter()]
14 | [string]
15 | $FilePath,
16 |
17 | [Parameter()]
18 | [Guid]
19 | $VMId,
20 |
21 | [Parameter()]
22 | [System.Object[]]
23 | $ArgumentList,
24 |
25 | [parameter()]
26 | [ValidateSet('Local','Domain')]
27 | [string]
28 | $SessionType = 'Domain',
29 |
30 | [Parameter()]
31 | [ValidateNotNullOrEmpty()]
32 | [pscredential]
33 | $LocalAdminCreds = $Script:LocalAdminCreds,
34 |
35 | [Parameter()]
36 | [ValidateNotNullOrEmpty()]
37 | [pscredential]
38 | $DomainAdminCreds = $Script:DomainAdminCreds
39 |
40 | )
41 |
42 | Write-Host "##########################" | out-null
43 | Write-Host "Started - $($MessageText)" | out-null
44 | $Result = $Null
45 |
46 | if (Test-LabConnection -Type $SessionType -VMId $VMId) {
47 | $Creds = Switch($SessionType) {
48 | "Local" {$LocalAdminCreds;break;}
49 | "Domain" {$DomainAdminCreds;break;}
50 | default {break;}
51 | }
52 |
53 | Write-Host "Invoking Remote Command" | out-null
54 | try {
55 | if ($ScriptBlock) {
56 | $Result = Invoke-Command -VMID $VMID -ScriptBlock $ScriptBlock -ArgumentList $ArgumentList -Credential $Creds
57 | }
58 | else {
59 | $Result = Invoke-Command -VMId $VMID -Credential $Creds -FilePath $FilePath
60 | }
61 | }
62 | catch {
63 | Write-Warning $_.Exception.Message | out-null
64 | break;
65 | }
66 |
67 | Write-Host "Remote Command Completed" | out-null
68 | }
69 | else {
70 | $Result = "Error"
71 | }
72 | Write-Host "Completed - $($MessageText)" | out-null
73 | return $Result
74 | }
75 |
--------------------------------------------------------------------------------
/Private/New-LabCMSQLSettingsINI.ps1:
--------------------------------------------------------------------------------
1 | function New-LabCMSQLSettingsINI {
2 | param (
3 | [Parameter()]
4 | [ValidateNotNullOrEmpty()]
5 | [string]
6 | $DomainNetBiosName,
7 |
8 | [Parameter()]
9 | [ValidateNotNullOrEmpty()]
10 | [string]
11 | $UserName,
12 |
13 | [Parameter()]
14 | [ValidateNotNullOrEmpty()]
15 | [string]
16 | $Password
17 | )
18 |
19 | $SQLHash = @{'ACTION' = '"Install"';
20 | 'SUPPRESSPRIVACYSTATEMENTNOTICE' = '"TRUE"';
21 | 'IACCEPTROPENLICENSETERMS' = '"TRUE"';
22 | 'ENU' = '"TRUE"';
23 | 'QUIET' = '"TRUE"';
24 | 'UpdateEnabled' = '"TRUE"';
25 | 'USEMICROSOFTUPDATE' = '"TRUE"';
26 | 'FEATURES' = 'SQLENGINE,RS';
27 | 'UpdateSource' = '"MU"';
28 | 'HELP' = '"FALSE"';
29 | 'INDICATEPROGRESS' = '"FALSE"';
30 | 'X86' = '"FALSE"';
31 | 'INSTANCENAME' = '"MSSQLSERVER"';
32 | 'INSTALLSHAREDDIR' = '"C:\Program Files\Microsoft SQL Server"';
33 | 'INSTALLSHAREDWOWDIR' = '"C:\Program Files (x86)\Microsoft SQL Server"';
34 | 'INSTANCEID' = '"MSSQLSERVER"';
35 | 'RSINSTALLMODE' = '"DefaultNativeMode"';
36 | 'SQLTELSVCACCT' = '"NT Service\SQLTELEMETRY"';
37 | 'SQLTELSVCSTARTUPTYPE' = '"Automatic"';
38 | 'INSTANCEDIR' = '"C:\Program Files\Microsoft SQL Server"';
39 | 'AGTSVCACCOUNT' = '"NT Service\SQLSERVERAGENT"';
40 | 'AGTSVCSTARTUPTYPE' = '"Manual"';
41 | 'COMMFABRICPORT' = '"0"';
42 | 'COMMFABRICNETWORKLEVEL' = '"0"';
43 | 'COMMFABRICENCRYPTION' = '"0"';
44 | 'MATRIXCMBRICKCOMMPORT' = '"0"';
45 | 'SQLSVCSTARTUPTYPE' = '"Automatic"';
46 | 'FILESTREAMLEVEL' = '"0"';
47 | 'ENABLERANU' = '"FALSE"';
48 | 'SQLCOLLATION' = '"SQL_Latin1_General_CP1_CI_AS"';
49 | 'SQLSVCACCOUNT' = """$($UserName)""";
50 | 'SQLSVCPASSWORD' = """$($Password)"""
51 | 'SQLSVCINSTANTFILEINIT' = '"FALSE"';
52 | 'SQLSYSADMINACCOUNTS' = """$($UserName)"" ""$($DomainNetBiosName)\Domain Users""";
53 | 'SQLTEMPDBFILECOUNT' = '"1"';
54 | 'SQLTEMPDBFILESIZE' = '"8"';
55 | 'SQLTEMPDBFILEGROWTH' = '"64"';
56 | 'SQLTEMPDBLOGFILESIZE' = '"8"';
57 | 'SQLTEMPDBLOGFILEGROWTH' = '"64"';
58 | 'ADDCURRENTUSERASSQLADMIN' = '"FALSE"';
59 | 'TCPENABLED' = '"1"';
60 | 'NPENABLED' = '"1"';
61 | 'BROWSERSVCSTARTUPTYPE' = '"Disabled"';
62 | 'RSSVCACCOUNT' = '"NT Service\ReportServer"';
63 | 'RSSVCSTARTUPTYPE' = '"Automatic"';
64 | }
65 | $SQLHASHINI = @{'OPTIONS' = $SQLHash}
66 | $SQLInstallINI = ""
67 | foreach ($i in $SQLHASHINI.keys) {
68 | $SQLInstallINI += "[$i]`r`n"
69 | foreach ($j in $($SQLHASHINI[$i].keys | Sort-Object)) {
70 | $SQLInstallINI += "$j=$($SQLHASHINI[$i][$j])`r`n"
71 | }
72 | $SQLInstallINI += "`r`n"
73 | }
74 | return $SQLInstallINI
75 | }
--------------------------------------------------------------------------------
/Private/New-LabUnattendXML.ps1:
--------------------------------------------------------------------------------
1 | function New-LabUnattendXML {
2 | [cmdletbinding()]
3 | param (
4 | [Parameter()]
5 | [hashtable]
6 | $BaseConfig,
7 |
8 | [Parameter()]
9 | [hashtable]
10 | $LabEnvConfig,
11 |
12 | [Parameter()]
13 | [ValidateNotNullOrEmpty()]
14 | [string]
15 | $AdministratorPassword = $LabEnvConfig.EnvAdminPW,
16 |
17 | [Parameter()]
18 | [ValidateNotNullOrEmpty()]
19 | [string]
20 | $TimeZone = $LabEnvConfig.EnvTimeZone,
21 |
22 | [Parameter()]
23 | [ValidateNotNullOrEmpty()]
24 | [string]
25 | $InputLocale = $LabEnvConfig.InputLocale,
26 |
27 | [Parameter()]
28 | [ValidateNotNullOrEmpty()]
29 | [string]
30 | $SystemLocale = $LabEnvConfig.SystemLocale,
31 |
32 | [Parameter()]
33 | [ValidateNotNullOrEmpty()]
34 | [string]
35 | $UILanguage = $LabEnvConfig.UILanguage,
36 |
37 | [Parameter()]
38 | [ValidateNotNullOrEmpty()]
39 | [string]
40 | $UILanguageFallback = $LabEnvConfig.UILanguageFB,
41 |
42 | [Parameter()]
43 | [ValidateNotNullOrEmpty()]
44 | [string]
45 | $UserLocale = $LabEnvConfig.UserLocale,
46 |
47 | [Parameter()]
48 | [ValidateNotNullOrEmpty()]
49 | [string]
50 | $OutputFile = "Unattend.XML",
51 |
52 | [Parameter()]
53 | [ValidateNotNullOrEmpty()]
54 | [string]
55 | $OutputPath = $BaseConfig.VMPath
56 |
57 | )
58 |
59 | New-Item -Path $OutputPath -ItemType Directory -Force
60 |
61 | $unattendTemplate = [xml]@"
62 |
63 |
64 |
65 |
66 |
67 |
68 | $($AdministratorPassword)
69 | True
70 |
71 |
72 |
73 |
74 | true
75 | true
76 |
77 | true
78 | true
79 | true
80 | 3
81 | true
82 | Work
83 | true
84 |
85 | $($TimeZone)
86 |
87 |
88 | $($InputLocale)
89 | $($SystemLocale)
90 | $($UILanguage)
91 | $($UILanguageFallback)
92 | $($UserLocale)
93 |
94 |
95 |
96 | "@
97 | $unattendTemplate.Save("$($OutputPath)\$($OutputFile)")
98 | }
--------------------------------------------------------------------------------
/Private/Test-LabConnection.ps1:
--------------------------------------------------------------------------------
1 | #https://blogs.technet.microsoft.com/virtualization/2016/10/11/waiting-for-vms-to-restart-in-a-complex-configuration-script-with-powershell-direct/
2 | function Test-LabConnection {
3 | [cmdletbinding()]
4 | param (
5 | [parameter()]
6 | [ValidateSet('Local','Domain')]
7 | [string]
8 | $Type = 'Domain',
9 |
10 | [Parameter()]
11 | [Guid]
12 | $VMId,
13 |
14 | [Parameter()]
15 | [ValidateNotNullOrEmpty()]
16 | [pscredential]
17 | $LocalAdminCreds = $Script:LocalAdminCreds,
18 |
19 | [Parameter()]
20 | [ValidateNotNullOrEmpty()]
21 | [pscredential]
22 | $DomainAdminCreds = $Script:DomainAdminCreds
23 | )
24 |
25 | $Password = ConvertTo-SecureString -String $LabEnvConfig.EnvAdminPW -AsPlainText -Force
26 | $LocalAdminCreds = new-object -typename System.Management.Automation.PSCredential($BaseConfig.LocalAdminName, $Password)
27 |
28 | $VM = Get-VM -Id $VMId
29 |
30 | $Creds = Switch($Type) {
31 | "Local" {$LocalAdminCreds; break;}
32 | "Domain" {$DomainAdminCreds; break;}
33 | default {break;}
34 | }
35 |
36 | try {
37 | if ($VM.State -eq "Off") {
38 | write-Host "VM Not Running. Starting VM."
39 | $VM | Start-VM -WarningAction SilentlyContinue
40 | }
41 |
42 | # Wait for the VM's heartbeat integration component to come up if it is enabled
43 | $heartbeatic = (Get-VMIntegrationService -VM $VM | Where-Object Id -match "84EAAE65-2F2E-45F5-9BB5-0E857DC8EB47")
44 | if ($heartbeatic -and ($heartbeatic.Enabled -eq $true)) {
45 | $startTime = Get-Date
46 | do {
47 | $timeElapsed = $(Get-Date) - $startTime
48 | if ($($timeElapsed).TotalMinutes -ge 10) {
49 | Write-Host "Integration components did not come up after 10 minutes" -MessageType Error
50 | throw
51 | }
52 | Start-Sleep -sec 1
53 | }
54 | until ($heartbeatic.PrimaryStatusDescription -eq "OK")
55 | Write-Host "Heartbeat IC connected."
56 | }
57 | do {
58 | Write-Host "Testing $($Type) Connection."
59 |
60 | $timeElapsed = $(Get-Date) - $startTime
61 | if ($($timeElapsed).TotalMinutes -ge 10) {
62 | Write-Host "Could not connect to PS Direct after 10 minutes"
63 | throw
64 | }
65 | Start-Sleep -sec 1
66 | $psReady = Invoke-Command -VMId $VM.VMId -Credential $Creds -ErrorAction SilentlyContinue -ScriptBlock { $True }
67 | if ($Type -eq 'Domain') {
68 | Invoke-Command -VMId $VM.VMId -Credential $Creds -ErrorAction SilentlyContinue -ScriptBlock {
69 | do {
70 | Write-Host "." -NoNewline -ForegroundColor Gray
71 | Start-Sleep -Seconds 5
72 | # query AD for the local computer
73 | #Get-ADComputer $env:COMPUTERNAME | Out-Null
74 | Get-WMIObject Win32_ComputerSystem | Out-Null
75 | } until ($?) # exits the loop if last call was successful
76 | Write-Host "succeeded."
77 | }
78 | }
79 | }
80 | until ($psReady)
81 | }
82 |
83 | catch {
84 | Write-Warning $_.Exception.Message
85 | break;
86 | }
87 |
88 | return $psReady
89 | }
--------------------------------------------------------------------------------
/Public/Add-LabAdditionalApps.ps1:
--------------------------------------------------------------------------------
1 | function Add-LabAdditionalApps {
2 | [cmdletbinding()]
3 | param (
4 |
5 | [Parameter()]
6 | [PSCustomObject]
7 | $VMConfig,
8 |
9 | [Parameter()]
10 | [hashtable]
11 | $BaseConfig,
12 |
13 | [Parameter()]
14 | [hashtable]
15 | $LabEnvConfig,
16 |
17 | [Parameter()]
18 | [ValidateNotNullOrEmpty()]
19 | [string]
20 | $VMName = $VMConfig.VMName,
21 |
22 | [Parameter()]
23 | [ValidateNotNullOrEmpty()]
24 | [string]
25 | $ClientDriveRoot = "c:",
26 |
27 | [Parameter()]
28 | [ValidateSet("sql-server-management-studio","vscode","snagit","postman")]
29 | [string[]]
30 | $AppList,
31 |
32 | [Parameter()]
33 | [ValidateNotNullOrEmpty()]
34 | [pscredential]
35 | $DomainAdminCreds = $BaseConfig.DomainAdminCreds,
36 |
37 | [Parameter()]
38 | [ValidateNotNullOrEmpty()]
39 | [string]
40 | $ScriptPath = $BaseConfig.VMScriptPath,
41 |
42 | [Parameter()]
43 | [ValidateNotNullOrEmpty()]
44 | [string]
45 | $LogPath = $BaseConfig.VMLogPath,
46 |
47 | [Parameter()]
48 | [ValidateNotNullOrEmpty()]
49 | [string]
50 | $LabPath = $BaseConfig.LabPath
51 |
52 | )
53 |
54 | #region Standard Setup
55 | $LabScriptPath = "$($LabPath)$($ScriptPath)\$($VMName)"
56 | $ClientScriptPath = "$($ClientDriveRoot)$($ScriptPath)"
57 |
58 | if (-not (Test-Path -Path "$($LabScriptPath)")) {
59 | New-Item -Path "$($LabScriptPath)" -ItemType Directory -ErrorAction SilentlyContinue
60 | }
61 |
62 | $LogPath = "C:$($LogPath)"
63 | $SBDefaultParams = @"
64 | param
65 | (
66 | `$_LogPath = "$($LogPath)"
67 | )
68 | "@
69 |
70 | $SBScriptTemplateBegin = {
71 | if (-not (Test-Path -Path $_LogPath -ErrorAction SilentlyContinue)) {
72 | New-Item -Path $_LogPath -ItemType Directory -ErrorAction SilentlyContinue;
73 | }
74 |
75 | $_LogFile = "$($_LogPath)\Transcript.log";
76 |
77 | Start-Transcript $_LogFile -Append -IncludeInvocationHeader | Out-Null;
78 | Write-Output "Logging to $_LogFile";
79 |
80 | #region Do Stuff Here
81 | }
82 |
83 | $SBScriptTemplateEnd = {
84 | #endregion
85 | Stop-Transcript
86 | }
87 |
88 | #endregion
89 |
90 | $_AppList = $AppList -join '","'
91 | $SBDefaultParams = @"
92 | param
93 | (
94 | `$_LogPath = "$($LogPath)",
95 | `$_AppList = @("$($_AppList)")
96 | )
97 | "@
98 |
99 | #region Script Blocks
100 | $SBInstallAdditionalApps = {
101 | Set-ExecutionPolicy Bypass -Scope Process -Force;
102 | Invoke-Expression ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))
103 | choco upgrade chocolatey -y -f
104 | ForEach($app in $_AppList) {
105 | choco install "$($app)" -y -f
106 | }
107 | }
108 |
109 | $InstallAdditionalApps += $SBDefaultParams
110 | $InstallAdditionalApps += $SBScriptTemplateBegin.ToString()
111 | $InstallAdditionalApps += $SBInstallAdditionalApps.ToString()
112 | $InstallAdditionalApps += $SBScriptTemplateEnd.ToString()
113 | $InstallAdditionalApps | Out-File "$($LabScriptPath)\InstallAdditionalApps.ps1"
114 |
115 | $Scripts = Get-Item -Path "$($LabScriptPath)\*.*"
116 |
117 | #endregion
118 |
119 | $VM = Get-VM -VM $VMName
120 | $VM | Start-VM -WarningAction SilentlyContinue
121 | start-sleep 10
122 |
123 | while (-not (Invoke-Command -VMName $VMName -Credential $DomainAdminCreds {Get-Process "LogonUI" -ErrorAction SilentlyContinue;})) {Start-Sleep -seconds 5}
124 |
125 | foreach ($Script in $Scripts) {
126 | Copy-VMFile -VM $VM -SourcePath $Script.FullName -DestinationPath "$($ClientScriptPath)\$($Script.Name)" -CreateFullPath -FileSource Host -Force
127 | }
128 |
129 | Invoke-LabCommand -FilePath "$($LabScriptPath)\InstallAdditionalApps.ps1" -MessageText "InstallAdditionalApps" -SessionType Domain -VMID $VM.VMId
130 |
131 | Write-Host "Install Additional Apps Complete!"
132 |
133 | }
--------------------------------------------------------------------------------
/Public/Add-LabRoleCA.ps1:
--------------------------------------------------------------------------------
1 | function Add-LabRoleCA {
2 | [cmdletbinding()]
3 | param (
4 |
5 | [Parameter()]
6 | [PSCustomObject]
7 | $VMConfig,
8 |
9 | [Parameter()]
10 | [hashtable]
11 | $BaseConfig,
12 |
13 | [Parameter()]
14 | [hashtable]
15 | $LabEnvConfig,
16 |
17 | [Parameter()]
18 | [ValidateNotNullOrEmpty()]
19 | [string]
20 | $VMName = $VMConfig.VMName,
21 |
22 | [Parameter()]
23 | [ValidateNotNullOrEmpty()]
24 | [string]
25 | $DomainFQDN = $LabEnvConfig.EnvFQDN,
26 |
27 | [Parameter()]
28 | [ValidateNotNullOrEmpty()]
29 | [pscredential]
30 | $DomainAdminCreds = $BaseConfig.DomainAdminCreds,
31 |
32 | [Parameter()]
33 | [ValidateNotNullOrEmpty()]
34 | [string]
35 | $ScriptPath = $BaseConfig.VMScriptPath,
36 |
37 | [Parameter()]
38 | [ValidateNotNullOrEmpty()]
39 | [string]
40 | $LogPath = $BaseConfig.VMLogPath,
41 |
42 | [Parameter()]
43 | [ValidateNotNullOrEmpty()]
44 | [string]
45 | $LabPath = $BaseConfig.LabPath
46 |
47 | )
48 |
49 | #region Standard Setup
50 | Write-Host "Starting $($MyInvocation.MyCommand)" -ForegroundColor Cyan
51 | $LabScriptPath = "$($LabPath)$($ScriptPath)\$($VMName)"
52 | $ClientScriptPath = "C:$($ScriptPath)"
53 |
54 | if (-not (Test-Path -Path "$($LabScriptPath)")) {
55 | New-Item -Path "$($LabScriptPath)" -ItemType Directory -ErrorAction SilentlyContinue
56 | }
57 |
58 | $LogPath = "C:$($LogPath)"
59 | $SBDefaultParams = @"
60 | param
61 | (
62 | `$_LogPath = "$($LogPath)"
63 | )
64 | "@
65 |
66 | $SBScriptTemplateBegin = {
67 | if (-not (Test-Path -Path $_LogPath -ErrorAction SilentlyContinue)) {
68 | New-Item -Path $_LogPath -ItemType Directory -ErrorAction SilentlyContinue;
69 | }
70 |
71 | $_LogFile = "$($_LogPath)\Transcript.log";
72 |
73 | Start-Transcript $_LogFile -Append -IncludeInvocationHeader | Out-Null;
74 | Write-Output "Logging to $_LogFile";
75 |
76 | #region Do Stuff Here
77 | }
78 |
79 | $SBScriptTemplateEnd = {
80 | #endregion
81 | Stop-Transcript
82 | }
83 |
84 | #endregion
85 |
86 | #region Script Blocks
87 | $SBInstallCA = {
88 | Add-WindowsFeature -Name Adcs-Cert-Authority -IncludeManagementTools;
89 | Install-AdcsCertificationAuthority -CAType EnterpriseRootCA -KeyLength 2048 -HashAlgorithm SHA1 -CryptoProviderName "RSA#Microsoft Software Key Storage Provider" -ValidityPeriod Years -ValidityPeriodUnits 5 -Force -confirm:$false
90 | }
91 |
92 | $InstallCA += $SBDefaultParams
93 | $InstallCA += $SBScriptTemplateBegin.ToString()
94 | $InstallCA += $SBInstallCA.ToString()
95 | $InstallCA += $SBScriptTemplateEnd.ToString()
96 | $InstallCA | Out-File "$($LabScriptPath)\InstallCA.ps1"
97 |
98 | $Scripts = Get-Item -Path "$($LabScriptPath)\*.*"
99 |
100 | #endregion
101 |
102 | $VM = Get-VM -VM $VMName
103 | $VM | Start-VM -WarningAction SilentlyContinue
104 | start-sleep 10
105 |
106 | while (-not (Invoke-Command -VMName $VMName -Credential $DomainAdminCreds {Get-Process "LogonUI" -ErrorAction SilentlyContinue;})) {Start-Sleep -seconds 5}
107 |
108 | foreach ($Script in $Scripts) {
109 | Copy-VMFile -VM $VM -SourcePath $Script.FullName -DestinationPath "C:$($ScriptPath)\$($Script.Name)" -CreateFullPath -FileSource Host -Force
110 | }
111 |
112 | Invoke-LabCommand -FilePath "$($LabScriptPath)\InstallCA.ps1" -MessageText "InstallCA" -SessionType Domain -VMID $VM.VMId
113 |
114 | #TODO Create-PKICertTemplate
115 | Write-Host "$($MyInvocation.MyCommand) Complete!" -ForegroundColor Cyan
116 | }
--------------------------------------------------------------------------------
/Public/Add-LabRoleCM.ps1:
--------------------------------------------------------------------------------
1 | function Add-LabRoleCM {
2 | [cmdletBinding()]
3 | param (
4 |
5 | [Parameter()]
6 | [PSCustomObject]
7 | $VMConfig,
8 |
9 | [Parameter()]
10 | [hashtable]
11 | $BaseConfig,
12 |
13 | [Parameter()]
14 | [hashtable]
15 | $LabEnvConfig,
16 |
17 | [Parameter()]
18 | [ValidateNotNullOrEmpty()]
19 | [string]
20 | $VMName = $VMConfig.VMName,
21 |
22 | [Parameter()]
23 | [ValidateNotNullOrEmpty()]
24 | [string]
25 | $VMWinName = $VMConfig.VMWinName,
26 |
27 | [Parameter()]
28 | [ValidateNotNullOrEmpty()]
29 | [string]
30 | $VMPath = ("$($VMConfig.VMHDPath)\$($VMConfig.VMHDName)"),
31 |
32 | [Parameter()]
33 | [ValidateNotNullOrEmpty()]
34 | [string]
35 | $VMDataPath = $BaseConfig.VMDataPath,
36 |
37 | [Parameter()]
38 | [ValidateNotNullOrEmpty()]
39 | [string]
40 | $ADKMediaPath = $BaseConfig.PathADK,
41 |
42 | [Parameter()]
43 | [ValidateNotNullOrEmpty()]
44 | [string]
45 | $ADKWinPEMediaPath = $BaseConfig.PathADKWinPE,
46 |
47 | [Parameter()]
48 | [ValidateNotNullOrEmpty()]
49 | [object[]]
50 | $PackageMediaPath = $BaseConfig.Packages,
51 |
52 | [Parameter()]
53 | [ValidateNotNullOrEmpty()]
54 | [string]
55 | $ClientDriveRoot = "c:",
56 |
57 | [Parameter()]
58 | [ValidateNotNullOrEmpty()]
59 | [string]
60 | $DomainNetBiosName = $LabEnvConfig.EnvNetBios,
61 |
62 | [Parameter()]
63 | [ValidateNotNullOrEmpty()]
64 | [string]
65 | $DomainFQDN = $LabEnvConfig.EnvFQDN,
66 |
67 | [Parameter()]
68 | [ValidateNotNullOrEmpty()]
69 | [string]
70 | $ConfigMgrSiteCode = $VMConfig.CMSiteCode,
71 |
72 | [Parameter()]
73 | [ValidateNotNullOrEmpty()]
74 | [ValidateSet("Prod","TP")]
75 | [string]
76 | $ConfigMgrVersion = $VMConfig.CMVersion,
77 |
78 | [Parameter()]
79 | [int]
80 | $ConfigMgrPrereqsPreDL = $VMConfig.CMPreReqPreDL,
81 |
82 | [Parameter()]
83 | [ValidateNotNullOrEmpty()]
84 | [pscredential]
85 | $DomainAdminCreds = $BaseConfig.DomainAdminCreds,
86 |
87 | [Parameter()]
88 | [ValidateNotNullOrEmpty()]
89 | [string]
90 | $ScriptPath = $BaseConfig.VMScriptPath,
91 |
92 | [Parameter()]
93 | [ValidateNotNullOrEmpty()]
94 | [string]
95 | $LogPath = $BaseConfig.VMLogPath,
96 |
97 | [Parameter()]
98 | [ValidateNotNullOrEmpty()]
99 | [string]
100 | $LabPath = $BaseConfig.LabPath
101 |
102 | )
103 |
104 | #region Standard Setup
105 | Write-Host "Starting $($MyInvocation.MyCommand)" -ForegroundColor Cyan
106 | $LabScriptPath = "$($LabPath)$($ScriptPath)\$($VMName)"
107 | $ClientScriptPath = "$($ClientDriveRoot)$($ScriptPath)"
108 |
109 | $ConfigMgrMediaPath = Switch($VMConfig.CMVersion) {"TP" {$BaseConfig.PathConfigMgrTP; break;} "Prod" {$BaseConfig.PathConfigMgrCB; break;}}
110 |
111 | if (-not (Test-Path -Path "$($LabScriptPath)")) {
112 | New-Item -Path "$($LabScriptPath)" -ItemType Directory -ErrorAction SilentlyContinue
113 | }
114 |
115 | $LogPath = "$($ClientDriveRoot)$($LogPath)"
116 | $SBDefaultParams = @"
117 | param
118 | (
119 | `$_LogPath = "$($LogPath)"
120 | )
121 | "@
122 |
123 | $SBScriptTemplateBegin = {
124 | if (-not (Test-Path -Path $_LogPath -ErrorAction SilentlyContinue)) {
125 | New-Item -Path $_LogPath -ItemType Directory -ErrorAction SilentlyContinue;
126 | }
127 |
128 | $_LogFile = "$($_LogPath)\Transcript.log";
129 |
130 | Start-Transcript $_LogFile -Append -IncludeInvocationHeader | Out-Null;
131 | Write-Output "Logging to $_LogFile";
132 |
133 | #region Do Stuff Here
134 | }
135 |
136 | $SBScriptTemplateEnd = {
137 | #endregion
138 | Stop-Transcript | Out-Null
139 | }
140 |
141 | #endregion
142 |
143 | #region Copy media to VM
144 | $VM = Get-VM -Name $VMName
145 | if ((Get-VM -Name $VMName).State -eq "Running") {
146 | Stop-VM -Name $VMName -WarningAction SilentlyContinue
147 | }
148 |
149 | $Disk = (Mount-VHD -Path $VMPath -Passthru | Get-Disk | Get-Partition | Where-Object {$_.type -eq 'Basic'}).DriveLetter
150 | $ConfigMgrPath = "$($disk):$($VMDataPath)\ConfigMgr"
151 | $ConfigMgrPrereqsPath = "$($disk):$($VMDataPath)\ConfigMgr\Prereqs"
152 | $ADKPath = "$($disk):$($VMDataPath)\adk"
153 | $ADKWinPEPath = "$($disk):$($VMDataPath)\adkwinpe"
154 | $PackagePath = "$($disk):$($VMDataPath)\Packages"
155 |
156 | Copy-Item -Path $ConfigMgrMediaPath -Destination $ConfigMgrPath -Recurse -ErrorAction SilentlyContinue
157 | Copy-Item -Path $ADKMediaPath -Destination $ADKPath -Recurse -ErrorAction SilentlyContinue
158 | Copy-Item -Path $ADKWinPEMediaPath -Destination $ADKWinPEPath -Recurse -ErrorAction SilentlyContinue
159 | New-Item -Path $PackagePath -ItemType Directory -Force
160 | Copy-Item -Path $PackageMediaPath -Destination $PackagePath -Recurse -ErrorAction SilentlyContinue
161 | Dismount-VHD $VMPath
162 | #endregion
163 |
164 | $ConfigMgrPath = $ConfigMgrPath -replace "$($disk):", "$($ClientDriveRoot)"
165 | $ConfigMgrPrereqsPath = $ConfigMgrPrereqsPath -replace "$($disk):", "$($ClientDriveRoot)"
166 | $ADKPath = $ADKPath -replace "$($disk):", "$($ClientDriveRoot)"
167 | $ADKWinPEPath = $ADKWinPEPath -replace "$($disk):", "$($ClientDriveRoot)"
168 | $PackagePath = $PackagePath -replace "$($disk):", "$($ClientDriveRoot)"
169 |
170 | #region Script Blocks
171 | $SBInstallSQLNativeClientParams = @"
172 | param
173 | (
174 | `$_LogPath = "$($LogPath)",
175 | `$_ConfigMgrPath = "$($ConfigMgrPath)"
176 | )
177 | "@
178 |
179 | $SBInstallSQLNativeClient = {
180 | start-process -FilePath "C:\windows\system32\msiexec.exe" -ArgumentList "/I $($_ConfigMgrPath)\Prereqs\sqlncli.msi /QN REBOOT=ReallySuppress /l*v $($ConfigMgrPath)\SQLLog.log" -Wait
181 | }
182 |
183 | $SBGetSQLSettings = {
184 | Start-Service MSSQLSERVER -ErrorAction SilentlyContinue | Out-Null
185 | [reflection.assembly]::LoadWithPartialName("Microsoft.SqlServer.Smo") | Out-Null
186 | $Settings = (new-object ('Microsoft.SqlServer.Management.Smo.Server') $env:COMPUTERNAME).Settings | Select-Object DefaultFile, Defaultlog
187 | }
188 |
189 | $SBAddFeaturesParams = @"
190 | param
191 | (
192 | `$_LogPath = "$($LogPath)",
193 | `$_PackagePath = "$($PackagePath)"
194 | )
195 | "@
196 |
197 | $SBAddFeatures = {
198 | $FeatureList = @("BITS","BITS-IIS-Ext","BITS-Compact-Server","Web-Server","Web-WebServer","Web-Common-Http","Web-Default-Doc","Web-Dir-Browsing","Web-Http-Errors","Web-Static-Content","Web-Http-Redirect","Web-App-Dev","Web-Net-Ext45","Web-ASP","Web-Asp-Net","Web-Asp-Net45","Web-CGI","Web-ISAPI-Ext","Web-ISAPI-Filter","Web-Health","Web-Http-Logging","Web-Custom-Logging","Web-Log-Libraries","Web-Request-Monitor","Web-Http-Tracing","Web-Performance","Web-Stat-Compression","Web-Security","Web-Filtering","Web-Basic-Auth","Web-IP-Security","Web-Url-Auth","Web-Windows-Auth","Web-Mgmt-Tools","Web-Mgmt-Console","Web-Mgmt-Compat","Web-Metabase","Web-Lgcy-Mgmt-Console","Web-Lgcy-Scripting","Web-WMI","Web-Scripting-Tools","Web-Mgmt-Service","RDC")
199 | foreach ($Feature in $FeatureList) {
200 | Write-Output "Adding Feature: $($Feature)"
201 | Add-WindowsFeature -Name $Feature -Source $_PackagePath
202 | }
203 | }
204 |
205 | $SBADKParams = @"
206 | param
207 | (
208 | `$_LogPath = "$($LogPath)",
209 | `$_ADKPath = "$($ADKPath)"
210 | )
211 | "@
212 | $SBADK = {
213 | $_SetupSwitches = "/Features OptionId.DeploymentTools OptionId.ImagingAndConfigurationDesigner OptionId.ICDConfigurationDesigner OptionId.UserStateMigrationTool /norestart /quiet /ceip off"
214 | Start-Process -FilePath "$($_ADKPath)\adksetup.exe" -ArgumentList $_SetupSwitches -NoNewWindow -Wait
215 | }
216 |
217 | $SBWinPEADKParams = @"
218 | param
219 | (
220 | `$_LogPath = "$($LogPath)",
221 | `$_ADKWinPEPath = "$($ADKWinPEPath)"
222 | )
223 | "@
224 | $SBWinPEADK = {
225 | $_SetupSwitches = "/Features OptionId.WindowsPreinstallationEnvironment /norestart /quiet /ceip off"
226 | Start-Process -FilePath "$($_ADKWinPEPath)\adkwinpesetup.exe" -ArgumentList $_SetupSwitches -NoNewWindow -Wait
227 | Restart-Computer -Force
228 | }
229 |
230 | $SBExtSchemaParams = @"
231 | param
232 | (
233 | `$_LogPath = "$($LogPath)",
234 | `$_ConfigMgrPath = "$($ConfigMgrPath)"
235 | )
236 | "@
237 | $SBExtSchema = {
238 | Start-Process -FilePath "$($_ConfigMgrPath)\SMSSETUP\bin\x64\extadsch.exe" -wait
239 | }
240 |
241 | $SBInstallCMParams = @"
242 | param
243 | (
244 | `$_LogPath = "$($LogPath)",
245 | `$_ConfigMgrPath = "$($ConfigMgrPath)",
246 | `$_ClientScriptPath = "$($ClientScriptPath)"
247 | )
248 | "@
249 | $SBInstallCM = {
250 | $SQLService = Get-Service -Name MSSQLSERVER -ErrorAction SilentlyContinue
251 | if ($SQLService) {
252 | $SQLService | Where-Object {$_.Status -ne 'Running'} | Start-Service
253 | Start-Process -FilePath "$($_ConfigMgrPath)\SMSSETUP\bin\x64\setup.exe" -ArgumentList "/script $($_ClientScriptPath)\CMinstall.ini" -Wait
254 | }
255 | else {
256 | Write-Output "SQL Server Not Running"
257 | }
258 | }
259 |
260 | $SBCMExtrasParams = @"
261 | param
262 | (
263 | `$_LogPath = "$($LogPath)",
264 | `$_ConfigMgrSiteCode = "$($ConfigMgrSiteCode)",
265 | `$_DomainFQDN = "$($DomainFQDN)"
266 | )
267 | "@
268 | $SBCMExtras = {
269 | import-module "$(($env:SMS_ADMIN_UI_PATH).remove(($env:SMS_ADMIN_UI_PATH).Length -4, 4))ConfigurationManager.psd1";
270 | if ($null -eq (Get-PSDrive -Name $_ConfigMgrSiteCode -PSProvider CMSite -ErrorAction SilentlyContinue)) {New-PSDrive -Name $_ConfigMgrSiteCode -PSProvider CMSite -Root $env:COMPUTERNAME}
271 | Set-Location "$((Get-PSDrive -PSProvider CMSite).name)`:";
272 | #New-CMBoundary -Type IPSubnet -Value "$($ipsub)/24" -name $Subnetname;
273 | New-CMBoundary -DisplayName "DefaultBoundary" -BoundaryType ADSite -Value "Default-First-Site-Name"
274 | New-CMBoundaryGroup -name "DefaultBoundary" -DefaultSiteCode "$((Get-PSDrive -PSProvider CMSite).name)";
275 | Add-CMBoundaryToGroup -BoundaryName "DefaultBoundary" -BoundaryGroupName "DefaultBoundary";
276 | $_Schedule = New-CMSchedule -RecurInterval Minutes -Start "2012/10/20 00:00:00" -End "2013/10/20 00:00:00" -RecurCount 10;
277 | Set-CMDiscoveryMethod -ActiveDirectorySystemDiscovery -SiteCode $_ConfigMgrSiteCode -Enabled $True -EnableDeltaDiscovery $True -PollingSchedule $_Schedule -AddActiveDirectoryContainer "LDAP://$_DomainFQDN" -Recursive;
278 | Get-CMDevice | Where-Object {$_.ADSiteName -eq "Default-First-Site-Name"} | Install-CMClient -IncludeDomainController $true -AlwaysInstallClient $true -SiteCode $_ConfigMgrSiteCode;
279 | }
280 |
281 |
282 | $InstallSQLNativeClient += $SBInstallSQLNativeClientParams
283 | $InstallSQLNativeClient += $SBScriptTemplateBegin.ToString()
284 | $InstallSQLNativeClient += $SBInstallSQLNativeClient.ToString()
285 | $InstallSQLNativeClient += $SBScriptTemplateEnd.ToString()
286 | $InstallSQLNativeClient | Out-File "$($LabScriptPath)\InstallSQLNativeClient.ps1"
287 |
288 | $GetSQLSettings += $SBDefaultParams
289 | $GetSQLSettings += $SBScriptTemplateBegin.ToString()
290 | $GetSQLSettings += $SBGetSQLSettings.ToString()
291 | $GetSQLSettings += $SBScriptTemplateEnd.ToString()
292 | $GetSQLSettings += 'Return $Settings'
293 | $GetSQLSettings | Out-File "$($LabScriptPath)\GetSQLSettings.ps1"
294 |
295 | $AddFeatures += $SBAddFeaturesParams
296 | $AddFeatures += $SBScriptTemplateBegin.ToString()
297 | $AddFeatures += $SBAddFeatures.ToString()
298 | $AddFeatures += $SBScriptTemplateEnd.ToString()
299 | $AddFeatures | Out-File "$($LabScriptPath)\AddFeatures.ps1"
300 |
301 | $ADK += $SBADKParams
302 | $ADK += $SBScriptTemplateBegin.ToString()
303 | $ADK += $SBADK.ToString()
304 | $ADK += $SBScriptTemplateEnd.ToString()
305 | $ADK | Out-File "$($LabScriptPath)\ADK.ps1"
306 |
307 | $WinPEADK += $SBWinPEADKParams
308 | $WinPEADK += $SBScriptTemplateBegin.ToString()
309 | $WinPEADK += $SBWinPEADK.ToString()
310 | $WinPEADK += $SBScriptTemplateEnd.ToString()
311 | $WinPEADK | Out-File "$($LabScriptPath)\WinPEADK.ps1"
312 |
313 | $ExtSchema += $SBExtSchemaParams
314 | $ExtSchema += $SBScriptTemplateBegin.ToString()
315 | $ExtSchema += $SBExtSchema.ToString()
316 | $ExtSchema += $SBScriptTemplateEnd.ToString()
317 | $ExtSchema | Out-File "$($LabScriptPath)\ExtSchema.ps1"
318 |
319 | $InstallCM += $SBInstallCMParams
320 | $InstallCM += $SBScriptTemplateBegin.ToString()
321 | $InstallCM += $SBInstallCM.ToString()
322 | $InstallCM += $SBScriptTemplateEnd.ToString()
323 | $InstallCM | Out-File "$($LabScriptPath)\InstallCM.ps1"
324 |
325 | $CMExtras += $SBCMExtrasParams
326 | $CMExtras += $SBScriptTemplateBegin.ToString()
327 | $CMExtras += $SBCMExtras.ToString()
328 | $CMExtras += $SBScriptTemplateEnd.ToString()
329 | $CMExtras | Out-File "$($LabScriptPath)\CMExtras.ps1"
330 |
331 | $Scripts = Get-Item -Path "$($LabScriptPath)\*.*"
332 |
333 | #endregion
334 |
335 | $VM = Get-VM -Name $VMName
336 | $VM | Start-VM -WarningAction SilentlyContinue
337 | start-sleep 10
338 |
339 | while (-not (Invoke-Command -VMName $VMName -Credential $DomainAdminCreds {Get-Process "LogonUI" -ErrorAction SilentlyContinue;})) {Start-Sleep -seconds 5}
340 |
341 | foreach ($Script in $Scripts) {
342 | Copy-VMFile -VM $VM -SourcePath $Script.FullName -DestinationPath "$($ClientScriptPath)\$($Script.Name)" -CreateFullPath -FileSource Host -Force
343 | }
344 |
345 | Invoke-LabCommand -FilePath "$($LabScriptPath)\InstallSQLNativeClient.ps1" -MessageText "InstallSQLNativeClient" -SessionType Domain -VMID $VM.VMId
346 | $SQLSettings = Invoke-LabCommand -FilePath "$($LabScriptPath)\GetSQLSettings.ps1" -MessageText "GetSQLSettings" -SessionType Domain -VMID $VM.VMId
347 |
348 | #region INIFile
349 | if ($ConfigMgrVersion -eq "Prod") {
350 | $HashIdent = @{'Action' = 'InstallPrimarySite'
351 | }
352 | $SiteName = "Current Branch $($ConfigMgrSiteCode)"
353 | }
354 | else {
355 | $HashIdent = @{
356 | 'Action' = 'InstallPrimarySite';
357 | 'Preview' = "1"
358 | }
359 | $SiteName = "Tech Preview $($ConfigMgrSiteCode)"
360 | }
361 | $HashOptions = @{
362 | 'ProductID' = 'EVAL';
363 | 'SiteCode' = "$($ConfigMgrSiteCode)";
364 | 'SiteName' = "$($SiteName)";
365 | 'SMSInstallDir' = 'C:\Program Files\Microsoft Configuration Manager';
366 | 'SDKServer' = "$($VMWinName).$($DomainFQDN)";
367 | 'RoleCommunicationProtocol' = "HTTPorHTTPS";
368 | 'ClientsUsePKICertificate' = "0";
369 | 'PrerequisiteComp' = "$($ConfigMgrPrereqsPreDL)";
370 | 'PrerequisitePath' = "$($ConfigMgrPrereqsPath)";
371 | 'ManagementPoint' = "$($VMWinName).$($DomainFQDN)";
372 | 'ManagementPointProtocol' = "HTTP";
373 | 'DistributionPoint' = "$($VMWinName).$($DomainFQDN)";
374 | 'DistributionPointProtocol' = "HTTP";
375 | 'DistributionPointInstallIIS' = "0";
376 | 'AdminConsole' = "1";
377 | 'JoinCEIP' = "0";
378 | }
379 |
380 | $hashSQL = @{
381 | 'SQLServerName' = "$($VMWinName).$($DomainFQDN)";
382 | 'SQLServerPort' = '1433';
383 | 'DatabaseName' = "CM_$($ConfigMgrSiteCode)";
384 | 'SQLSSBPort' = '4022'
385 | 'SQLDataFilePath' = "$($sqlsettings.DefaultFile)";
386 | 'SQLLogFilePath' = "$($sqlsettings.DefaultLog)"
387 | }
388 |
389 | $hashCloud = @{
390 | 'CloudConnector' = "1";
391 | 'CloudConnectorServer' = "$($VMWinName).$($DomainFQDN)"
392 | }
393 |
394 | $hashSCOpts = @{
395 | }
396 |
397 | $hashHierarchy = @{
398 |
399 | }
400 |
401 | $HASHCMInstallINI = @{
402 | 'Identification' = $hashident;
403 | 'Options' = $hashoptions;
404 | 'SQLConfigOptions' = $hashSQL;
405 | 'CloudConnectorOptions' = $hashCloud;
406 | 'SystemCenterOptions' = $hashSCOpts;
407 | 'HierarchyExpansionOption' = $hashHierarchy
408 | }
409 | $CMInstallINI = ""
410 | foreach ($i in $HASHCMInstallINI.keys) {
411 | $CMInstallINI += "[$i]`r`n"
412 | foreach ($j in $($HASHCMInstallINI[$i].keys | Sort-Object)) {
413 | $CMInstallINI += "$j=$($HASHCMInstallINI[$i][$j])`r`n"
414 | }
415 | $CMInstallINI += "`r`n"
416 | }
417 | #endregion
418 |
419 | $CreateINI += $CMInstallINI.ToString()
420 | $CreateINI | Out-File "$($LabScriptPath)\CMinstall.ini" -Force
421 | Copy-VMFile -VM $VM -SourcePath "$($LabScriptPath)\CMinstall.ini" -DestinationPath "$($ClientScriptPath)\CMinstall.ini" -CreateFullPath -FileSource Host -Force
422 |
423 | Invoke-LabCommand -FilePath "$($LabScriptPath)\AddFeatures.ps1" -MessageText "AddFeatures" -SessionType Domain -VMID $VM.VMId
424 | Start-Sleep -seconds 120
425 | Invoke-LabCommand -FilePath "$($LabScriptPath)\ADK.ps1" -MessageText "ADK" -SessionType Domain -VMID $VM.VMId
426 | Invoke-LabCommand -FilePath "$($LabScriptPath)\WinPEADK.ps1" -MessageText "WinPEADK" -SessionType Domain -VMID $VM.VMId
427 | Start-Sleep -seconds 120
428 | Invoke-LabCommand -FilePath "$($LabScriptPath)\ExtSchema.ps1" -MessageText "ExtSchema" -SessionType Domain -VMID $VM.VMId
429 | Invoke-LabCommand -FilePath "$($LabScriptPath)\InstallCM.ps1" -MessageText "InstallCM" -SessionType Domain -VMID $VM.VMId
430 | Invoke-LabCommand -FilePath "$($LabScriptPath)\CMExtras.ps1" -MessageText "CMExtras" -SessionType Domain -VMID $VM.VMId
431 |
432 | #Checkpoint-VM -VM $VM -SnapshotName "ConfigMgr Configuration Complete"
433 |
434 | Write-Host "$($MyInvocation.MyCommand) Complete!" -ForegroundColor Cyan
435 | }
--------------------------------------------------------------------------------
/Public/Add-LabRoleDC.ps1:
--------------------------------------------------------------------------------
1 | function Add-LabRoleDC {
2 | [cmdletbinding()]
3 | param (
4 |
5 | [Parameter()]
6 | [PSCustomObject]
7 | $VMConfig,
8 |
9 | [Parameter()]
10 | [hashtable]
11 | $BaseConfig,
12 |
13 | [Parameter()]
14 | [hashtable]
15 | $LabEnvConfig,
16 |
17 | [Parameter()]
18 | [ValidateNotNullOrEmpty()]
19 | [string]
20 | $VMName = $VMConfig.VMName,
21 |
22 | [Parameter()]
23 | [ValidateNotNullOrEmpty()]
24 | [string]
25 | $VMWinName = $VMConfig.VMWinName,
26 |
27 | [Parameter()]
28 | [ValidateNotNullOrEmpty()]
29 | [string]
30 | $IPAddress = $VMConfig.VMIPAddress,
31 |
32 | [Parameter()]
33 | [ValidateNotNullOrEmpty()]
34 | [string]
35 | $IPSubNet = $LabEnvConfig.EnvIPSubnet,
36 |
37 | [Parameter()]
38 | [ValidateNotNullOrEmpty()]
39 | [string]
40 | $RRASMac = $LabEnvConfig.RRASMAC,
41 |
42 | [Parameter()]
43 | [ValidateNotNullOrEmpty()]
44 | [string]
45 | $RRASName = $LabEnvConfig.RRASName,
46 |
47 | [Parameter()]
48 | [ValidateNotNullOrEmpty()]
49 | [string]
50 | $DomainFQDN = $LabEnvConfig.EnvFQDN,
51 |
52 | [Parameter()]
53 | [ValidateNotNullOrEmpty()]
54 | [pscredential]
55 | $LocalAdminCreds = $BaseConfig.LocalAdminCreds,
56 |
57 | [Parameter()]
58 | [ValidateNotNullOrEmpty()]
59 | [pscredential]
60 | $DomainAdminCreds = $BaseConfig.DomainAdminCreds,
61 |
62 | [Parameter()]
63 | [ValidateNotNullOrEmpty()]
64 | [string]
65 | $ScriptPath = $BaseConfig.VMScriptPath,
66 |
67 | [Parameter()]
68 | [ValidateNotNullOrEmpty()]
69 | [string]
70 | $LogPath = $BaseConfig.VMLogPath,
71 |
72 | [Parameter()]
73 | [ValidateNotNullOrEmpty()]
74 | [string]
75 | $LabPath = $BaseConfig.LabPath
76 |
77 | )
78 |
79 | #region Standard Setup
80 | Write-Host "Starting $($MyInvocation.MyCommand)" -ForegroundColor Cyan
81 | $LabScriptPath = "$($LabPath)$($ScriptPath)\$($VMName)"
82 | $ClientScriptPath = "C:$($ScriptPath)"
83 |
84 | if (-not (Test-Path -Path "$($LabScriptPath)")) {
85 | New-Item -Path "$($LabScriptPath)" -ItemType Directory -ErrorAction SilentlyContinue
86 | }
87 |
88 | $LogPath = "C:$($LogPath)"
89 | $SBDefaultParams = @"
90 | param
91 | (
92 | `$_LogPath = "$($LogPath)"
93 | )
94 | "@
95 |
96 | $SBScriptTemplateBegin = {
97 | if (-not (Test-Path -Path $_LogPath -ErrorAction SilentlyContinue)) {
98 | New-Item -Path $_LogPath -ItemType Directory -ErrorAction SilentlyContinue;
99 | }
100 |
101 | $_LogFile = "$($_LogPath)\Transcript.log";
102 |
103 | Start-Transcript $_LogFile -Append -IncludeInvocationHeader;
104 | Write-Output "Logging to $_LogFile";
105 |
106 | #region Do Stuff Here
107 | }
108 |
109 | $SBScriptTemplateEnd = {
110 | #endregion
111 | Stop-Transcript
112 | }
113 |
114 | #endregion
115 |
116 | #region Script Blocks
117 | $SBSetDCIPParams = @"
118 | param
119 | (
120 | `$_LogPath = "$($LogPath)",
121 | `$_IPAddress = "$($IPAddress)",
122 | `$_DefaultGateway = "$($IPSubNet)1",
123 | `$_InterfaceID = (Get-NetAdapter).InterfaceIndex,
124 | `$_DNSAddress = ('127.0.0.1')
125 | )
126 | "@
127 |
128 | $SBSetDCIP = {
129 | New-NetIPAddress -InterfaceIndex $_InterfaceID -AddressFamily IPv4 -IPAddress $_IPAddress -PrefixLength 24 -DefaultGateway $_DefaultGateway;
130 | Set-DnsClientServerAddress -ServerAddresses $_DNSAddress -InterfaceIndex $_InterfaceID;
131 | #Restart-Computer -Force;
132 | }
133 |
134 | $SBAddDCFeatures = {
135 | Install-WindowsFeature -Name DHCP, DNS, AD-Domain-Services -IncludeManagementTools;
136 | }
137 |
138 | $SBDCPromoParams = @"
139 | param
140 | (
141 | `$_LogPath = "$($LogPath)",
142 | `$_FQDN = "$($DomainFQDN)",
143 | `$_DomainAdminName = "$($LabEnvConfig.EnvNetBios)\Administrator",
144 | `$_DomainAdminPassword = "$($LabEnvConfig.EnvAdminPW)"
145 | )
146 | "@
147 |
148 | $SBDCPromo = {
149 | $_Password = ConvertTo-SecureString -String $_DomainAdminPassword -AsPlainText -Force
150 | $_Creds = new-object -typename System.Management.Automation.PSCredential($_DomainAdminName,$_Password)
151 | Install-ADDSForest -DomainName $_FQDN -SafeModeAdministratorPassword $_Creds.Password -confirm:$false -WarningAction SilentlyContinue;
152 | }
153 |
154 | $SBConfigureDHCPParams = @"
155 | param
156 | (
157 | `$_LogPath = "$($LogPath)",
158 | `$_DomainFQDN = "$($DomainFQDN)",
159 | `$_ServerName = "$($VMWinName)",
160 | `$_IPAddress = "$($IPAddress)",
161 | `$_IPSubnet = "$($IPSubnet)",
162 | [ipaddress]`$_ScopeID = "$($IPSubnet)0",
163 | `$_RRASMAC = "$($RRASMAC)"
164 | )
165 | "@
166 |
167 | $SBConfigureDHCP = {
168 | & netsh dhcp add securitygroups;
169 | Restart-Service dhcpserver;
170 | Restart-Service dhcpserver;
171 | start-sleep -seconds 60
172 | Add-DhcpServerInDC # -DnsName "$($_ServerName).$($_DomainFQDN)" -IPAddress $_IPAddress;
173 | Set-ItemProperty -Path registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\ServerManager\Roles\12 -Name ConfigurationState -Value 2;
174 | Add-DhcpServerv4Scope -name $_DomainFQDN -StartRange "$($_IPSubnet)100" -EndRange "$($_IPSubnet)150" -SubnetMask "255.255.255.0";
175 | Set-DhcpServerv4OptionValue -Router "$($_IPSubnet)`1" -DNSDomain $_DomainFQDN -DNSServer $_IPAddress -ScopeId $_ScopeID
176 | Add-DhcpServerv4Reservation -IPAddress "$($_IPSubnet)`1" -ClientId $_RRASMAC -ScopeId "$($_IPSubnet)0" -Name "RRAS"
177 | }
178 |
179 | $SBCreateDCLabDomain = {
180 | Import-Module ActiveDirectory;
181 | $root = (Get-ADRootDSE).defaultNamingContext;
182 | if (-not ([adsi]::Exists("LDAP://CN=System Management,CN=System,$root"))) {
183 | $null = New-ADObject -Type Container -name "System Management" -Path "CN=System,$root" -Passthru
184 | };
185 | $acl = get-acl "ad:CN=System Management,CN=System,$root";
186 | New-ADGroup -name "SCCM Servers" -groupscope Global;
187 | $objGroup = Get-ADGroup -filter {Name -eq "SCCM Servers"};
188 | $All = [System.DirectoryServices.ActiveDirectorySecurityInheritance]::SelfAndChildren;
189 | $ace = New-Object System.DirectoryServices.ActiveDirectoryAccessRule $objGroup.SID, "GenericAll", "Allow", $All;
190 | $acl.AddAccessRule($ace);
191 | Set-acl -aclobject $acl "ad:CN=System Management,CN=System,$root"
192 | }
193 |
194 | $SetDCIP += $SBSetDCIPParams
195 | $SetDCIP += $SBScriptTemplateBegin.ToString()
196 | $SetDCIP += $SBSetDCIP.ToString()
197 | $SetDCIP += $SBScriptTemplateEnd.ToString()
198 | $SetDCIP | Out-File "$($LabScriptPath)\SetDCIP.ps1"
199 |
200 | $AddDCFeatures += $SBDefaultParams
201 | $AddDCFeatures += $SBScriptTemplateBegin.ToString()
202 | $AddDCFeatures += $SBAddDCFeatures.ToString()
203 | $AddDCFeatures += $SBScriptTemplateEnd.ToString()
204 | $AddDCFeatures | Out-File "$($LabScriptPath)\AddDCFeatures.ps1"
205 |
206 | $DCPromo += $SBDCPromoParams
207 | $DCPromo += $SBScriptTemplateBegin.ToString()
208 | $DCPromo += $SBDCPromo.ToString()
209 | $DCPromo += $SBScriptTemplateEnd.ToString()
210 | $DCPromo | Out-File "$($LabScriptPath)\DCPromo.ps1"
211 |
212 | $ConfigureDHCP += $SBConfigureDHCPParams
213 | $ConfigureDHCP += $SBScriptTemplateBegin.ToString()
214 | $ConfigureDHCP += $SBConfigureDHCP.ToString()
215 | $ConfigureDHCP += $SBScriptTemplateEnd.ToString()
216 | $ConfigureDHCP | Out-File "$($LabScriptPath)\ConfigureDHCP.ps1"
217 |
218 | $CreateDCLabDomain += $SBDefaultParams
219 | $CreateDCLabDomain += $SBScriptTemplateBegin.ToString()
220 | $CreateDCLabDomain += $SBCreateDCLabDomain.ToString()
221 | $CreateDCLabDomain += $SBScriptTemplateEnd.ToString()
222 | $CreateDCLabDomain | Out-File "$($LabScriptPath)\CreateDCLabDomain.ps1"
223 |
224 | $Scripts = Get-Item -Path "$($LabScriptPath)\*.*"
225 |
226 | #endregion
227 |
228 | $VM = Get-VM -VM $VMName
229 | $VM | Start-VM -WarningAction SilentlyContinue
230 | start-sleep 10
231 |
232 | while (-not (Invoke-Command -VMName $VMName -Credential $LocalAdminCreds {Get-Process "LogonUI" -ErrorAction SilentlyContinue;})) {Start-Sleep -seconds 5}
233 |
234 | foreach ($Script in $Scripts) {
235 | Copy-VMFile -VM $VM -SourcePath $Script.FullName -DestinationPath "C:$($ScriptPath)\$($Script.Name)" -CreateFullPath -FileSource Host -Force
236 | }
237 |
238 | Invoke-LabCommand -FilePath "$($LabScriptPath)\SetDCIP.ps1" -MessageText "SetDCIP" -SessionType Local -VMID $VM.VMId
239 | $VM | Stop-VM -Force -WarningAction SilentlyContinue
240 | Invoke-LabCommand -FilePath "$($LabScriptPath)\AddDCFeatures.ps1" -MessageText "AddDCFeatures" -SessionType Local -VMID $VM.VMId
241 | Invoke-LabCommand -FilePath "$($LabScriptPath)\DCPromo.ps1" -MessageText "DCPromo" -SessionType Local -VMID $VM.VMId
242 | #Checkpoint-VM -VM $VM -SnapshotName "DC Promo Complete"
243 | #endregion
244 | start-sleep -seconds 360
245 | while (-not (Invoke-Command -VMName $VMName -Credential $DomainAdminCreds {Get-Process "LogonUI" -ErrorAction SilentlyContinue;})) {Start-Sleep -seconds 5}
246 | while ((Invoke-Command -VMName $VM.VMName -Credential $DomainAdminCreds {(get-command get-adgroup).count} -ErrorAction Continue) -ne 1) {Start-Sleep -Seconds 5}
247 | Invoke-LabCommand -FilePath "$($LabScriptPath)\ConfigureDHCP.ps1" -MessageText "ConfigureDHCP" -SessionType Domain -VMID $VM.VMId
248 | #Checkpoint-VM -VM $VM -SnapshotName "DHCP Configured"
249 |
250 | while ((Invoke-Command -VMName $VM.VMName -Credential $DomainAdminCreds {(get-command get-adgroup).count} -ErrorAction Continue) -ne 1) {Start-Sleep -Seconds 5}
251 | Invoke-LabCommand -FilePath "$($LabScriptPath)\CreateDCLabDomain.ps1" -MessageText "CreateDCLabDomain" -SessionType Domain -VMID $VM.VMId
252 |
253 | $VM | Stop-VM -Force -WarningAction SilentlyContinue
254 | Get-VM -VM $RRASName | Restart-VM -Force -ErrorAction SilentlyContinue
255 | $VM | Start-VM -WarningAction SilentlyContinue
256 | start-sleep -seconds 120
257 |
258 | Write-Host "$($MyInvocation.MyCommand) Complete!" -ForegroundColor Cyan
259 | }
--------------------------------------------------------------------------------
/Public/Add-LabRoleRRAS.ps1:
--------------------------------------------------------------------------------
1 | function Add-LabRoleRRAS {
2 | [cmdletbinding()]
3 | param (
4 |
5 | [Parameter()]
6 | [PSCustomObject]
7 | $VMConfig,
8 |
9 | [Parameter()]
10 | [hashtable]
11 | $BaseConfig,
12 |
13 | [Parameter()]
14 | [hashtable]
15 | $LabEnvConfig,
16 |
17 | [Parameter()]
18 | [ValidateNotNullOrEmpty()]
19 | [string]
20 | $VMName = $VMConfig.VMName,
21 |
22 | [Parameter()]
23 | [ValidateNotNullOrEmpty()]
24 | [string]
25 | $InternetSwitchName = $LabEnvConfig.InternetSwitchName,
26 |
27 | [Parameter()]
28 | [ValidateNotNullOrEmpty()]
29 | [string]
30 | $DomainFQDN = $LabEnvConfig.EnvFQDN,
31 |
32 | [Parameter()]
33 | [ValidateNotNullOrEmpty()]
34 | [pscredential]
35 | $DomainAdminCreds = $BaseConfig.DomainAdminCreds,
36 |
37 | [Parameter()]
38 | [ValidateNotNullOrEmpty()]
39 | [string]
40 | $ScriptPath = $BaseConfig.VMScriptPath,
41 |
42 | [Parameter()]
43 | [ValidateNotNullOrEmpty()]
44 | [string]
45 | $LogPath = $BaseConfig.VMLogPath,
46 |
47 | [Parameter()]
48 | [ValidateNotNullOrEmpty()]
49 | [string]
50 | $LabPath = $BaseConfig.LabPath
51 |
52 | )
53 |
54 | #region Standard Setup
55 | Write-Host "Starting $($MyInvocation.MyCommand)" -ForegroundColor Cyan
56 | $LabScriptPath = "$($LabPath)$($ScriptPath)\$($VMName)"
57 | $ClientScriptPath = "C:$($ScriptPath)"
58 |
59 | if (-not (Test-Path -Path "$($LabScriptPath)")) {
60 | New-Item -Path "$($LabScriptPath)" -ItemType Directory -ErrorAction SilentlyContinue
61 | }
62 |
63 | $LogPath = "C:$($LogPath)"
64 | $SBDefaultParams = @"
65 | param
66 | (
67 | `$_LogPath = "$($LogPath)"
68 | )
69 | "@
70 |
71 | $SBScriptTemplateBegin = {
72 | if (-not (Test-Path -Path $_LogPath -ErrorAction SilentlyContinue)) {
73 | New-Item -Path $_LogPath -ItemType Directory -ErrorAction SilentlyContinue;
74 | }
75 |
76 | $_LogFile = "$($_LogPath)\Transcript.log";
77 |
78 | Start-Transcript $_LogFile -Append -IncludeInvocationHeader | Out-Null;
79 | Write-Output "Logging to $_LogFile";
80 |
81 | #region Do Stuff Here
82 | }
83 |
84 | $SBScriptTemplateEnd = {
85 | #endregion
86 | Stop-Transcript
87 | }
88 |
89 | #endregion
90 |
91 | #region Script Blocks
92 | $SBInstallRRAS = {
93 | Install-WindowsFeature Routing,RSAT-RemoteAccess-Mgmt -IncludeManagementTools
94 | Get-NetAdapter -Physical -Name "Ethernet" | Rename-NetAdapter -newname "External"
95 | Install-RemoteAccess -VpnType RoutingOnly
96 | netsh routing ip nat install
97 | netsh routing ip nat add interface "External"
98 | netsh routing ip nat set interface "External" mode=full
99 | Set-LocalUser -Name "Administrator" -PasswordNeverExpires 1
100 | Set-ItemProperty -Path Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\ServerManager -Name DoNotOpenServerManagerAtLogon -Type DWord -Value 1 -Force
101 | Set-ItemProperty -Path Registry::HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\RemoteAccess\Parameters -Name ModernStackEnabled -Value 0 -Type DWord -Force
102 | }
103 |
104 | $InstallRRAS += $SBDefaultParams
105 | $InstallRRAS += $SBScriptTemplateBegin.ToString()
106 | $InstallRRAS += $SBInstallRRAS.ToString()
107 | $InstallRRAS += $SBScriptTemplateEnd.ToString()
108 | $InstallRRAS | Out-File "$($LabScriptPath)\InstallRRAS.ps1"
109 |
110 | $Scripts = Get-Item -Path "$($LabScriptPath)\*.*"
111 |
112 | #endregion
113 |
114 | $VM = Get-VM -VM $VMName
115 | $VM | Start-VM -WarningAction SilentlyContinue
116 | start-sleep 10
117 |
118 | while (-not (Invoke-Command -VMName $VMName -Credential $DomainAdminCreds {Get-Process "LogonUI" -ErrorAction SilentlyContinue;})) {Start-Sleep -seconds 5}
119 |
120 | foreach ($Script in $Scripts) {
121 | Copy-VMFile -VM $VM -SourcePath $Script.FullName -DestinationPath "$($ClientScriptPath)\$($Script.Name)" -CreateFullPath -FileSource Host -Force
122 | }
123 |
124 | $Adapter = Get-VMNetworkAdapter -VMName $VMName
125 | $Adapter | Connect-VMNetworkAdapter -SwitchName $InternetSwitchName
126 | $Adapter | Set-VMNetworkAdapter -DeviceNaming On
127 | $Adapter | Set-VMNetworkAdapterVlan -Untagged
128 | $Adapter | Rename-VMNetworkAdapter -NewName "Internet"
129 |
130 | Invoke-LabCommand -FilePath "$($LabScriptPath)\InstallRRAS.ps1" -MessageText "InstallRRAS" -SessionType Local -VMID $VM.VMId
131 |
132 | Write-Host "$($MyInvocation.MyCommand) Complete!" -ForegroundColor Cyan
133 | }
--------------------------------------------------------------------------------
/Public/Add-LabRoleSQL.ps1:
--------------------------------------------------------------------------------
1 | function Add-LabRoleSQL {
2 | [cmdletBinding()]
3 | param (
4 |
5 | [Parameter()]
6 | [PSCustomObject]
7 | $VMConfig,
8 |
9 | [Parameter()]
10 | [hashtable]
11 | $BaseConfig,
12 |
13 | [Parameter()]
14 | [hashtable]
15 | $LabEnvConfig,
16 |
17 | [Parameter()]
18 | [ValidateNotNullOrEmpty()]
19 | [string]
20 | $VMName = $VMConfig.VMName,
21 |
22 | [Parameter()]
23 | [ValidateNotNullOrEmpty()]
24 | [string]
25 | $SQLISO = $BaseConfig.SQLISO,
26 |
27 | [Parameter()]
28 | [string]
29 | $AddWSUS = $VMConfig.AddWSUS,
30 |
31 | [Parameter()]
32 | [ValidateNotNullOrEmpty()]
33 | [string]
34 | $VMDataPath = $BaseConfig.VMDataPath,
35 |
36 | [Parameter()]
37 | [ValidateNotNullOrEmpty()]
38 | [pscredential]
39 | $DomainAdminCreds = $BaseConfig.DomainAdminCreds,
40 |
41 | [Parameter()]
42 | [ValidateNotNullOrEmpty()]
43 | [string]
44 | $ScriptPath = $BaseConfig.VMScriptPath,
45 |
46 | [Parameter()]
47 | [ValidateNotNullOrEmpty()]
48 | [string]
49 | $LogPath = $BaseConfig.VMLogPath,
50 |
51 | [Parameter()]
52 | [ValidateNotNullOrEmpty()]
53 | [string]
54 | $LabPath = $BaseConfig.LabPath
55 |
56 | )
57 |
58 | #region Standard Setup
59 | Write-Host "Starting $($MyInvocation.MyCommand)" -ForegroundColor Cyan
60 | $LabScriptPath = "$($LabPath)$($ScriptPath)\$($VMName)"
61 | $ClientScriptPath = "C:$($ScriptPath)"
62 |
63 | if (-not (Test-Path -Path "$($LabScriptPath)")) {
64 | New-Item -Path "$($LabScriptPath)" -ItemType Directory -ErrorAction SilentlyContinue
65 | }
66 |
67 | $LogPath = "C:$($LogPath)"
68 | $SBDefaultParams = @"
69 | param
70 | (
71 | `$_LogPath = "$($LogPath)"
72 | )
73 | "@
74 |
75 | $SBScriptTemplateBegin = {
76 | if (-not (Test-Path -Path $_LogPath -ErrorAction SilentlyContinue)) {
77 | New-Item -Path $_LogPath -ItemType Directory -ErrorAction SilentlyContinue;
78 | }
79 |
80 | $_LogFile = "$($_LogPath)\Transcript.log";
81 |
82 | Start-Transcript $_LogFile -Append -IncludeInvocationHeader | Out-Null;
83 | Write-Output "Logging to $_LogFile";
84 |
85 | #region Do Stuff Here
86 | }
87 |
88 | $SBScriptTemplateEnd = {
89 | #endregion
90 | Stop-Transcript
91 | }
92 |
93 | #endregion
94 |
95 | Get-VMDvdDrive -VMName $VMName
96 | Add-VMDvdDrive -VMName $VMName -ControllerNumber 0 -ControllerLocation 1
97 | Set-VMDvdDrive -Path $SQLISO -VMName $VMName -ControllerNumber 0 -ControllerLocation 1
98 |
99 | $SQLInstallINI = New-LabCMSQLSettingsINI -DomainNetBiosName $LabEnvConfig.EnvFQDN -UserName $BaseConfig.DomainAdminName -Password $LabEnvConfig.EnvAdminPW
100 |
101 | #region Script Blocks
102 | $SBSQLInstallCmdParams = @"
103 | param (
104 | `$_LogPath = "$($LogPath)",
105 | `$_ClientScriptPath = "$($ClientScriptPath)"
106 | )
107 | "@
108 |
109 | $SBSQLInstallCmd = {
110 | $_SQLDisk = (Get-PSDrive -PSProvider FileSystem | where-object {$_.name -ne "c"}).root
111 | Start-Process -FilePath "$($_SQLDisk)Setup.exe" -Wait -ArgumentList "/ConfigurationFile=$($_ClientScriptPath)\ConfigurationFile.INI /IACCEPTSQLSERVERLICENSETERMS"
112 | }
113 |
114 | $SBSQLMemory = {
115 | [reflection.assembly]::LoadWithPartialName("Microsoft.SqlServer.Smo") | Out-Null
116 | $srv = New-Object Microsoft.SQLServer.Management.Smo.Server($env:COMPUTERNAME)
117 | if ($srv.status) {
118 | $srv.Configuration.MaxServerMemory.ConfigValue = 8kb
119 | $srv.Configuration.MinServerMemory.ConfigValue = 4kb
120 | $srv.Configuration.Alter()
121 | }
122 | }
123 |
124 | $SBAddWSUS = {
125 | Add-WindowsFeature UpdateServices-Services, UpdateServices-db
126 | }
127 |
128 | $SBWSUSPostInstall = {
129 | Start-Process -filepath "C:\Program Files\Update Services\Tools\WsusUtil.exe" -ArgumentList "postinstall CONTENT_DIR=C:\WSUS SQL_INSTANCE_NAME=$env:COMPUTERNAME" -Wait
130 | }
131 |
132 | $SQLIni += $SQLInstallINI.ToString()
133 | $SQLIni | Out-File "$($LabScriptPath)\ConfigurationFile.INI" -Force
134 |
135 | $SQLInstallCmd += $SBSQLInstallCmdParams
136 | $SQLInstallCmd += $SBScriptTemplateBegin.ToString()
137 | $SQLInstallCmd += $SBSQLInstallCmd.ToString()
138 | $SQLInstallCmd += $SBScriptTemplateEnd.ToString()
139 | $SQLInstallCmd | Out-File "$($LabScriptPath)\SQLInstallCmd.ps1"
140 |
141 | $SQLMemory += $SBDefaultParams
142 | $SQLMemory += $SBScriptTemplateBegin.ToString()
143 | $SQLMemory += $SBSQLMemory.ToString()
144 | $SQLMemory += $SBScriptTemplateEnd.ToString()
145 | $SQLMemory | Out-File "$($LabScriptPath)\SQLMemory.ps1"
146 |
147 | $AddWSUS += $SBDefaultParams
148 | $AddWSUS += $SBScriptTemplateBegin.ToString()
149 | $AddWSUS += $SBAddWSUS.ToString()
150 | $AddWSUS += $SBScriptTemplateEnd.ToString()
151 | $AddWSUS | Out-File "$($LabScriptPath)\AddWSUS.ps1"
152 |
153 | $WSUSPostInstall += $SBDefaultParams
154 | $WSUSPostInstall += $SBScriptTemplateBegin.ToString()
155 | $WSUSPostInstall += $SBWSUSPostInstall.ToString()
156 | $WSUSPostInstall += $SBScriptTemplateEnd.ToString()
157 | $WSUSPostInstall | Out-File "$($LabScriptPath)\WSUSPostInstall.ps1"
158 |
159 | $Scripts = Get-Item -Path "$($LabScriptPath)\*.*"
160 |
161 | #endregion
162 |
163 | $VM = Get-VM -Name $VMName
164 | $VM | Start-VM -WarningAction SilentlyContinue
165 | start-sleep 10
166 |
167 | while (-not (Invoke-Command -VMName $VMName -Credential $DomainAdminCreds {Get-Process "LogonUI" -ErrorAction SilentlyContinue;})) {Start-Sleep -seconds 5}
168 |
169 | foreach ($Script in $Scripts) {
170 | Copy-VMFile -VM $VM -SourcePath $Script.FullName -DestinationPath "$($ClientScriptPath)\$($Script.Name)" -CreateFullPath -FileSource Host -Force
171 | }
172 |
173 | #Invoke-LabCommand -FilePath "$($LabScriptPath)\SQLIni.ps1" -MessageText "SQLIni" -SessionType Domain -VMID $VM.VMId
174 | Invoke-LabCommand -FilePath "$($LabScriptPath)\SQLInstallCmd.ps1" -MessageText "SQLInstallCmd" -SessionType Domain -VMID $VM.VMId
175 | Invoke-LabCommand -FilePath "$($LabScriptPath)\SQLMemory.ps1" -MessageText "SQLMemory" -SessionType Domain -VMID $VM.VMId
176 | if($AddWSUS = 1) {
177 | Invoke-LabCommand -FilePath "$($LabScriptPath)\AddWSUS.ps1" -MessageText "AddWSUS" -SessionType Domain -VMID $VM.VMId
178 | Invoke-LabCommand -FilePath "$($LabScriptPath)\WSUSPostInstall.ps1" -MessageText "WSUSPostInstall" -SessionType Domain -VMID $VM.VMId
179 | }
180 | Set-VMDvdDrive -VMName $VMName -Path $null
181 |
182 | Write-Host "$($MyInvocation.MyCommand) Complete!" -ForegroundColor Cyan
183 | }
--------------------------------------------------------------------------------
/Public/Get-LabConfig.ps1:
--------------------------------------------------------------------------------
1 | function Get-LabConfig {
2 | [cmdletBinding()]
3 | [OutputType([PSCustomObject])]
4 | param (
5 | [Parameter()]
6 | [ValidateNotNullOrEmpty()]
7 | [ValidateScript({ Test-Path $(Resolve-Path $_) })]
8 | [string]
9 | $ConfigFileName,
10 |
11 | [Parameter()]
12 | [switch]
13 | $CreateFolders
14 | )
15 |
16 | Write-Host "Starting $($MyInvocation.MyCommand)" -ForegroundColor Cyan
17 |
18 | $RawConfig = Get-Content $ConfigFileName -Raw | ConvertFrom-Json
19 | $RawENVConfig = $RawConfig.ENVConfig | Where-Object {$_.ENV -eq $RawConfig.ENVToBuild}
20 | $RawSvrRefConfig = $RawConfig.ServerRef
21 | $RawWksRefConfig = $RawConfig.WorkstationRef
22 |
23 | $BaseConfig = @{}
24 | $LabEnvConfig = @{}
25 | $ServerRefConfig = @{}
26 | $WorkstationRefConfig = @{}
27 |
28 | ($RawConfig | Select-Object -Property * -ExcludeProperty "ENVConfig", "VMList", "ServerRef", "WorkstationRef").psobject.properties | foreach-Object {$BaseConfig[$_.Name] = $_.Value}
29 | ($RawENVConfig | Select-Object -Property * -ExcludeProperty "ServerVMList", "WorkstationVMList").psobject.properties | foreach-Object {$LabEnvConfig[$_.Name] = $_.Value}
30 |
31 | foreach ($Img in $RawSvrRefConfig) {
32 | ($Img).psobject.properties | foreach-Object {$ServerRefConfig[$_.Name] = $_.Value}
33 | }
34 |
35 | foreach ($Img in $RawWksRefConfig) {
36 | ($Img).psobject.properties | foreach-Object {$WorkstationRefConfig[$_.Name] = $_.Value}
37 | }
38 |
39 | $BaseConfig["ConfigMgrCBPrereqsPath"] = "$($BaseConfig.PathConfigMgr)\Prereqs"
40 | $BaseConfig["ConfigMgrTPPrereqsPath"] = "$($BaseConfig.PathConfigMgrTP)\Prereqs"
41 |
42 | foreach ($key in @($BaseConfig.keys)) {
43 | If ($key -like "Path*")
44 | {
45 | $BaseConfig[$key] = $BaseConfig.SourcePath + $BaseConfig[$key]
46 | if ($CreateFolders) {
47 | if (-not (Test-Path -path $BaseConfig[$key])) {New-Item -path $BaseConfig[$key] -ItemType Directory;}
48 | }
49 | }
50 | }
51 |
52 | $BaseConfig["VMPath"] = Join-Path -Path $BaseConfig.LabPath -ChildPath $BaseConfig.ENVToBuild
53 | $BaseConfig["SQLISO"] = Get-ChildItem -Path $BaseConfig.PathSQL -Filter "*.ISO" | Select-Object -First 1 -ExpandProperty FullName
54 | $BaseConfig["SvrISO"] = Get-ChildItem -Path $BaseConfig.PathSvr -Filter "*.ISO" | Select-Object -First 1 -ExpandProperty FullName
55 | $BaseConfig["WinISO"] = Get-ChildItem -Path $BaseConfig.PathWin10 -Filter "*.ISO" | Select-Object -First 1 -ExpandProperty FullName
56 | $BaseConfig["Packages"] = Get-ChildItem -Path $BaseConfig.PathPackages -Filter "*.CAB" | Select-Object -ExpandProperty FullName
57 | $BaseConfig["Drivers"] = Get-ChildItem -Path $BaseConfig.PathDrivers -Filter "*.*" | Select-Object -ExpandProperty FullName
58 | $BaseConfig["SvrVHDX"] = Get-ChildItem -Path $BaseConfig.PathRefImage | Where-Object {$_.Name -eq $ServerRefConfig.RefVHDXName} | Select-Object -ExpandProperty FullName
59 | $BaseConfig["WksVHDX"] = Get-ChildItem -Path $BaseConfig.PathRefImage | Where-Object {$_.Name -eq $WorkstationRefConfig.RefVHDXName} | Select-Object -ExpandProperty FullName
60 |
61 | $BaseConfig["LocalAdminName"] = ".\$($LabEnvConfig.EnvAdminName)"
62 | $BaseConfig["LocalAdminPassword"] = ConvertTo-SecureString -String $LabEnvConfig.EnvAdminPW -AsPlainText -Force
63 | $BaseConfig["LocalAdminCreds"] = new-object -typename System.Management.Automation.PSCredential($BaseConfig.LocalAdminName, $BaseConfig.LocalAdminPassword)
64 |
65 | $BaseConfig["DomainAdminName"] = "$($LabEnvConfig.EnvNetBios)\$($LabEnvConfig.EnvAdminName)"
66 | $BaseConfig["DomainAdminPassword"] = ConvertTo-SecureString -String $LabEnvConfig.EnvAdminPW -AsPlainText -Force
67 | $BaseConfig["DomainAdminCreds"] = new-object -typename System.Management.Automation.PSCredential($BaseConfig.DomainAdminName,$BaseConfig.DomainAdminPassword)
68 |
69 | $ServerVMs = $RawENVConfig.ServerVMList | ForEach-Object {
70 | $VMConfig = [PSCustomObject]@{}
71 | ($_[0]).psobject.properties | foreach-Object {$VMConfig | Add-Member -NotePropertyName $_.Name -NotePropertyValue $_.Value -ErrorAction SilentlyContinue}
72 | $VMConfig | Add-Member -NotePropertyName "SvrVHDX" -NotePropertyValue $Null -ErrorAction SilentlyContinue
73 | $VMConfig | Add-Member -NotePropertyName "VMIPAddress" -NotePropertyValue $Null -ErrorAction SilentlyContinue
74 | $VMConfig | Add-Member -NotePropertyName "VMWinName" -NotePropertyValue $Null -ErrorAction SilentlyContinue
75 | $VMConfig | Add-Member -NotePropertyName "VMName" -NotePropertyValue $Null -ErrorAction SilentlyContinue
76 | $VMConfig | Add-Member -NotePropertyName "VMHDPath" -NotePropertyValue $Null -ErrorAction SilentlyContinue
77 | $VMConfig | Add-Member -NotePropertyName "VMHDName" -NotePropertyValue $Null -ErrorAction SilentlyContinue
78 | $VMConfig | Add-Member -NotePropertyName "EnableSnapshot" -NotePropertyValue $Null -ErrorAction SilentlyContinue
79 | $VMConfig | Add-Member -NotePropertyName "AutoStartup" -NotePropertyValue $Null -ErrorAction SilentlyContinue
80 | $VMConfig | Add-Member -NotePropertyName "StartupMemory" -NotePropertyValue $Null -ErrorAction SilentlyContinue
81 |
82 | $VMConfig.SvrVHDX = $BaseConfig.SvrVHDX
83 | $VMConfig.VMIPAddress = "$($LabEnvConfig.EnvIPSubnet)$($_.VMIPLastOctet)"
84 | $VMConfig.VMWinName = "$($_.VMName)"
85 | $VMConfig.VMName = "$($LabEnvConfig.Env)-$($_.VMName)"
86 | $VMConfig.VMHDPath = "$($BaseConfig.VMPath)\$($VMConfig.VMName)\Virtual Hard Disks"
87 | $VMConfig.VMHDName = "$($VMConfig.VMName)c.vhdx"
88 | $VMConfig.EnableSnapshot = if ($_.EnableSnapshot -eq 1) {$true} else {$false}
89 | $VMConfig.AutoStartup = if ($_.AutoStartup -eq 1) {$true} else {$false}
90 | $VMConfig.StartupMemory = [int64]$_.StartupMemory.Replace('gb','') * 1GB
91 | $VMConfig
92 | }
93 |
94 | #TODO
95 | <#
96 | $WksVMs = $RawENVConfig.WorkstationVMList | ForEach-Object {
97 | $VMConfig = [PSCustomObject]@{}
98 | ($_[0]).psobject.properties | foreach-Object {$VMConfig | Add-Member -NotePropertyName $_.Name -NotePropertyValue $_.Value -ErrorAction SilentlyContinue}
99 | $VMConfig | Add-Member -NotePropertyName "WksVHDX" -NotePropertyValue $Null -ErrorAction SilentlyContinue
100 | $VMConfig | Add-Member -NotePropertyName "VMIPAddress" -NotePropertyValue $Null -ErrorAction SilentlyContinue
101 | $VMConfig | Add-Member -NotePropertyName "VMWinName" -NotePropertyValue $Null -ErrorAction SilentlyContinue
102 | $VMConfig | Add-Member -NotePropertyName "VMName" -NotePropertyValue $Null -ErrorAction SilentlyContinue
103 | $VMConfig | Add-Member -NotePropertyName "VMHDPath" -NotePropertyValue $Null -ErrorAction SilentlyContinue
104 | $VMConfig | Add-Member -NotePropertyName "VMHDName" -NotePropertyValue $Null -ErrorAction SilentlyContinue
105 | $VMConfig | Add-Member -NotePropertyName "EnableSnapshot" -NotePropertyValue $Null -ErrorAction SilentlyContinue
106 | $VMConfig | Add-Member -NotePropertyName "AutoStartup" -NotePropertyValue $Null -ErrorAction SilentlyContinue
107 | $VMConfig | Add-Member -NotePropertyName "StartupMemory" -NotePropertyValue $Null -ErrorAction SilentlyContinue
108 |
109 | $VMConfig.SvrVHDX = $BaseConfig.SvrVHDX
110 | $VMConfig.VMIPAddress = "$($LabEnvConfig.EnvIPSubnet)$($_.VMIPLastOctet)"
111 | $VMConfig.VMWinName = "$($_.VMName)"
112 | $VMConfig.VMName = "$($LabEnvConfig.Env)-$($_.VMName)"
113 | $VMConfig.VMHDPath = "$($BaseConfig.VMPath)\$($_.VMName)\Virtual Hard Disks"
114 | $VMConfig.VMHDName = "$($_.VMName)c.vhdx"
115 | $VMConfig.EnableSnapshot = if ($_.EnableSnapshot -eq 1) {$true} else {$false}
116 | $VMConfig.AutoStartup = if ($_.AutoStartup -eq 1) {$true} else {$false}
117 | $VMConfig.StartupMemory = [int64]$_.StartupMemory.Replace('gb','') * 1GB
118 | $VMConfig
119 | }
120 |
121 |
122 | $VMs = Get-VM
123 | $VLans = foreach ($VM in $VMs) {
124 | $VM | Get-VMNetworkAdapterVlan | Select -ExpandProperty AccessVlanId
125 | }
126 |
127 | $LabEnvConfig["VLanID"] = if ($VLans) {
128 | ($VLans | Measure-Object -Maximum).Maximum + 1
129 | }
130 | else {
131 | 1
132 | }
133 | #>
134 |
135 | #Setting these to avoiding needing to pass in creds with each lab connection test
136 | $Script:LocalAdminCreds = $BaseConfig.LocalAdminCreds
137 | $Script:DomainAdminCreds = $BaseConfig.DomainAdminCreds
138 |
139 | $Config = @{}
140 | $Config["BaseConfig"] = $BaseConfig
141 | $Config.BaseConfig["ServerRef"] = $ServerRefConfig
142 | $Config.BaseConfig["WorkstationRef"] = $WorkstationRefConfig
143 |
144 | $Config["LabEnvConfig"] = $LabEnvConfig
145 | $Config.LabEnvConfig["ServerVMs"] = $ServerVMs
146 | $Config.LabEnvConfig["WorkstationVMs"] = $WorkstationVMs
147 | return $Config
148 | }
--------------------------------------------------------------------------------
/Public/Join-LabDomain.ps1:
--------------------------------------------------------------------------------
1 | function Join-LabDomain {
2 | [cmdletbinding()]
3 | param (
4 |
5 | [Parameter()]
6 | [PSCustomObject]
7 | $VMConfig,
8 |
9 | [Parameter()]
10 | [hashtable]
11 | $BaseConfig,
12 |
13 | [Parameter()]
14 | [hashtable]
15 | $LabEnvConfig,
16 |
17 | [Parameter()]
18 | [ValidateNotNullOrEmpty()]
19 | [string]
20 | $VMName = $VMConfig.VMName,
21 |
22 | [Parameter()]
23 | [ValidateNotNullOrEmpty()]
24 | [string]
25 | $DomainFQDN = $LabEnvConfig.EnvFQDN,
26 |
27 | [Parameter()]
28 | [ValidateNotNullOrEmpty()]
29 | [pscredential]
30 | $LocalAdminCreds = $BaseConfig.LocalAdminCreds,
31 |
32 | [Parameter()]
33 | [ValidateNotNullOrEmpty()]
34 | [string]
35 | $ScriptPath = $BaseConfig.VMScriptPath,
36 |
37 | [Parameter()]
38 | [ValidateNotNullOrEmpty()]
39 | [string]
40 | $LogPath = $BaseConfig.VMLogPath,
41 |
42 | [Parameter()]
43 | [ValidateNotNullOrEmpty()]
44 | [string]
45 | $LabPath = $BaseConfig.LabPath,
46 |
47 | [Parameter()]
48 | [ValidateNotNullOrEmpty()]
49 | [string]
50 | $DomainAdminName = "$($LabEnvConfig.EnvNetBios)\Administrator",
51 |
52 | [Parameter()]
53 | [ValidateNotNullOrEmpty()]
54 | [string]
55 | $DomainAdminPassword = $LabEnvConfig.EnvAdminPW
56 |
57 | )
58 |
59 | #region Standard Setup
60 | Write-Host "Starting $($MyInvocation.MyCommand)" -ForegroundColor Cyan
61 | $LabScriptPath = "$($LabPath)$($ScriptPath)\$($VMName)"
62 | $ClientScriptPath = "C:$($ScriptPath)"
63 |
64 | if (-not (Test-Path -Path "$($LabScriptPath)")) {
65 | New-Item -Path "$($LabScriptPath)" -ItemType Directory -ErrorAction SilentlyContinue
66 | }
67 |
68 | $LogPath = "C:$($LogPath)"
69 | $SBDefaultParams = @"
70 | param
71 | (
72 | `$_LogPath = "$($LogPath)"
73 | )
74 | "@
75 |
76 | $SBScriptTemplateBegin = {
77 | if (-not (Test-Path -Path $_LogPath -ErrorAction SilentlyContinue)) {
78 | New-Item -Path $_LogPath -ItemType Directory -ErrorAction SilentlyContinue;
79 | }
80 |
81 | $_LogFile = "$($_LogPath)\Transcript.log";
82 |
83 | Start-Transcript $_LogFile -Append -IncludeInvocationHeader | Out-Null;
84 | Write-Output "Logging to $_LogFile";
85 |
86 | #region Do Stuff Here
87 | }
88 |
89 | $SBScriptTemplateEnd = {
90 | #endregion
91 | Stop-Transcript
92 | }
93 |
94 | #endregion
95 |
96 | #region Script Blocks
97 | $SBJoinDomainParams = @"
98 | param
99 | (
100 | `$_LogPath = "$($LogPath)",
101 | `$_FQDN = "$($DomainFQDN)",
102 | `$_DomainAdminName = "$($DomainAdminName)",
103 | `$_DomainAdminPassword = "$($DomainAdminPassword)"
104 | )
105 | "@
106 |
107 | $SBJoinDomain = {
108 | $_Password = ConvertTo-SecureString -String $_DomainAdminPassword -AsPlainText -Force
109 | $_Creds = new-object -typename System.Management.Automation.PSCredential($_DomainAdminName,$_Password)
110 | Add-Computer -Credential $_Creds -DomainName $_FQDN -Restart
111 | $DomainJoined = (((Get-ComputerInfo).CsDomainRole -eq "PrimaryDomainController") -or (Test-ComputerSecureChannel -ErrorAction SilentlyContinue))
112 | Return $DomainJoined
113 | }
114 |
115 | $JoinDomain += $SBJoinDomainParams
116 | $JoinDomain += $SBScriptTemplateBegin.ToString()
117 | $JoinDomain += $SBJoinDomain.ToString()
118 | $JoinDomain += $SBScriptTemplateEnd.ToString()
119 | $JoinDomain | Out-File "$($LabScriptPath)\JoinDomain.ps1"
120 |
121 | $Scripts = Get-Item -Path "$($LabScriptPath)\*.*"
122 |
123 | #endregion
124 |
125 | $VM = Get-VM -VM $VMName
126 | $VM | Start-VM -WarningAction SilentlyContinue
127 | start-sleep 20
128 |
129 | $DomainJoined = $False
130 | while (-not (Invoke-Command -VMName $VMName -Credential $LocalAdminCreds {Get-Process "LogonUI" -ErrorAction SilentlyContinue;})) {Start-Sleep -seconds 5}
131 | do {
132 | foreach ($Script in $Scripts) {
133 | Copy-VMFile -VM $VM -SourcePath $Script.FullName -DestinationPath "C:$($ScriptPath)\$($Script.Name)" -CreateFullPath -FileSource Host -Force
134 | }
135 | $DomainJoined = Invoke-LabCommand -FilePath "$($LabScriptPath)\JoinDomain.ps1" -MessageText "JoinDomain" -SessionType Local -VMID $VM.VMId
136 | } until ($DomainJoined)
137 |
138 | Start-Sleep -Seconds 60
139 | Write-Host "$($MyInvocation.MyCommand) Complete!" -ForegroundColor Cyan
140 | }
--------------------------------------------------------------------------------
/Public/New-LabEnv.ps1:
--------------------------------------------------------------------------------
1 | #TODO Add params to this function to allow customizing what we need. CreateVHDX, CreateFolders, ETC, ReUseSwitch
2 | function New-LabEnv {
3 | [cmdletbinding()]
4 | param (
5 | [Parameter()]
6 | [String]
7 | $ConfigFileName
8 | )
9 |
10 | $OriginalPref = $ProgressPreference # Default is 'Continue'
11 | $ProgressPreference = "SilentlyContinue"
12 |
13 | try {
14 | Write-Host "Starting Lab Build" -ForegroundColor Yellow
15 |
16 | $ModulePath = $script:PSCommandPath
17 | $Config = Get-LabConfig -ConfigFileName $ConfigFileName -CreateFolders
18 |
19 | if ($Config.BaseConfig.ServerRef.RefVHDXName -and -not $Config.BaseConfig.SvrVHDX) {
20 | New-LabUnattendXML -BaseConfig $Config.BaseConfig -LabEnvConfig $Config.LabEnvConfig
21 | $Config.BaseConfig.SvrVHDX = New-LabRefVHDX -BuildType Server -BaseConfig $Config.BaseConfig
22 | }
23 | if ($Config.BaseConfig.WorkstationRef.RefVHDXName -and -not $Base.WksVHDX) {
24 | New-LabUnattendXML -BaseConfig $Config.BaseConfig -LabEnvConfig $Config.LabEnvConfig
25 | $Config.BaseConfig.WksVHDX = New-LabRefVHDX -BuildType Workstation -BaseConfig $Config.BaseConfig
26 | }
27 |
28 | New-LabSwitch -LabEnvConfig $Config.LabEnvConfig
29 |
30 | Write-Host "Starting Batch Job to Create VMs." -ForegroundColor Cyan
31 | Write-Host " - No status will be returned while VMs are being created. Please wait." -ForegroundColor Cyan
32 | Write-Host " - Logs can be viewed in $($BaseConfig.LabPath)$($BaseConfig.VMScriptPath)\\.log" -ForegroundColor Cyan
33 | $Job = $Config.LabEnvConfig.ServerVMs | ForEach-Object -AsJob -ThrottleLimit 5 -Parallel {
34 | Import-Module $using:ModulePath -Force
35 | Write-Host "Creating New VM: $($_.VMName)" -ForegroundColor Cyan
36 | $ConfigSplat = @{
37 | VMConfig = $_
38 | BaseConfig = $Using:Config.BaseConfig
39 | LabEnvConfig = $Using:Config.LabEnvConfig
40 | }
41 |
42 | New-LabVM @ConfigSplat | Out-Null
43 | }
44 |
45 | $job | Wait-Job | Receive-Job
46 |
47 | foreach ($VM in $Config.LabEnvConfig.ServerVMs) {
48 | Write-Host "Installing Roles for: $($VM.VMName)"
49 | $VMRoles = $VM.VMRoles.Split(",")
50 | foreach($role in $VMRoles) {
51 | $ConfigSplat = @{
52 | VMConfig = $VM
53 | BaseConfig = $Config.BaseConfig
54 | LabEnvConfig = $Config.LabEnvConfig
55 | }
56 |
57 | Write-Host " - Found Role $($role) for $($VM.VMName)" -ForegroundColor Cyan
58 | Switch($role) {
59 | "RRAS" {
60 | Add-LabRoleRRAS @ConfigSplat
61 | break
62 | }
63 | "DC" {
64 | Update-LabRRAS @ConfigSplat
65 | Add-LabRoleDC @ConfigSplat
66 | break
67 | }
68 | "CA" {
69 | Join-LabDomain @ConfigSplat
70 | Add-LabRoleCA @ConfigSplat
71 | Break
72 | }
73 | "SQL" {
74 | Join-LabDomain @ConfigSplat
75 | Add-LabRoleSQL @ConfigSplat
76 | Add-LabAdditionalApps @ConfigSplat -AppList @("sql-server-management-studio")
77 | Break
78 | }
79 | "CM" {
80 | Join-LabDomain @ConfigSplat
81 | Add-LabRoleCM @ConfigSplat
82 | Add-LabAdditionalApps @ConfigSplat -AppList @("sql-server-management-studio","vscode","snagit")
83 | Break
84 | }
85 | Default {Write-Host "No Role Found"; Break;}
86 | }
87 | }
88 | }
89 |
90 | <#
91 | foreach ($VM in $Script:WksVMs) {
92 | $Script:VMConfig = @{}
93 | ($VM[0]).psobject.properties | foreach-Object {$VMConfig[$_.Name] = $_.Value}
94 | $VMConfig["WksVHDX"] = $Config.BaseConfig["WksVHDX"]
95 | $VMConfig["VMIPAddress"] = "$($Config.LabEnvConfig["EnvIPSubnet"])$($script:VMConfig.VMIPLastOctet)"
96 | $VMConfig["VMWinName"] = "$($script:VMConfig.VMName)"
97 | $VMConfig["VMName"] = "$($Config.LabEnvConfig.Env)-$($script:VMConfig.VMName)"
98 | $VMConfig["VMHDPath"] = "$($Config.BaseConfig.VMPath)\$($script:VMConfig.VMName)\Virtual Hard Disks"
99 | $VMConfig["VMHDName"] = "$($script:VMConfig.VMName)c.vhdx"
100 | $VMConfig["EnableSnapshot"] = if ($Script:VMConfig.EnableSnapshot -eq 1) {$true} else {$false}
101 | $VMConfig["AutoStartup"] = if ($Script:VMConfig.AutoStartup -eq 1) {$true} else {$false}
102 | $VMConfig["StartupMemory"] = [int64]$Script:VMConfig.StartupMemory.Replace('gb','') * 1GB
103 |
104 | Write-Host $VM.VMName
105 | New-LabVM
106 | }
107 | #>
108 |
109 | Write-Host "New lab build Finished." -ForegroundColor Cyan
110 | (Get-date).DateTime
111 |
112 | }
113 | catch {
114 |
115 | }
116 | finally {
117 | $ProgressPreference = $OriginalPref
118 | }
119 |
120 | }
--------------------------------------------------------------------------------
/Public/New-LabRefVHDX.ps1:
--------------------------------------------------------------------------------
1 | function New-LabRefVHDX {
2 | [cmdletbinding()]
3 | param (
4 |
5 | [Parameter()]
6 | [hashtable]
7 | $BaseConfig,
8 |
9 | [Parameter()]
10 | [ValidateNotNullOrEmpty()]
11 | [ValidateSet("Server","Workstation")]
12 | [string]
13 | $BuildType="Server"
14 |
15 | )
16 |
17 | Write-Host "Starting $($MyInvocation.MyCommand)" -ForegroundColor Cyan
18 |
19 | $params = Switch($BuildType) {
20 | "Server" {
21 | @{
22 | SourcePath = switch($BaseConfig.ServerRef.RefSrcType)
23 | {
24 | "ISO" {$BaseConfig.SvrISO; break;}
25 | "WIM" {$BaseConfig.SvrWim;break;}
26 | default {$BaseConfig.SvrISO;break;}
27 | }
28 | Edition = $BaseConfig.ServerRef.RefIndex
29 | VhdPath = Join-Path -Path $BaseConfig.PathRefImage -ChildPath $BaseConfig.ServerRef.RefVHDXName
30 | SizeBytes = [uint64]($BaseConfig.ServerRef.RefHVDSize/1)
31 | UnattendPath = Join-Path -Path $BaseConfig.VMPath -ChildPath "Unattend.xml"
32 | VhdType = "Dynamic"
33 | VhdFormat = "VHDX"
34 | DiskLayout = "UEFI"
35 | Feature = if (-not ([string]::IsNullOrEmpty($BaseConfig.ServerRef.RefFeature))) {$BaseConfig.ServerRef.RefFeature} else {$null}
36 | }
37 | }
38 | "Workstation" {
39 | @{
40 | SourcePath = switch($BaseConfig.WorkstationRef.RefSrcType)
41 | {
42 | "ISO" {$BaseConfig.WksISO; break;}
43 | "WIM" {$BaseConfig.WksWim;break;}
44 | default {$BaseConfig.WksISO;break;}
45 | }
46 | Edition = $BaseConfig.WorkstationRef.RefIndex
47 | VhdPath = Join-Path -Path $BaseConfig.PathRefImage -ChildPath $BaseConfig.ServerRef.RefVHDXName
48 | SizeBytes = [uint64]($BaseConfig.WorkstationRef.RefHVDSize/1)
49 | UnattendPath = Join-Path -Path $BaseConfig.VMPath -ChildPath "Unattend.xml"
50 | VhdType = "Dynamic"
51 | VhdFormat = "VHDX"
52 | DiskLayout = "UEFI"
53 | Feature = if (-not ([string]::IsNullOrEmpty($BaseConfig.WorkstationRef.RefFeature))) {$BaseConfig.WorkstationRef.RefFeature} else {$null}
54 | }
55 | }
56 | default {$null; break;}
57 | }
58 |
59 | if (-not (Test-Path -Path $params.VhdPath -ErrorAction SilentlyContinue)) {
60 | $module = Get-Module -ListAvailable -Name 'Hyper-ConvertImage'
61 | if ($module.count -lt 1) {
62 | Install-Module -Name 'Hyper-ConvertImage'
63 | $module = Get-Module -ListAvailable -Name 'Hyper-ConvertImage'
64 | }
65 | #Hyper-ConvertImage doesn't play nice with PowerShell 7 so we need to force it to use Powershell 5 with the -UseWindowsPowerShell parameter
66 | if ($PSVersionTable.PSVersion.Major -eq 7) {
67 | Import-Module -Name (Split-Path $module.ModuleBase -Parent) -UseWindowsPowerShell -ErrorAction SilentlyContinue 3>$null
68 | }
69 | else {
70 | Import-Module -Name 'Hyper-ConvertImage'
71 | }
72 | Convert-WindowsImage @Params
73 | }
74 |
75 | if(Test-Path $params.VhdPath) {
76 | Write-Host "$($MyInvocation.MyCommand) Complete!" -ForegroundColor Cyan
77 | Return $params.VhdPath
78 | }
79 | else {
80 | Throw "Failed to create VHDX."
81 | }
82 | }
83 |
84 |
--------------------------------------------------------------------------------
/Public/New-LabSwitch.ps1:
--------------------------------------------------------------------------------
1 | function New-LabSwitch {
2 | [cmdletbinding()]
3 | Param
4 | (
5 |
6 | [Parameter()]
7 | [hashtable]
8 | $LabEnvConfig,
9 |
10 | [Parameter()]
11 | [String]
12 | $SwitchName = $LabEnvConfig.EnvSwitchName,
13 |
14 | [Parameter()]
15 | [String]
16 | $IPSubnet = $LabEnvConfig.EnvIPSubnet,
17 |
18 | [Parameter()]
19 | [String]
20 | $RRASName = $LabEnvConfig.RRASName,
21 |
22 | [Parameter()]
23 | [Switch]
24 | $RemoveExisting
25 |
26 | )
27 |
28 | Write-Host "Starting $($MyInvocation.MyCommand)" -ForegroundColor Cyan
29 |
30 | $ExistingSwitch = Get-VMSwitch -Name $SwitchName -ErrorAction SilentlyContinue
31 | if (-not $ExistingSwitch) {
32 | New-VMSwitch -Name $SwitchName -SwitchType Internal | Out-Null
33 | }
34 |
35 | Write-Host "$($MyInvocation.MyCommand) Complete!" -ForegroundColor Cyan
36 | }
--------------------------------------------------------------------------------
/Public/New-LabVM.ps1:
--------------------------------------------------------------------------------
1 |
2 | function New-LabVM {
3 | [cmdletbinding()]
4 | param (
5 |
6 | [Parameter()]
7 | [PSCustomObject]
8 | $VMConfig,
9 |
10 | [Parameter()]
11 | [hashtable]
12 | $BaseConfig,
13 |
14 | [Parameter()]
15 | [hashtable]
16 | $LabEnvConfig,
17 |
18 | [Parameter()]
19 | [ValidateNotNullOrEmpty()]
20 | [string]
21 | $ENVName = $LabEnvConfig.Env,
22 |
23 | [Parameter()]
24 | [ValidateNotNullOrEmpty()]
25 | [string]
26 | $VMName = $VMConfig.VMName,
27 |
28 | [Parameter()]
29 | [ValidateNotNullOrEmpty()]
30 | [string]
31 | $VMWinName = $VMConfig.VMWinName,
32 |
33 | [Parameter()]
34 | [ValidateNotNullOrEmpty()]
35 | [string]
36 | $ReferenceVHDX = $BaseConfig.SvrVHDX,
37 |
38 | [Parameter()]
39 | [ValidateNotNullOrEmpty()]
40 | [string]
41 | $VMPath = $BaseConfig.VMPath,
42 |
43 | [Parameter()]
44 | [ValidateNotNullOrEmpty()]
45 | [string]
46 | $VMHDPath = $VMConfig.VMHDPath,
47 |
48 | [Parameter()]
49 | [ValidateNotNullOrEmpty()]
50 | [string]
51 | $VMHDName = $VMConfig.VMHDName,
52 |
53 | [Parameter()]
54 | [UInt64]
55 | [ValidateNotNullOrEmpty()]
56 | [ValidateRange(512MB, 64TB)]
57 | $StartupMemory = ($VMConfig.StartupMemory /1),
58 |
59 | [Parameter()]
60 | [UInt64]
61 | $HDDSize = ($VMConfig.VMHDDSize / 1),
62 |
63 | [Parameter()]
64 | [int]
65 | $ProcessorCount = $VMConfig.ProcessorCount,
66 |
67 | [ValidateNotNullOrEmpty()]
68 | [int]
69 | $Generation = $VMConfig.Generation,
70 |
71 | [Parameter()]
72 | [switch]
73 | $EnableSnapshot = $VMConfig.EnableSnapshot,
74 |
75 | [Parameter()]
76 | [switch]
77 | $StartUp = $VMConfig.AutoStartup,
78 |
79 | [Parameter()]
80 | [string]
81 | $DomainName = $LabEnvConfig.EnvFQDN,
82 |
83 | [Parameter()]
84 | [ValidateNotNullOrEmpty()]
85 | [string]
86 | $IPAddress = $VMConfig.IPAddress,
87 |
88 | [Parameter()]
89 | [ValidateNotNullOrEmpty()]
90 | [string]
91 | $SwitchName = $LabEnvConfig.EnvSwitchName,
92 |
93 | [Parameter()]
94 | [ValidateNotNullOrEmpty()]
95 | [int]
96 | $VLanID = $LabEnvConfig.VLanID,
97 |
98 | [Parameter()]
99 | [pscredential]
100 | $LocalAdminCreds = $BaseConfig.LocalAdminCreds,
101 |
102 | [Parameter()]
103 | [ValidateNotNullOrEmpty()]
104 | [string]
105 | $ScriptPath = $BaseConfig.VMScriptPath,
106 |
107 | [Parameter()]
108 | [ValidateNotNullOrEmpty()]
109 | [string]
110 | $LogPath = $BaseConfig.VMLogPath,
111 |
112 | [Parameter()]
113 | [ValidateNotNullOrEmpty()]
114 | [string]
115 | $LabPath = $BaseConfig.LabPath
116 |
117 | )
118 |
119 | #Setting these to avoiding needing to pass in creds with each lab connection test
120 | $Script:LocalAdminCreds = $BaseConfig.LocalAdminCreds
121 | $Script:DomainAdminCreds = $BaseConfig.DomainAdminCreds
122 |
123 | #region Standard Setup
124 | $LabScriptPath = "$($LabPath)$($ScriptPath)\$($VMName)"
125 | $ClientScriptPath = "$($ClientDriveRoot)$($ScriptPath)"
126 | if (-not (Test-Path -Path "$($LabScriptPath)")) {
127 | New-Item -Path "$($LabScriptPath)" -ItemType Directory -ErrorAction SilentlyContinue
128 | }
129 |
130 | Start-Transcript -Path "$($LabScriptPath)\$($VMName).log" -Force -ErrorAction SilentlyContinue | Out-Null
131 | Write-Host "Starting $($MyInvocation.MyCommand)" -ForegroundColor Cyan
132 | Write-Host "BaseConfig: $($BaseConfig)"
133 | Write-Host "ReferenceVHDX: $($ReferenceVHDX)"
134 |
135 | $LogPath = "$($ClientDriveRoot)$($LogPath)"
136 | $SBDefaultParams = @"
137 | param
138 | (
139 | `$_LogPath = "$($LogPath)"
140 | )
141 | "@
142 |
143 | $SBScriptTemplateBegin = {
144 | if (-not (Test-Path -Path $_LogPath -ErrorAction SilentlyContinue)) {
145 | New-Item -Path $_LogPath -ItemType Directory -ErrorAction SilentlyContinue;
146 | }
147 |
148 | $_LogFile = "$($_LogPath)\Transcript.log";
149 |
150 | Start-Transcript $_LogFile -Append -IncludeInvocationHeader | Out-Null;
151 | Write-Output "Logging to $_LogFile";
152 |
153 | #region Do Stuff Here
154 | }
155 |
156 | $SBScriptTemplateEnd = {
157 | #endregion
158 | Stop-Transcript | Out-Null
159 | }
160 |
161 | #endregion
162 |
163 | #$Password = ConvertTo-SecureString -String $LabEnvConfig.EnvAdminPW -AsPlainText -Force
164 | #$LocalAdminCreds = new-object -typename System.Management.Automation.PSCredential($BaseConfig.LocalAdminName, $Password)
165 |
166 | if (Get-VM -Name $VMName -ErrorAction SilentlyContinue) {
167 | Write-Host "VM Already Exists. Skipping Creating VM."
168 | }
169 | else {
170 | #region Script Blocks
171 |
172 | $SBResizeRenameComputerParams = @"
173 | param
174 | (
175 | `$_LogPath = "$($LogPath)",
176 | `$_VMWinName = "$($VMWinName)"
177 | )
178 | "@
179 | $SBResizeRenameComputer = {
180 | #Disable IE Enhanced Security and UAC
181 | $AdminKey = "HKLM:\SOFTWARE\Microsoft\Active Setup\Installed Components\{A509B1A7-37EF-4b3f-8CFC-4F3A74704073}"
182 | $UserKey = "HKLM:\SOFTWARE\Microsoft\Active Setup\Installed Components\{A509B1A8-37EF-4b3f-8CFC-4F3A74704073}"
183 | Set-ItemProperty -Path $AdminKey -Name "IsInstalled" -Value 0
184 | Set-ItemProperty -Path $UserKey -Name "IsInstalled" -Value 0
185 | Stop-Process -Name Explorer -Erroraction SilentlyContinue
186 | Write-Host "IE Enhanced Security Configuration (ESC) has been disabled."
187 | Set-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System" -Name "ConsentPromptBehaviorAdmin" -Value 00000000
188 | Set-ItemProperty -Path Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\ServerManager -Name DoNotOpenServerManagerAtLogon -Type DWord -Value 1 -Force
189 | Write-Host "User Access Control (UAC) has been disabled."
190 |
191 | $MaxSize = (Get-PartitionSupportedSize -DriveLetter c).SizeMax
192 | $CurrentSize = (Get-Disk).AllocatedSize
193 | if($CurrentSize -lt $MaxSize) {
194 | Resize-Partition -DriveLetter c -Size $MaxSize
195 | }
196 | Rename-Computer -NewName "$($_VMWinName)";
197 | }
198 |
199 | $ResizeRenameComputer += $SBResizeRenameComputerParams
200 | $ResizeRenameComputer += $SBScriptTemplateBegin.ToString()
201 | $ResizeRenameComputer += $SBResizeRenameComputer.ToString()
202 | $ResizeRenameComputer += $SBScriptTemplateEnd.ToString()
203 | $ResizeRenameComputer | Out-File "$($LabScriptPath)\ResizeRenameComputer.ps1"
204 | $Scripts = Get-Item -Path "$($LabScriptPath)\*.*" -Exclude "*.log"
205 | #endregion
206 |
207 | if (-not (Test-Path "$($VMHDPath)\$($VMHDName)" -ErrorAction SilentlyContinue)) {
208 | New-Item -Path $VMHDPath -ItemType Directory
209 | Copy-Item -Path $ReferenceVHDX -Destination "$($VMHDPath)\$($VMHDName)"
210 | }
211 |
212 | $VM = Get-VM -Name $VMName -ErrorAction SilentlyContinue
213 | if (-not $VM) {
214 | $VM = New-VM -Name $VMName -MemoryStartupBytes $StartupMemory -VHDPath "$($VMHDPath)\$($VMHDName)" -Generation $Generation -Path $VMPath
215 | if ($EnableSnapshot) {
216 | Set-VM -VM $VM -checkpointtype Production -AutomaticCheckpointsEnabled $False
217 | }
218 | }
219 |
220 | if(-not $HDDSize) {$HDDSize = 150gb /1 }
221 | if(($VM.VMId | Get-VHD).Size -lt $HDDSize ) {
222 | Resize-VHD -Path "$($VMHDPath)\$($VMHDName)" -SizeBytes $HDDSize
223 | }
224 | Enable-VMIntegrationService -VMName $VMName -Name "Guest Service Interface"
225 | Set-VM -name $VMName -checkpointtype Disabled -ProcessorCount $ProcessorCount
226 | $Adapter = Get-VMNetworkAdapter -VMName $VMName
227 | $Adapter | Connect-VMNetworkAdapter -SwitchName $SwitchName
228 | $Adapter | Set-VMNetworkAdapterVlan -VlanId $VLanID -Access
229 |
230 | if ($VM.State -eq "Off") {
231 | write-Host "VM Not Running. Starting VM."
232 | Start-VM -Name $VMName -WarningAction SilentlyContinue
233 | Start-Sleep -Seconds 120
234 | }
235 |
236 | Write-Host $LabEnvConfig.EnvAdminPW
237 | Write-Host $BaseConfig.LocalAdminName
238 |
239 | while (-not (Invoke-Command -VMName $VMName -Credential $LocalAdminCreds {Get-Process "LogonUI" -ErrorAction SilentlyContinue;})) {Start-Sleep -seconds 5}
240 | foreach ($Script in $Scripts) {
241 | Copy-VMFile -VM $VM -SourcePath $Script.FullName -DestinationPath "$($ClientScriptPath)\$($Script.Name)" -CreateFullPath -FileSource Host -Force
242 | }
243 |
244 | Invoke-LabCommand -FilePath "$($LabScriptPath)\ResizeRenameComputer.ps1" -MessageText "ResizeRenameComputer" -SessionType Local -VMID $VM.VMId
245 | $VMName | Restart-VM -Force -ErrorAction SilentlyContinue
246 | start-sleep -Seconds 120
247 | }
248 | Write-Host "$($MyInvocation.MyCommand) Complete!" -ForegroundColor Cyan
249 |
250 | Stop-Transcript | Out-Null
251 | }
--------------------------------------------------------------------------------
/Public/Update-LabRRAS.ps1:
--------------------------------------------------------------------------------
1 | function Update-LabRRAS {
2 | [cmdletbinding()]
3 | param (
4 |
5 | [Parameter()]
6 | [PSCustomObject]
7 | $VMConfig,
8 |
9 | [Parameter()]
10 | [hashtable]
11 | $BaseConfig,
12 |
13 | [Parameter()]
14 | [hashtable]
15 | $LabEnvConfig,
16 |
17 | [Parameter()]
18 | [ValidateNotNullOrEmpty()]
19 | [string]
20 | $VMName = $LabEnvConfig.RRASName,
21 |
22 | [Parameter()]
23 | [String]
24 | $SwitchName = $LabEnvConfig.EnvSwitchName,
25 |
26 | [Parameter()]
27 | [ValidateNotNullOrEmpty()]
28 | [string]
29 | $RRASName = $LabEnvConfig.RRASName,
30 |
31 | [Parameter()]
32 | [ValidateNotNullOrEmpty()]
33 | [string]
34 | $ENVName = $LabEnvConfig.Env,
35 |
36 | [Parameter()]
37 | [ValidateNotNullOrEmpty()]
38 | [pscredential]
39 | $LocalAdminCreds = $BaseConfig.LocalAdminCreds,
40 |
41 | [Parameter()]
42 | [ValidateNotNullOrEmpty()]
43 | [pscredential]
44 | $DomainAdminCreds = $BaseConfig.DomainAdminCreds,
45 |
46 | [Parameter()]
47 | [ValidateNotNullOrEmpty()]
48 | [string]
49 | $ScriptPath = $BaseConfig.VMScriptPath,
50 |
51 | [Parameter()]
52 | [ValidateNotNullOrEmpty()]
53 | [string]
54 | $LogPath = $BaseConfig.VMLogPath,
55 |
56 | [Parameter()]
57 | [ValidateNotNullOrEmpty()]
58 | [string]
59 | $LabPath = $BaseConfig.LabPath
60 |
61 | )
62 |
63 | #region Standard Setup
64 | Write-Host "Starting $($MyInvocation.MyCommand)" -ForegroundColor Cyan
65 | $LabScriptPath = "$($LabPath)$($ScriptPath)\$($VMName)"
66 | $ClientScriptPath = "C:$($ScriptPath)"
67 |
68 | if (-not (Test-Path -Path "$($LabScriptPath)")) {
69 | New-Item -Path "$($LabScriptPath)" -ItemType Directory -ErrorAction SilentlyContinue
70 | }
71 |
72 | $LogPath = "C:$($LogPath)"
73 | $SBDefaultParams = @"
74 | param
75 | (
76 | `$_LogPath = "$($LogPath)"
77 | )
78 | "@
79 |
80 | $SBScriptTemplateBegin = {
81 | if (-not (Test-Path -Path $_LogPath -ErrorAction SilentlyContinue)) {
82 | New-Item -Path $_LogPath -ItemType Directory -ErrorAction SilentlyContinue;
83 | }
84 |
85 | $_LogFile = "$($_LogPath)\Transcript.log";
86 |
87 | Start-Transcript $_LogFile -Append -IncludeInvocationHeader | Out-Null;
88 | Write-Output "Logging to $_LogFile";
89 |
90 | #region Do Stuff Here
91 | }
92 |
93 | $SBScriptTemplateEnd = {
94 | #endregion
95 | Stop-Transcript
96 | }
97 |
98 | #endregion
99 |
100 | $VM = Get-VM -VM $VMName
101 | $VM | Get-VMNetworkAdapter | Where-Object {$_.SwitchName -eq $SwitchName} | Remove-VMNetworkAdapter
102 | $NewRRASAdapter = $VM | Add-VMNetworkAdapter -SwitchName $SwitchName -Name $ENVName -Passthru
103 | $NewRRASAdapter | Set-VMNetworkAdapterVlan -VlanId 4 -Access
104 | $NewRRASAdapter | Set-VMNetworkAdapter -DeviceNaming On -Passthru | Rename-VMNetworkAdapter -NewName $ENVName
105 | $LabEnvConfig["RRASMAC"] = $NewRRASAdapter.MACAddress
106 | $RRASMAC = $LabEnvConfig["RRASMAC"]
107 |
108 | #region Script Blocks
109 |
110 | $SBUpdateRRASParams = @"
111 | param
112 | (
113 | `$_LogPath = "$($LogPath)",
114 | `$_RRASMAC = "$($RRASMAC)",
115 | `$_ENVName = "$($ENVName)"
116 | )
117 | "@
118 |
119 | $SBUpdateRRAS = {
120 | $ExistingNIC = Get-ChildItem -Path "HKLM:SYSTEM\CurrentControlSet\Control\Network" -Recurse -ErrorAction 0 | Get-ItemProperty -Name "Name" -ErrorAction 0 | Where-Object {$_.Name -eq $_ENVName} | ForEach-Object { Get-ItemPropertyValue -Path $_.PSPath -Name PnPInstanceId}
121 | if($ExistingNIC) {
122 | $Dev = Get-PnpDevice -class net | Where-Object { $_.Status -eq "Unknown" -and $_.InstanceId -eq $ExistingNIC}
123 | $RemoveKey = "HKLM:\SYSTEM\CurrentControlSet\Enum\$($Dev.InstanceId)"
124 | Get-Item $RemoveKey | Select-Object -ExpandProperty Property | ForEach-Object { Remove-ItemProperty -Path $RemoveKey -Name $_}
125 | }
126 |
127 | $NewNIC = Get-NetAdapter | Where-Object {$_.MACAddress.Replace("-","") -eq $_RRASMAC}
128 | $NewNIC | Rename-NetAdapter -NewName $_ENVName
129 | Get-Service -name "remoteaccess" | Restart-Service -WarningAction SilentlyContinue;
130 | netsh routing ip nat add interface "$($_ENVName)"
131 | $NewNIC | Restart-NetAdapter
132 | Start-Sleep -Seconds 60
133 | Get-Service -name "remoteaccess" | Restart-Service -WarningAction SilentlyContinue;
134 | }
135 |
136 | $UpdateRRAS += $SBUpdateRRASParams
137 | $UpdateRRAS += $SBScriptTemplateBegin.ToString()
138 | $UpdateRRAS += $SBUpdateRRAS.ToString()
139 | $UpdateRRAS += $SBScriptTemplateEnd.ToString()
140 | $UpdateRRAS | Out-File "$($LabScriptPath)\$($ENVName).ps1"
141 |
142 | $Scripts = Get-Item -Path "$($LabScriptPath)\*.*"
143 |
144 | #endregion
145 |
146 | $VM = Get-VM -VM $RRASName
147 | $VM | Start-VM -WarningAction SilentlyContinue
148 | start-sleep 10
149 |
150 | while (-not (Invoke-Command -VMName $VMName -Credential $LocalAdminCreds {Get-Process "LogonUI" -ErrorAction SilentlyContinue;})) {Start-Sleep -seconds 5}
151 |
152 | foreach ($Script in $Scripts) {
153 | Copy-VMFile -VM $VM -SourcePath $Script.FullName -DestinationPath "C:$($ScriptPath)\$($Script.Name)" -CreateFullPath -FileSource Host -Force
154 | }
155 |
156 | Invoke-LabCommand -FilePath "$($LabScriptPath)\$($ENVName).ps1" -MessageText "Update RRAS" -SessionType Local -VMID $VM.VMId
157 |
158 | Write-Host "$($MyInvocation.MyCommand) Complete!" -ForegroundColor Cyan
159 | }
--------------------------------------------------------------------------------
/Public/UpgradeCM:
--------------------------------------------------------------------------------
1 | # Import the ConfigurationManager module
2 | Import-Module -FullyQualifiedName "$env:SMS_ADMIN_UI_PATH\..\ConfigurationManager.psd1"
3 | # Get the site code
4 | $SiteCode = (Get-CimInstance -Namespace ROOT/SMS -ClassName SMS_ProviderLocation).SiteCode
5 | # Change to the site psdrive
6 | Set-Location -Path "$($SiteCode):"
7 | # Find the latest update
8 | $LatestSiteUpdate = (Get-CMSiteUpdate -Fast | Sort-Object -Property LastUpdateTime | Select-Object -First 1).Name
9 | # Install the update
10 | Install-CMSiteUpdate -Name $LatestSiteUpdate -Confirm:$false -Force
--------------------------------------------------------------------------------
/Public/Write-LogEntry.ps1:
--------------------------------------------------------------------------------
1 | function Write-LogEntry {
2 | [cmdletBinding()]
3 | param (
4 | [parameter()]
5 | [ValidateSet("Information", "Error")]
6 | [string]
7 | $Type = "Information",
8 |
9 | [parameter(Mandatory = $true)]
10 | [string]
11 | $Message,
12 |
13 | [parameter()]
14 | [ValidateScript({ Test-Path $(Resolve-Path $_) })]
15 | [string]
16 | $Logfile = "$($PSScriptRoot)\Build.log"
17 | )
18 | switch ($Type) {
19 | 'Error' {
20 | $Severity = 3
21 | break;
22 | }
23 | 'Information' {
24 | $Severity = 6
25 | break;
26 | }
27 | }
28 | $DateTime = New-Object -ComObject WbemScripting.SWbemDateTime
29 | $DateTime.SetVarDate($(Get-Date))
30 | $UtcValue = $DateTime.Value
31 | $UtcOffset = $UtcValue.Substring(21, $UtcValue.Length - 21)
32 | $scriptname = (Get-PSCallStack)[1]
33 | $logline = `
34 | "<-not [LOG[$message]LOG]-not >" + `
35 | "