github.com/cloudfoundry-incubator/stembuild@v0.0.0-20211223202937-5b61d62226c6/modules/BOSH.Sysprep/BOSH.Sysprep.psm1 (about) 1 <# 2 .Synopsis 3 Sysprep Utilities 4 .Description 5 This cmdlet enables enabling a local security policy for a stemcell 6 #> 7 function Enable-LocalSecurityPolicy { 8 Param ( 9 [string]$PolicySource =$(throw "Policy backup filepath is required") 10 ) 11 Write-Log "Starting LocalSecurityPolicy" 12 13 # Convert registry.txt files into registry.pol files 14 $MachineDir="$PolicySource/DomainSysvol/GPO/Machine" 15 LGPO.exe /r "$MachineDir/registry.txt" /w "$MachineDir/registry.pol" 16 if ($LASTEXITCODE -ne 0) { 17 Write-Error "Generating policy: Machine" 18 } 19 20 $UserDir="$PolicySource/DomainSysvol/GPO/User" 21 LGPO.exe /r "$UserDir/registry.txt" /w "$UserDir/registry.pol" 22 if ($LASTEXITCODE -ne 0) { 23 Write-Error "Generating policy: User" 24 } 25 26 # Apply policies 27 LGPO.exe /g "$PolicySource/DomainSysvol" /v 28 if ($LASTEXITCODE -ne 0) { 29 Write-Error "Applying policy: $PolicySource/DomainSysvol" 30 } 31 32 Write-Log "Ending LocalSecurityPolicy" 33 } 34 35 <# 36 .Synopsis 37 Sysprep Utilities 38 .Description 39 This cmdlet creates the Unattend file for sysprep 40 #> 41 function Create-Unattend { 42 Param ( 43 [string]$UnattendDestination = "C:\Windows\Panther\Unattend", 44 [string]$NewPassword, 45 [string]$ProductKey, 46 [string]$Organization, 47 [string]$Owner 48 ) 49 Write-Log "Starting Create-Unattend" 50 51 New-Item -ItemType directory $UnattendDestination -Force 52 $UnattendPath = Join-Path $UnattendDestination "unattend.xml" 53 54 Write-Log "Writing unattend.xml to $UnattendPath" 55 56 $ProductKeyXML="" 57 if ($ProductKey -ne "") { 58 $ProductKeyXML="<ProductKey>$ProductKey</ProductKey>" 59 } 60 61 $OrganizationXML="<RegisteredOrganization />" 62 if ($Organization -ne "" -and $Organization -ne $null) { 63 $OrganizationXML="<RegisteredOrganization>$Organization</RegisteredOrganization>" 64 } 65 66 $OwnerXML="<RegisteredOwner />" 67 if ($Owner -ne "" -and $Owner -ne $null) { 68 $OwnerXML="<RegisteredOwner>$Owner</RegisteredOwner>" 69 } 70 71 $AdministratorPasswordXML = "" 72 if ($NewPassword -ne "" -and $NewPassword -ne $null) { 73 $NewPassword = [system.convert]::ToBase64String([system.text.encoding]::Unicode.GetBytes($NewPassword + "AdministratorPassword")) 74 $AdministratorPasswordXML = @" 75 <UserAccounts> 76 <AdministratorPassword> 77 <Value>$NewPassword</Value> 78 <PlainText>false</PlainText> 79 </AdministratorPassword> 80 </UserAccounts> 81 "@ 82 } 83 84 $PostUnattend = @" 85 <?xml version="1.0" encoding="utf-8"?> 86 <unattend xmlns="urn:schemas-microsoft-com:unattend"> 87 <settings pass="specialize"> 88 <component xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS"> 89 <OEMInformation> 90 <HelpCustomized>false</HelpCustomized> 91 </OEMInformation> 92 <ComputerName>*</ComputerName> 93 <TimeZone>UTC</TimeZone> 94 $ProductKeyXML 95 $OrganizationXML 96 $OwnerXML 97 </component> 98 <component xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="Microsoft-Windows-ServerManager-SvrMgrNc" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS"> 99 <DoNotOpenServerManagerAtLogon>true</DoNotOpenServerManagerAtLogon> 100 </component> 101 <component xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="Microsoft-Windows-OutOfBoxExperience" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS"> 102 <DoNotOpenInitialConfigurationTasksAtLogon>true</DoNotOpenInitialConfigurationTasksAtLogon> 103 </component> 104 <component xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="Microsoft-Windows-Security-SPP-UX" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS"> 105 <SkipAutoActivation>true</SkipAutoActivation> 106 </component> 107 <component name="Microsoft-Windows-NetBT" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 108 <Interfaces> 109 <Interface wcm:action="add"> 110 <NetbiosOptions>2</NetbiosOptions> 111 <Identifier>Ethernet0</Identifier> 112 </Interface> 113 </Interfaces> 114 </component> 115 </settings> 116 <settings pass="generalize"> 117 <component name="Microsoft-Windows-PnpSysprep" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 118 <PersistAllDeviceInstalls>false</PersistAllDeviceInstalls> 119 <DoNotCleanUpNonPresentDevices>false</DoNotCleanUpNonPresentDevices> 120 </component> 121 </settings> 122 <settings pass="oobeSystem"> 123 <component name="Microsoft-Windows-International-Core" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 124 <InputLocale>en-US</InputLocale> 125 <SystemLocale>en-US</SystemLocale> 126 <UILanguage>en-US</UILanguage> 127 <UserLocale>en-US</UserLocale> 128 </component> 129 <component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 130 <OOBE> 131 <HideEULAPage>true</HideEULAPage> 132 <ProtectYourPC>3</ProtectYourPC> 133 <NetworkLocation>Home</NetworkLocation> 134 <HideWirelessSetupInOOBE>true</HideWirelessSetupInOOBE> 135 </OOBE> 136 <TimeZone>UTC</TimeZone> 137 $AdministratorPasswordXML 138 </component> 139 </settings> 140 </unattend> 141 "@ 142 143 Out-File -FilePath $UnattendPath -InputObject $PostUnattend -Encoding utf8 144 } 145 146 <# 147 .Synopsis 148 Sanity check that the unattend.xml shipped with GCP has not changed. 149 .Description 150 Sanity check that the unattend.xml shipped with GCP has not changed. 151 #> 152 function Check-Default-GCP-Unattend() { 153 154 [xml]$Expected = @' 155 <?xml version="1.0" encoding="utf-8"?> 156 <unattend xmlns="urn:schemas-microsoft-com:unattend"> 157 <!-- 158 For more information about unattended.xml please refer too 159 http://technet.microsoft.com/en-us/library/cc722132(v=ws.10).aspx 160 --> 161 <settings pass="generalize"> 162 <component name="Microsoft-Windows-PnpSysprep" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 163 <PersistAllDeviceInstalls>true</PersistAllDeviceInstalls> 164 </component> 165 </settings> 166 <settings pass="specialize"> 167 <component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 168 <!-- Random ComputerName, will be replaced by specialize script --> 169 <ComputerName></ComputerName> 170 <TimeZone>Greenwich Standard Time</TimeZone> 171 </component> 172 </settings> 173 <settings pass="oobeSystem"> 174 <!-- Setting Location Information --> 175 <component name="Microsoft-Windows-International-Core" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 176 <InputLocale>en-us</InputLocale> 177 <SystemLocale>en-us</SystemLocale> 178 <UILanguage>en-us</UILanguage> 179 <UserLocale>en-us</UserLocale> 180 </component> 181 <component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 182 <OOBE> 183 <!-- Setting EULA --> 184 <HideEULAPage>true</HideEULAPage> 185 <!-- Setting network location to public --> 186 <NetworkLocation>Other</NetworkLocation> 187 <!-- Hide Wirelss setup --> 188 <HideWirelessSetupInOOBE>true</HideWirelessSetupInOOBE> 189 <ProtectYourPC>1</ProtectYourPC> 190 <SkipMachineOOBE>true</SkipMachineOOBE> 191 <SkipUserOOBE>true</SkipUserOOBE> 192 </OOBE> 193 <!-- Setting timezone to GMT --> 194 <ShowWindowsLive>false</ShowWindowsLive> 195 <TimeZone>Greenwich Standard Time</TimeZone> 196 <!--Setting OEM information --> 197 <OEMInformation> 198 <Manufacturer>Google Cloud Platform</Manufacturer> 199 <Model>Google Compute Engine Virtual Machine</Model> 200 <SupportURL>https://support.google.com/enterprisehelp/answer/142244?hl=en#cloud</SupportURL> 201 <Logo>C:\Program Files\Google Compute Engine\sysprep\gcp.bmp</Logo> 202 </OEMInformation> 203 </component> 204 </settings> 205 </unattend> 206 '@ 207 208 $UnattendPath = "C:\Program Files\Google\Compute Engine\sysprep\unattended.xml" 209 [xml]$Unattend = (Get-Content -Path $UnattendPath) 210 211 if (-Not ($Unattend.xml.Equals($Expected.xml))) { 212 Write-Error "The unattend.xml shipped with GCP has changed." 213 } 214 } 215 216 function Create-Unattend-GCP() { 217 Param ( 218 [string]$UnattendDestination = "C:\Program Files\Google\Compute Engine\sysprep" 219 ) 220 $UnattendXML = @' 221 <?xml version="1.0" encoding="utf-8"?> 222 <unattend xmlns="urn:schemas-microsoft-com:unattend"> 223 <!-- 224 For more information about unattended.xml please refer too 225 http://technet.microsoft.com/en-us/library/cc722132(v=ws.10).aspx 226 --> 227 <settings pass="generalize"> 228 <component name="Microsoft-Windows-PnpSysprep" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 229 <PersistAllDeviceInstalls>true</PersistAllDeviceInstalls> 230 </component> 231 </settings> 232 <settings pass="specialize"> 233 <component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 234 <!-- Random ComputerName, will be replaced by specialize script --> 235 <ComputerName></ComputerName> 236 <TimeZone>UTC</TimeZone> 237 </component> 238 </settings> 239 <settings pass="oobeSystem"> 240 <!-- Setting Location Information --> 241 <component name="Microsoft-Windows-International-Core" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 242 <InputLocale>en-us</InputLocale> 243 <SystemLocale>en-us</SystemLocale> 244 <UILanguage>en-us</UILanguage> 245 <UserLocale>en-us</UserLocale> 246 </component> 247 <component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 248 <OOBE> 249 <!-- Setting EULA --> 250 <HideEULAPage>true</HideEULAPage> 251 <!-- Setting network location to public --> 252 <NetworkLocation>Other</NetworkLocation> 253 <!-- Hide Wirelss setup --> 254 <HideWirelessSetupInOOBE>true</HideWirelessSetupInOOBE> 255 <ProtectYourPC>3</ProtectYourPC> 256 <SkipMachineOOBE>true</SkipMachineOOBE> 257 <SkipUserOOBE>true</SkipUserOOBE> 258 </OOBE> 259 <!-- Setting timezone to GMT --> 260 <ShowWindowsLive>false</ShowWindowsLive> 261 <TimeZone>UTC</TimeZone> 262 <!--Setting OEM information --> 263 <OEMInformation> 264 <Manufacturer>Google Cloud Platform</Manufacturer> 265 <Model>Google Compute Engine Virtual Machine</Model> 266 <SupportURL>https://support.google.com/enterprisehelp/answer/142244?hl=en#cloud</SupportURL> 267 <Logo>C:\Program Files\Google Compute Engine\sysprep\gcp.bmp</Logo> 268 </OEMInformation> 269 </component> 270 </settings> 271 </unattend> 272 '@ 273 274 $UnattendPath = Join-Path $UnattendDestination "unattended.xml" 275 276 Out-File -FilePath $UnattendPath -InputObject $UnattendXML -Encoding utf8 -Force 277 } 278 279 function Remove-WasPassProcessed { 280 Param ( 281 [string]$AnswerFilePath 282 ) 283 284 If (!$(Test-Path $AnswerFilePath)) { 285 Throw "Answer file $AnswerFilePath does not exist" 286 } 287 288 Write-Log "Removing wasPassProcessed" 289 290 $content = [xml](Get-Content $AnswerFilePath) 291 292 foreach ($specializeBlock in $content.unattend.settings) { 293 $specializeBlock.RemoveAttribute("wasPassProcessed") 294 } 295 296 $content.Save($AnswerFilePath) 297 } 298 299 function Remove-UserAccounts { 300 Param ( 301 [string]$AnswerFilePath 302 ) 303 304 If (!$(Test-Path $AnswerFilePath)) { 305 Throw "Answer file $AnswerFilePath does not exist" 306 } 307 308 Write-Log "Removing UserAccounts block from Answer File" 309 310 $content = [xml](Get-Content $AnswerFilePath) 311 $mswShellSetup = (($content.unattend.settings|where {$_.pass -eq 'oobeSystem'}).component|where {$_.name -eq "Microsoft-Windows-Shell-Setup"}) 312 313 if ($mswShellSetup -eq $Null) { 314 Throw "Could not locate oobeSystem XML block. You may not be running this function on an answer file." 315 } 316 317 $userAccountsBlock = $mswShellSetup.UserAccounts 318 319 if ($userAccountsBlock.Count -eq 0) { 320 Return 321 } 322 323 $mswShellSetup.RemoveChild($userAccountsBlock) 324 325 $content.Save($AnswerFilePath) 326 } 327 328 function Update-AWS2012R2Config { 329 $ec2config = [xml] (get-content 'C:\Program Files\Amazon\Ec2ConfigService\Settings\config.xml') 330 331 # Enable password generation and retrieval 332 ($ec2config.ec2configurationsettings.plugins.plugin | where { $_.Name -eq "Ec2SetPassword" }).State = 'Enabled' 333 334 # Disable SetDnsSuffixList setting 335 $ec2config.ec2configurationsettings.GlobalSettings.SetDnsSuffixList = "false" 336 337 $ec2config.Save("C:\Program Files\Amazon\Ec2ConfigService\Settings\config.xml") 338 339 # Enable sysprep 340 $ec2settings = [xml] (get-content 'C:\Program Files\Amazon\Ec2ConfigService\Settings\BundleConfig.xml') 341 ($ec2settings.BundleConfig.Property | where { $_.Name -eq "AutoSysprep" }).Value = 'Yes' 342 343 # Don't shutdown when running sysprep, let packer do it 344 # ($ec2settings.BundleConfig.GeneralSettings.Sysprep | where { $_.AnswerFilePath -eq "sysprep2008.xml" }).Switches = "/oobe /quit /generalize" 345 346 $ec2settings.Save('C:\Program Files\Amazon\Ec2ConfigService\Settings\BundleConfig.xml') 347 } 348 349 function Update-AWS2016Config 350 { 351 $LaunchConfigJson = 'C:\ProgramData\Amazon\EC2-Windows\Launch\Config\LaunchConfig.json' 352 $LaunchConfig = Get-Content $LaunchConfigJson -raw | ConvertFrom-Json 353 $LaunchConfig.addDnsSuffixList = $False 354 $LaunchConfig.extendBootVolumeSize = $False 355 $LaunchConfig | ConvertTo-Json | Set-Content $LaunchConfigJson 356 } 357 358 function Enable-AWS2016Sysprep { 359 # Enable sysprep 360 cd 'C:\ProgramData\Amazon\EC2-Windows\Launch\Scripts' 361 ./InitializeInstance.ps1 -Schedule 362 ./SysprepInstance.ps1 363 } 364 365 <# 366 .Synopsis 367 Sysprep Utilities 368 .Description 369 This cmdlet runs Sysprep and generalizes a VM so it can be a BOSH stemcell 370 #> 371 function Invoke-Sysprep() 372 { 373 Param ( 374 [string]$IaaS = $( Throw "Provide the IaaS this stemcell will be used for" ), 375 [string]$NewPassword, 376 [string]$ProductKey = "", 377 [string]$Organization = "", 378 [string]$Owner = "", 379 [switch]$SkipLGPO, 380 [switch]$EnableRDP 381 ) 382 383 Write-Log "Invoking Sysprep for IaaS: ${IaaS}" 384 385 $OsVersion = Get-OSVersion 386 387 # WARN WARN: this should be removed when Microsoft fixes this bug 388 # See tracker story https://www.pivotaltracker.com/story/show/150238324 389 # Skip sysprep if using Windows Server 2016 insider build with UALSVC bug 390 $RegPath = "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion" 391 If ((Get-ItemProperty -Path $RegPath).CurrentBuildNumber -Eq '16278') 392 { 393 Stop-Computer 394 } 395 396 Allow-NTPSync 397 398 if (-Not $SkipLGPO) 399 { 400 if (-Not (Test-Path "C:\Windows\LGPO.exe")) { 401 Throw "Error: LGPO.exe is expected to be installed to C:\Windows\LGPO.exe" 402 } 403 404 switch ($OsVersion) 405 { 406 "windows2012R2" { 407 Enable-LocalSecurityPolicy (Join-Path $PSScriptRoot "cis-merge-2012R2") 408 } 409 410 "windows1803" { 411 Enable-LocalSecurityPolicy (Join-Path $PSScriptRoot "cis-merge-1803") 412 } 413 414 "windows2019" { 415 Enable-LocalSecurityPolicy (Join-Path $PSScriptRoot "cis-merge-2019") 416 } 417 } 418 } 419 420 switch ($IaaS) { 421 "aws" { 422 switch ($OsVersion) { 423 "windows2012R2" { 424 Update-AWS2012R2Config 425 Start-Process "C:\Program Files\Amazon\Ec2ConfigService\Ec2Config.exe" -ArgumentList "-sysprep" -Wait 426 } 427 {($_ -eq"windows2016") -or ($_ -eq"windows1803") -or ($_ -eq"windows2019")} { 428 Update-AWS2016Config 429 Enable-AWS2016Sysprep 430 } 431 } 432 } 433 "gcp" { 434 Create-Unattend-GCP 435 GCESysprep 436 } 437 "azure" { 438 C:\Windows\System32\Sysprep\sysprep.exe /generalize /quiet /oobe /quit 439 } 440 "vsphere" { 441 Create-Unattend -NewPassword $NewPassword -ProductKey $ProductKey ` 442 -Organization $Organization -Owner $Owner 443 444 Invoke-Expression -Command 'C:/windows/system32/sysprep/sysprep.exe /generalize /oobe /unattend:"C:/Windows/Panther/Unattend/unattend.xml" /quiet /shutdown' 445 } 446 Default { Throw "Invalid IaaS '${IaaS}' supported platforms are: AWS, Azure, GCP and Vsphere" } 447 } 448 } 449 450 function ModifyInfFile() { 451 Param( 452 [string]$InfFilePath = $(Throw "inf file path missing"), 453 [string]$KeyName = $(Throw "keyname missing"), 454 [string]$KeyValue = $(Throw "keyvalue missing") 455 ) 456 457 $Regex = "^$KeyName" 458 $TempFile = $InfFilePath + ".tmp" 459 460 Get-Content $InfFilePath | ForEach-Object { 461 $ValueToWrite=$_ 462 if($_ -match $Regex) { 463 $ValueToWrite="$KeyName=$KeyValue" 464 } 465 $ValueToWrite | Out-File -Append $TempFile 466 } 467 468 Move-Item -Path $TempFile -Destination $InfFilePath -Force 469 } 470 471 function Allow-NTPSync() { 472 Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\W32Time\Config" -Name 'MaxNegPhaseCorrection' -Value 0xFFFFFFFF -Type dword 473 Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\W32Time\Config" -Name 'MaxPosPhaseCorrection' -Value 0xFFFFFFFF -Type dword 474 }