PowerShell Hyper-V VM creation and boot - powershell

I am attempting to use PowerShell to create and start a VM:
$vmName = "vm" + (Get-Date -Format "yyyy-MM-dd-HH-mm")
New-VM -Name $vmName -NewVHDPath "$vmName.vhdx" -NewVHDSizeBytes 64GB -MemoryStartupBytes 8GB -Path $vmName -Generation 2
# Attach the Windows 10 ISO as a DVD drive to the VM
Add-VMDvdDrive -VMName $vmName -Path win.iso
# Set correct boot order (DVD drive first)
$dvd = Get-VMDVDDrive -VMName $vmName
Set-VMFirmware -VMName $vmName -FirstBootDevice $dvd
# Start the VM and connect to it
Start-VM -Name $vmName
vmconnect $env:COMPUTERNAME $vmName
This works well, creates the VM, attaches the Windows 10 ISO, sets the correct boot order, starts the VM and connects to it.
However, right after starting up, the VM fails to boot. First, a black screen prompting me to press any key to boot from the DVD pops up, however, it is only for a brief second and before I manage to do it, I get this screen:
The boot order is correct in the VM settings: DVD first, then network, then the VHD. I want to boot from the DVD, but I don't have a chance to press a key to do so before the white screen appears.
Morever, I want to make the script so that it automatically enters the DVD/ISO boot without me having to press a key to enter that boot option. How can I do that? My ultimate goal is a completely unattended installation which starts by invoking the scripts and ends by the installed Windows 10 guest executing a PowerShell script shared from the host. That means I can't ask the user to press a key at a certain time to help the boot sequence along.
Edit: Bounty of 50 points for someone who can demonstrate a PowerShell script which creates, starts, connects and boots a Hyper-V VM with a Windows 10 ISO so that at the end there is a running VM on the first screen of the Windows 10 installer.

I think your issue is not a powershell issue. Your issue is that you are using a regular boot iso, but in your case you need to create a custom WIM (Windows Imaging File). If you create one you can start directly the installation process without human interaction.
I don't want to duplicate the text written already on superuser.com; it is long and takes many steps. I recommend using the second approach - Creating custom ISO from Windows 10 as it makes sense and takes you step-by-step over the creating custom WIM.

Try this:
# Start the VM and connect to it
vmconnect $env:COMPUTERNAME $vmName
Start-VM -Name $vmName
Start-Sleep -Seconds 1
[System.Windows.Forms.SendKeys]::SendWait("{ENTER}")
You might have to adjust the sleep time, so a custom wim is probably the better option.

Related

WOL works outside of Powershell

Regardless of what Script I use I can not get PowerShell 5.1 to trigger a boot on my Hyper-V Host.
I can use the solarwinds WakeonLan tool to boot the server, but I would like to find a solution that would work natively.
I tried many scripts I had found online and as a last ditch effort, I installed the "WakeOnLAN 1.0" Module but while it says it executes successfully the server does not boot
PS C:\WINDOWS\system32> Invoke-WakeOnLan 52:a4:4c:52:d7:52 -Verbose
VERBOSE: Wake-on-Lan Packet sent to 52:a4:4c:52:d7:52
What could cause the server only to boot with the SolarWinds WakeOnLan.exe but not natively in Powershell?
As it may be relevant the computer I am attempting to send the MagicPacket from is a MultiNic Machine but only 1 NIC is IP'd on the subnet of the Hyper-V server.
Other Scripts I attempted to use:
https://www.pdq.com/blog/wake-on-lan-wol-magic-packet-powershell/
https://powershell.one/code/11.html
Something like this works for me with remote powershell, going to the same subnet the down computers are on. Fast startup also has to be disabled in the windows 10 registry (HiberbootEnabled=0).
$mac = #{comp002 = '00:11:22:33:44:55'; comp003 = '00:11:22:33:44:56'}
$compsDown = 'comp002','comp003'
# (,) is silly workaround to pass array as invoke-command arguments
icm comp001 invoke-wakeonlan.ps1 -args (,$mac[$compsDown])

How can I resize the Docker Desktop Virtual Machine on Windows 10 from a PowerShell script?

