Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
if (-not(Get-VMSwitch -SwitchType Internal -ErrorAction SilentlyContinue| Where Name -eq 'Internal-Test' )) {
# Create an internal switch on Hyper-V
($VMswitch = New-VMSwitch -Name "Internal-Test" -SwitchType Internal)
# Set a static IP address on Hyper-V switch
Get-NetAdapter |
Where Name -eq "vEthernet ($($VMswitch.Name))" |
Where InterfaceDescription -match "Hyper-V\sVirtual\sEthernet Adapter" |
New-NetIPAddress -IPAddress 10.0.0.1 -PrefixLength 24
} else {
Write-Information -Msg "Got an internal VM switch named Internal-Test" -InfA 2
Get-NetAdapter |
Where Name -eq "vEthernet (Internal-Test)" |
Where InterfaceDescription -match "Hyper-V\sVirtual\sEthernet Adapter" |
Get-NetIPAddress -AddressFamily IPv4
}
# Set the path to ISO
$iso = $ExecutionContext.SessionState.Path.
GetUnresolvedProviderPathFromPSPath(
'~/downloads/W2016TP3/en_windows_server_2016_technical_preview_3_x64_dvd_6942082.iso'
)
# Integrity check of ISO file
if (
(Get-FileHash -Path $ISO -Algorithm SHA256 -ErrorAction SilentlyContinue).Hash -eq
'18BE2F1068EB22216C6F01E586C211AB4FF72D57F53CCFE797DF2B8A257959BE'
){
Write-Information -Msg "Got the correct Technical Preview 3 iso file" -InfA 2
} else {
Write-Warning -Message "Don't have the correct ISO of the Technical Preview 3"
break
}
# Mount ISO
Mount-DiskImage -ImagePath $iso -StorageType ISO -Access ReadOnly -PassThru
$dl = (Get-DiskImage -ImagePath $iso | Get-Volume).DriveLetter
# Dot source the 2 scripts in the NanoServer folder
if (Test-Path -Path "$($dl):\NanoServer\*.ps1") {
# Dot-sourcing functions inside a script
. "$($dl):\NanoServer\Convert-WindowsImage.ps1"
# Fix hard-coded path in script
(Get-Content -Path "$($dl):\NanoServer\new-nanoserverimage.ps1" -ReadCount 1 -ErrorAction Stop) -replace
[regex]::Escape('. .\Convert-WindowsImage.ps1'),"" |
Set-Content -Path ~/Downloads/new-nanoserverimage.ps1 -Encoding UTF8 -ErrorAction Stop
# Load the modified version
. ~/Downloads/new-nanoserverimage.ps1
}
# Define VM Name
$VM = "DC1-test"
# Set parent VHD
$ServerVHD = (Join-Path -Path ((Get-VMHost).VirtualHardDiskPath) -ChildPath "$VM.vhd")
# Create parent VHD
# Convert the WIM file to a VHD using the loaded Convert-WindowsImage function
if (-not(Test-Path -Path $ServerVHD -PathType Leaf)) {
Convert-WindowsImage -Sourcepath "$($dl):\sources\install.wim" `
-VHD $ServerVHD `
-VHDformat VHD -Edition "Windows Server 2012 R2 SERVERSTANDARD" `
-VHDPartitionStyle MBR -Verbose:$true
}
Write-Information -Msg "Created parent VHD: size = $('{0:N2} GB' -f ((Get-item $ServerVHD).Length/1GB))" -InfA 2
# Create child VHD
$cvp = (Join-Path -Path ((Get-VMHost).VirtualHardDiskPath) -ChildPath "$VM-child.vhd")
$childVHD = New-VHD -Path $cvp -ParentPath $ServerVHD -Differencing
# Create a VM Gen 1
New-VM -Name $VM -MemoryStartupBytes 2048MB -NoVHD -SwitchName Internal-Test -Generation 1
# Attach disk
Get-VM $VM | Add-VMHardDiskDrive -Path $childVHD.Path
# Increase processor count for DC
Get-VM $VM | Set-VMProcessor -Count 2
# Mount the VHD
$cm = Mount-VHD -Path $childVHD.Path -Passthru
$cml = (Get-Disk $cm.DiskNumber | Get-Partition | Where DriveLetter | Select -First 1).DriveLetter
# Prepare a Nano VHD with the new script
$bdir = Join-Path (Split-Path $iso -Parent) -ChildPath "Base"
if (-not(Test-Path -Path $bdir -PathType Container)) {
mkdir $bdir
}
$admincred = Get-Credential -Message 'Admin password of your Nano image' -UserName 'Administrator'
if (Test-Path -Path "$bdir\Target") {
Get-Item -Path "$bdir\Target" | Remove-Item -Verbose
}
$nnHT = @{
ComputerName = 'Nano-PXE' ;
MediaPath = "$($dl):\" ;
BasePath = $bdir ; # The location for the copy of the source media
TargetPath = "$bdir\Target" ; # The location of the final, modified image
Language = 'en-US' ; # The language locale of the packages
GuestDrivers = $true ; # Add the Guest Drivers package (enables integration of Nano Server with Hyper-V when running as a guest).
EnableIPDisplayOnBoot = $true ; # Configures the image to show the output of 'ipconfig' on every boot
AdministratorPassword = $admincred.Password ;
}
New-NanoServerImage @nnHT
<#
gcm New-NanoServerImage -Syntax
# Syntax
New-NanoServerImage [[-MediaPath] <String>] [-BasePath] <String> [-TargetPath] <String> [[-ExistingVHDPath]
<String>] [[-Language] <String>] [-Storage] [-Compute] [-Defender] [-Clustering] [-OEMDrivers] [-GuestDrivers]
[-ReverseForwarders] [[-ExtraPackages] <String[]>] [-ForAzure] [[-ComputerName] <String>] [-AdministratorPassword]
<SecureString> [[-DomainName] <String>] [[-DomainBlobPath] <String>] [-ReuseDomainNode] [[-DriversPath] <String>]
[-EnableIPDisplayOnBoot] [[-DebugMethod] <String>] [-EnableEMS] [[-EMSPort] <Int32>] [[-EMSBaudRate] <Int32>]
[-EnableRemoteManagementPort] [<CommonParameters>]
#>
# New in TP3 version:
# -Defender
# -ForAzure
# Setupcomplete.cmd file
$s = @'
@echo off
:: Define a static IP for the DC
netsh int ip set address name="Ethernet" source=static address=10.0.0.10/24 gateway=10.0.0.1
:: Configure the DNS client
netsh dns set dnsservers name="Ethernet" source=static address=10.0.0.10 validate=no
'@
mkdir "$($cml):\Windows\Setup\Scripts"
$s | Out-File -FilePath "$($cml):\Windows\Setup\Scripts\setupcomplete.cmd" -Encoding ASCII
# Unattend.xml
$unattendDC1 = @'
<?xml version="1.0" encoding="utf-8"?>
<unattend xmlns="urn:schemas-microsoft-com:unattend">
<settings pass="oobeSystem">
<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">
<UserAccounts>
<AdministratorPassword>
<PlainText>false</PlainText>
<Value>UABAAHMAcwB3ADAAcgBkAEEAZABtAGkAbgBpAHMAdAByAGEAdABvAHIAUABhAHMAcwB3AG8AcgBkAA==</Value>
</AdministratorPassword>
</UserAccounts>
<RegisteredOwner>Tuva user</RegisteredOwner>
<RegisteredOrganization>NanoRocks</RegisteredOrganization>
<OOBE>
<HideEULAPage>true</HideEULAPage>
</OOBE>
</component>
<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">
<SystemLocale>en-US</SystemLocale>
<InputLocale>0409:0000040c</InputLocale>
<UILanguage>en-US</UILanguage>
<UserLocale>en-US</UserLocale>
</component>
</settings>
<settings pass="specialize">
<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">
<ComputerName>DC1-test</ComputerName>
<ProductKey>NB4WH-BBBYV-3MPPC-9RCMV-46XCB</ProductKey>
</component>
<component name="Microsoft-Windows-DNS-Client" 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">
<DNSSuffixSearchOrder>
<DomainName wcm:action="add" wcm:keyValue="1">10.0.0.10</DomainName>
</DNSSuffixSearchOrder>
</component>
<component name="Microsoft-Windows-UnattendedJoin" 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">
<Identification>
<JoinWorkgroup>test.local</JoinWorkgroup>
</Identification>
</component>
</settings>
<cpi:offlineImage cpi:source="wim:c:/iso/sources/install.wim#Windows Server 2012 R2 SERVERSTANDARD" xmlns:cpi="urn:schemas-microsoft-com:cpi" />
</unattend>
'@
$unattendDC1 | Out-File -FilePath "$($cml):\Unattend.xml" -Encoding UTF8
# Get required DSC resource
if (-not (Get-Module -ListAvailable -Name xActiveDirectory)) {
Find-Module -Name xActiveDirectory -Repository PSGallery | Install-Module -Verbose
}
# Define environment
$ConfigData = @{
AllNodes = @(
@{
NodeName = 'localhost';
PSDscAllowPlainTextPassword = $true;
RequiredFeatures = @(
@{ Name = 'DHCP'}
@{ Name = 'DNS'}
@{ Name = 'WDS'}
@{ Name = 'RSAT-DHCP'}
@{ Name = 'RSAT-DNS-Server'}
@{ Name = 'WDS-AdminPack'}
)
DCAdminPassword = New-Object pscredential -ArgumentList 'nanorocks\administrator',
(ConvertTo-SecureString -String 'P@ssw0rd' -Force -AsPlainText)
SafeAdminPassword = New-Object pscredential -ArgumentList 'Password Only',
(ConvertTo-SecureString -String 'Azerty@123' -Force -AsPlainText)
}
)
}
# DSC config
Configuration DCConfig {
Param()
Import-DscResource -ModuleName xActiveDirectory
Node localhost {
LocalConfigurationManager {
RebootNodeIfNeeded = $true;
}
WindowsFeature ADDS {
Name = 'AD-Domain-Services';
Ensure = 'Present';
}
foreach ($f in $Node.RequiredFeatures)
{
WindowsFeature $f.Name
{
Name = $f.Name ;
Ensure = 'Present';
}
}
xADDomain DSDC1 {
DomainName = 'nanorocks.local';
DomainAdministratorCredential = $Node.DCAdminPassword
SafemodeAdministratorPassword = $Node.SafeAdminPassword
DependsOn = '[WindowsFeature]ADDS';
}
}
}
# Compile config into MOF file
if (-not(Test-Path -Path ~/Documents/DSC) ){ mkdir ~/Documents/DSC }
DCConfig -outputPath ~/Documents/DSC -ConfigurationData $ConfigData
# Copy DSC resource
$cHT = @{
Path = 'C:\Program Files\WindowsPowerShell\Modules\xActiveDirectory';
Destination = "$($cml):\Program Files\WindowsPowerShell\Modules\xActiveDirectory"
}
Copy-Item @cHT -Recurse -Force
# Copy DSC config
Copy-Item -Path ~/documents/DSC/*.mof -Destination "$($cml):\Users\Public\Documents"
# Copy original boot image from ISO
Copy-Item -Path "$($dl):\Sources\boot.wim" -Destination "$($cml):\Users\Public\Documents"
# Copy prepared Nano.vhd
Copy-Item -Path "$bdir\Target\*.VHD" -Destination "$($cml):\Users\Public\Documents"
# Unmount ISO file
Get-DiskImage -ImagePath $iso | Dismount-DiskImage
# Unmount VHD
Dismount-VHD -Path $childVHD.Path
Start-Vm -VMName $vm
# Missing in Unattend.xml > skip Product Key > fixed with by entering a product key ending with 46XCB from Internet :\
# Missing in Unattend.xml > skip EULA > fixed with OOBE/HideEULAPage in OOBE phase
# DCPromo over PowerShell Direct
Invoke-Command -VMName $VM -Credential (Get-Credential 'test.local\administrator') -ScriptBlock {
Set-DscLocalConfigurationManager C:\Users\Public\Documents
Start-DscConfiguration C:\Users\Public\Documents -Verbose -Wait
exit
}
# Post-install
Invoke-Command -VMName $VM -Credential (Get-Credential 'nanorocks\administrator') -ScriptBlock {
# DHCP configuration
# Authorize
if (-not(Get-DhcpServerInDC | Where DnsName -eq "$($env:computername).$($env:USERDNSDOMAIN)")) {
Add-DhcpServerInDC
} else {
Get-DhcpServerInDC
}
# Scope
Add-DhcpServerv4Scope -StartRange 10.0.0.20 -EndRange 10.0.0.100 -Name "Nano scope" -State Active -SubnetMask 255.255.255.0
# Activate: done with add-dhcpserverv4scope -state param
# WDS
mkdir C:\RemoteInstall
wdsutil /verbose /progress /initialize-server /RemInst:c:\RemoteInstall # /Authorize
wdsutil /start-server
wdsutil /verbose /progress /set-server /AnswerClients:ALL
Import-WdsBootImage -Path C:\Users\Public\Documents\boot.wim
dir C:\Users\Public\Documents\*.vhd | Import-WdsInstallImage
}
# Create test VM Generation 1 and add legacy network card for PXE boot
$testVM = 'Nano-test-pxe'
New-VHD -Path (Join-Path -Path ((Get-VMHost).VirtualHardDiskPath) -ChildPath "$($testVM).vhdx") -Dynamic -SizeBytes 127GB
New-VM -VMName $testVM -Generation 1 -MemoryStartupBytes 1024MB -NoVHD -SwitchName Internal-test |
Remove-VMNetworkAdapter
Get-VM -VMName $testVM |
Add-VMNetworkAdapter -IsLegacy:$true -SwitchName 'Internal-test'
Get-VM -VMName $testVM |
Add-VMHardDiskDrive -Path (Join-Path -Path ((Get-VMHost).VirtualHardDiskPath) -ChildPath "$($testVM).vhdx")
Start-VM -VMName $testVM
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment