├── .gitignore
├── .vscode
└── settings.json
├── ENV.json
├── Lab.Classes.ps1
├── LabTest.ps1
├── New-DCUsers.ps1
├── New-GenerateUsers.ps1
├── New-LabVHDX.ps1
├── New-UnattendXml.ps1
├── New.tests.ps1
├── NewCAServer.PS1
├── NewCMSettingfile.ps1
├── NewENV.Testsold.ps1old
├── NewENV.ps1
├── NewSCCMServer.PS1
├── Optimize-AllVHDX.ps1
├── SVRTemplates.json
├── Unattended.xml
├── WKS-Unattend.xml
├── WriteLogEntry.ps1
├── new-NDESClientCert.ps1
├── new-NDESUserCert.ps1
├── new-ccmwebcert.ps1
├── new-kdccert.ps1
├── newCMInstance.ps1
├── newCMSQLsettingsINI.ps1
├── newCMWorkStation.ps1
├── newDCServer.ps1
├── newRRASServer.ps1
├── newcmSQLInstance.ps1
├── readme.md
└── v5.Testcases.ps1
/.gitignore:
--------------------------------------------------------------------------------
1 | TestExplorerResults.xml
2 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "powershell.codeFormatting.addWhitespaceAroundPipe": true
3 | }
--------------------------------------------------------------------------------
/ENV.json:
--------------------------------------------------------------------------------
1 | {
2 | "ENV": "UsedHouseSalesMan",
3 | "RRASName": "RRAS",
4 | "SQLISO": "D:\\Software\\SQL\\en_sql_server_2019_enterprise_x64_dvd_5e1ecc6b.iso",
5 | "ADKPATH": "D:\\Software\\ADK",
6 | "SCCMPath": "D:\\Software\\ConfigMgr\\ConfigMgr1902",
7 | "WIN16ISO": "D:\\Software\\WindowsServer\\en_windows_server_2019_updated_jan_2021_x64_dvd_5ef22372.iso",
8 | "WINNET35CAB": "D:\\Software\\WindowsServer\\en_windows_server_2019_updated_jan_2021_x64_dvd_5ef22372\\sources\\sxs",
9 | "REFVHDX": "D:\\lab\\ref19c.vhdx",
10 | "SCCMVersion": "PROD",
11 | "SCCMENVType": "PRI",
12 | "SCCMDLPreDown": "1",
13 | "EnableSnapShot": "1",
14 | "ENVConfig": [
15 | {
16 | "ENV": "UsedHouseSalesMan",
17 | "DomainNetBiosName": "UsedHouse",
18 | "DomainFQDN": "UsedHouse.lab",
19 | "IPSubnet": "172.16.205.",
20 | "VMPath": "D:\\Lab\\UsedHouse",
21 | "SwitchName": "Usedhouse",
22 | "AdminPW": "P@ssw0rd",
23 | "CMSiteCode": "UH1"
24 | },
25 | {
26 | "ENV": "carlab1",
27 | "DomainNetBiosName": "carlab1",
28 | "DomainFQDN": "carlab1.lab",
29 | "IPSubnet": "172.16.201.",
30 | "VMPath": "D:\\Lab\\carlab1",
31 | "SwitchName": "carlab1",
32 | "AdminPW": "P@ssw0rd",
33 | "CMSiteCode": "CL1"
34 | },
35 | {
36 | "ENV": "carlab2",
37 | "DomainNetBiosName": "carlab2",
38 | "DomainFQDN": "carlab2.lab",
39 | "IPSubnet": "172.16.202.",
40 | "VMPath": "D:\\Lab\\carlab2",
41 | "SwitchName": "carlab2",
42 | "AdminPW": "P@ssw0rd",
43 | "CMSiteCode": "CL2"
44 | },
45 | {
46 | "ENV": "IntuneTraining",
47 | "DomainNetBiosName": "IntuneTraining",
48 | "DomainFQDN": "IntuneTraining.lab",
49 | "IPSubnet": "172.16.120.",
50 | "VMPath": "D:\\Lab\\IntuneTraining",
51 | "SwitchName": "IntuneTraining",
52 | "AdminPW": "P@ssw0rd",
53 | "CMSiteCode": "OP1"
54 | },
55 | {
56 | "ENV": "MMDTraining",
57 | "DomainNetBiosName": "MMDTraining",
58 | "DomainFQDN": "MMDTraining.lab",
59 | "IPSubnet": "172.16.160.",
60 | "VMPath": "D:\\Lab\\MMDTraining",
61 | "SwitchName": "MMDTraining",
62 | "AdminPW": "P@ssw0rd",
63 | "CMSiteCode": "MMD"
64 | },
65 | {
66 | "ENV": "SHM365LAB",
67 | "DomainNetBiosName": "SHM365LAB",
68 | "DomainFQDN": "SHM365LAB.lab",
69 | "IPSubnet": "172.16.120.",
70 | "VMPath": "D:\\Lab\\SHM365LAB",
71 | "SwitchName": "SHM365LAB",
72 | "AdminPW": "P@ssw0rd",
73 | "CMSiteCode": "OP1"
74 | },
75 | {
76 | "ENV": "M365",
77 | "DomainNetBiosName": "M365",
78 | "DomainFQDN": "M365.lab",
79 | "IPSubnet": "172.16.130.",
80 | "VMPath": "D:\\Lab\\M365",
81 | "SwitchName": "M365",
82 | "AdminPW": "P@ssw0rd",
83 | "CMSiteCode": "365"
84 | },
85 | {
86 | "ENV": "MMS",
87 | "DomainNetBiosName": "MMS",
88 | "DomainFQDN": "MMS.lab",
89 | "IPSubnet": "172.16.10.",
90 | "VMPath": "D:\\Lab\\MMS",
91 | "SwitchName": "MMS",
92 | "AdminPW": "P@ssw0rd",
93 | "CMSiteCode": "MMS"
94 | },
95 | {
96 | "ENV": "TP2",
97 | "DomainNetBiosName": "tp2",
98 | "DomainFQDN": "tp2.corp",
99 | "IPSubnet": "172.16.20.",
100 | "VMPath": "d:\\Lab\\TP2",
101 | "SwitchName": "TP2",
102 | "AdminPW": "P@ssw0rd",
103 | "CMSiteCode": "TP2"
104 | },
105 | {
106 | "ENV": "TP3",
107 | "DomainNetBiosName": "tp3",
108 | "DomainFQDN": "tp3.lab",
109 | "IPSubnet": "172.16.30.",
110 | "VMPath": "D:\\Lab\\TP3",
111 | "SwitchName": "TP3",
112 | "AdminPW": "P@ssw0rd",
113 | "CMSiteCode": "TP3"
114 | },
115 | {
116 | "ENV": "TP4",
117 | "DomainNetBiosName": "tp4",
118 | "DomainFQDN": "tp4.lab",
119 | "IPSubnet": "172.16.40.",
120 | "VMPath": "D:\\Lab\\TP4",
121 | "SwitchName": "TP4",
122 | "AdminPW": "P@ssw0rd",
123 | "CMSiteCode": "TP4"
124 | }
125 | ]
126 | }
--------------------------------------------------------------------------------
/Lab.Classes.ps1:
--------------------------------------------------------------------------------
1 | class DC {
2 | [string]$Name
3 | [int]$cores
4 | [int]$Ram
5 | [string]$IPAddress
6 | [string]$network
7 | [string]$VHDXpath
8 | [pscredential]$localadmin
9 | [string]$domainFQDN
10 | [string]$AdmPwd
11 | [pscredential]$domainuser
12 | [bool]$VMSnapshotenabled
13 | [string]$refvhdx
14 | Save ([string] $path) {
15 | $this | ConvertTo-Json | Out-File $path
16 | }
17 | load ([string] $path) {
18 | $settings = get-content $path | ConvertFrom-Json
19 | $this.name = $settings.name
20 | $this.cores = $settings.cores
21 | $this.Ram = $settings.ram
22 | $this.IPAddress = $settings.ipaddress
23 | $this.network = $settings.network
24 | $this.VHDXpath = $settings.VHDXpath
25 | $this.domainFQDN = $settings.domainFQDN
26 | $this.AdmPwd = $settings.AdmPwd
27 | $this.VMSnapshotenabled = $settings.vmSnapshotenabled
28 | $this.refvhdx = $settings.refvhdx
29 | }
30 | }
31 | class RRAS {
32 | [string]$Name
33 | [int]$cores
34 | [int]$ram
35 | [string]$ipaddress
36 | [string]$network
37 | [pscredential]$localadmin
38 | [bool]$vmSnapshotenabled
39 | [string]$VHDXpath
40 | [string]$RefVHDX
41 | Save ([string] $path) {
42 | $this | ConvertTo-Json | Out-File $path
43 | }
44 | load ([string]$path) {
45 | $settings = get-content $path | ConvertFrom-Json
46 | $this.name = $settings.name
47 | $this.cores = $settings.cores
48 | $this.ram = $settings.ram
49 | $this.ipaddress = $settings.ipaddress
50 | $this.network = $settings.network
51 | $this.localadmin = $null
52 | $this.vmSnapshotenabled = $settings.vmSnapshotenabled
53 | $this.VHDXpath = $settings.VHDXpath
54 | $this.RefVHDX = $settings.RefVHDX
55 | }
56 | }
57 | class CM {
58 | #14
59 | [string]$name
60 | [int]$cores #
61 | [int]$ram #
62 | [string]$IPAddress #
63 | [string]$network #
64 | [string]$VHDXpath #
65 | [pscredential]$localadmin #
66 | [pscredential]$domainuser #
67 | [string]$AdmPwd #
68 | [string]$domainFQDN #
69 | [bool]$VMSnapshotenabled #
70 | [string]$cmsitecode #
71 | [bool]$SCCMDLPreDownloaded #
72 | [string]$DCIP #
73 | [string]$RefVHDX
74 | [string]$SQLISO
75 | [string]$SCCMPath
76 | [string]$ADKPath
77 | [string]$domainnetbios
78 | [string]$CMServerType
79 | [string]$CASIPAddress
80 | [string]$SCCMVer
81 | [bool]$Built
82 | Save ([string] $path) {
83 | $this | ConvertTo-Json | Out-File $path -Force
84 | }
85 | load ([string] $path) {
86 | $settings = get-content $path | ConvertFrom-Json
87 | $this.name = $settings.name
88 | $this.cores = $settings.cores
89 | $this.ram = $settings.ram
90 | $this.IPAddress = $settings.ipaddress
91 | $this.network = $settings.network
92 | $this.VHDXpath = $settings.VHDXpath
93 | $this.AdmPwd = $settings.AdmPwd
94 | $this.domainFQDN = $settings.domainFQDN
95 | $this.VMSnapshotenabled = $settings.vmSnapshotenabled
96 | $this.cmsitecode = $settings.cmsitecode
97 | $this.SCCMDLPreDownloaded = $settings.SCCMDLPreDownloaded
98 | $this.DCIP = $settings.DCIP
99 | $this.RefVHDX = $settings.refvhdx
100 | $this.SQLISO = $settings.SQLISO
101 | $this.SCCMPath = $settings.SCCMPath
102 | $this.ADKPath = $settings.ADKPath
103 | $this.domainnetbios = $settings.domainnetbios
104 | $this.CMServerType = $settings.CMServerType
105 | $this.CASIPAddress = $settings.CASIPAddress
106 | $this.SCCMVer = $settings.SCCMVer
107 | $this.Built = $settings.built
108 | }
109 | }
110 | class env {
111 | [string]$vmpath
112 | [string]$RefVHDX
113 | [string]$Win16ISOPath
114 | [string]$Win16Net35Cab
115 | [string]$network
116 | [string]$DefaultPwd
117 | Save ([string] $path) {
118 | $this | ConvertTo-Json | Out-File $path
119 | }
120 | }
121 | class CA {
122 | [string]$Name
123 | [int]$cores
124 | [int]$ram
125 | [string]$IPAddress
126 | [string]$network
127 | [string]$VHDXpath
128 | [pscredential]$localadmin
129 | [string]$domainFQDN
130 | [pscredential]$domainuser
131 | [bool]$VMSnapshotenabled
132 | [string]$RefVHDX
133 | [string]$DCIP
134 | save ([string] $path) {
135 | $this | ConvertTo-Json | Out-File $path
136 | }
137 | load ([string] $path) {
138 | $settings = get-content $path | ConvertFrom-Json
139 | $this.name = $settings.name
140 | $this.cores = $settings.cores
141 | $this.Ram = $settings.ram
142 | $this.IPAddress = $settings.ipaddress
143 | $this.network = $settings.network
144 | $this.VHDXpath = $settings.VHDXpath
145 | $this.domainFQDN = $settings.domainFQDN
146 | $this.VMSnapshotenabled = $settings.vmSnapshotenabled
147 | $this.refvhdx = $settings.refvhdx
148 | $this.DCIP = $Settings.DCIP
149 | }
150 | }
151 | class CASP {
152 |
153 | }
154 | class CASC {
155 |
156 | }
157 | class WKS {
158 |
159 | }
160 |
161 | class testframes {
162 | [pscredential]$localadmin
163 | [pscredential]$domuser
164 | [string]$vmpath
165 | [string]$swname
166 | [string]$DomainFQDN
167 | [string]$RefVHDX
168 | }
--------------------------------------------------------------------------------
/LabTest.ps1:
--------------------------------------------------------------------------------
1 | function Set-LabSettings {
2 | #process to create x number of workstation clients
3 | #process to create x number of dummy clients
4 | #find a solution to ensure the latest TP is installed
5 | }
6 |
7 | #endregion
8 | #LAZY MODULE TESTING, WILL BE FIXED ONCE COMPLETED
9 | #Who am i kidding this is how it will be for ever :)
10 | foreach ($psfile in get-childitem -Filter *.ps1 | Where-Object { $_.name -notin ("NewENV.Tests.ps1", "labtest.ps1","new.tests.ps1","v5.testcases.ps1") }) {
11 | . $psfile.FullName
12 | }
13 |
14 | #region import JSON Settings
15 | $scriptpath = $PSScriptRoot
16 | $config = Get-Content "$scriptpath\env.json" -Raw | ConvertFrom-Json
17 | $envConfig = $config.ENVConfig | Where-Object { $_.env -eq $config.env }
18 | $script:logfile = "$($envConfig.vmpath)\Build.log"
19 | if (!(Test-Path $envConfig.vmpath)) { new-item -ItemType Directory -Force -Path $envConfig.vmpath | Out-Null }
20 | Write-LogEntry -Type Information -Message "Start of build process for $($config.env) ------"
21 | $admpwd = $envConfig.AdminPW
22 | Write-LogEntry -Type Information -Message "Admin password set to: $admpwd"
23 | $localadmin = new-object -typename System.Management.Automation.PSCredential -argumentlist "administrator", (ConvertTo-SecureString -String $admpwd -AsPlainText -Force)
24 | $domuser = new-object -typename System.Management.Automation.PSCredential -argumentlist "$($envconfig.DomainNetBiosName)\administrator", (ConvertTo-SecureString -String $admpwd -AsPlainText -Force)
25 | $vmpath = $envConfig.VMPath
26 | Write-LogEntry -Type Information -Message "Path for VHDXs set to: $vmpath"
27 | $swname = $envConfig.SwitchName
28 | Write-LogEntry -Type Information -Message "vSwitch name is: $swname"
29 | $ipsub = $envConfig.ipsubnet
30 | Write-LogEntry -type Information -Message "IP Subnet used for this lab is: $ipsub"
31 | $DomainFQDN = $envconfig.DomainFQDN
32 | Write-LogEntry -Type Information -Message "Fully Quilified Domain Name is: $domainfqdn"
33 | $RRASname = $Config.RRASname
34 | Write-LogEntry -Type Information -Message "Routing and Remote Access Services server name is: $RRASName"
35 | $RefVHDX = $config.REFVHDX
36 | Write-LogEntry -Type Information -Message "Path to Reference VHDX is: $RefVHDX"
37 | $domainnetbios = $envconfig.DomainNetBiosName
38 | Write-LogEntry -Type Information -Message "WINNT domain name is: $domainnetbios"
39 | $cmsitecode = $envConfig.CMSiteCode
40 | Write-LogEntry -Type Information -Message "SCCM Site code is: $cmsitecode"
41 | $SCCMDLPreDown = $config.SCCMDLPreDown
42 | Write-LogEntry -Type Information -Message "SCCM Content was Predownloaded: $($sccmdlpredown -eq 1)"
43 | $vmsnapshot = if ($config.Enablesnapshot -eq 1) { $true }else { $false }
44 | Write-LogEntry -Type Information -Message "Snapshots have been: $vmsnapshot"
45 | $unattendpath = $config.REFVHDX -replace ($config.REFVHDX.split('\') | Select-Object -last 1), "Unattended.xml"
46 | Write-LogEntry -Type Information -Message "Windows 2016 unattend file is: $unattendpath"
47 | $SCCMENVType = $Config.SCCMENVType
48 | $SCCMVer = $config.SCCMVersion
49 | #$servertemplates = (Get-Content "$scriptpath\SVRTemplates.json" -Raw | ConvertFrom-Json).ServerTemplates
50 | #endregion
51 |
52 | #region ENVConfig
53 | $envconfig = [env]::new()
54 | $envconfig.vmpath = $vmpath
55 | $envConfig.RefVHDX = $RefVHDX
56 | $envConfig.Win16ISOPath = $config.WIN16ISO
57 | $envConfig.Win16Net35Cab = $config.WINNET35CAB
58 | $envConfig.network = $swname
59 | $envconfig.DefaultPwd = $admpwd
60 | $envConfig.Save("$vmpath`\envconfig.json")
61 | #endregion
62 |
63 | #region RRASConfig
64 | $RRASConfig = [RRAS]::new()
65 | $RRASConfig.name = $RRASname
66 | $RRASConfig.cores = 1
67 | $RRASConfig.ram = 4
68 | $RRASConfig.ipaddress = "$ipsub`1"
69 | $RRASConfig.network = $swname
70 | $RRASConfig.localadmin = $localadmin
71 | $RRASConfig.vmSnapshotenabled = $false
72 | $RRASConfig.VHDXpath = "$(split-path $vmpath)\RRASc.vhdx"
73 | $RRASConfig.RefVHDX = $RefVHDX
74 | $RRASConfig.Save("$(split-path $vmpath)\RRASConfig.json")
75 | #endregion
76 |
77 | #region DCConfig
78 | $DCConfig = [DC]::new()
79 | $DCConfig.Name = "$($config.env)`DC"
80 | $DCConfig.cores = 1
81 | $DCConfig.Ram = 4
82 | $DCConfig.IPAddress = "$ipsub`10"
83 | $DCConfig.network = $swname
84 | $DCConfig.VHDXpath = "$vmpath\$($config.env)`DCc.vhdx"
85 | $DCConfig.localadmin = $localadmin
86 | $DCConfig.domainFQDN = $domainfqdn
87 | $DCConfig.AdmPwd = $admpwd
88 | $DCConfig.domainuser = $domuser
89 | $DCConfig.VMSnapshotenabled = $false
90 | $DCConfig.refvhdx = $RefVHDX
91 | $DCConfig.Save("$vmpath\dcconfig.json")
92 | #endregion
93 |
94 | #region CMConfig - Primary Server
95 | if ($SCCMENVType -eq "PRI") {
96 | $CMConfig = [CM]::new()
97 | $CMConfig.name = "$($config.env)`CM"
98 | $CMConfig.cores = 4
99 | $CMConfig.ram = 12
100 | $CMConfig.IPAddress = "$ipsub`11"
101 | $CMConfig.network = $swname
102 | $CMConfig.VHDXpath = "$vmpath\$($config.env)`CMc.vhdx"
103 | $CMConfig.localadmin = $localadmin
104 | $CMConfig.domainuser = $domuser
105 | $CMConfig.AdmPwd = $admpwd
106 | $CMConfig.domainFQDN = $domainfqdn
107 | $CMConfig.VMSnapshotenabled = $false
108 | $CMConfig.cmsitecode = $cmsitecode
109 | $CMConfig.SCCMDLPreDownloaded = $sccmdlpredown
110 | $CMConfig.DCIP = $DCConfig.IPAddress
111 | $CMConfig.RefVHDX = $RefVHDX
112 | $CMConfig.SQLISO = $config.SQLISO
113 | $CMConfig.SCCMPath = $config.SCCMPath
114 | $CMConfig.ADKPath = $config.ADKPATH
115 | $CMConfig.domainnetbios = $domainnetbios
116 | $CMConfig.CMServerType = "PRI"
117 | $CMConfig.SCCMVer = $SCCMVer
118 | $CMConfig.save("$vmpath\cmconfig.json")
119 | }
120 | #endregion
121 |
122 | #region CMConfig - CAS ENV
123 | else {
124 | $CMCASConfig = [CM]::new()
125 | $CMCASConfig.name = "$($config.env)`CMCAS"
126 | $CMCASConfig.cores = 4
127 | $CMCASConfig.ram = 12
128 | $CMCASConfig.IPAddress = "$ipsub`11"
129 | $CMCASConfig.network = $swname
130 | $CMCASConfig.VHDXpath = "$vmpath\$($config.env)`CMCASc.vhdx"
131 | $CMCASConfig.localadmin = $localadmin
132 | $CMCASConfig.domainuser = $domuser
133 | $CMCASConfig.AdmPwd = $admpwd
134 | $CMCASConfig.domainFQDN = $domainfqdn
135 | $CMCASConfig.VMSnapshotenabled = $false
136 | $CMCASConfig.cmsitecode = $cmsitecode
137 | $CMCASConfig.SCCMDLPreDownloaded = $sccmdlpredown
138 | $CMCASConfig.DCIP = $DCConfig.IPAddress
139 | $CMCASConfig.RefVHDX = $RefVHDX
140 | $CMCASConfig.SQLISO = $config.SQLISO
141 | $CMCASConfig.SCCMPath = $config.SCCMPath
142 | $CMCASConfig.ADKPath = $config.ADKPATH
143 | $CMCASConfig.domainnetbios = $domainnetbios
144 | $CMCASConfig.CMServerType = "CAS"
145 | $CMConfig.SCCMVer = $SCCMVer
146 | $CMCASConfig.save("$vmpath\cmCASconfig.json")
147 |
148 | $CMCASPRIConfig = [CM]::new()
149 | $CMCASPRIConfig.name = "$($config.env)`CMCASPRI"
150 | $CMCASPRIConfig.cores = 4
151 | $CMCASPRIConfig.ram = 12
152 | $CMCASPRIConfig.IPAddress = "$ipsub`12"
153 | $CMCASPRIConfig.network = $swname
154 | $CMCASPRIConfig.VHDXpath = "$vmpath\$($config.env)`CMCASPRIc.vhdx"
155 | $CMCASPRIConfig.localadmin = $localadmin
156 | $CMCASPRIConfig.domainuser = $domuser
157 | $CMCASPRIConfig.AdmPwd = $admpwd
158 | $CMCASPRIConfig.domainFQDN = $domainfqdn
159 | $CMCASPRIConfig.VMSnapshotenabled = $false
160 | $CMCASPRIConfig.cmsitecode = $cmsitecode
161 | $CMCASPRIConfig.SCCMDLPreDownloaded = $sccmdlpredown
162 | $CMCASPRIConfig.DCIP = $DCConfig.IPAddress
163 | $CMCASPRIConfig.RefVHDX = $RefVHDX
164 | $CMCASPRIConfig.SQLISO = $config.SQLISO
165 | $CMCASPRIConfig.SCCMPath = $config.SCCMPath
166 | $CMCASPRIConfig.ADKPath = $config.ADKPATH
167 | $CMCASPRIConfig.domainnetbios = $domainnetbios
168 | $CMCASPRIConfig.CMServerType = "CASPRI"
169 | $CMConfig.SCCMVer = $SCCMVer
170 | $CMCASPRIConfig.CASIPAddress = $CMCASConfig.IPAddress
171 | $CMCASPRIConfig.save("$vmpath\cmCASPRIconfig.json")
172 | }
173 | #endregion
174 |
175 | #region CAConfig
176 | $CAConfig = [CA]::new()
177 | $CAConfig.name = "$($config.env)`CA"
178 | $CAConfig.cores = 1
179 | $CAConfig.Ram = 4
180 | $CAConfig.IPAddress = "$ipsub`20"
181 | $CAConfig.domainuser = $domuser
182 | $CAConfig.localadmin = $localadmin
183 | $CAConfig.network = $swname
184 | $CAConfig.VHDXpath = "$vmpath\$($config.env)`CAc.vhdx"
185 | $CAConfig.domainFQDN = $DomainFQDN
186 | $CAConfig.VMSnapshotenabled = $false
187 | $CAConfig.refvhdx = $RefVHDX
188 | $CAConfig.DCIP = $DCConfig.IPAddress
189 | $CAConfig.save("$vmpath\CAConfig.json")
190 | #endregion
191 |
192 | #region create VMs
193 | new-env -ENVConfig $envconfig
194 | new-RRASServer -RRASConfig $RRASConfig
195 | new-DC -DCConfig $DCConfig
196 | New-CAServer -CAConfig $CAConfig
197 | if ($SCCMENVType -eq "PRI") {
198 | new-SCCMServer -CMConfig $CMConfig
199 | }
200 | else {
201 | new-SCCMServer -CMConfig $CMCASConfig
202 | new-SCCMServer -CMConfig $CMCASPRIConfig
203 | }
204 | #endregion
--------------------------------------------------------------------------------
/New-DCUsers.ps1:
--------------------------------------------------------------------------------
1 | Function New-DCUsers {
2 | param(
3 | [Parameter()]
4 | [PSCustomObject]
5 | $UserList,
6 | [Parameter()]
7 | [pscredential]
8 | $DomAdmin,
9 | [Parameter()]
10 | [string]
11 | $DCVM,
12 | [Parameter()]
13 | [string]
14 | $domainname,
15 | [Parameter()]
16 | [string]
17 | $newpwd
18 | )
19 | $ouname = "AADusers"
20 | $psses = New-PSSession -VMName $DCVM -Credential $DomAdmin
21 | $oucount = (Invoke-Command -Session $psses -ScriptBlock { Param($ou)(Get-ADOrganizationalUnit -filter * | where-Object { $_.name -eq $ou }).Name } -ArgumentList $ouname).count
22 | if ($oucount -eq 0) {
23 | invoke-command -Session $psses -ScriptBlock { Param($ou)new-ADOrganizationalUnit $ou } -ArgumentList $ouname
24 | }
25 | $ou = Invoke-Command -Session $psses -ScriptBlock { Param($ou)Get-ADOrganizationalUnit -filter * | where-Object { $_.name -eq $ou } } -ArgumentList $ouname
26 | foreach ($user in $UserList) {
27 | Invoke-Command -Session $psses -ScriptBlock { Param($fn, $sn, $dn, $ou, $pw)if("$fn.$sn".Length -gt 19){$sam = ("$fn.$sn").substring(0,19)} else {$sam= "$fn.$sn"};new-aduser -name "$fn.$sn" -UserPrincipalName "$fn.$sn@$dn" -path $ou -samaccountname $sam -GivenName $fn -Surname $sn -enabled $true -AccountPassword (ConvertTo-SecureString -String $pw -AsPlainText -Force)} -ArgumentList $user.FirstName.replace("+","").replace(' ',''), $user.lastname.Replace("+","").replace(' ',''), $domainname, $ou.DistinguishedName, $newpwd
28 | }
29 | $mgruser = $UserList | Get-Random
30 | $mgradobj = Invoke-Command -Session $psses -ScriptBlock {Param($fn, $sn) get-aduser -Identity "$fn.$sn"} -ArgumentList $mgruser.FirstName.replace("+","").replace(' ',''), $mgruser.lastname.Replace("+","").replace(' ','')
31 | foreach ($u in ($UserList | Where-Object {$_.firstname -ne $mgruser.FirstName -and $_.lastname -ne $mgruser.lastname})) {
32 | if("$($u.FirstName.replace('+','').replace(' ','')).$($u.lastname.Replace('+','').replace(' ',''))".Length -gt 19)
33 | {
34 | $sam = ("$($u.FirstName.replace('+','').replace(' ','')).$($u.lastname.Replace('+','').replace(' ',''))").substring(0,19)
35 | } else {
36 | $sam= "$($u.FirstName.replace('+','').replace(' ','')).$($u.lastname.Replace('+','').replace(' ',''))"
37 | }
38 | Invoke-Command -Session $psses -ScriptBlock { Param($name,$mgr)set-aduser -Identity $name -Manager (get-aduser -identity $mgr.name)} -ArgumentList $sam, $mgradobj
39 | }
40 | }
--------------------------------------------------------------------------------
/New-GenerateUsers.ps1:
--------------------------------------------------------------------------------
1 | function New-GenerateUsers {
2 | param(
3 | [Parameter()]
4 | [int]
5 | $numofusers
6 | )
7 | $filepath = ".\users.csv"
8 | if (!(test-path $filepath)) {
9 | invoke-webrequest -uri "https://raw.githubusercontent.com/microsoft/sql-server-samples/master/samples/databases/adventure-works/oltp-install-script/Person.csv" -usebasicparsing -OutFile $filepath | Out-Null
10 | }
11 | $rawusers = import-csv -path $filepath -Header 'ID', 'a', 'b', 'title', 'FirstName', 'middlename', 'lastname', 'd', 'e', 'f', 'schema', 'date' -Delimiter '|'
12 | $filteredusers = $rawusers | Get-Random -Count ($numofusers * 2) | Select-object -Property FirstName, middlename, lastname -Unique -First $numofusers
13 | return $filteredusers
14 | }
--------------------------------------------------------------------------------
/New-LabVHDX.ps1:
--------------------------------------------------------------------------------
1 | function new-LabVHDX {
2 | param
3 | (
4 | [parameter(Mandatory)]
5 | [string]
6 | $vhdxpath,
7 | [parameter(Mandatory)]
8 | [string]
9 | $unattend,
10 | [parameter]
11 | [switch]
12 | $core,
13 | [parameter(Mandatory)]
14 | [string]
15 | $WinISO,
16 | [parameter(Mandatory)]
17 | [String]
18 | $WinNet35Cab
19 | )
20 | $convmod = get-module -ListAvailable -Name 'Hyper-ConvertImage'
21 | if ($convmod.count -ne 1) {
22 | Install-Module -name 'Hyper-ConvertImage' -Scope AllUsers
23 | }
24 | else {
25 | Update-Module -Name 'Hyper-ConvertImage'
26 | }
27 | Import-module -name 'Hyper-ConvertImage'
28 | $cornum = 2
29 | if ($core.IsPresent) { $cornum = 3 }else { $cornum = 4 }
30 | Convert-WindowsImage -SourcePath $WinISO -Edition $cornum -VhdType Dynamic -VhdFormat VHDX -VhdPath $vhdxpath -DiskLayout UEFI -SizeBytes 127gb -UnattendPath $unattend
31 | $drive = (Mount-VHD -Path $vhdxpath -Passthru | Get-Disk | Get-Partition | Where-Object { $_.type -eq 'Basic' }).DriveLetter
32 | new-item "$drive`:\data" -ItemType Directory | Out-Null
33 | $netfiles = get-childitem -Path $winnet35cab -Filter "*netfx*"
34 | foreach ($net in $netfiles) {
35 | Copy-Item -Path $net.fullname -Destination "$drive`:\data\$($net.name)"
36 | }
37 | Dismount-VHD -Path $vhdxpath
38 | }
--------------------------------------------------------------------------------
/New-UnattendXml.ps1:
--------------------------------------------------------------------------------
1 | function New-UnattendXml {
2 | [CmdletBinding()]
3 | Param
4 | (
5 | # The password to have unattnd.xml set the local Administrator to
6 | [Parameter(Mandatory)]
7 | [ValidateNotNull()]
8 | [ValidateNotNullOrEmpty()]
9 | [Alias('password')]
10 | [string]
11 | $admpwd,
12 | [Parameter(Mandatory)]
13 | [string]
14 | $outfile,
15 | [Parameter]
16 | [switch]
17 | $WKS,
18 | [Parameter]
19 | [string]
20 | $domainFQDN,
21 | [Parameter]
22 | [string]
23 | $Adminuname,
24 | [Parameter]
25 | [string]
26 | $domainNetBios
27 | )
28 | if ($WKS.IsPresent) {
29 | $unattendTemplate = [xml]@"
30 |
31 |
32 |
33 |
34 |
35 |
36 | <>
37 | <>
38 | <>
39 |
40 | <>
41 |
42 |
43 |
44 |
45 | "@
46 | $unattendTemplate -replace "<>", $admpwd
47 | $unattendTemplate -replace "<>", $domainNetBios
48 | $unattendTemplate -replace "<>", $Adminuname
49 | $unattendTemplate -replace "<>", $domainFQDN
50 | $unattendTemplate | Out-File -FilePath $outfile -Encoding utf8
51 | }
52 | else {
53 | $unattendTemplate = [xml]@"
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 | <>
67 | True
68 |
69 |
70 |
71 |
72 | true
73 | true
74 |
75 | true
76 | true
77 | true
78 | 3
79 | true
80 | Work
81 | true
82 |
83 |
84 |
85 | en-au
86 | en-us
87 | en-au
88 | en-us
89 | en-au
90 |
91 |
92 |
93 | "@
94 | $unattendTemplate -replace "<>", $admpwd | Out-File -FilePath $outfile -Encoding utf8
95 | }
96 | }
--------------------------------------------------------------------------------
/New.tests.ps1:
--------------------------------------------------------------------------------
1 | BeforeAll {
2 | . .\v5.Testcases.ps1
3 | }
4 |
5 | #region ENV
6 | Describe 'Env' -Tag 'ENV' {
7 | it "ReferenceVHDX" -Tag "RefVHDX" {
8 | get-RefVHDXstate -spath $PSScriptRoot | should -be $true
9 | }
10 | it 'Internet VSwitch should exist' -Tag "ExternalSwitch" {
11 | get-ExternalSwitch | should -be $true
12 | }
13 | it "Lab vSwitch should exist" -Tag "LabSwitch" {
14 | get-labswitch -spath $PSScriptRoot | should -be $true
15 | }
16 | }
17 | #endregion
18 |
19 | #region RRAS
20 | Describe 'RRAS' -Tag 'RRAS' {
21 | it "RRAS VHDX should exist" -Tag "RRASVHDX" {
22 | get-rrasVHDXstate -spath $PSScriptRoot | should -be $true
23 | }
24 | it "RRAS VM should exist" -Tag "RRASVM" {
25 | get-rrasVMexists -spath $PSScriptRoot | should -be 1
26 | }
27 | it "RRAS is running" -Tag "RRASRunning" {
28 | get-rrasVMrunning -spath $PSScriptRoot | should -be 1
29 | }
30 | it "RRAS Features enabled" -Tag "RRASFeatures" {
31 | get-rrasVMfeatures -spath $PSScriptRoot | should -be "Installed"
32 | }
33 | it "RRAS Ext NIC Connected" -Tag "RRASExtNIC" {
34 | (get-rrasVMExternalNIC -spath $PSScriptRoot) | should -be "External"
35 | }
36 | it "RRAS Lab NIC Connected" -Tag "RRASLabNIC" {
37 | get-rrasVMLabNIC -spath $PSScriptRoot | should -be $true
38 | }
39 | it "RRAS Routing" -Tag "RRASVPN" {
40 | get-rrasvmVPN -spath $PSScriptRoot | should -be "RemoteAccessVpn"
41 | }
42 | it "RRAS Lab IP Correct" -Tag "RRASLabIP" {
43 | get-rrasVMIP -spath $PSScriptRoot | should -Be $true
44 | }
45 | it "RRAS has Internet" -Tag "RRASInternet" {
46 | get-rrasvminternet -spath $PSScriptRoot | should -Be $true
47 | }
48 | }
49 | #endregion
50 |
51 | #region DC
52 | describe "DC" -Tag "DC" {
53 | it 'DC VHDX Should Exist' -Tag "DCVHDX" {
54 | get-dcvhdxstate -spath $PSScriptRoot | should -be $true
55 | }
56 | it "DC Should Exist" -Tag "DCVM" {
57 | get-dcvmexists -spath $PSScriptRoot | should -be 1
58 | }
59 | it "DC Should be running" -Tag "DCRunning" {
60 | get-dcvmrunning -spath $PSScriptRoot | should -be 1
61 | }
62 | it "DC IP Set correctly" -Tag "DCIP" {
63 | get-DCVMIP -spath $PSScriptRoot | should -be $true
64 | }
65 | it 'DC Domain Services Installed' -Tag "DCFeatures" {
66 | get-dcvmfeature -spath $PSScriptRoot | should -be $true
67 | }
68 | it 'DC has access to Internet' -Tag "DCInternet" {
69 | get-DCVMInternet -spath $PSScriptRoot | should -be $true
70 | }
71 | it "DC is promoted" -Tag "DCPromo" {
72 | get-DCVMPromoted -spath $PSScriptRoot | should -be $true
73 | }
74 | it "DC DHCP Scope enabled" -Tag "DCDHCP" {
75 | get-DCVMDHCPScope -spath $PSScriptRoot | should -be $true
76 | }
77 | it "DC CM Servers Group exists" -Tag "DCCM" {
78 | Get-DCVMCMGroupExists -spath $PSScriptRoot | should -be $true
79 | }
80 | }
81 | #endregion
82 |
83 | #region CA
84 | Describe "CA" -tag "CA" {
85 | it 'CA VHDX Should Exist' -tag "CAVHDX" {
86 | get-CAvhdxstate -spath $PSScriptRoot | should -be $true
87 | }
88 | it "CA Should Exist" -tag "CAVM" {
89 | get-CAvmexists -spath $PSScriptRoot | should -be 1
90 | }
91 | it "CA Should be running" -tag "CARunning" {
92 | get-CAvmrunning -spath $PSScriptRoot | should -be 1
93 | }
94 | it "CA IP Set correctly" -tag "CAIP" {
95 | get-CAVMIP -spath $PSScriptRoot | should -be $true
96 | }
97 | it 'CA Certificate features Installed' -tag "CAFeatures" {
98 | get-CAvmfeature -spath $PSScriptRoot | should -be $true
99 | }
100 | it 'CA has access to Internet' -tag "CAInternet" {
101 | get-CAVMInternet -spath $PSScriptRoot | should -be $true
102 | }
103 | it 'CA can ping domain' -tag 'CADOM' {
104 | Get-CAVMDomain -spath $PSScriptRoot | should -be $true
105 | }
106 | }
107 | #endregion
108 |
109 | #region CMpri
110 | Describe "CM" -tag "CM" {
111 | it 'CM VHDX Should Exist' -tag "CMVHDX" {
112 | get-CMprivhdxstate -spath $PSScriptRoot | should -be $true
113 | }
114 | it "CM Should Exist" -tag "CMVM" {
115 | get-CMprivmexists -spath $PSScriptRoot | should -be 1
116 | }
117 | it "CM Should be running" -tag "CMRunning" {
118 | get-CMprivmrunning -spath $PSScriptRoot | should -be 1
119 | }
120 | it "CM IP Set correctly" -tag "CMIP" {
121 | get-CMpriVMIP -spath $PSScriptRoot | should -be $true
122 | }
123 | it 'CM Features Installed' -tag "CMFeatures" {
124 | get-CMprivmfeature -spath $PSScriptRoot | should -be $true
125 | }
126 | it 'CM .Net is Installed' -tag "CMNETFeatures" {
127 | get-CMprivmnetfeature -spath $PSScriptRoot | should -be $true
128 | }
129 | it 'CM has access to Internet' -tag "CMInternet" {
130 | get-CMpriVMInternet -spath $PSScriptRoot | should -be $true
131 | }
132 | it 'CM can ping domain' -tag 'CMDOM' {
133 | Get-CMpriVMDomain -spath $PSScriptRoot | should -be $true
134 | }
135 | it 'CM SQL Instance is installed' -tag "CMSQLInst" {
136 | Get-CMPriVMSQLSvc -spath $PSScriptRoot | should -be 1
137 | }
138 | it 'CM ADK Installed' -tag 'CMADK' {
139 | get-CMPriVMADK -spath $PSScriptRoot | should -be $true
140 | }
141 | it 'CM Server in Group' -tag 'CMServerGroup' {
142 | get-CMPriVMSVRGRP -spath $PSScriptRoot | should -be 1
143 | }
144 | it 'CM SCCM Installed' -tag 'CMInstalled' {
145 | get-CMPriVMCMInstalled -spath $PSScriptRoot | should -be 1
146 | }
147 | it 'CM SCCM Console Installed' -tag 'CMConsole' {
148 | get-CMPriVMCMConsoleInstalled -spath $PSScriptRoot | should -be $true
149 | }
150 | it 'CM Site Boundary added' -tag 'CMSiteBound' {
151 | get-CMPriVMCMBoundary -spath $PSScriptRoot | should -be 1
152 | }
153 | it 'CM System Discovery enabled' -tag 'CMSysDisc' {
154 | get-CMPriVMCMDiscovery -spath $PSScriptRoot | should -be 6
155 | }
156 | }
157 | #endregion
--------------------------------------------------------------------------------
/NewCAServer.PS1:
--------------------------------------------------------------------------------
1 | function new-CAServer {
2 | param(
3 | [Parameter(ParameterSetName = 'CAClass')]
4 | [CA]
5 | $CAConfig,
6 | [Parameter(ParameterSetName = 'NoClass')]
7 | [string]
8 | $VHDXpath,
9 | [Parameter(ParameterSetName = 'NoClass')]
10 | [pscredential]
11 | $localadmin,
12 | [Parameter(ParameterSetName = 'NoClass')]
13 | [string]
14 | $Network,
15 | [Parameter(ParameterSetName = 'NoClass')]
16 | [string]
17 | $ipAddress,
18 | [Parameter(ParameterSetName = 'NoClass')]
19 | [string]
20 | $DomainFQDN,
21 | [Parameter(ParameterSetName = 'NoClass')]
22 | [pscredential]
23 | $domainuser,
24 | [parameter(ParameterSetName = 'NoClass', Mandatory = $false)]
25 | [switch]
26 | $vmSnapshotenabled,
27 | [Parameter(ParameterSetName = 'NoClass')]
28 | [int]
29 | $cores,
30 | [Parameter(ParameterSetName = 'NoClass')]
31 | [int]
32 | $ram,
33 | [Parameter(ParameterSetName = 'NoClass')]
34 | [string]
35 | $name,
36 | [Parameter(ParameterSetName = 'NoClass')]
37 | [string]
38 | $refvhdx,
39 | [Parameter(ParameterSetName = 'NoClass')]
40 | [string]
41 | $DCIP
42 | )
43 | if (!$PSBoundParameters.ContainsKey('CAConfig')) {
44 | $CAConfig = [CA]::new()
45 | $CAConfig.Name = $name
46 | $CAConfig.cores = $cores
47 | $CAConfig.ram = $ram
48 | $CAConfig.IPAddress = $ipAddress
49 | $CAConfig.network = $Network
50 | $CAConfig.VHDXpath = $VHDXpath
51 | $CAConfig.localadmin = $localadmin
52 | $CACOnfig.domainFQDN = $DomainFQDN
53 | $CAConfig.domainuser = $domainuser
54 | $CAConfig.VMSnapshotenabled = $vmSnapshotenabled.IsPresent
55 | $CAConfig.RefVHDX = $refvhdx
56 | $CAConfig.DCIP = $DCIP
57 | }
58 | $ipsubnet = $CAConfig.IPAddress.substring(0, ($CAConfig.IPAddress.length - ([ipaddress] $CAConfig.IPAddress).GetAddressBytes()[3].count - 1))
59 | Write-LogEntry -Message "CA Server Started: $(Get-Date)" -Type Information
60 | Write-LogEntry -Message "CA Settings are: $($CAConfig | ConvertTo-Json)" -Type Information
61 | Write-LogEntry -Message "New CA server name is: $($caconfig.name)" -Type Information
62 | Write-LogEntry -Message "Path for the VHDX for $($CAConfig.name) is: $($CAConfig.VHDXpath)" -Type Information
63 | if (!(Invoke-Pester -tagfilter "CAVM" -passthru -output none).result -ne "Passed") {
64 | if ((Invoke-Pester -tagfilter "CAVHDX" -passthru -output none).result -eq "Passed") {
65 | Write-LogEntry -Message "CA VHDX already exists at path: $($CAConfig.VHDXpath) Please clean up and Rerun. BUILD STOPPED" -Type Error
66 | throw "CA VHDX Already Exists at path: $($CAConfig.VHDXpath) Please clean up and Rerun."
67 | }
68 | else {
69 | Copy-Item -Path $CAConfig.RefVHDX -Destination $CAConfig.VHDXpath
70 | Write-LogEntry -Message "Reference VHDX $($CAConfig.RefVHDX) has been copied to: $($CAConfig.VHDXpath)" -Type Information
71 | }
72 | if ((Invoke-Pester -tagfilter "CAVHDX" -passthru -output none).result -ne "Passed") {
73 | Write-LogEntry -Message "Error creating the VHDX for CA. BUILD STOPPED" -Type Error
74 | throw "Error Creating the VHDX for CA"
75 | }
76 | else {
77 | Write-LogEntry -Message "Starting to create CA Server" -Type Information
78 | $vm = new-vm -name $cAconfig.name -MemoryStartupBytes ($CAConfig.ram * 1gb) -VHDPath $CAConfig.VHDXpath -Generation 2 | Set-VMMemory -DynamicMemoryEnabled:$false
79 | $vm | Set-VMProcessor -Count $CAConfig.cores
80 | if (!($CAConfig.VMSnapshotenabled)) {
81 | set-vm -name $caconfig.name -checkpointtype Disabled
82 | }
83 | Write-LogEntry -Message "$($cAconfig.name) has been created" -Type Information
84 | start-vm -Name $cAconfig.name
85 | Write-LogEntry -Message "CA Server named $($caconfig.name) has been started" -Type Information
86 | Get-VMNetworkAdapter -VMName $cAconfig.name | Connect-VMNetworkAdapter -SwitchName $CAConfig.network
87 | Write-LogEntry -Message "vSwitch named $($CAConfig.network) has been attached to $($cAconfig.name)" -Type Information
88 | }
89 | while ((Invoke-Command -VMName $cAconfig.name -Credential $CAConfig.localadmin { "Test" } -ErrorAction SilentlyContinue) -ne "Test") { Start-Sleep -Seconds 5 }
90 | $cAsessionLA = New-PSSession -vmname $cAconfig.name -credential $CAConfig.localadmin
91 | Write-LogEntry -Message "PowerShell Direct session for $($CAConfig.localadmin.UserName) has been initiated to $($cAconfig.name)" -Type Information
92 | if ($null -eq $casessionLA) { throw "Issue with CA Local User Account" }
93 | $canics = Invoke-Command -session $casessionLA -ScriptBlock { Get-NetAdapter }
94 | Write-LogEntry -Message "Network Adaptor $($canics -join ",") were found on $($cAconfig.name)" -Type Information
95 | if ((Invoke-Pester -tagfilter "CAIP" -passthru -output none).result -ne "Passed") {
96 | $IPGateway = "$ipsubnet`1"
97 | $null = Invoke-Command -session $casessionLA -ScriptBlock { param($t, $i, $g, $d) new-NetIPAddress -InterfaceIndex $t -AddressFamily IPv4 -IPAddress "$i" -PrefixLength 24 -DefaultGateway "$g"; Set-DnsClientServerAddress -ServerAddresses ($d) -InterfaceIndex $t } -ArgumentList $canics.InterfaceIndex, $caconfig.ipaddress, $IPGateway, $CAConfig.DCIP | Out-Null
98 | Write-LogEntry -Message "IP Address $($CAConfig.IPAddress) has been assigned to $($cAconfig.name)" -Type Information
99 | start-sleep 120
100 | }
101 | if ((Invoke-Pester -tagfilter "CADOM" -passthru -output none).result -eq "Passed") {
102 | while ((Invoke-Command -VMName $caconfig.name -Credential $CAConfig.localadmin { param($i)(test-netconnection "$i`10" -ErrorAction SilentlyContinue).pingsucceeded } -ArgumentList $ipsub -ErrorAction SilentlyContinue) -ne $true -and $stop -ne (get-date)) { Start-Sleep -Seconds 5 }
103 | Invoke-Command -session $casessionLA -ErrorAction SilentlyContinue -ScriptBlock { param($env, $DU) Clear-DnsClientCache; Add-Computer -DomainName $env -domainCredential $DU -Restart; Start-Sleep -Seconds 15; Restart-Computer -Force -Delay 0 } -ArgumentList $CACOnfig.domainFQDN, $CAConfig.domainuser
104 | Write-LogEntry -Message "$($cAconfig.name) has been joined to $($CACOnfig.domainFQDN)" -Type Information
105 | $stop = (get-date).AddMinutes(5)
106 | while ((Invoke-Command -VMName $caconfig.name -Credential $CAConfig.domainuser { "Test" } -ErrorAction SilentlyContinue) -ne "Test" -and $stop -ne (get-date)) { Start-Sleep -Seconds 5 }
107 | }
108 | else {
109 | throw "CA Server can't resolve $($CACOnfig.domainFQDN)"
110 | }
111 | $casession = New-PSSession -VMName $cAconfig.name -Credential $CAConfig.domainuser
112 | Write-LogEntry -Message "PowerShell Direct session for user $($CAConfig.domainuser.UserName) has been initiated to $($cAconfig.name)" -Type Information
113 | if ((Invoke-Pester -tagfilter "CAFeatures" -passthru -output none).result -ne "Passed") {
114 | Invoke-Command -session $casession -ScriptBlock { Add-WindowsFeature -Name ADCS-Cert-Authority, ADCS-Web-Enrollment, Storage-Services, Web-Default-Doc, Web-Dir-Browsing, Web-Http-Errors, Web-Static-Content, Web-Http-Redirect, Web-Http-Logging, Web-Log-Libraries, Web-Request-Monitor, Web-Http-Tracing, Web-Stat-Compression, Web-Filtering, Web-Windows-Auth, Web-ASP, Web-ISAPI-Ext, Web-Mgmt-Console, Web-Metabase, NET-Framework-45-Core, NET-WCF-TCP-PortSharing45, RSAT-ADCS-Mgmt, RSAT-Online-Responder, RSAT-AD-PowerShell | Out-Null }
115 | Write-LogEntry -Message "Cert Authority feature has been enabled on $($caconfig.name)" -Type Information
116 | }
117 | # add new service account
118 | # grant service account permissions to the CA to manage certs
119 |
120 | Invoke-Command -Session $casession -ScriptBlock { Set-ItemProperty -path HKLM:\SOFTWARE\Microsoft\ServerManager -name DoNotOpenServerManagerAtLogon -Type DWord -value "1" -Force }
121 | Invoke-Command -session $casession -ScriptBlock { param($env)Install-AdcsCertificationAuthority -CAType EnterpriseRootCa -CryptoProviderName "RSA#Microsoft Software Key Storage Provider" -KeyLength 2048 -HashAlgorithmName SHA256 -validityPeriod Months -validityPeriodUnits 6 -CACommonName "$($env)-root" -confirm:$false | Out-Null } -ArgumentList $CAConfig.network
122 | Invoke-Command -session $casession -ScriptBlock { Install-AdcsWebEnrollment -Confirm:$false | Out-Null }
123 | Invoke-Command -session $casession -ScriptBlock { Get-CACrlDistributionPoint | Where-Object { $_.uri -like "http*" } | Remove-CACrlDistributionPoint -Confirm:$false | Out-Null }
124 | Invoke-Command -session $casession -ScriptBlock { Add-CACrlDistributionPoint -Uri "http:///CertEnroll/.crl" -AddToCertificateCdp -AddToFreshestCrl -AddToCrlIdp -Confirm:$false | Out-Null }
125 | Invoke-Command -session $casession -ScriptBlock { Get-CAAuthorityInformationAccess | Where-Object { $_.URI -like 'http:*' } | Remove-CAAuthorityInformationAccess -Confirm:$false | Out-Null }
126 | Invoke-Command -session $casession -ScriptBlock { Add-CAAuthorityInformationAccess -Uri "http:///CertEnroll/_.crt" -AddToCertificateAia -Confirm:$false | Out-Null }
127 | Invoke-Command -session $casession -ScriptBlock { Get-Service -Name certsvc | Restart-Service | Out-Null }
128 | $ndessvcuser = "ndessvc"
129 |
130 | $KDCScriptBlock = [ScriptBlock]::create((get-command new-kdccert).Definition.Replace("`$domain", $domainnetbios))
131 | Invoke-Command -Session $casession -ScriptBlock $KDCScriptBlock
132 | $CCMWebScriptBlock = [ScriptBlock]::create((get-command new-ccmwebcert).Definition.Replace("`$domain", $domainnetbios).Replace("`$ndessvc",$ndessvcuser))
133 | Invoke-Command -Session $casession -ScriptBlock $CCMWebScriptBlock
134 | $NDESScriptBlock = [scriptblock]::Create((get-command new-NDESUsercert).Definition.Replace("`$domain", $domainnetbios).Replace("`$ndessvc",$ndessvcuser))
135 | Invoke-Command -Session $casession -ScriptBlock $NDESScriptBlock
136 | Invoke-Command -session $casession -ScriptBlock { Remove-CATemplate DomainControllerAuthentication -Confirm:$false }
137 | Invoke-Command -session $casession -ScriptBlock { Remove-CATemplate KerberosAuthentication -Confirm:$false }
138 | Invoke-Command -session $casession -ScriptBlock { Remove-CATemplate DomainController -Confirm:$false }
139 | Write-LogEntry -Message "Certificate Authority role has been installed on $($cAconfig.name)" -Type Information
140 | Invoke-Command -Session $casession -ScriptBlock { param($env)Get-ChildItem -Path Cert:\LocalMachine\Root | Where-Object { $_.subject -like "CN=$env*" } | Select-Object -Unique | Export-Certificate -FilePath c:\rootcert.cer | out-null } -ArgumentList $CAConfig.network
141 | Copy-Item -FromSession $casession -Path "C:\rootcert.cer" -Destination "$(split-path $CAConfig.VHDXpath)\rootcert.cer" | Out-Null
142 | Invoke-Command -Session $casession -ScriptBlock { param($env)Get-ChildItem -Path Cert:\LocalMachine\CA | Where-Object { $_.subject -like "CN=$env*" } | Select-Object -Unique | Export-Certificate -FilePath c:\intcert.cer | out-null } -ArgumentList $CAConfig.network
143 | Copy-Item -FromSession $casession -Path "C:\intcert.cer" -Destination "$(split-path $CAConfig.VHDXpath)\intcert.cer" | Out-Null
144 | $casession | Remove-PSSession
145 |
146 | $rootcert = "$vmpath\rootcert.cer"
147 | $intCert = "$vmpath\intcert.cer"
148 | $dcsessiondom = New-PSSession -VMName "$($caconfig.network)DC" -Credential $CAconfig.domainuser
149 | Copy-Item -ToSession $dcsessiondom -Path $rootcert -Destination "c:\rootcert.cer" | Out-Null
150 | copy-item -ToSession $dcsessiondom -Path $intCert -Destination "c:\intcert.cer" | Out-Null
151 | Invoke-Command -Session $dcsessiondom -ScriptBlock { Import-Certificate -FilePath C:\rootcert.cer -CertStoreLocation Cert:\LocalMachine\Root | out-null }
152 | Invoke-Command -Session $dcsessiondom -ScriptBlock { Import-Certificate -FilePath C:\intcert.cer -CertStoreLocation Cert:\LocalMachine\CA | out-null }
153 | Invoke-Command -Session $dcsessiondom -ScriptBlock { Get-ChildItem Cert:\LocalMachine\My | Remove-Item }
154 | Invoke-Command -Session $dcsessiondom -ScriptBlock { certreq -machine -q -enroll "Domain Controller Authentication (KDC)" | Out-Null }
155 | $dcsessiondom | Remove-PSSession
156 | Write-LogEntry -Message "PowerShell Direct session for $($CAConfig.domainuser.UserName) has been disconnected from $($cAconfig.name)" -Type Information
157 | Invoke-Pester -TagFilter "CA" -Output Detailed
158 | Write-LogEntry -Message "Installation of CA Server named $($cAconfig.name) is completed" -Type Information
159 | }
160 | }
161 |
--------------------------------------------------------------------------------
/NewCMSettingfile.ps1:
--------------------------------------------------------------------------------
1 | function New-CMSettingfile {
2 | param(
3 | [Parameter(ParameterSetName = 'NoClass')]
4 | [ValidateSet("CAS", "PRI", "CASPRI")]
5 | [string]
6 | $CMServerType,
7 | $ServerName,
8 | $cmsitecode,
9 | $domainFQDN,
10 | $sqlsettings,
11 | [parameter(Mandatory = $false)]
12 | $CasServerName,
13 | [parameter(Mandatory = $false)]
14 | $CasSiteCode,
15 | [ValidateSet("TP", "Prod")]
16 | [string]
17 | $ver
18 | )
19 | if ($ver -eq "Prod") {
20 | if ($CMServerType -eq "CAS") {
21 | $hashident = @{'action' = 'InstallCAS' }
22 | }
23 | elseif ($CMServerType -eq "PRI") {
24 | $hashident = @{'action' = 'InstallPrimarySite' }
25 | }
26 | elseif ($CMServerType -eq "CASPRI") {
27 | $hashident = @{'action' = 'InstallPrimarySite';
28 | 'CDLatest' = "1"
29 | }
30 | }
31 | }
32 | elseif ($ver -eq "TP") {
33 | $hashident = @{'action' = 'InstallPrimarySite';
34 | 'Preview' = "1"
35 | }
36 | }
37 | if ($CMServerType -eq "CAS") {
38 | $hashoptions = @{'ProductID' = 'EVAL';
39 | 'SiteCode' = $cmsitecode;
40 | 'SiteName' = "Tech Preview $cmsitecode";
41 | 'SMSInstallDir' = 'C:\Program Files\Microsoft Configuration Manager';
42 | 'SDKServer' = "$cmOSName.$DomainFQDN";
43 | 'PrerequisiteComp' = "$SCCMDLPreDown";
44 | 'PrerequisitePath' = "C:\DATA\SCCM\DL";
45 | 'MobileDeviceLanguage' = "0";
46 | 'AdminConsole' = "1";
47 | 'JoinCEIP' = "0";
48 | }
49 | }
50 | elseif ($CMServerType -eq "PRI") {
51 | $hashoptions = @{'ProductID' = 'EVAL';
52 | 'SiteCode' = $cmsitecode;
53 | 'SiteName' = "Tech Preview $cmsitecode";
54 | 'SMSInstallDir' = 'C:\Program Files\Microsoft Configuration Manager';
55 | 'SDKServer' = "$cmOSName.$DomainFQDN";
56 | 'RoleCommunicationProtocol' = "HTTPorHTTPS";
57 | 'ClientsUsePKICertificate' = "0";
58 | 'PrerequisiteComp' = "$SCCMDLPreDown";
59 | 'PrerequisitePath' = "C:\DATA\SCCM\DL";
60 | 'ManagementPoint' = "$cmOSName.$DomainFQDN";
61 | 'ManagementPointProtocol' = "HTTP";
62 | 'DistributionPoint' = "$cmOSName.$DomainFQDN";
63 | 'DistributionPointProtocol' = "HTTP";
64 | 'DistributionPointInstallIIS' = "0";
65 | 'AdminConsole' = "1";
66 | 'JoinCEIP' = "0";
67 | }
68 | }
69 | elseif ($CMServerType -eq "CASPRI") {
70 | $hashoptions = @{'ProductID' = 'EVAL';
71 | 'SiteCode' = $cmsitecode;
72 | 'SiteName' = "Tech Preview";
73 | 'SMSInstallDir' = 'C:\Program Files\Microsoft Configuration Manager';
74 | 'SDKServer' = "$cmOSName.$DomainFQDN";
75 | 'RoleCommunicationProtocol' = "HTTPorHTTPS";
76 | 'ClientsUsePKICertificate' = "0";
77 | 'PrerequisiteComp' = "$SCCMDLPreDown";
78 | 'PrerequisitePath' = "\\$CasServerName\SMS_$CasSiteCode\cd.latest\DL";
79 | 'ManagementPoint' = "$cmOSName.$DomainFQDN";
80 | 'ManagementPointProtocol' = "HTTP";
81 | 'DistributionPoint' = "$cmOSName.$DomainFQDN";
82 | 'DistributionPointProtocol' = "HTTP";
83 | 'DistributionPointInstallIIS' = "0";
84 | 'AdminConsole' = "1";
85 | 'JoinCEIP' = "0";
86 | }
87 | }
88 | $hashSQL = @{'SQLServerName' = "$cmOSName.$DomainFQDN";
89 | 'SQLServerPort' = '1433';
90 | 'DatabaseName' = "CM_$cmsitecode";
91 | 'SQLSSBPort' = '4022';
92 | 'SQLDataFilePath' = "$($sqlsettings.DefaultFile)";
93 | 'SQLLogFilePath' = "$($sqlsettings.DefaultLog)"
94 | }
95 | $hashCloud = @{
96 | 'CloudConnector' = "1";
97 | 'CloudConnectorServer' = "$cmOSName.$DomainFQDN"
98 | }
99 | $hashSCOpts = @{
100 | }
101 | if ($CMServerType -eq "CASPRI") {
102 | $hashHierarchy = @{
103 | 'CCARSiteServer' = "$CasServerName"
104 | }
105 | }
106 | else {
107 | $hashHierarchy = @{ }
108 | }
109 | $HASHCMInstallINI = @{'Identification' = $hashident;
110 | 'Options' = $hashoptions;
111 | 'SQLConfigOptions' = $hashSQL;
112 | 'CloudConnectorOptions' = $hashCloud;
113 | 'SystemCenterOptions' = $hashSCOpts;
114 | 'HierarchyExpansionOption' = $hashHierarchy
115 | }
116 | $CMInstallINI = ""
117 | Foreach ($i in $HASHCMInstallINI.keys) {
118 | $CMInstallINI += "[$i]`r`n"
119 | foreach ($j in $($HASHCMInstallINI[$i].keys | Sort-Object)) {
120 | $CMInstallINI += "$j=$($HASHCMInstallINI[$i][$j])`r`n"
121 | }
122 | $CMInstallINI += "`r`n"
123 | }
124 | return $CMInstallINI
125 | }
--------------------------------------------------------------------------------
/NewENV.Testsold.ps1old:
--------------------------------------------------------------------------------
1 | $scriptpath = $PSScriptRoot
2 | $config = Get-Content "$scriptpath\env.json" -Raw | ConvertFrom-Json
3 | $envConfig = $config.ENVConfig | Where-Object { $_.env -eq $config.env }
4 | $admpwd = $envConfig.AdminPW
5 | $localadmin = new-object -typename System.Management.Automation.PSCredential -argumentlist "administrator", (ConvertTo-SecureString -String $admpwd -AsPlainText -Force)
6 | $domuser = new-object -typename System.Management.Automation.PSCredential -argumentlist "$($envconfig.env)\administrator", (ConvertTo-SecureString -String $admpwd -AsPlainText -Force)
7 | $vmpath = $envConfig.VMPath
8 | $swname = $envConfig.SwitchName
9 | #$ipsub = $envConfig.ipsubnet
10 | $DomainFQDN = $envconfig.DomainFQDN
11 | #$RRASname = $Config.RRASname
12 | $RefVHDX = $config.REFVHDX
13 | #$dcname = "$($envconfig.env)`DC"
14 | #if ($Config.SCCMCAS -eq "1") {
15 | # $cmconfig.name = "$($envconfig.ENV)`CMCAS"
16 | #}
17 | #else {
18 | # $cmconfig.name = "$($envconfig.env)`CM"
19 | #}
20 |
21 | . .\Lab.Classes.ps1
22 | Describe "RRAS" -Tag ("Network", "RRAS", "VM") {
23 | $RRASConfig = [RRAS]::new()
24 | $rrasconfig.load("$(split-path $vmpath)\RRASConfig.json")
25 | $tRRASVHDXExists = test-path $RRASConfig.VHDXpath
26 | $tRRASExist = (get-vm -Name $RRASConfig.Name -ErrorAction SilentlyContinue).count
27 | $trrasrunning = (get-vm -Name $RRASConfig.Name -ErrorAction SilentlyContinue | Where-Object { $_.State -match "Running" }).Count
28 | if ($tRRASExist -eq 1 -and $trrasrunning -eq 1) {
29 | $trrasSession = New-PSSession -VMName $RRASConfig.Name -Credential $localadmin
30 | $rrasfeat = (Invoke-Command -Session $trrasSession -ScriptBlock { (get-windowsfeature -name routing).installstate }).value
31 | $rrasEXTrename = (Invoke-Command -Session $trrasSession -ScriptBlock { Get-NetAdapter -Physical -Name "External" -ErrorAction SilentlyContinue }).name
32 | $rrasLABrename = (Invoke-Command -Session $trrasSession -ScriptBlock { param($n)Get-NetAdapter -Physical -Name $n -ErrorAction SilentlyContinue } -ArgumentList $RRASConfig.network).name
33 | $rrasVPNStatus = (Invoke-Command -Session $trrasSession -ScriptBlock { if ((get-command Get-RemoteAccess -ErrorAction SilentlyContinue).count -eq 1) { Get-RemoteAccess -ErrorAction SilentlyContinue } })
34 | $rrasLabIPAddress = (Invoke-Command -Session $trrasSession -ScriptBlock { param($n)(Get-NetIPAddress -interfacealias $n -AddressFamily IPv4 -ErrorAction SilentlyContinue).ipaddress } -ArgumentList $RRASConfig.network)
35 | $tRRASInternet = (Invoke-Command -Session $trrasSession -ScriptBlock { test-netconnection "8.8.8.8" -WarningAction SilentlyContinue -ErrorAction SilentlyContinue }).PingSucceeded
36 | $trrasSession | Remove-PSSession
37 | }
38 | it 'RRAS VHDX Should exist' { $tRRASVHDXExists | should be $true }
39 | it 'RRAS Server Should exist' { $tRRASExist | should be 1 }
40 | it 'RRAS Server is Running' { $trrasrunning | should be 1 }
41 | it 'RRAS Routing Installed' -Skip:(!($tRRASExist -eq 1 -and $trrasrunning -eq 1)) { $rrasfeat | should be "Installed" }
42 | it 'RRAS External NIC Renamed' -Skip:(!($tRRASExist -eq 1 -and $trrasrunning -eq 1)) { $rrasEXTrename | should be "External" }
43 | it 'RRAS Lab NIC Renamed' -Skip:(!($tRRASExist -eq 1 -and $trrasrunning -eq 1)) { $rrasLABrename | should be $RRASConfig.network }
44 | it 'RRAS Lab IP Address Set' -Skip:(!($tRRASExist -eq 1 -and $trrasrunning -eq 1)) { $rrasLabIPAddress | should be $RRASConfig.ipaddress }
45 | it 'RRAS VPN enabled' -Skip:(!($tRRASExist -eq 1 -and $trrasrunning -eq 1)) { $rrasVPNStatus.VpnStatus | should be 'Installed' }
46 | it 'RRAS has access to Internet' -Skip:(!($tRRASExist -eq 1 -and $trrasrunning -eq 1)) { $tRRASInternet | should be $true }
47 | }
48 |
49 | Describe "DC" -Tag ("Domain", "VM") {
50 | $DCConfig = [DC]::new()
51 | $dcconfig.load("$vmpath\dcconfig.json")
52 | $TDCVHDXExists = (Test-Path -path $DCConfig.VHDXpath)
53 | $TDCExists = (get-vm -name $dcconfig.Name -ErrorAction SilentlyContinue).count
54 | $TDCRunning = (get-vm -name $dcconfig.Name -ErrorAction SilentlyContinue | Where-Object { $_.State -match "Running" }).count
55 | if ($TDCExists -eq 1 -and $TDCRunning -eq 1) {
56 | $TDCSession = new-PSSession -VMName $dcconfig.Name -Credential $localadmin -ErrorAction SilentlyContinue
57 | if (!($TDCSession)) { $TDCSession = new-PSSession -VMName $dcconfig.Name -Credential $domuser; $TDCPromoted = $true } else { $TDCPromoted = $false }
58 | $TDCIPAddress = (Invoke-Command -Session $TDCSession -ScriptBlock { (Get-NetIPAddress -AddressFamily IPv4 -PrefixOrigin Manual -ErrorAction SilentlyContinue).ipaddress })
59 | $TDCFeat = (Invoke-Command -Session $TDCSession -ScriptBlock { (get-windowsfeature -name AD-Domain-Services).installstate }).value
60 | $TDCTestInternet = (Invoke-Command -Session $TDCSession -ScriptBlock { test-netconnection "steven.hosking.com.au" -CommonTCPPort HTTP -WarningAction SilentlyContinue -ErrorAction SilentlyContinue }).TcpTestSucceeded
61 | $TDCPromoted = (Invoke-Command -Session $TDCSession -ScriptBlock { Get-Service -Name "NTDS" -ErrorAction SilentlyContinue }).status
62 | $TDCDHCPScopeexists = (Invoke-Command -Session $TDCSession -ScriptBlock { if (get-command Get-DhcpServerv4Scope -ErrorAction SilentlyContinue) { Get-DhcpServerv4Scope -ErrorAction SilentlyContinue -warningaction SilentlyContinue } })
63 | $TDCADWSState = (Invoke-Command -session $TDCSession { Get-WmiObject -class Win32_Service -filter 'name="adws"' }).state
64 | if ($TDCADWSState -eq "Running")
65 | { $TDCSCCMGroupExists = (Invoke-Command -Session $TDCSession -ScriptBlock { if (get-command get-adgroup -ErrorAction SilentlyContinue -WarningAction SilentlyContinue) { get-adgroup -Filter "name -eq 'SCCM Servers'" -ErrorAction SilentlyContinue -WarningAction SilentlyContinue } }) }
66 | $TDCSession | Remove-PSSession
67 | }
68 | it 'DC VHDX Should Exist' { $TDCVHDXExists | should be $true }
69 | it "DC Should Exist" { $TDCExists | should be 1 }
70 | it "DC Should be running" { $TDCRunning | should be 1 }
71 | it 'DC IP Address' -Skip:(!($TDCExists -eq 1 -and $TDCRunning -eq 1)) { $TDCIPAddress | should be $DCConfig.IPAddress }
72 | it 'DC has access to Internet' -Skip:(!($TDCExists -eq 1 -and $TDCRunning -eq 1)) { $TDCTestInternet | should be $true }
73 | it 'DC Domain Services Installed' -Skip:(!($TDCExists -eq 1 -and $TDCRunning -eq 1)) { $TDCFeat | should be "Installed" }
74 | it 'DC Promoted' -Skip:(!($TDCExists -eq 1 -and $TDCRunning -eq 1)) { $TDCPromoted | should be "Running" }
75 | it 'DC DHCP Scope Active' -Skip:(!($TDCExists -eq 1 -and $TDCRunning -eq 1)) { $TDCDHCPScopeexists[0].State | should be "Active" }
76 | it 'DC SCCM Servers Group' -Skip:(!($TDCExists -eq 1 -and $TDCRunning -eq 1)) { $TDCSCCMGroupExists[0].name | should be "SCCM Servers" }
77 | }
78 |
79 | if ($Config.SCCMENVType -eq "CAS") {
80 | Describe "CMCAS" -tag ("CAS") {
81 | $CMConfig = [CM]::new()
82 | $CMConfig.load("$vmpath\$($config.env)`cmCASconfig.json")
83 | $TCMVHDXExists = (Test-Path -path $CMConfig.VHDXpath)
84 | $TCMExists = (get-vm -name $cmconfig.name -ErrorAction SilentlyContinue).count
85 | $TCMRunning = (get-vm -name $cmconfig.name -ErrorAction SilentlyContinue | Where-Object { $_.State -match "Running" }).count
86 | if ($TCMExists -eq 1 -and $TCMRunning -eq 1) {
87 | $TCMSession = new-PSSession -VMName $cmconfig.name -Credential $localadmin -ErrorAction SilentlyContinue
88 | if (!($TCMSession)) { $TCMSession = new-PSSession -VMName $cmconfig.name -Credential $domuser }
89 | $TCMIPAddress = (Invoke-Command -Session $TCMSession -ScriptBlock { (Get-NetIPAddress -AddressFamily IPv4 -PrefixOrigin Manual -ErrorAction SilentlyContinue).ipaddress })
90 | $TCMTestInternet = (Invoke-Command -Session $TCMSession -ScriptBlock { test-netconnection "8.8.8.8" -WarningAction SilentlyContinue -ErrorAction SilentlyContinue }).PingSucceeded
91 | $TCMTestDomain = (Invoke-Command -Session $TCMSession -ScriptBlock { param($d)Test-NetConnection $d -erroraction SilentlyContinue -WarningAction SilentlyContinue } -ArgumentList $CMConfig.domainFQDN ).PingSucceeded
92 | $TCMFeat = (Invoke-Command -Session $TCMSession -ScriptBlock { (get-windowsfeature -name 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-Ext, 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) | Where-Object { $_.installstate -eq "Installed" } }).count
93 | $TCMNetFeat = (Invoke-Command -Session $TCMSession -ScriptBlock { (get-windowsfeature -name NET-Framework-Features, NET-Framework-Core) | Where-Object { $_.installstate -eq "Installed" } }).count
94 | $TCMSQLInstalled = (Invoke-Command -Session $TCMSession -ScriptBlock { get-service -name "MSSQLSERVER" -ErrorAction SilentlyContinue }).name.count
95 | $TCMADKInstalled = (Invoke-Command -Session $TCMSession -ScriptBlock { test-path "C:\Program Files (x86)\Windows Kits\10\Assessment and deployment kit" -ErrorAction SilentlyContinue })
96 | $TCMSCCMServerinGRP = (Invoke-Command -Session $TCMSession -ScriptBlock { Get-ADGroupMember "SCCM Servers" | Where-Object { $_.name -eq $env:computername } } -ErrorAction SilentlyContinue).name.count
97 | $TCMSCCMInstalled = (Invoke-Command -Session $TCMSession -ScriptBlock { get-service -name "SMS_EXECUTIVE" -ErrorAction SilentlyContinue }).name.count
98 | $TCMSCCMConsoleInstalled = (Invoke-Command -Session $TCMSession -ScriptBlock { test-path "C:\Program Files (x86)\Microsoft Configuration Manager\AdminConsole\bin\Microsoft.ConfigurationManagement.exe" })
99 | if ($TCMSCCMConsoleInstalled) {
100 | Invoke-Command -Session $TCMSession -ScriptBlock { param ($sitecode) import-module "$(($env:SMS_ADMIN_UI_PATH).remove(($env:SMS_ADMIN_UI_PATH).Length -4, 4))ConfigurationManager.psd1"; if ($null -eq (Get-PSDrive -Name $SiteCode -PSProvider CMSite -ErrorAction SilentlyContinue)) { New-PSDrive -Name $SiteCode -PSProvider CMSite -Root $env:COMPUTERNAME }; Set-Location "$((Get-PSDrive -PSProvider CMSite).name)`:" } -ArgumentList $CMConfig.cmsitecode
101 | $TCMBoundary = (Invoke-Command -Session $TCMSession -ScriptBlock { param($subname) Get-CMBoundary -name $subname } -ArgumentList $CMConfig.network).displayname.count
102 | $TCMDiscovery = (Invoke-Command -Session $TCMSession -ScriptBlock { Get-CMDiscoveryMethod -Name ActiveDirectorySystemDiscovery }).flag
103 | }
104 | $TCMSession | Remove-PSSession
105 | }
106 | it 'CM VHDX Should Exist' { $TCMVHDXExists | should be $true }
107 | it 'CM Should Exist' { $TCMExists | should be 1 }
108 | it 'CM Should be running' { $TCMRunning | should be 1 }
109 | it 'CM IP Address' -Skip:(!($TCMExists -eq 1 -and $TCMRunning -eq 1)) { $TCMIPAddress | should be $CMConfig.IPAddress }
110 | it 'CM has access to Internet' -Skip:(!($TCMExists -eq 1 -and $TCMRunning -eq 1)) { $TCMTestInternet | should be $true }
111 | it "CM has access to $DomainFQDN" -Skip:(!($TCMExists -eq 1 -and $TCMRunning -eq 1)) { $TCMTestDomain | Should be $true }
112 | it 'CM .Net Feature installed' -Skip:(!($TCMExists -eq 1 -and $TCMRunning -eq 1)) { $TCMNetFeat | should be 2 }
113 | it 'CM Features are installed' -Skip:(!($TCMExists -eq 1 -and $TCMRunning -eq 1)) { $TCMFeat | should be 44 }
114 | it 'CM SQL Instance is installed' -Skip:(!($TCMExists -eq 1 -and $TCMRunning -eq 1)) { $TCMSQLInstalled | should be 1 }
115 | it 'CM ADK Installed' -Skip:(!($TCMExists -eq 1 -and $TCMRunning -eq 1)) { $TCMADKInstalled | should be $true }
116 | it 'CM Server in Group' -Skip:(!($TCMExists -eq 1 -and $TCMRunning -eq 1)) { $TCMSCCMServerinGRP | should be 1 }
117 | it 'CM SCCM Installed' -Skip:(!($TCMExists -eq 1 -and $TCMRunning -eq 1)) { $TCMSCCMInstalled | should be 1 }
118 | it 'CM SCCM Console Installed' -Skip:(!($TCMExists -eq 1 -and $TCMRunning -eq 1)) { $TCMSCCMConsoleInstalled | should be $true }
119 | it 'CM Site Boundary added' -Skip:(!($TCMExists -eq 1 -and $TCMRunning -eq 1 -and $TCMSCCMConsoleInstalled)) { $TCMBoundary | should be 1 }
120 | it 'CM System Discovery enabled' -Skip:(!($TCMExists -eq 1 -and $TCMRunning -eq 1 -and $TCMSCCMConsoleInstalled)) { $TCMDiscovery | should be 6 }
121 | }
122 | Describe "CMCAS" -tag ("CASPRI") {
123 | $CMConfig = [CM]::new()
124 | $CMConfig.load("$vmpath\$($config.env)`cmCASPRIconfig.json")
125 | $TCMVHDXExists = (Test-Path -path $CMConfig.VHDXpath)
126 | $TCMExists = (get-vm -name $cmconfig.name -ErrorAction SilentlyContinue).count
127 | $TCMRunning = (get-vm -name $cmconfig.name -ErrorAction SilentlyContinue | Where-Object { $_.State -match "Running" }).count
128 | if ($TCMExists -eq 1 -and $TCMRunning -eq 1) {
129 | $TCMSession = new-PSSession -VMName $cmconfig.name -Credential $localadmin -ErrorAction SilentlyContinue
130 | if (!($TCMSession)) { $TCMSession = new-PSSession -VMName $cmconfig.name -Credential $domuser }
131 | $TCMIPAddress = (Invoke-Command -Session $TCMSession -ScriptBlock { (Get-NetIPAddress -AddressFamily IPv4 -PrefixOrigin Manual -ErrorAction SilentlyContinue).ipaddress })
132 | $TCMTestInternet = (Invoke-Command -Session $TCMSession -ScriptBlock { test-netconnection "8.8.8.8" -WarningAction SilentlyContinue -ErrorAction SilentlyContinue }).PingSucceeded
133 | $TCMTestDomain = (Invoke-Command -Session $TCMSession -ScriptBlock { param($d)Test-NetConnection $d -erroraction SilentlyContinue -WarningAction SilentlyContinue } -ArgumentList $CMConfig.domainFQDN ).PingSucceeded
134 | $TCMFeat = (Invoke-Command -Session $TCMSession -ScriptBlock { (get-windowsfeature -name 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-Ext, 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) | Where-Object { $_.installstate -eq "Installed" } }).count
135 | $TCMNetFeat = (Invoke-Command -Session $TCMSession -ScriptBlock { (get-windowsfeature -name NET-Framework-Features, NET-Framework-Core) | Where-Object { $_.installstate -eq "Installed" } }).count
136 | $TCMSQLInstalled = (Invoke-Command -Session $TCMSession -ScriptBlock { get-service -name "MSSQLSERVER" -ErrorAction SilentlyContinue }).name.count
137 | $TCMADKInstalled = (Invoke-Command -Session $TCMSession -ScriptBlock { test-path "C:\Program Files (x86)\Windows Kits\10\Assessment and deployment kit" -ErrorAction SilentlyContinue })
138 | $TCMSCCMServerinGRP = (Invoke-Command -Session $TCMSession -ScriptBlock { Get-ADGroupMember "SCCM Servers" | Where-Object { $_.name -eq $env:computername } } -ErrorAction SilentlyContinue).name.count
139 | $TCMSCCMInstalled = (Invoke-Command -Session $TCMSession -ScriptBlock { get-service -name "SMS_EXECUTIVE" -ErrorAction SilentlyContinue }).name.count
140 | $TCMSCCMConsoleInstalled = (Invoke-Command -Session $TCMSession -ScriptBlock { test-path "C:\Program Files (x86)\Microsoft Configuration Manager\AdminConsole\bin\Microsoft.ConfigurationManagement.exe" })
141 | if ($TCMSCCMConsoleInstalled) {
142 | Invoke-Command -Session $TCMSession -ScriptBlock { param ($sitecode) import-module "$(($env:SMS_ADMIN_UI_PATH).remove(($env:SMS_ADMIN_UI_PATH).Length -4, 4))ConfigurationManager.psd1"; if ($null -eq (Get-PSDrive -Name $SiteCode -PSProvider CMSite -ErrorAction SilentlyContinue)) { New-PSDrive -Name $SiteCode -PSProvider CMSite -Root $env:COMPUTERNAME }; Set-Location "$((Get-PSDrive -PSProvider CMSite).name)`:" } -ArgumentList $CMConfig.cmsitecode
143 | $TCMBoundary = (Invoke-Command -Session $TCMSession -ScriptBlock { param($subname) Get-CMBoundary -name $subname } -ArgumentList $CMConfig.network).displayname.count
144 | $TCMDiscovery = (Invoke-Command -Session $TCMSession -ScriptBlock { Get-CMDiscoveryMethod -Name ActiveDirectorySystemDiscovery }).flag
145 | }
146 | $TCMSession | Remove-PSSession
147 | }
148 | it 'CM VHDX Should Exist' { $TCMVHDXExists | should be $true }
149 | it 'CM Should Exist' { $TCMExists | should be 1 }
150 | it 'CM Should be running' { $TCMRunning | should be 1 }
151 | it 'CM IP Address' -Skip:(!($TCMExists -eq 1 -and $TCMRunning -eq 1)) { $TCMIPAddress | should be $CMConfig.IPAddress }
152 | it 'CM has access to Internet' -Skip:(!($TCMExists -eq 1 -and $TCMRunning -eq 1)) { $TCMTestInternet | should be $true }
153 | it "CM has access to $DomainFQDN" -Skip:(!($TCMExists -eq 1 -and $TCMRunning -eq 1)) { $TCMTestDomain | Should be $true }
154 | it 'CM .Net Feature installed' -Skip:(!($TCMExists -eq 1 -and $TCMRunning -eq 1)) { $TCMNetFeat | should be 2 }
155 | it 'CM Features are installed' -Skip:(!($TCMExists -eq 1 -and $TCMRunning -eq 1)) { $TCMFeat | should be 44 }
156 | it 'CM SQL Instance is installed' -Skip:(!($TCMExists -eq 1 -and $TCMRunning -eq 1)) { $TCMSQLInstalled | should be 1 }
157 | it 'CM ADK Installed' -Skip:(!($TCMExists -eq 1 -and $TCMRunning -eq 1)) { $TCMADKInstalled | should be $true }
158 | it 'CM Server in Group' -Skip:(!($TCMExists -eq 1 -and $TCMRunning -eq 1)) { $TCMSCCMServerinGRP | should be 1 }
159 | it 'CM SCCM Installed' -Skip:(!($TCMExists -eq 1 -and $TCMRunning -eq 1)) { $TCMSCCMInstalled | should be 1 }
160 | it 'CM SCCM Console Installed' -Skip:(!($TCMExists -eq 1 -and $TCMRunning -eq 1)) { $TCMSCCMConsoleInstalled | should be $true }
161 | it 'CM Site Boundary added' -Skip:(!($TCMExists -eq 1 -and $TCMRunning -eq 1 -and $TCMSCCMConsoleInstalled)) { $TCMBoundary | should be 1 }
162 | it 'CM System Discovery enabled' -Skip:(!($TCMExists -eq 1 -and $TCMRunning -eq 1 -and $TCMSCCMConsoleInstalled)) { $TCMDiscovery | should be 6 }
163 | }
164 | }
165 | else {
166 | Describe "CM" -tag ("PRI") {
167 | $CMConfig = [CM]::new()
168 | $CMConfig.load("$vmpath\$($config.env)`cmconfig.json")
169 | $TCMVHDXExists = (Test-Path -path $CMConfig.VHDXpath)
170 | $TCMExists = (get-vm -name $cmconfig.name -ErrorAction SilentlyContinue).count
171 | $TCMRunning = (get-vm -name $cmconfig.name -ErrorAction SilentlyContinue | Where-Object { $_.State -match "Running" }).count
172 | if ($TCMExists -eq 1 -and $TCMRunning -eq 1) {
173 | $TCMSession = new-PSSession -VMName $cmconfig.name -Credential $localadmin -ErrorAction SilentlyContinue
174 | if (!($TCMSession)) { $TCMSession = new-PSSession -VMName $cmconfig.name -Credential $domuser }
175 | $TCMIPAddress = (Invoke-Command -Session $TCMSession -ScriptBlock { (Get-NetIPAddress -AddressFamily IPv4 -PrefixOrigin Manual -ErrorAction SilentlyContinue).ipaddress })
176 | $TCMTestInternet = (Invoke-Command -Session $TCMSession -ScriptBlock { test-netconnection "8.8.8.8" -WarningAction SilentlyContinue -ErrorAction SilentlyContinue }).PingSucceeded
177 | $TCMTestDomain = (Invoke-Command -Session $TCMSession -ScriptBlock { param($d)Test-NetConnection $d -erroraction SilentlyContinue -WarningAction SilentlyContinue } -ArgumentList $CMConfig.domainFQDN ).PingSucceeded
178 | $TCMFeat = (Invoke-Command -Session $TCMSession -ScriptBlock { (get-windowsfeature -name 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-Ext, 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) | Where-Object { $_.installstate -eq "Installed" } }).count
179 | $TCMNetFeat = (Invoke-Command -Session $TCMSession -ScriptBlock { (get-windowsfeature -name NET-Framework-Features, NET-Framework-Core) | Where-Object { $_.installstate -eq "Installed" } }).count
180 | $TCMSQLInstalled = (Invoke-Command -Session $TCMSession -ScriptBlock { get-service -name "MSSQLSERVER" -ErrorAction SilentlyContinue }).name.count
181 | $TCMADKInstalled = (Invoke-Command -Session $TCMSession -ScriptBlock { test-path "C:\Program Files (x86)\Windows Kits\10\Assessment and deployment kit" -ErrorAction SilentlyContinue })
182 | $TCMSCCMServerinGRP = (Invoke-Command -Session $TCMSession -ScriptBlock { Get-ADGroupMember "SCCM Servers" | Where-Object { $_.name -eq $env:computername } } -ErrorAction SilentlyContinue).name.count
183 | $TCMSCCMInstalled = (Invoke-Command -Session $TCMSession -ScriptBlock { get-service -name "SMS_EXECUTIVE" -ErrorAction SilentlyContinue }).name.count
184 | $TCMSCCMConsoleInstalled = (Invoke-Command -Session $TCMSession -ScriptBlock { test-path "C:\Program Files (x86)\Microsoft Configuration Manager\AdminConsole\bin\Microsoft.ConfigurationManagement.exe" })
185 | if ($TCMSCCMConsoleInstalled) {
186 | Invoke-Command -Session $TCMSession -ScriptBlock { param ($sitecode) import-module "$(($env:SMS_ADMIN_UI_PATH).remove(($env:SMS_ADMIN_UI_PATH).Length -4, 4))ConfigurationManager.psd1"; if ($null -eq (Get-PSDrive -Name $SiteCode -PSProvider CMSite -ErrorAction SilentlyContinue)) { New-PSDrive -Name $SiteCode -PSProvider CMSite -Root $env:COMPUTERNAME }; Set-Location "$((Get-PSDrive -PSProvider CMSite).name)`:" } -ArgumentList $CMConfig.cmsitecode
187 | $TCMBoundary = (Invoke-Command -Session $TCMSession -ScriptBlock { param($subname) Get-CMBoundary -name $subname } -ArgumentList $CMConfig.network).displayname.count
188 | $TCMDiscovery = (Invoke-Command -Session $TCMSession -ScriptBlock { Get-CMDiscoveryMethod -Name ActiveDirectorySystemDiscovery }).flag
189 | }
190 | $TCMSession | Remove-PSSession
191 | }
192 | it 'CM VHDX Should Exist' { $TCMVHDXExists | should be $true }
193 | it 'CM Should Exist' { $TCMExists | should be 1 }
194 | it 'CM Should be running' { $TCMRunning | should be 1 }
195 | it 'CM IP Address' -Skip:(!($TCMExists -eq 1 -and $TCMRunning -eq 1)) { $TCMIPAddress | should be $CMConfig.IPAddress }
196 | it 'CM has access to Internet' -Skip:(!($TCMExists -eq 1 -and $TCMRunning -eq 1)) { $TCMTestInternet | should be $true }
197 | it "CM has access to $DomainFQDN" -Skip:(!($TCMExists -eq 1 -and $TCMRunning -eq 1)) { $TCMTestDomain | Should be $true }
198 | it 'CM .Net Feature installed' -Skip:(!($TCMExists -eq 1 -and $TCMRunning -eq 1)) { $TCMNetFeat | should be 2 }
199 | it 'CM Features are installed' -Skip:(!($TCMExists -eq 1 -and $TCMRunning -eq 1)) { $TCMFeat | should be 44 }
200 | it 'CM SQL Instance is installed' -Skip:(!($TCMExists -eq 1 -and $TCMRunning -eq 1)) { $TCMSQLInstalled | should be 1 }
201 | it 'CM ADK Installed' -Skip:(!($TCMExists -eq 1 -and $TCMRunning -eq 1)) { $TCMADKInstalled | should be $true }
202 | it 'CM Server in Group' -Skip:(!($TCMExists -eq 1 -and $TCMRunning -eq 1)) { $TCMSCCMServerinGRP | should be 1 }
203 | it 'CM SCCM Installed' -Skip:(!($TCMExists -eq 1 -and $TCMRunning -eq 1)) { $TCMSCCMInstalled | should be 1 }
204 | it 'CM SCCM Console Installed' -Skip:(!($TCMExists -eq 1 -and $TCMRunning -eq 1)) { $TCMSCCMConsoleInstalled | should be $true }
205 | it 'CM Site Boundary added' -Skip:(!($TCMExists -eq 1 -and $TCMRunning -eq 1 -and $TCMSCCMConsoleInstalled)) { $TCMBoundary | should be 1 }
206 | it 'CM System Discovery enabled' -Skip:(!($TCMExists -eq 1 -and $TCMRunning -eq 1 -and $TCMSCCMConsoleInstalled)) { $TCMDiscovery | should be 6 }
207 | }
208 | }
209 |
210 |
211 | Describe "CA" -tag ("CA", "VM") {
212 | $CAConfig = [CA]::new()
213 | $CAConfig.load("$VMpath\CAconfig.json")
214 | $TCAVHDXExists = (Test-Path -path $CAConfig.VHDXpath)
215 | $TCAExists = (get-vm -name $CAConfig.Name -ErrorAction SilentlyContinue).count
216 | $TCARunning = (get-vm -name $CAConfig.Name -ErrorAction SilentlyContinue | Where-Object { $_.State -match "Running" }).count
217 | if ($TCAExists -eq 1 -and $TCARunning -eq 1) {
218 | $TCASession = new-PSSession -VMName $CAConfig.Name -Credential $localadmin -ErrorAction SilentlyContinue
219 | if (!($TCASession)) { $TCASession = new-PSSession -VMName $CAConfig.Name -Credential $domuser }
220 | $TCAIPAddress = (Invoke-Command -Session $TCASession -ScriptBlock { (Get-NetIPAddress -AddressFamily IPv4 -PrefixOrigin Manual -ErrorAction SilentlyContinue).ipaddress })
221 | $TCATestInternet = (Invoke-Command -Session $TCASession -ScriptBlock { test-netconnection "8.8.8.8" -WarningAction SilentlyContinue -ErrorAction SilentlyContinue }).PingSucceeded
222 | $TCATestDomain = (Invoke-Command -Session $TCASession -ScriptBlock { param($d)Test-NetConnection $d -erroraction SilentlyContinue -WarningAction SilentlyContinue } -ArgumentList $CAConfig.domainFQDN ).PingSucceeded
223 | $TCAFeat = (Invoke-Command -Session $TCASession -ScriptBlock { (get-windowsfeature -name Adcs-Cert-Authority | Where-Object { $_.installstate -eq "Installed" }).count })
224 | $TCASession | Remove-PSSession
225 | }
226 | it 'CA VHDX Should Exist' { $TCAVHDXExists | should be $true }
227 | it 'CA Should Exist' { $TCAExists | should be 1 }
228 | it 'CA Should be running' { $TCARunning | should be 1 }
229 | it 'CA IP Address' -Skip:(!($TCAExists -eq 1 -and $TCARunning -eq 1)) { $TCAIPAddress | should be $CAConfig.IPAddress }
230 | it 'CA has access to Internet' -Skip:(!($TCAExists -eq 1 -and $TCARunning -eq 1)) { $TCATestInternet | should be $true }
231 | it "CA has access to $DomainFQDN" -Skip:(!($TCAExists -eq 1 -and $TCARunning -eq 1)) { $TCATestDomain | Should be $true }
232 | it 'CA Feature is installed' -Skip:(!($TCAExists -eq 1 -and $TCARunning -eq 1)) { $TCAFeat | should be 1 }
233 |
234 | }
235 |
236 | Describe "vSwitch" -tag ("Network", "ENV") {
237 | $lresult = (Get-VMSwitch -Name $swname -ErrorAction SilentlyContinue).count
238 | $Iresult = (Get-VMSwitch -Name "Internet" -ErrorAction SilentlyContinue).count
239 | it "Lab VMSwitch Should exist" { $lresult | should be 1 }
240 | it 'Internet VSwitch should exist' { $Iresult | should be 1 }
241 | }
242 |
243 | Describe "Reference-VHDX" -Tag ("VM", "Template") {
244 | $result = (Test-Path -Path "$RefVHDX")
245 | it 'VHDX Should exist' { $result | should be $true }
246 | }
247 |
248 | Describe "Test Source Media" -tag ("VM", "ENV") {
249 | $Win16iso = (Test-path -Path "$($config.WIN16ISO)")
250 | $SQLMedia = (Test-Path -Path "$($config.SQLISO)")
251 | $adkmedia = (Test-Path -Path "$($config.ADKPATH)")
252 | $SCCMMedia = (Test-Path -Path "$($config.SCCMPath)")
253 | $SCCMDLMedia = (Test-Path -Path "$($config.SCCMPath)\DL")
254 | $net35path = (Test-Path -Path "$($config.WINNET35CAB)")
255 | $unattendpath = $config.REFVHDX -replace ($config.REFVHDX.split('\') | Select-Object -last 1), "Unattended.xml" ## is wrong, need to change to correct path
256 | $win16unattend = (test-path "$($unattendpath)")
257 | it 'Windows 2016 source media' { $Win16iso | should be $true }
258 | it 'Windows 2016 Unattend' { $win16unattend | should be $true }
259 | it 'SQL 2016 Media' { $SQLMedia | Should be $true }
260 | it 'ADK Content' { $adkmedia | should be $true }
261 | it 'SCCM Media' { $SCCMMedia | should be $true }
262 | it 'SCCM Download Media' { $SCCMDLMedia | should be $true }
263 | it '.net 3.5 Media' { $net35path | should be $true }
264 | }
--------------------------------------------------------------------------------
/NewENV.ps1:
--------------------------------------------------------------------------------
1 | function new-ENV {
2 | param(
3 | [Parameter(ParameterSetName = 'ENVClass')]
4 | [env]
5 | $ENVConfig,
6 | [Parameter(ParameterSetName = 'NoClass')]
7 | [string]
8 | $vmpath,
9 | [Parameter(ParameterSetName = 'NoClass')]
10 | [string]
11 | $RefVHDX,
12 | [Parameter(ParameterSetName = 'NoClass')]
13 | [string]
14 | $Win16ISOPath,
15 | [Parameter(ParameterSetName = 'NoClass')]
16 | [string]
17 | $Win16Net35Cab,
18 | [Parameter(ParameterSetName = 'NoClass')]
19 | [string]
20 | $network,
21 | [Parameter(ParameterSetName = 'NoClass')]
22 | [string]
23 | $DefaultPwd
24 | )
25 | if (!$PSBoundParameters.ContainsKey('ENVConfig')) {
26 | $ENVConfig = [env]::new()
27 | $ENVConfig.vmpath = $vmpath
28 | $ENVConfig.RefVHDX = $RefVHDX
29 | $ENVConfig.Win16ISOPath = $Win16ISOPath
30 | $ENVConfig.Win16Net35Cab = $Win16Net35Cab
31 | $ENVConfig.network = $network
32 | $ENVConfig.DefaultPwd = $DefaultPwd
33 | }
34 | Write-LogEntry -Type Information -Message "Creating the base requirements for Lab Environment"
35 | Write-LogEntry -Type Information -Message "ENV Settings are: $($envconfig | ConvertTo-Json)"
36 | if ((Invoke-Pester -TagFilter "RefVHDX" -PassThru -Output None).result -eq "Passed") {
37 | Write-LogEntry -Type Information -Message "Reference image already exists in: $($ENVConfig.RefVHDX)"
38 | }
39 | else {
40 | if (!(Test-Path $ENVConfig.vmpath)) { New-Item -ItemType Directory -Force -Path $ENVConfig.vmpath }
41 | else {
42 | if (!(Test-Path "$($scriptpath)\unattended.xml")) {
43 | New-UnattendXml -admpwd $ENVConfig.DefaultPwd -outfile "$($scriptpath)\unattended.xml"
44 | }
45 | Write-LogEntry -Type Information -Message "Reference image doesn't exist, will create it now"
46 | new-LabVHDX -VHDXPath $ENVConfig.RefVHDX -Unattend "$($scriptpath)\unattended.xml" -WinISO $ENVConfig.Win16ISOPath -WinNet35Cab $ENVConfig.Win16Net35Cab
47 | Write-LogEntry -Type Information -Message "Reference image has been created in: $($ENVConfig.RefVHDX)"
48 | }
49 | }
50 | if ((invoke-pester -TagFilter "ExternalSwitch" -PassThru -Output None).result -ne 'Passed') {
51 | Write-LogEntry -Type Information -Message "vSwitch named Internet does not exist"
52 | $nic = Get-NetAdapter -Physical
53 | Write-LogEntry -Type Information -Message "Following physical network adaptors found: $($nic.Name -join ",")"
54 | if ($nic.count -gt 1) {
55 | Write-Verbose "Multiple Network Adptors found. "
56 | $i = 1
57 | $oOptions = @()
58 | $nic | ForEach-Object {
59 | $oOptions += [pscustomobject]@{
60 | Item = $i
61 | Name = $_.Name
62 | }
63 | $i++
64 | }
65 | $oOptions | Out-Host
66 | $selection = Read-Host -Prompt "Please make a selection"
67 | Write-LogEntry -Type Information -Message "The following physical network adaptor has been selected for Internet access: $selection"
68 | $Selected = $oOptions | Where-Object { $_.Item -eq $selection }
69 | New-VMSwitch -Name 'Internet' -NetAdapterName $selected.name -AllowManagementOS:$true | Out-Null
70 | Write-LogEntry -Type Information -Message "Internet vSwitch has been created."
71 | }
72 | }
73 | if ((invoke-pester -TagFilter "LabSwitch" -PassThru -Output None).result -ne 'Passed') {
74 | Write-LogEntry -Type Information -Message "Private vSwitch named $($ENVConfig.network) does not exist"
75 | New-VMSwitch -Name $ENVConfig.network -SwitchType Private | Out-Null
76 | Write-LogEntry -Type Information -Message "Private vSwitch named $($ENVConfig.network) has been created."
77 | }
78 | Write-LogEntry -Type Information -Message "Base requirements for Lab Environment has been met"
79 | }
--------------------------------------------------------------------------------
/NewSCCMServer.PS1:
--------------------------------------------------------------------------------
1 | function new-SCCMServer {
2 | param(
3 | [Parameter(ParameterSetName = 'CMClass')]
4 | [CM]
5 | $CMConfig,
6 | [Parameter(ParameterSetName = 'NoClass')]
7 | [psobject]
8 | $envconfig,
9 | [Parameter(ParameterSetName = 'NoClass')]
10 | [string]
11 | $VHDXpath,
12 | [Parameter(ParameterSetName = 'NoClass')]
13 | [pscredential]
14 | $localadmin,
15 | [Parameter(ParameterSetName = 'NoClass')]
16 | [string]
17 | $IPAddress,
18 | [Parameter(ParameterSetName = 'NoClass')]
19 | [string]
20 | $DomainFQDN,
21 | [Parameter(ParameterSetName = 'NoClass')]
22 | [pscredential]
23 | $DomainUser,
24 | [Parameter(ParameterSetName = 'NoClass')]
25 | [psobject]
26 | $config,
27 | [Parameter(ParameterSetName = 'NoClass')]
28 | [string]
29 | $admpwd,
30 | [Parameter(ParameterSetName = 'NoClass')]
31 | [string]
32 | $domainnetbios,
33 | [Parameter(ParameterSetName = 'NoClass')]
34 | [string]
35 | $cmsitecode,
36 | [Parameter(ParameterSetName = 'NoClass')]
37 | [string]
38 | $SCCMDLPreDownloaded,
39 | [parameter(ParameterSetName = 'NoClass', Mandatory = $false)]
40 | [switch]
41 | $vmSnapshotenabled,
42 | [parameter(ParameterSetName = 'NoClass', Mandatory = $false)]
43 | [switch]
44 | $CAS,
45 | [Parameter(ParameterSetName = 'NoClass')]
46 | [switch]
47 | $PRI,
48 | [Parameter(ParameterSetName = 'NoClass')]
49 | [string]
50 | $casservername,
51 | [Parameter(ParameterSetName = 'NoClass')]
52 | [int]
53 | $cores,
54 | [Parameter(ParameterSetName = 'NoClass')]
55 | [int]
56 | $ram,
57 | [Parameter(ParameterSetName = 'NoClass')]
58 | [string]
59 | $name,
60 | [Parameter(ParameterSetName = 'NoClass')]
61 | [string]
62 | $DCIP,
63 | [Parameter(ParameterSetName = 'NoClass')]
64 | [string]
65 | $RefVHDX,
66 | [Parameter(ParameterSetName = 'NoClass')]
67 | [string]
68 | $SQLISO,
69 | [Parameter(ParameterSetName = 'NoClass')]
70 | [string]
71 | $SCCMPath,
72 | [Parameter(ParameterSetName = 'NoClass')]
73 | [string]
74 | $ADKPath,
75 | [Parameter(ParameterSetName = 'NoClass')]
76 | [ValidateSet("CAS", "PRI", "CASPRI")]
77 | [string]
78 | $CMServerType = "PRI",
79 | [Parameter(ParameterSetName = 'NoClass')]
80 | [string]
81 | $CASIPAddress,
82 | [Parameter(ParameterSetName = 'NoClass')]
83 | [string]
84 | $SCCMVer
85 | )
86 | if (!$PSBoundParameters.ContainsKey('CMConfig')) {
87 | $CMConfig = [CM]::new()
88 | $CMConfig.AdmPwd = $admpwd
89 | $CMConfig.cmsitecode = $cmsitecode
90 | $CMConfig.cores = $Cores
91 | $CMConfig.ram = $ram
92 | $CMConfig.domainFQDN = $DomainFQDN
93 | $CMConfig.domainuser = $DomainUser
94 | $CMConfig.IPAddress = $IPAddress
95 | $CMConfig.DCIP = $DCIP
96 | $CMConfig.localadmin = $localadmin
97 | $CMConfig.network = $network
98 | $CMConfig.VHDXpath = $VHDXpath
99 | $CMConfig.VMSnapshotenabled = $vmSnapshotenabled.IsPresent
100 | $CMConfig.SCCMDLPreDownloaded = $SCCMDLPreDownloaded
101 | $CMConfig.name = $name
102 | $CMConfig.RefVHDX = $RefVHDX
103 | $CMConfig.SQLISO = $SQLISO
104 | $CMConfig.SCCMPath = $SCCMPath
105 | $CMConfig.ADKPath = $ADKPath
106 | $CMConfig.domainnetbios = $domainnetbios
107 | $CMConfig.CMServerType = $CMServerType
108 | $CMConfig.CASIPAddress = $CASIPAddress
109 | $CMConfig.SCCMVer = $SCCMVer
110 | }
111 | $ipsubnet = $CMConfig.IPAddress.substring(0, ($CMConfig.IPAddress.length - ([ipaddress] $CMConfig.IPAddress).GetAddressBytes()[3].count - 1))
112 | Write-logentry -message "CM Server Started: $(Get-Date)" -type information
113 | #if ($cas.ispresent) {
114 | # $cmname = "$($envconfig.env)`CMCAS"
115 | #}
116 | #else {
117 | # $cmname = "$($envconfig.env)`CM"
118 | #}
119 | write-logentry -message "VM for CM will be named: $($CMConfig.name)" -type information
120 | Write-LogEntry -Message "CM Settings are: $($CMConfig | ConvertTo-Json)" -Type Information
121 | write-logentry -message "Path for the VHDX for $($CMConfig.name) is: $($CMConfig.VHDXpath)" -type information
122 | if (!(Invoke-Pester -tagfilter "CMVM" -passthru -output none).result -ne "Passed") {
123 | write-logentry -message "CM for env:$($envconfig.env) doesn't exist, creating now" -type information
124 | if ((Invoke-Pester -tagfilter "CMVHDX" -passthru -output none).result -eq "Passed") {
125 | write-logentry -message "CM VHDX Already exists at path: $($CMConfig.VHDXpath) Please clean up and ReRun" -type error
126 | throw "CM VHDX Already Exists at path: $($CMConfig.VHDXpath) Please clean up and Rerun."
127 | }
128 | else {
129 | Copy-Item -Path $cmconfig.RefVHDX -Destination $CMConfig.VHDXpath
130 | write-logentry -message "Reference VHDX: $($CMConfig.refvhdx) has been copied to: $($CMConfig.VHDXpath)" -type information
131 | $disk = (mount-vhd -Path $CMConfig.VHDXpath -Passthru | Get-disk | Get-Partition | Where-Object { $_.type -eq 'Basic' }).DriveLetter
132 | write-logentry -message "$($CMConfig.VHDXpath) has been mounted to allow for file copy to $disk" -type information
133 | Copy-Item -Path $cmconfig.SCCMPath -Destination "$disk`:\data\SCCM" -Recurse
134 | write-logentry -message "SCCM Media copied to $disk`:\data\SCCM" -type information
135 | Copy-Item -Path $cmconfig.ADKPath -Destination "$disk`:\data\adk" -Recurse
136 | write-logentry -message "ADK Media copied to $disk`:\data\adk" -type information
137 | Dismount-VHD $CMConfig.VHDXpath
138 | write-logentry -message "$disk has been dismounted" -type information
139 | }
140 | if ((Invoke-Pester -tagfilter "CMVHDX" -passthru -output none).result -ne "Passed") {
141 | write-logentry -message "Error creating VHDX for CM. BUILD STOPPED" -type error
142 | throw "Error Creating the VHDX for CM"
143 | }
144 | else {
145 | write-logentry -message "Starting to create $($CMConfig.name)" -type information
146 | new-vm -name $CMConfig.name -MemoryStartupBytes ($cmconfig.ram * 1gb) -VHDPath $CMConfig.VHDXpath -Generation 2 | Set-VMMemory -DynamicMemoryEnabled:$false
147 | write-logentry -message "Setting vCPU for $($CMConfig.name) to 4" -type information
148 | get-vm -name $CMConfig.name | Set-VMProcessor -Count $CMConfig.cores
149 | if (!($cmconfig.vmSnapshotenabled)) {
150 | set-vm -name $CMConfig.name -checkpointtype Disabled
151 | }
152 | write-logentry -message "$($CMConfig.name) has been created" -type information
153 | start-vm -Name $CMConfig.name
154 | write-logentry -message "CM Server named $($CMConfig.name) has been started" -type information
155 | Get-VMNetworkAdapter -VMName $CMConfig.name | Connect-VMNetworkAdapter -SwitchName $cmconfig.network
156 | write-logentry -message "vSwitch $($cmconfig.network) has been attached to $($CMConfig.name)" -type information
157 | }
158 | while ((Invoke-Command -VMName $CMConfig.name -Credential $CMConfig.localadmin { "Test" } -ErrorAction SilentlyContinue) -ne "Test") { Start-Sleep -Seconds 5 }
159 | $cmsessionLA = New-PSSession -vmname $CMConfig.name -credential $CMConfig.localadmin
160 | if ($null -eq $cmsessionLA) { throw "Issue with CM Local User Account" }
161 | write-logentry -message "PowerShell Direct session for $($CMConfig.localadmin.username) has been initated with CM server named: $($CMConfig.name)" -type information
162 | $cmnics = Invoke-Command -session $cmsessionLA -ScriptBlock { Get-NetAdapter }
163 | write-logentry -message "The following network adaptors $($cmnics -join ",") have been found on: $($CMConfig.name)" -type information
164 | if ((Invoke-Pester -tagfilter "CMIP" -passthru -output none).result -ne "Passed") {
165 | $IPGateway = "$ipsubnet`1"
166 | $null = Invoke-Command -session $cmsessionLA -ScriptBlock { param($t, $i, $g, $d) new-NetIPAddress -InterfaceIndex $t -AddressFamily IPv4 -IPAddress "$i" -PrefixLength 24 -DefaultGateway "$g"; Set-DnsClientServerAddress -ServerAddresses ($d) -InterfaceIndex $t } -ArgumentList $cmnics.InterfaceIndex, $CMConfig.IPAddress, $IPGateway, $CMConfig.DCIP
167 | write-logentry -message "IP Address $($CMConfig.IPAddress) has been assigned to $($CMConfig.name)" -type information
168 | start-sleep 300
169 | }
170 | if ((Invoke-Pester -tagfilter "CMDOM" -passthru -output none).result -eq "Passed") {
171 | while ((Invoke-Command -VMName $CMConfig.name -Credential $CMConfig.localadmin { param($i)(test-netconnection "$i" -ErrorAction SilentlyContinue).pingsucceeded } -ArgumentList $cmconfig.DCIP -ErrorAction SilentlyContinue) -ne $true -and $stop -ne (get-date)) { Start-Sleep -Seconds 5 }
172 | Invoke-Command -session $cmsessionLA -ErrorAction SilentlyContinue -ScriptBlock { param($env, $domuser) Clear-DnsClientCache; Add-Computer -DomainName $env -domainCredential $domuser -Restart; Start-Sleep -Seconds 15; Restart-Computer -Force -Delay 0 } -ArgumentList $cmconfig.domainFQDN, $CMConfig.domainuser
173 | write-logentry -message "Joined $($CMConfig.name) to domain $($cmconfig.domainFQDN)" -type information
174 | $stop = (get-date).AddMinutes(5)
175 | while ((Invoke-Command -VMName $CMConfig.name -Credential $CMConfig.domainuser { "Test" } -ErrorAction SilentlyContinue) -ne "Test" -and $stop -ne (get-date)) { Start-Sleep -Seconds 5 }
176 | }
177 | else {
178 | write-logentry -message "Couldn't find $($cmconfig.domainFQDN)" -type error
179 | throw "CM Server can't resolve $($cmconfig.domainFQDN)"
180 | }
181 | $cmsession = New-PSSession -VMName $CMConfig.name -Credential $CMConfig.domainuser
182 | write-logentry -message "PowerShell Direct session for $($CMConfig.domainuser.username) has been initated with CM Server named: $($CMConfig.name)" -type information
183 | if ($null -eq $cmsession) { throw "Issue with CM Domain User Account" }
184 | if ((Invoke-Pester -tagfilter "CMNETFeatures" -passthru -output none).result -ne "Passed") {
185 | Invoke-Command -session $cmsession -ScriptBlock { Add-WindowsFeature -Name NET-Framework-Features, NET-Framework-Core -Source "C:\data" } | Out-Null
186 | write-logentry -message ".Net 3.5 enabled on $($CMConfig.name)" -type information
187 | }
188 | #invoke-command -Session $cmsession -ScriptBlock { Restart-Computer}
189 | #$stop = (get-date).AddMinutes(5)
190 | #while ((Invoke-Command -VMName $CMConfig.name -Credential $CMConfig.domainuser { "Test" } -ErrorAction SilentlyContinue) -ne "Test" -and $stop -ne (get-date)) { Start-Sleep -Seconds 5 }
191 | if ((Invoke-Pester -tagfilter "CMFeatures" -passthru -output none).result -ne "Passed") {
192 | invoke-command -session $cmsession -scriptblock { $feature = @('BITS', 'BITSExtensions-Upload', 'LightweightServer', 'IIS-WebServerRole', 'IIS-WebServer', 'IIS-CommonHttpFeatures', 'IIS-DefaultDocument', 'IIS-DirectoryBrowsing', 'IIS-HttpErrors', 'IIS-StaticContent', 'IIS-HttpRedirect', 'IIS-ApplicationDevelopment', 'IIS-NetFxExtensibility', 'IIS-NetFxExtensibility45', 'IIS-ASP', 'IIS-ASPNET', 'IIS-ASPNET45', 'IIS-CGI', 'IIS-ISAPIExtensions', 'IIS-ISAPIFilter', 'IIS-HealthAndDiagnostics', 'IIS-HttpLogging', 'IIS-CustomLogging', 'IIS-LoggingLibraries', 'IIS-BasicAuthentication', 'IIS-IPSecurity', 'IIS-URLAuthorization', 'IIS-WindowsAuthentication', 'IIS-WebServerManagementTools', 'IIS-ManagementConsole', 'IIS-IIS6ManagementCompatibility', 'IIS-Metabase', 'IIS-LegacySnapIn', 'IIS-LegacyScripts', 'IIS-WMICompatibility', 'IIS-ManagementScriptingTools', 'IIS-ManagementService', 'MSRDC-Infrastructure', 'ActiveDirectory-PowerShell', 'IIS-RequestMonitor', 'IIS-HttpTracing', 'IIS-Performance', 'IIS-HttpCompressionStatic', 'IIS-Security', 'IIS-RequestFiltering');
193 | $feature | ForEach-Object { dism /online /quiet /enable-feature /FeatureName:$_ /all }
194 | }
195 | write-logentry -message "Windows Features enabled on $($CMConfig.name)" -type information
196 | }
197 | if ((Invoke-Pester -tagfilter "CMSQLInst" -passthru -output none).result -ne "Passed") {
198 | write-logentry -message "Start SQL Install on $($CMConfig.name)" -type information
199 | new-CMSQLInstance -cmname $CMConfig.name -cmsession $cmsession -SQLISO $CMConfig.SQLISO -domainnetbios $CMConfig.domainnetbios -admpwd $cmconfig.admpwd
200 | }
201 | if ((Invoke-Pester -tagfilter "CMADK" -passthru -output none).result -ne "Passed") {
202 | write-logentry -message "ADK is installing on $($CMConfig.name)" -type information
203 | Invoke-Command -Session $cmsession -ScriptBlock { Start-Process -FilePath "c:\data\adk\adksetup.exe" -Wait -ArgumentList " /Features OptionId.DeploymentTools OptionId.WindowsPreinstallationEnvironment OptionId.ImagingAndConfigurationDesigner OptionId.UserStateMigrationTool /norestart /quiet /ceip off" }
204 | write-logentry -message "ADK is installed on $($CMConfig.name)" -type information
205 | }
206 | if ($CMConfig.CMServerType -eq "CAS") {
207 | invoke-command -Session $cmsession -ScriptBlock { new-netfirewallrule -DisplayName "CAS Inbound" -Action Allow -Profile Any -Enabled true -Direction Inbound -Protocol TCP -LocalPort 1433, 4022 }
208 | }
209 | if ((Invoke-Pester -tagfilter "CMInstalled" -passthru -output none).result -ne "Passed") {
210 | if ($CMConfig.CMServerType -eq "CASPRI") {
211 | new-CMInstance -CMServerType $CMConfig.CMServerType -cmsession $cmsession -cmname $CMConfig.name -cmsitecode $cmconfig.cmsitecode -domainfqdn $CMConfig.domainFQDN -ver $CMConfig.SCCMVer -ipsub $ipsubnet -domainnetbios $CMConfig.domainnetbios -CASIPAddress $CMConfig.CASIPAddress
212 | }
213 | else {
214 | new-CMInstance -CMServerType $CMConfig.CMServerType -cmsession $cmsession -cmname $CMConfig.name -cmsitecode $cmconfig.cmsitecode -domainfqdn $CMConfig.domainFQDN -ver $CMConfig.SCCMVer -ipsub $ipsubnet -domainnetbios $CMConfig.domainnetbios #-cas:($cas.IsPresent) -pri:($pri.ispresent) -casservername $casservername
215 | }
216 |
217 | }
218 | Invoke-Command -Session $cmsession -ScriptBlock { Set-ItemProperty -path HKLM:\SOFTWARE\Microsoft\ServerManager -name DoNotOpenServerManagerAtLogon -Type DWord -value "1" -Force }
219 | Invoke-Command -Session $cmsession -ScriptBlock { New-NetFirewallRule -DisplayName "SQL1433" -Direction Inbound -Protocol TCP -Action Allow -LocalPort 1433 -Profile any }
220 | Invoke-Command -Session $cmsession -ScriptBlock { Set-ExecutionPolicy Bypass -Scope Process -Force
221 | Invoke-Expression ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))
222 | choco install git.install -y -f -x --no-progress -r
223 | choco install vscode-insiders -y -f -x --no-progress -r
224 | choco install sql-server-management-studio -y -f -x --no-progress -r
225 | }
226 | #TODO: still need to work on checking to see if there is an update available
227 | write-logentry -message "Checking for updates from Microsoft for SCCM, this might take some time depending upon your internet" -type information
228 | Invoke-Command -Session $cmsession -ScriptBlock { param($sitecode)
229 | Get-Service SMS_EXECUTIVE | Restart-Service
230 | start-sleep -seconds 120
231 | $update = $null
232 | $update = Get-WmiObject -Namespace "root\sms\site_$sitecode" -Class sms_cm_updatepackages -ErrorAction SilentlyContinue
233 | if($null -eq $update){
234 | Start-Sleep -Seconds 120
235 | $update = Get-WmiObject -Namespace "root\sms\site_$sitecode" -Class sms_cm_updatepackages -ErrorAction SilentlyContinue
236 | }
237 | if (!($update.PackageExistsInToBeDownloadedList()).PackageExists) {
238 | while (!(Get-WmiObject -Namespace "root\sms\site_$sitecode" -Query "select * from sms_cm_updatepackages where State = 262146")) { "downloading"; Start-Sleep -Seconds 60 }
239 | $update.InitiateUpgrade($update.PrereqFlag)
240 | while ((Get-WmiObject -namespace "root\sms\site_$sitecode" `
241 | -Query "select substagename, IsComplete from SMS_CM_UpdatePackDetailedMonitoring where substagename = 'Updating Client folder on Site Server' and packageguid = '$($update.packageguid)'" `
242 | -erroraction SilentlyContinue ).IsComplete -ne 2) { "wait"; start-sleep -Seconds 60 }
243 | }
244 |
245 | } -ArgumentList $CMConfig.cmsitecode
246 | write-logentry -message "Installation of SCCM updates have been installed" -type Information
247 | $cmsession | remove-PSSession
248 | write-logentry -message "Powershell Direct session for $($CMConfig.domainuser.username) on $($CMConfig.name) has been disposed" -type information
249 | }
250 | $CMConfig.Built = $true
251 | $CMConfig.save("$vmpath\config.json")
252 | Invoke-Pester -tagfilter "CM" -output detailed
253 | Write-Output "CM Server Completed: $(Get-Date)"
254 | write-logentry -message "SCCM Server installation has completed on $($CMConfig.name)" -type information
255 | }
256 |
--------------------------------------------------------------------------------
/Optimize-AllVHDX.ps1:
--------------------------------------------------------------------------------
1 | function Optimize-VHDs {
2 | $vms = get-vm
3 | foreach ($vm in $vms) {
4 | if ($vm.state -eq "off") {
5 | foreach ($disk in $vm.harddrives) {
6 | Optimize-VHD -Path $disk.path -Mode Full
7 | }
8 | }
9 | }
10 | }
--------------------------------------------------------------------------------
/SVRTemplates.json:
--------------------------------------------------------------------------------
1 | {
2 | "ServerTemplates": [
3 | {
4 | "NameSuffix": "CM",
5 | "Cores": 4,
6 | "RAM": 12,
7 | "IPSuffix": 11,
8 | "ServerType": "PRI",
9 | "SQLMax": 8,
10 | "SQLMin": 4
11 | },
12 | {
13 | "NameSuffix": "DC",
14 | "Cores": 1,
15 | "RAM": 4,
16 | "IPSuffix": 10,
17 | "ServerType": "DC"
18 | },
19 | {
20 | "NameSuffix": "CA",
21 | "Cores": 1,
22 | "RAM": 4,
23 | "IPSuffix": 13,
24 | "ServerType": "CA"
25 | },
26 | {
27 | "NameSuffix": "RRAS",
28 | "Cores": 1,
29 | "RAM": 4,
30 | "IPSuffix": 10,
31 | "ServerType": "RRAS"
32 | },
33 | {
34 | "NameSuffix": "WKS",
35 | "Cores": 1,
36 | "RAM": 4,
37 | "ServerType": "WKS",
38 | "IPSuffix": 0
39 | },
40 | {
41 | "NameSuffix": "CAS",
42 | "SVRS": [
43 | {
44 | "NameSuffix": "CMCAS",
45 | "Cores": 4,
46 | "RAM": 12,
47 | "IPSuffix": 11,
48 | "ServerType": "CAS",
49 | "SQLMax": 8,
50 | "SQLMin": 4,
51 | "CAS": 1
52 | },
53 | {
54 | "NameSuffix": "CMCP",
55 | "Cores": 4,
56 | "RAM": 12,
57 | "IPSuffix": 12,
58 | "ServerType": "CPRI",
59 | "SQLMax": 8,
60 | "SQLMin": 4,
61 | "PRI": 1
62 | }
63 | ]
64 | }
65 | ]
66 | }
--------------------------------------------------------------------------------
/Unattended.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | P@ssw0rd
14 | True
15 |
16 |
17 |
18 |
19 | true
20 | true
21 |
22 | true
23 | true
24 | true
25 | 3
26 | true
27 | Work
28 | true
29 |
30 |
31 |
32 | en-au
33 | en-us
34 | en-au
35 | en-us
36 | en-au
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/WKS-Unattend.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | TP1
8 | P@ssw0rd
9 | administrator
10 |
11 | TP1.lab
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/WriteLogEntry.ps1:
--------------------------------------------------------------------------------
1 |
2 | function Write-LogEntry {
3 | [cmdletBinding()]
4 | param (
5 | [ValidateSet("Information", "Error")]
6 | $Type = "Information",
7 | [parameter(Mandatory = $true)]
8 | $Message
9 | )
10 | switch ($Type) {
11 | 'Error' {
12 | $Severity = 3
13 | break;
14 | }
15 | 'Information' {
16 | $Severity = 6
17 | break;
18 | }
19 | }
20 | $DateTime = New-Object -ComObject WbemScripting.SWbemDateTime
21 | $DateTime.SetVarDate($(Get-Date))
22 | $UtcValue = $DateTime.Value
23 | $UtcOffset = $UtcValue.Substring(21, $UtcValue.Length - 21)
24 | $scriptname = (Get-PSCallStack)[1]
25 | $logline = `
26 | "" + `
27 | "