Hyper-V and the need for speed…

Sometimes I need to build a new Windows image  to deploy with SCCM at work.
And it would be nice if it didn´t took too long time to build, because sometimes you need to test new things and the image might fail while building it and you have to correct the fault and start over again.

At work I have a Hyper-V host with plenty of ram, so why not make a ramdisk to have the VM-disks on?
But the backside is that when you reboot the host, the disk-files is lost and you manually need to remove and add new disks to the VM….or do you?

My setup is:

  • MDT and ADK hosted on another server
  • Hyper-V host with Windows Server 2012 R2 and 192Gb ram
  • A 80Gb ramdrive (enough for 2*40Gb virtual disk) made with ImDrive software
  • Powershell of course!

My VMs are stored on a ordinary disk and have these specification:

  • Generation 1 VM
  • 4Gb ram
  • 1 cpu, 2 cores
  • No HDD!
  • 1 Network adapter, legacy adapter is not necessary in my case. I boot from an ISO-files from the MDT-share directly.
  • A static MAC-adress
  • A snapshot when everything is configured

So, my idea is to script a sequence where I create a virtual disk on the ramdrive -> connect it to the VM -> start VM and buid image -> disconnect disk when finished -> delete disk file.

This script will do that. It starts the VM and waits for it to shutdown and then removes the disks and disk-files and finaly reverts the snapshot.

$VMName = "Windows10x64BC"
$DiskFileName = "Disk0.vhdx"
$VMDiskFolder = "R:\Hyper-V" # Location to ramdisk-drive and a subfolder. will be created by hyper-v if not existing
$VMDiskPath = "$VMDiskFolder\$VMName\$DiskFileName" #Folder doesnt need to exist
$DiskSize = "40960000000" # 40Gb in Bytes!

#Removes old drive
Function RemoveAllDrives {
    Get-VMHardDiskDrive -VMName $VMName | ForEach-Object {
        Write-Host "Found Drive $($_.Path)"
        Write-Host "Removing drive from VM"
        Remove-VMHardDiskDrive -VMName $VMName -ControllerNumber $($_.ControllerNumber) -ControllerLocation $($_.ControllerLocation) -ControllerType $($_.ControllerType)
        Write-Host "Deleting Drive-file from disk"
        Remove-Item -LiteralPath $($_.Path) -Force
    Remove-Item -LiteralPath $VMDiskPath -Recurse -Force
    Remove-Item -LiteralPath "$VMDiskFolder\$VMName" -Recurse -Force
#Adds new drive
New-VHD -Path $VMDiskPath -SizeBytes $DiskSize
Add-VMHardDiskDrive -VMName $VMName -ControllerType IDE -Path $VMDiskPath

#Run and wait for VM to finish, then revert to snapshot
# Start VM
Start-VM -VMName $VMName

# Monitor VM to see if it's running
$VM = Get-VM -Name $VMName
while ($VM.State -ne "off")
    write-host "The VM is still running"
    sleep 20
# Restore VMSnapshot
Get-VM –Name $VMName | Get-VMSnapshot  | Sort CreationTime | Select -Last 1 | Restore-VMSnapshot -Confirm:$false

Happy image-building!

Copy files to flat file structure

Recently I needed to copy a bunch of files within a lot of subfolders, but I didn’t want the folders.
I just needed a flat file structure. Who needs folders anyway? 🙂

So, my solution is of course powershell.

$Source = "x:\sourcefolder"
$Destination = "y:\destinationfolder"
$Files = Get-ChildItem -LiteralPath $Source -Recurse -file -Force
[INT]$nr = '1'
ForEach($File in $Files){
    Write-Output "------------------------------------------------------------------------------------------"
    Write-Output "File $nr/$($Files.Count)"
    Write-Output "Copying file: $($File.name)"
    Write-Output "------------------------------------------------------------------------------------------"
    $File | Copy-Item -Destination $Destination
    $nr ++

Read and Write BIOS settings to Lenovo computers



As I often say, if you can automate things you have time to do more fun stuff.
And in windows deployment from SCCM/MDT i’ts always nice to even automate BIOS settings.

Lenovo have been smart in this way. Instead of using special tools, like HP and Dell, you can use WMI methods instead.

This might not be the best coding ever, but you might get the idea here….

Reading settings

The easiest way is probably to sett BIOS as you want it, boot up in Windows or Windows PE with powershell support in it and run this script.

ForEach($Obj in $BiosSettings){
    if ($Obj.CurrentSetting -ne "") {
        Write-Host $Obj.CurrentSetting.replace(",",";")

This will output all the BIOS settings in a textfile in the same directory as the script. You can easily change the values and/or remove values you don’t want to change.

Writing settings

$SettingsFile = "Settings.txt"
$SettingsObj = ""
$SettingsObj = Get-Content $PSScriptRoot\$SettingsFile
$PasswordState = (gwmi -class Lenovo_BiosPasswordSettings -namespace root\wmi).PasswordState

function Set-LenovoBiosSettingsValues
    Param( [string]$WMIObj, [string]$WMIValue )

    If ($PasswordIsSet -eq $false) {
        (gwmi -class Lenovo_SetBiosSetting –namespace root\wmi).SetBiosSetting("$WMIObj,$WMIValue")
    Else {
     (gwmi -class Lenovo_SetBiosSetting -namespace root\wmi).SetBiosSetting("$WMIObj,$WMIValue,$BiosPass,ascii,us")

    gwmi -class Lenovo_BiosSetting -namespace root\wmi | Where-Object {$_.CurrentSetting.split(",",[StringSplitOptions]::RemoveEmptyEntries) -eq "$WMIObj"} |
    Format-List CurrentSetting

function Set-LenovoBiosSettings {

    #Check if BIOS password is set
    If ($PasswordState -eq '0') {
        $PasswordIsSet = $false
        Write-Host "BIOS password not set"
    Else {
        $PasswordIsSet = $true
        Write-Host "BIOS password is set"

    foreach ($setting in $SettingsObj) {
        $Sobj = ""
        $Svar1 = ""
        $Svar2 = ""
        $Sobj = $Setting -split ';'

        Write-Host "Sets ""$Svar1"" to ""$Svar2"""
        Set-LenovoBiosSettingsValues -WMIObj $Svar1 -WMIValue $Svar2
    #Saves the bios-settings
    Write-Host "Saving settings"
    (gwmi -class Lenovo_SaveBiosSettings -namespace root\wmi).SaveBiosSettings("$BiosPass,ascii,us")

# Start writing settings

There are some shortcomings with the way Lenovo has implemented this, some settings cannot be made.
For an example you cannot sett a BIOS password if there aren’t any allready. So you can only change password.
And you cannot set “PhysicalPresenceForTpmClear” to Disable. But only change from Disable to Enable.


You you want to read more about this, you can read the offical documentation and maybe find other things you can do via the wmi.