I am attempting to write a PowerShell script (using PS core 7.0) to install and configure a Kubernetes cluster running on Kind on Windows 10 machines used by my teams. I have a working script to start up and configure the cluster the only issue is that I would like to (need to) ensure the Docker Desktop VM has enough memory available to run a few of our micro services inside the cluster at the same time.
I've got a bit of code cobbled together to perform the task and it works up to the very last step where I attempt to get the docker daemon working again after the restart. As soon as I run the command to do that, the VM is reconfigured back to its previous memory size.
Here's what I have to perform the resizing:
Stop-Service *docker*
Get-VM DockerDesktopVM | Stop-VM
Get-VM DockerDesktopVM | Set-VMMemory -StartupBytes 12888MB
Get-VM DockerDesktopVM | Start-VM
Start-Service *docker*
# https://stackoverflow.com/questions/51760214/how-to-restart-docker-for-windows-process-in-powershell
&$Env:ProgramFiles\Docker\Docker\DockerCli.exe -SwitchDaemon
&$Env:ProgramFiles\Docker\Docker\DockerCli.exe -SwitchDaemon
Note: I found the post # How to restart docker for windows process in powershell? which is were I got the last 2 lines.
In researching the issue further I have found that I can use the following single line instead, but I still have the same issue in that the memory size is reverted back once the command is run.
&$Env:ProgramFiles\Docker\Docker\DockerCli.exe -SwitchLinuxEngine
If I do not run either DockerCli.exe -SwitchDaemon twice or DockerCli.exe -SwitchLinuxEngine once then I get the error:
error during connect: Get http://%2F%2F.%2Fpipe%2Fdocker_engine/v1.40/containers/json: open //./pipe/docker_engine: The system cannot find the file specified. In the default daemon configuration on Window
s, the docker client must be run elevated to connect. This error may also indicate that the docker daemon is not running.
Is there a better way to go about resizing the VM memory or to shutdown and restart docker without causing the change to be reverted?
For anyone else who is attempting the same thing, or something similar I got a hint from the Docker Desktop for Windows Community on GitHub that helped me find a solution. In a nutshell the recommendation was to simply change the settings file directly. What I found worked was to:
Stop the Docker Services (There are 2 of them)
Update the settings file (# ~\AppData\Roaming\Docker\settings.json)
Start the Docker Services
Switch the Daemon Context to Linux (Same as it was before, but it appears to need a nudge to pick things up after restarting the services).
Here's the PowerShell:
Stop-Service *docker*
$settingsFile = "$env:APPDATA\Docker\settings.json"
$settings = Get-Content $settingsFile | ConvertFrom-Json
$settings.memoryMiB = 8192
$settings | ConvertTo-Json | Set-Content $settingsFile
Start-Service *docker*
&$Env:ProgramFiles\Docker\Docker\DockerCli.exe -SwitchLinuxEngine

Sophos - Antivirus last update tacker Script -Powershell

I have been tasked with compiling a list which contains the version and last successful auto update for all the machines on the domain.
I understand this would be much easier if I used the Sophos enterprise console but unfortunately this is not a resource that is available to me at this time.
So far I have created a PowerShell script which currently gives me back the current Sophos version, computer name, and the exe file. However I am now struggling to find a way to also display the date and time of the last successful auto update. the domain is set up to auto update every 10 minuets.
PowerShell Script :
function Get-AntiVirusProduct {
[CmdletBinding()]
param (
[parameter(ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)]
[Alias('name')]
$computername=$env:computername
)
$AntiVirusProduct = Get-WmiObject -Namespace "root\SecurityCenter2" -Class AntiVirusProduct -ComputerName $computername
#Create hash-table for each computer
$ht = #{}
$ht.'Computername' = $computername
$ht.Name = $AntiVirusProduct.displayName
$ht.'Product Executable' = $AntiVirusProduct.pathToSignedProductExe
$ht.'Version' = [System.Diagnostics.FileVersionInfo]::GetVersionInfo ("C:\Program Files (x86)\Sophos\AutoUpdate\ALUpdate.exe").FileVersion
#Create a new object for each computer
New-Object -TypeName PSObject -Property $ht
}
Get-AntiVirusProduct
I have done some research and seen where a K100 script has been used to query the auto update file but I am not sure if this would be applicable for my solution.
FileExists(C:\Windows\system32\WindowsPowerShell\v1.0\powershell.exe) AND ShellCommandTextReturn(cmd /q /c powershell.exe -command "$f=[DATETIME] '01/01/1970 00:00:00'; $f.AddSeconds((Get-ItemProperty -Path 'REGISTRY::HKLM\SOFTWARE\Sophos\AutoUpdate\UpdateStatus' LastUpdateTime).LastUpdateTime) | ForEach-Object {'{0:yyyy}-{0:MM}-{0:dd} {0:HH}:{0:mm}:{0:ss}' -f ($_.AddHours(-0))}")
The module which the update runs to is ALUpdate.exe
would appreciate any help or suggestions.
Sophos Bootable Anti-Virus (SBAV) is an antivirus tool that will allow you to perform scanning and cleaning of the infected computer without the need to install the software. This procedure will be useful when the Master Boot Record (MBR) is infected on your computer.
The Sophos Bootable Antivirus is provided for free as a Windows binary file .exe file. You can download the program to the Windows computer and then install it. Once the installation is done, you have to run a command. The program will now create an ISO file with the latest version of the Sophos Antivirus including the recent virus protection updates. The tool will boot the computer using the underlying Linux operating system and performs a scan of the computer by suppressing the local operating system.
There are practically two different methods in which you can create the Sophos Bootable Antivirus:
By using a Bootable CD
By using a Bootable USB stick
Creating a bootable CD
Double-click on the bootable downloaded sbav_sfx file.
Click Accept to the License agreement and later on specify the installation location (default location is C:\SBAV). Take note of the specified location.
Open the command prompt.
You can open the Run command by pressing the Windows + R button on the keyboard.
Type cmd then press the Enter button.

Task sequence variable for OS, I want to install

I'm verry beginer in powershell, I'm wonking in a project, the goal it's to set the Biossetting like disabling or enabling the secureBoot and UEFI mode, while installing windows 7 or 10 by MDT.
I'm working with Dell and hp computer, I have the script for setting the bios of hp or dell
Hp:
$bios=Get-WmiObject -Namespace root/hp/instrumentedBIOS -Class HP_BIOSSettingInterface
$bios.SetBIOSSetting("UEFI Boot Options", "Enable","")
Dell:
(Get-WmiObject DCIM_BIOSService -namespace root\dcim\sysman -ComputerName .).SetBIOSAttributes($null,$null,"Secure Boot","1")
Then, my first problem these command is not working in any computer I need to install some modules, some cmdlet from hp or dell website, I want to know if make my script ".exe", it's gonna work in every-computer ?
Because I need to run my script with with deployement of windows.
My second and difficult task, I want to know with variable task sequence to use in my script, to detect the os of the tasksequence, I find this code in internet, after too much research in internet
$TaskPath = "$($MdtDrive):\Task Sequences"
$ControlPath = "$MDtroot\Control"
$OSPath = "$($MdtDrive):\Operating Systems"
$OS = (Get-ChildItem -Path $OSPath | Out-GridView -PassThru -Title "Select required OperatingSystem").Name
This code detect if the OS of the task sequence I want install in my computer is windos 7 or windows 10?
Thanks !
If I recall correctly from my days of systems deployment, Dell and HP both make dedicated tools for settigns BIOS configuration. Just make sure you run it in WinPE. Depending on which BIOS settings you change you make even have to boot WinPE twice to make sure the OS installs the way you want.
Dell: http://en.community.dell.com/techcenter/enterprise-client/w/wiki/7532.dell-command-configure
HP: https://deploymentbunny.com/2010/10/18/enable-tpm-via-task-sequence-on-hp-boxes/
Although it is definitely possible to make these settings in WMI I would only look to it as a last resort. Windows has to be compatible with every piece of hardware, whereas Dell/HP tools are targeted at their systems. It's like using a scalpel vs a Swiss army knife.
I have some difficults I’m working in a script who set the bios configuration while installing windows 7 or 10 by MDT, then my first question is:
Wich variable I can use to identify the os of the new task sequence I mean the current os the mdt preparing to install in the computer after the user select the os during the installation.
I’m wondering if this code doying the job
$OS = Get-ChildItem -Path $OSPath | Out-GridView -PassThru -Title “Select required OperatingSystem”
$OSPath = “$($MdtDrive):\Operating Systems”

Powershell: Re-create RDS Remote Apps by Looping?

I'm stumped. I can usually take the output of one powershell command and use it as the input to another powershell command. For example:
Get-Mailbox | Set-Mailbox -MaxSendSize 40MB
This will loop through every mailbox and then set the maximum send size to 40 MB in Exchange 2007.
...but the same doesn't work with get-rdremoteapp and new-rdremoteapp.
Get-RDRemoteApp | new-rdremoteapp -collectionname APPSNEW -connectionbroker edge-1.mydom.local
The goal of this command is that we are preparing to Migrate from a Windows 2012 RDS environment on virtual servers to a Windows 2012 R2 environment on physical servers.
On the virtual 'edge' server, I should be able to get all the RD Remote Apps, loop through them, and then use the 'new-rdremoteapp' command to create them on the new 'edge-1' server.
What actually happens is the command runs and creates the 1st remote app, then exits without an error. It doesn't process the apps in the list.
I think I need to use foreach-object, but after reading the docs and playing around, I can't seem to get it to work.
I couldn't find an easy out. I had to specify a bunch of parameters like so:
Get-RDRemoteApp | foreach-object -process {new-rdremoteapp -collectionname APPSNEW -connectionbroker edge-1.mydom.local -displayname $_.displayname -filepath $_.filepath -alias $_.alias -commandlinesetting $_.commandlinesetting -usergroups $_.usergroups}
Time to find a job that has more bash scripting... ;)