зеркало из https://github.com/microsoft/MSLab.git
354 строки
16 KiB
PowerShell
354 строки
16 KiB
PowerShell
# Verify Running as Admin
|
|
$isAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")
|
|
If (-not $isAdmin) {
|
|
Write-Host "-- Restarting as Administrator" -ForegroundColor Cyan ; Start-Sleep -Seconds 1
|
|
|
|
if($PSVersionTable.PSEdition -eq "Core") {
|
|
Start-Process pwsh.exe "-NoProfile -ExecutionPolicy Bypass -File `"$PSCommandPath`"" -Verb RunAs
|
|
} else {
|
|
Start-Process powershell.exe "-NoProfile -ExecutionPolicy Bypass -File `"$PSCommandPath`"" -Verb RunAs
|
|
}
|
|
|
|
exit
|
|
}
|
|
|
|
# Skipping 10 lines because if running when all prereqs met, statusbar covers powershell output
|
|
1..10 | ForEach-Object { Write-Host "" }
|
|
|
|
#region Functions
|
|
. $PSScriptRoot\0_Shared.ps1 # [!build-include-inline]
|
|
|
|
function Get-WindowsBuildNumber {
|
|
$os = Get-CimInstance -ClassName Win32_OperatingSystem
|
|
return [int]($os.BuildNumber)
|
|
}
|
|
#endregion
|
|
|
|
#region Initialization
|
|
|
|
# grab Time and start Transcript
|
|
Start-Transcript -Path "$PSScriptRoot\Prereq.log"
|
|
$StartDateTime = Get-Date
|
|
WriteInfo "Script started at $StartDateTime"
|
|
WriteInfo "`nMSLab Version $mslabVersion"
|
|
|
|
#Load LabConfig....
|
|
. "$PSScriptRoot\LabConfig.ps1"
|
|
|
|
# Telemetry Event
|
|
if((Get-TelemetryLevel) -in $TelemetryEnabledLevels) {
|
|
WriteInfo "Telemetry is set to $(Get-TelemetryLevel) level from $(Get-TelemetryLevelSource)"
|
|
Send-TelemetryEvent -Event "Prereq.Start" -NickName $LabConfig.TelemetryNickName | Out-Null
|
|
}
|
|
|
|
#define some variables if it does not exist in labconfig
|
|
If (!$LabConfig.DomainNetbiosName) {
|
|
$LabConfig.DomainNetbiosName="Corp"
|
|
}
|
|
|
|
If (!$LabConfig.DomainName) {
|
|
$LabConfig.DomainName="Corp.contoso.com"
|
|
}
|
|
|
|
#set TLS 1.2 for github downloads
|
|
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
|
|
|
|
#endregion
|
|
|
|
#region OS checks and folder build
|
|
|
|
# Check if not running in root folder
|
|
if (($psscriptroot).Length -eq 3) {
|
|
WriteErrorAndExit "`t MSLab canot run in root folder. Please put MSLab scripts into a folder. Exiting"
|
|
}
|
|
|
|
# Checking for Compatible OS
|
|
WriteInfoHighlighted "Checking if OS is Windows 10 1511 (10586)/Server 2016 or newer"
|
|
|
|
$BuildNumber=Get-WindowsBuildNumber
|
|
if ($BuildNumber -ge 10586){
|
|
WriteSuccess "`t OS is Windows 10 1511 (10586)/Server 2016 or newer"
|
|
}else{
|
|
WriteErrorAndExit "`t Windows version $BuildNumber detected. Version 10586 and newer is needed. Exiting"
|
|
}
|
|
|
|
# Checking Folder Structure
|
|
"ParentDisks","Temp","Temp\DSC","Temp\ToolsVHD\DiskSpd","Temp\ToolsVHD\SCVMM\ADK","Temp\ToolsVHD\SCVMM\ADKWinPE","Temp\ToolsVHD\SCVMM\SQL","Temp\ToolsVHD\SCVMM\SCVMM","Temp\ToolsVHD\SCVMM\UpdateRollup" | ForEach-Object {
|
|
if (!( Test-Path "$PSScriptRoot\$_" )) { New-Item -Type Directory -Path "$PSScriptRoot\$_" } }
|
|
|
|
"Temp\ToolsVHD\SCVMM\ADK\Copy_ADK_with_adksetup.exe_here.txt","Temp\ToolsVHD\SCVMM\ADKWinPE\Copy_ADKWinPE_with_adkwinpesetup.exe_here.txt","Temp\ToolsVHD\SCVMM\SQL\Copy_SQL2017_or_SQL2019_with_setup.exe_here.txt","Temp\ToolsVHD\SCVMM\SCVMM\Copy_SCVMM_with_setup.exe_here.txt","Temp\ToolsVHD\SCVMM\UpdateRollup\Copy_SCVMM_Update_Rollup_MSPs_here.txt" | ForEach-Object {
|
|
if (!( Test-Path "$PSScriptRoot\$_" )) { New-Item -Type File -Path "$PSScriptRoot\$_" } }
|
|
#endregion
|
|
|
|
#region Download Scripts
|
|
|
|
#add scripts for VMM
|
|
$filenames = "1_SQL_Install", "2_ADK_Install", "3_SCVMM_Install"
|
|
foreach ($filename in $filenames) {
|
|
$Path = "$PSScriptRoot\Temp\ToolsVHD\SCVMM\$filename.ps1"
|
|
if (Test-Path -Path $Path) {
|
|
WriteSuccess "`t $Filename is present, skipping download"
|
|
} else {
|
|
$FileContent = $null
|
|
|
|
try {
|
|
# try to download tagged version first
|
|
$FileContent = (Invoke-WebRequest -UseBasicParsing -Uri "https://raw.githubusercontent.com/microsoft/MSLab/$mslabVersion/Tools/$filename.ps1").Content
|
|
} catch {
|
|
WriteInfo "Download $filename failed with $($_.Exception.Message), trying master branch now"
|
|
# if that fails, try master branch
|
|
$FileContent = (Invoke-WebRequest -UseBasicParsing -Uri "https://raw.githubusercontent.com/microsoft/MSLab/master/Tools/$filename.ps1").Content
|
|
}
|
|
|
|
if ($FileContent) {
|
|
$script = New-Item $Path -type File -Force
|
|
$FileContent=$FileContent -replace "PasswordGoesHere",$LabConfig.AdminPassword #only applies to 1_SQL_Install and 3_SCVMM_Install.ps1
|
|
$FileContent=$FileContent -replace "DomainNameGoesHere",$LabConfig.DomainNetbiosName #only applies to 1_SQL_Install and 3_SCVMM_Install.ps1
|
|
Set-Content -Path $script -value $FileContent
|
|
} else {
|
|
WriteErrorAndExit "Unable to download $Filename."
|
|
}
|
|
}
|
|
}
|
|
|
|
# add createparentdisks, DownloadLatestCU and PatchParentDisks scripts to Parent Disks folder
|
|
$fileNames = "CreateParentDisk", "DownloadLatestCUs", "PatchParentDisks", "CreateVMFleetDisk"
|
|
if($LabConfig.Linux) {
|
|
$fileNames += "CreateLinuxParentDisk"
|
|
}
|
|
foreach ($filename in $fileNames) {
|
|
$path = "$PSScriptRoot\ParentDisks\$FileName.ps1"
|
|
If (Test-Path -Path $path) {
|
|
WriteSuccess "`t $filename is present, skipping download"
|
|
} else {
|
|
$FileContent = $null
|
|
|
|
try {
|
|
# try to download release version first
|
|
Invoke-WebRequest -UseBasicParsing -Uri "https://github.com/microsoft/MSLab/releases/download/$mslabVersion/$Filename.ps1" -OutFile $path
|
|
} catch {
|
|
WriteInfo "Download $filename failed with $($_.Exception.Message), trying master branch now"
|
|
|
|
# if that fails, try master branch
|
|
$FileContent = (Invoke-WebRequest -UseBasicParsing -Uri "https://raw.githubusercontent.com/microsoft/MSLab/master/Tools/$FileName.ps1").Content
|
|
if ($FileContent) {
|
|
$script = New-Item $path -type File -Force
|
|
Set-Content -Path $script -value $FileContent
|
|
} else {
|
|
WriteErrorAndExit "Unable to download $Filename."
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
# Download convert-windowsimage into Temp
|
|
WriteInfoHighlighted "Testing Convert-windowsimage presence"
|
|
$convertWindowsImagePath = "$PSScriptRoot\Temp\Convert-WindowsImage.ps1"
|
|
If (Test-Path -Path $convertWindowsImagePath) {
|
|
WriteSuccess "`t Convert-windowsimage.ps1 is present, skipping download"
|
|
} else {
|
|
WriteInfo "`t Downloading Convert-WindowsImage"
|
|
try {
|
|
Invoke-WebRequest -UseBasicParsing -Uri "https://github.com/microsoft/MSLab/releases/download/$mslabVersion/Convert-WindowsImage.ps1" -OutFile $convertWindowsImagePath
|
|
} catch {
|
|
try {
|
|
WriteInfo "Download Convert-windowsimage.ps1 failed with $($_.Exception.Message), trying master branch now"
|
|
Invoke-WebRequest -UseBasicParsing -Uri "https://raw.githubusercontent.com/microsoft/MSLab/master/Tools/Convert-WindowsImage.ps1" -OutFile $convertWindowsImagePath
|
|
} catch {
|
|
WriteError "`t Failed to download Convert-WindowsImage.ps1!"
|
|
}
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region some tools to download
|
|
# Downloading diskspd if its not in ToolsVHD folder
|
|
WriteInfoHighlighted "Testing diskspd presence"
|
|
If ( Test-Path -Path "$PSScriptRoot\Temp\ToolsVHD\DiskSpd\diskspd.exe" ) {
|
|
WriteSuccess "`t Diskspd is present, skipping download"
|
|
}else{
|
|
WriteInfo "`t Diskspd not there - Downloading diskspd"
|
|
try {
|
|
<# aka.ms/diskspd changed. Commented
|
|
$webcontent = Invoke-WebRequest -Uri "https://aka.ms/diskspd" -UseBasicParsing
|
|
if($PSVersionTable.PSEdition -eq "Core") {
|
|
$link = $webcontent.Links | Where-Object data-url -Match "/Diskspd.*zip$"
|
|
$downloadUrl = "{0}://{1}{2}" -f $webcontent.BaseResponse.RequestMessage.RequestUri.Scheme, $webcontent.BaseResponse.RequestMessage.RequestUri.Host, $link.'data-url'
|
|
} else {
|
|
$downloadurl = $webcontent.BaseResponse.ResponseUri.AbsoluteUri.Substring(0,$webcontent.BaseResponse.ResponseUri.AbsoluteUri.LastIndexOf('/'))+($webcontent.Links | where-object { $_.'data-url' -match '/Diskspd.*zip$' }|Select-Object -ExpandProperty "data-url")
|
|
}
|
|
#>
|
|
$downloadurl="https://github.com/microsoft/diskspd/releases/download/v2.2/DiskSpd.ZIP"
|
|
Invoke-WebRequest -Uri $downloadurl -OutFile "$PSScriptRoot\Temp\ToolsVHD\DiskSpd\diskspd.zip"
|
|
}catch{
|
|
WriteError "`t Failed to download Diskspd!"
|
|
}
|
|
# Unnzipping and extracting just diskspd.exe x64
|
|
Microsoft.PowerShell.Archive\Expand-Archive "$PSScriptRoot\Temp\ToolsVHD\DiskSpd\diskspd.zip" -DestinationPath "$PSScriptRoot\Temp\ToolsVHD\DiskSpd\Unzip"
|
|
Copy-Item -Path (Get-ChildItem -Path "$PSScriptRoot\Temp\ToolsVHD\diskspd\" -Recurse | Where-Object {$_.Directory -like '*amd64*' -and $_.name -eq 'diskspd.exe' }).fullname -Destination "$PSScriptRoot\Temp\ToolsVHD\DiskSpd\"
|
|
Remove-Item -Path "$PSScriptRoot\Temp\ToolsVHD\DiskSpd\diskspd.zip"
|
|
Remove-Item -Path "$PSScriptRoot\Temp\ToolsVHD\DiskSpd\Unzip" -Recurse -Force
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Installing PSDesiredStateConfiguration from the PowerShell gallery
|
|
|
|
# See https://learn.microsoft.com/en-us/powershell/dsc/overview?view=dsc-2.0 for details
|
|
# on the breaking change that requires this module to be installed.
|
|
WriteInfoHighlighted "Testing if PSDesiredStateConfiguration is present"
|
|
if (!(Get-Module -ListAvailable -Name PSDesiredStateConfiguration)) {
|
|
WriteInfo "`t Module PSDesiredStateConfiguration not found... Downloading"
|
|
Install-Module -Name PSDesiredStateConfiguration -Repository PSGallery -MaximumVersion 2.99
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Downloading required Posh Modules
|
|
# Downloading modules into Temp folder if needed.
|
|
|
|
$modules=("ActiveDirectoryDsc","6.3.0"),("xDHCPServer","3.1.1"),("DnsServerDsc","3.0.0"),("NetworkingDSC","9.0.0"),("xPSDesiredStateConfiguration","9.1.0"),("xHyper-V","3.18.0")
|
|
foreach ($module in $modules){
|
|
WriteInfoHighlighted "Testing if modules are present"
|
|
$modulename=$module[0]
|
|
$moduleversion=$module[1]
|
|
if (!(Test-Path "$PSScriptRoot\Temp\DSC\$modulename\$Moduleversion")){
|
|
WriteInfo "`t Module $module not found... Downloading"
|
|
#Install NuGET package provider
|
|
if ((Get-PackageProvider -Name NuGet) -eq $null){
|
|
Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Confirm:$false -Force
|
|
}
|
|
Find-DscResource -moduleName $modulename -RequiredVersion $moduleversion | Save-Module -Path "$PSScriptRoot\Temp\DSC"
|
|
}else{
|
|
WriteSuccess "`t Module $modulename version found... skipping download"
|
|
}
|
|
}
|
|
|
|
# Installing DSC modules if needed
|
|
foreach ($module in $modules) {
|
|
WriteInfoHighlighted "Testing DSC Module $module Presence"
|
|
# Check if Module is installed
|
|
if ((Get-DscResource -Module $Module[0] | where-object {$_.version -eq $module[1]}) -eq $Null) {
|
|
# module is not installed - install it
|
|
WriteInfo "`t Module $module will be installed"
|
|
$modulename=$module[0]
|
|
$moduleversion=$module[1]
|
|
Copy-item -Path "$PSScriptRoot\Temp\DSC\$modulename" -Destination "C:\Program Files\WindowsPowerShell\Modules" -Recurse -Force
|
|
WriteSuccess "`t Module was installed."
|
|
Get-DscResource -Module $modulename
|
|
} else {
|
|
# module is already installed
|
|
WriteSuccess "`t Module $Module is already installed"
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Linux prereqs
|
|
if($LabConfig.Linux -eq $true) {
|
|
WriteInfoHighlighted "Testing Linux prerequisites"
|
|
WriteInfo "`t Test Packer availability"
|
|
|
|
# Packer
|
|
if (Get-Command "packer.exe" -ErrorAction SilentlyContinue)
|
|
{
|
|
WriteSuccess "`t Packer is in PATH."
|
|
} else {
|
|
WriteInfo "`t`t Downloading latest Packer binary"
|
|
|
|
WriteInfo "`t`t Creating packer directory"
|
|
$linuxToolsDirPath = "$PSScriptRoot\LAB\bin"
|
|
New-Item $linuxToolsDirPath -ItemType Directory -Force | Out-Null
|
|
|
|
if(-not (Test-Path (Join-Path $linuxToolsDirPath "packer.exe"))) {
|
|
$packerReleaseInfo = Invoke-RestMethod -Uri "https://checkpoint-api.hashicorp.com/v1/check/packer"
|
|
$downloadUrl = "https://releases.hashicorp.com/packer/$($packerReleaseInfo.current_version)/packer_$($packerReleaseInfo.current_version)_windows_amd64.zip"
|
|
Start-BitsTransfer -Source $downloadUrl -Destination (Join-Path $linuxToolsDirPath "packer.zip")
|
|
Expand-Archive -Path (Join-Path $linuxToolsDirPath "packer.zip") -DestinationPath $linuxToolsDirPath -Force
|
|
Remove-Item -Path (Join-Path $linuxToolsDirPath "packer.zip")
|
|
}
|
|
|
|
WriteInfo "`t`t Creating Packer firewall rule"
|
|
$id = $PSScriptRoot -replace '[^a-zA-Z0-9]'
|
|
$fwRule = Get-NetFirewallRule -Name "mslab-packer-$id" -ErrorAction SilentlyContinue
|
|
if(-not $fwRule) {
|
|
New-NetFirewallRule -Name "mslab-packer-$id" -DisplayName "Allow MSLab Packer ($($PSScriptRoot))" -Action Allow -Program (Join-Path $linuxToolsDirPath "packer.exe") -Profile Any -ErrorAction SilentlyContinue
|
|
}
|
|
}
|
|
|
|
# Packer templates
|
|
WriteInfo "`t`t Downloading Packer templates"
|
|
$packerTemplatesDirectory = "$PSScriptRoot\ParentDisks\PackerTemplates\"
|
|
if (-not (Test-Path $packerTemplatesDirectory)) {
|
|
New-Item -Type Directory -Path $packerTemplatesDirectory
|
|
}
|
|
|
|
$templatesBase = "https://github.com/microsoft/mslab-templates/releases/latest/download/"
|
|
$templatesFile = "$($packerTemplatesDirectory)\templates.json"
|
|
|
|
Invoke-WebRequest -Uri "$($templatesBase)/templates.json" -OutFile $templatesFile
|
|
if(-not (Test-Path -Path $templatesFile)) {
|
|
WriteErrorAndExit "Download of packer templates failed"
|
|
}
|
|
|
|
$templatesInfo = Get-Content -Path $templatesFile | ConvertFrom-Json
|
|
foreach($template in $templatesInfo.templates) {
|
|
$templateZipFile = Join-Path $packerTemplatesDirectory $template.package
|
|
Invoke-WebRequest -Uri "$($templatesBase)/$($template.package)" -OutFile $templateZipFile
|
|
Expand-Archive -Path $templateZipFile -DestinationPath (Join-Path $packerTemplatesDirectory $template.directory)
|
|
Remove-Item -Path $templateZipFile
|
|
}
|
|
|
|
# OpenSSH
|
|
$capability = Get-WindowsCapability -Online -Name "OpenSSH.Client~~~~0.0.1.0"
|
|
if($capability.State -ne "Installed") {
|
|
WriteInfoHighlighted "`t Enabling OpensSH Client"
|
|
Add-WindowsCapability -Online -Name "OpenSSH.Client~~~~0.0.1.0"
|
|
Set-Service ssh-agent -StartupType Automatic
|
|
Start-Service ssh-agent
|
|
}
|
|
|
|
# SSH Key
|
|
WriteInfoHighlighted "`t SSH key"
|
|
if($LabConfig.SshKeyPath) {
|
|
if(-not (Test-Path $LabConfig.SshKeyPath)) {
|
|
WriteError "`t Cannot find specified SSH key $($LabConfig.SshKeyPath)."
|
|
}
|
|
|
|
$private = ssh-keygen.exe -y -e -f $LabConfig.SshKeyPath
|
|
$public = ssh-keygen.exe -y -e -f "$($LabConfig.SshKeyPath).pub"
|
|
$comparison = Compare-Object -ReferenceObject $private -DifferenceObject $public
|
|
if($comparison) {
|
|
WriteError "`t SSH Keypair $($LabConfig.SshKeyPath) does not match."
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WriteInfo "`t`t Generating new SSH key pair"
|
|
$sshKeyDir = "$PSScriptRoot\LAB\.ssh"
|
|
$key = "$sshKeyDir\lab_rsa"
|
|
New-Item -ItemType Directory $sshKeyDir -ErrorAction SilentlyContinue | Out-Null
|
|
ssh-keygen.exe -t rsa -b 4096 -C "$($LabConfig.DomainAdminName)" -f $key -q -N '""'
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
# Telemetry Event
|
|
if((Get-TelemetryLevel) -in $TelemetryEnabledLevels) {
|
|
$metrics = @{
|
|
'script.duration' = ((Get-Date) - $StartDateTime).TotalSeconds
|
|
}
|
|
|
|
Send-TelemetryEvent -Event "Prereq.End" -Metrics $metrics -NickName $LabConfig.TelemetryNickName | Out-Null
|
|
}
|
|
|
|
# finishing
|
|
WriteInfo "Script finished at $(Get-date) and took $(((get-date) - $StartDateTime).TotalMinutes) Minutes"
|
|
|
|
Stop-Transcript
|
|
|
|
If (!$LabConfig.AutoClosePSWindows) {
|
|
WriteSuccess "Press enter to continue..."
|
|
Read-Host | Out-Null
|
|
}
|