@george1421 https://docs.fogproject.org/en/latest/compile_ipxe_binaries
Just throwing in the permalink to the doc on this process.
Best posts made by JJ Fullmer
-
RE: Updating/Compiling the latest version of iPXE
-
RE: Fog Clients not joining the domain.
@John-L-Clark You should try 2 things. On that host in the fog gui, click the “reset encryption data” button and see if that fixes it.
If it does it should try to do the second thing for you, which would be updating to the latest fog client. The current version in .10.6 and you seem to have .9.12 and that error is from 5/5. So you should also check to make sure the fog service is started inservices.msc
-
RE: How to automatically run several .bat scripts after image deployment
@mecsr Use powershell instead of bat scripts, you’ll have more power. Pun intended, but it’s also just true. Especially when it comes to licensing tools. Sometimes the tools just don’t have command line options. Powershell has more user friendly tools for editing registry keys and environemnet variables which licenses sometimes require.
Also use the windows system image manager included in the windows ADK for creating an unattend.xml file
Snapins are an excellent method.
-
RE: Powershell API Module
A major version update has been released!
Added various functions and some new features. If you’re using fog 1.6 beta I added some tab complete of your server’s host names dynamically (the api in 1.6 is much faster, so there’s less overhead in making the call to list host names).
Also added a get-fogversion and various other requested features.One big and often requested thing included is a
Set-WinToBootToPxe
function that attempts to find the pxe boot entry in a windows hosts bcedit /enum {fwbootmgr} and sets it as the first boot option. I’ve used it with much success in my environment but I need feedback from other environments to make it truly universal.Another big update is pipeline support. It’s not quite yet as universal as I want, but I added things like
get-foghost -hostname somename | add-foghostmac -macaddress 00:00:00:00:00:00
Release notes: https://github.com/darksidemilk/FogApi/releases/tag/2408.9.2
Full change log:
https://github.com/darksidemilk/FogApi/compare/2311.6.4...2408.9.2
PSGallery: https://www.powershellgallery.com/packages/FogApi/2408.9.2 -
RE: UEFI-PXE-Boot (Asus t100 Tablet)
Ahem
There is a way to image these with fog.
Supposedly you should be able to just enable the network stack in bios and then if it’s a ethernet adapter that’s recognized you can set it as a boot option or select it by hitting esc to bring up the boot menu.
However since that didn’t work for me, I found a different method.
It’s a little bit abstract, but not too hard, I promise, give it a chance.What I used (I did 64 bit efi, substitute 32 bit versions of .efi files if you wanted to do 32 bit)
- A usb hub, any hub with 3 or more ports should do. I was using a powered usb 3 4 port hub.
- I used the startech USB210000S2 Usb ethernet adapter. It has the SMC LAN 7500 chipset, which is the important part
- 2 usb drives, no substantial size needed. (you may get away with one, but I used 2)
- On the first FAT32 formatted usb drive you just need a couple files in the root of the drive
-
- the efi driver for the usb (found at this link http://ww1.microchip.com/downloads/en//softwarelibrary/obj-lan95xx-uefi/lan95xx_7500_uefi_driver_0.5.zip, also attached 0_1479851633433_SmscUsbNetDriver.efi , also credit where credit is due, I discovered this file via this blog post http://www.johnwillis.com/2014/03/pxe-booting-using-usb-to-ethernet-dongle.html) (also I renamed this to usb.efi for simplicity later)
-
- ipxe.efi from your /tftpboot folder on your fog server, copy it off with your favorite ftp/scp client. (or just download the latest one straight from the fog project github https://github.com/FOGProject/fogproject/raw/dev-branch/packages/tftp/ipxe.efi)
-
- You can also put these files on the root of the C drive
- On the second flash drive
-
- create a refind efi bootable flash drive using a tool like rufus https://rufus.akeo.ie/downloads/ to put the USB flash drive image on a usb drive via dd that you get from here http://www.rodsbooks.com/refind/getting.html
-
- It makes a ~6MB partition that I’m not sure can be extended to fit the other files
Now plug the usb ethernet adapter, and the flash drives into the usb hub and plug the usb hub into the asus t100 usb port (well technically I have a T100H, but this method also worked on a Fusion5 chinese tablet, RCA Cambio tablet, and the atom and core M versions of the intel compute stick).
Now boot to the bios to make sure the secure boot setting is off and the network stack is enabled. It will probably work regardless of the network stack setting, but better safe than sorry. (Note: I always seem to have to hold shift and hit restart from windows to force it to boot to uefi firmware)
Save changes and exit and start tapping esc
tapping esc on boot should bring up a boot menu. Select the refind EFI usb drive.
On the ReFInd gui boot screen select one of the efi shell options.at the efi shell find which fs (file system) your efi files are on (the ones put on either the second flash drive or the C drive) by running these commands
fs0: ls
keep incrementing fs# (fs0: fs1: fs3: etc.) until you see your ipxe.efi and usb driver files.
When you find them run these two commands to start the pxe boot#replace usb.efi with whatever you named the driver file load usb.efi ipxe.efi
It should start at ipxe initializing devices
If you use the 32bit versions, don’t forget to set your kernel and init in the fog gui for that host.
Another caveat to this method is you have to remember to change the mac address from the usb ethernet adapter to the wifi mac of the device in the fog gui.Sure it’s not as smooth a system as wake on lan to network boot, but as daunting as it looks it all takes less than a minute to get it booted to pxe.
If you have problems with this, you may try setting a static ip address for your adapter in dhcp and make sure it’s pointed to fog. I have the uefi/bios coexistence setup with the policies found in the fog wiki in my windows dhcp and it works perfect.
If you read all that and think, that’s too much work for so many devices. Well than get a few of these usb setups. I used this method on about 30 intel compute sticks (didn’t require the refind usb, they have a built in efi shell) and it didn’t take all that long.
In theory, I imagine it’s possible to image these with wifi, but that’s a challenge for another day.
-
RE: Powershell API Module
Another Release! 2408.9.16
- Working towards automated releases, this release was created from an automation triggered by an accepted pull request!
- Added getting gpu inventory to get-foginventory which will work with the next release of Fog and already works in 1.6-beta. Capturing gpu inventory from FOS requires the latest experimental kernel and init as of writing. (EDIT: The required Kernel and Init are now what is downloaded with a Fog install/update by default (latest versions) )
- Fixed some issues with the new Get-WinBcdPxeID, fixed some logic issues and added some helper functions I forgot to include. Tested it in different environments with success.
- Added new Send-FogImage (Deploy fog image) parameters for Fog 1.6-beta and included switches for NoWol, shutdown after deploy, etc. Will later do the same for Receive-FogImage
- Still working out the release note formatting and versioning of automated releases. I have been appending each change where I increment the build version to the release notes, but the automation also append the combined commit of those changes, so some things are duplicated in the full change log.
- The nupkg from the powershell gallery, and the generated nupkg that will be later published to chocolatey (once the current version is approved I can add more versions) are now auto-added to the release assets in github, providing alternate install methods. There’s also a built version of the module in the zip of each release now too.
- I am attempting to unify the overview docs that end up being repeated in the module manifest, chocolatey nuspec, github readme, and about_ help files. I hope to later automate that a bit so it all comes from a single place to edit such.
Currently thinking I’ll switch to a dev branch system where I’ll have a testing version and whenever I pull that in to the master branch a release will be triggered, similar to how we now have Fog setup. That way there’s not a release overload by doing a release for every small feature I add. Hoping that the automatic release notes will include pull requests into dev since the last pull into master. Trying to find ways to adapt to the way github’s automations are designed.
Release notes: https://github.com/darksidemilk/FogApi/releases/tag/2408.9.16
Full change log:
https://github.com/darksidemilk/FogApi/compare/2408.9.3...2408.9.16
PSGallery: https://www.powershellgallery.com/packages/FogApi/2408.9.16
Chocolatey: (Coming soon, Pending Chocolatey Moderator Approval): https://community.chocolatey.org/packages/FogApi/2408.9.3 -
RE: snappin doesn't work
Also, for debugging.
If you put the script into a function and add [cmdletBinding()] you can run it with -debug
which means you can add lines like Write-Debug “variables is $variable”; that will only show up when -debug is specified and will pause for you. You can also add Write-Verbose “messages”; that only show
i.e. to do it while still running it as a ps1 script with arguments you’d have to be a little tricky. If you mad the script a .psm1 and added aexport-modulemember -function funcName;
line at the end and then ran this in a ps consoleipmo -Force -Global \path\to\psm1;
you could then run your script as a function that you can import into any script or console and add the -Debug and or -Debug lines directly when running the functionparam ( [String]$programme, [switch]$debug, [switch]$verbose ) function installProgramme { [CmdletBinding()] param ( [String] $programme ) $user = "install" $pwd = "1234500000000000000000000000000000000000000000000000000000AAAA=" $serveur = "\\fileserver.istic.univ-rennes1.fr\partage" $cert = $(Get-ChildItem cert:\CurrentUser\TrustedPublisher | where {$_.Subject -eq "CN=ISTIC/ESIR Signature"}) $tab_key = @() foreach ($i in $cert.SerialNumber.ToCharArray()){$tab_key += [convert]::ToInt16($i,16)} $password = ConvertTo-SecureString -key $tab_key -string $pwd $credential = New-Object -TypeName system.management.Automation.PSCredential -ArgumentList $user, $password Write-Verbose "Attempting to mount $serveur..."; #net use p: $dossier_partage /p:n /u:$($credential.GetNetworkCredential().username) $($credential.GetNetworkCredential().password) if (!(Test-Path -Path p:)){ $net = new-object -ComObject WScript.Network $net.MapNetworkDrive("p:", $serveur, $false, $credential.GetNetworkCredential().UserName,$credential.GetNetworkCredential().password) } Write-Debug "Check if P is mounted..."; #lorsque l'on lance un script powershell, si il y avait des espaces dans le nom, cela ne passait pas #lorsque l'on faisait un start-process et ce nom en argument. Donc on utilise plutot le nom court $prog_court = (New-Object -ComObject Scripting.FileSystemObject).GetFile($programme).ShortPath write-host "$(hostname):Dossier de l'installer $($dossier_installer)" write-host "" write-host "$(hostname):lancement de $($programme)" write-host "$(hostname):lancement de $($prog_court)" #start-process -FilePath $programme -wait -NoNewWindow $dossier_installer = $((get-item -path $programme).DirectoryName) if (!(Test-Path -Path "$dossier_installer\logs_fog_install")){New-Item -ItemType directory -Path "$dossier_installer\logs_fog_install"} $extension = (get-item -path $programme).Extension if ($extension -eq ".bat" -or $extension -eq ".cmd") { #write-host "$env:COMPUTERNAME:C'est un script bat" start-process -FilePath $prog_court -wait -NoNewWindow -RedirectStandardOutput ${dossier_installer}\logs_fog_install\${env:COMPUTERNAME}_log.txt -RedirectStandardError ${dossier_installer}\logs_fog_install\${env:COMPUTERNAME}_error.txt } if ($extension -eq ".ps1") { #write-host "$env:COMPUTERNAME:C'est un script powershell" $policy = Get-ExecutionPolicy Set-ExecutionPolicy AllSigned start-process -FilePath PowerShell -Arg $prog_court -wait -NoNewWindow -RedirectStandardOutput ${dossier_installer}\logs_fog_install\${env:COMPUTERNAME}_log.txt -RedirectStandardError ${dossier_installer}\logs_fog_install\${env:COMPUTERNAME}_error.txt Set-ExecutionPolicy $policy } #net use p: /delete $net.RemoveNetworkDrive("p:") } #create string to run function $runFunc = "installProgramme $programme"; if($debug){ $runFunc += " -Debug"; } if($verbose) { $runFunc += " -Verbose"; } $runFunc += ";"; Invoke-Expression $runFunc;
-
RE: Copy ipxe.efi to uefi partition?
@george1421 I’m pretty sure bootmgfw.efi is a bootmanager like refind and grub, it just doesn’t have a gui. And it chains bootx64.efi to boot to windows. From what I remember, trying to manually boot to bootx64.efi to get into windows doesn’t work, or doesn’t always work. So you want to use bootmgfw.efi to get into windows.
There’s probably a way to enable a gui on the windows 10 bootloader like you could in windows 7 and 8 and add additional boot options to it, but I haven’t found anything that works reliably or that would be easy to maintain. So I just started using different bootloaders which eradicated any issues I ever had with the windows bootloader randomly breaking and with added bonuses of not needing to try to get keystrokes in fast enough during initial boot to get to bios settings or fog. -
Adding Custom Printer Configuration
Add printer configuration to printer management. i.e. a sharp copier that requires you to manually click auto configuration for the printer to update it’s settings to match the printer.
I already have this scripted and imagine it would be pretty easy to add to the existing printer management. I would gladly add and test the code myself if someone could point me in the right direction.So lets say you have added a printer and configured it to all the correct settings, like how many input trays, types of output trays, maybe it requires putting in a security pin or it has a punch module. And it looks like this for example.
Then to save those configuration settings you simply need to run this command in a command prompt
RUNDLL32 PRINTUI.DLL,PrintUIEntry /Ss /n"Printer Name" /a Path\ConfigFile.dat m f g p
and then to configure the printer once it’s been added with the saved config
RUNDLL32 PRINTUI.DLL,PrintUIEntry /Sr /n"Printer Name" /a Path\ConfigFile.dat m f g p
I imagine that the way the print manager works is similar to the script I use to add a printer with the similar command line inputs.
For example, I can use the following script (manually adding in the parameters in the call of installPrinter in the main function) to install a printer. I could probably easily change it to take arguments into the execution like snapin arguments taken from the printer information. Which I imagine is somewhat how the add a printer works.@ECHO off call :main exit :main REM Function to call other functions and run the installation process call :setVars call :funcHead "Welcome to the Printer installer!" REM inputs: 1 - Printer Port Name, 2 - printer ip or hostname 3- driverPath 4 - printer name 5 - printer model 6 - config file 7 - raw or lpr call :installPrinter EXIT /B :setVars REM function for setting script variables, typically for directories call :funcHead "Setting script variables" set share="\\networkShare\Printers\Drivers" net use "%share%" echo. done! EXIT /B :installPrinter REM Function to add a new Printer REM inputs: 1 - Printer Port Name, 2 - printer ip or hostname 3- driverPath 4 - printer name 5 - printer model 6 - config file 7 - raw or lpr call :funcHead "Installing Printer %~4" call :printerPort %~1 %~2 %~7 call :printerDriver "%~3" call :addPrinter "%~4" "%~5" %~1 call :configPrinter "%~6" "%~4" echo. done installing printer %~4! EXIT /B :printerPort REM function for adding a printer port REM var inputs 1 - port name 2 -hostname or ip address 3 -port type (raw or lpr) call :dots echo. Creating the printer port... IF %~3==lpr ( Cscript %WINDIR%\System32\Printing_Admin_Scripts\en-US\Prnport.vbs -a -r %~1 -h %~2 -o lpr -q lp -n 515 ) ELSE ( REM raw Cscript %WINDIR%\System32\Printing_Admin_Scripts\en-US\Prnport.vbs -a -r %~1 -h %~2 -o raw -n 9100 ) echo. done! call :dots EXIT /B :printerDriver REM function to add the driver input 1=full driver path call :dots echo. Adding printer driver... PNPUTIL -i -a "%~1" echo. done! call :dots EXIT /B :addPrinter REM add the printer to the created port REM 1 - printer name 2 - printer model associated with driver 3 - port name call :dots echo. adding printer to network port... Cscript %WINDIR%\System32\Printing_Admin_Scripts\en-US\Prnmngr.vbs -a -p "%~1" -m "%~2" -r %~3 echo. done! call :dots :configPrinter REM add any special printer configurations REM 1 - config file path 2 - printer name call :dots echo. Configuring Printer... REM To create a config file for a printer, use the following syntax REM RUNDLL32 PRINTUI.DLL,PrintUIEntry /Ss /nPrinterName /a ConfigFilePath.dat m f g p RUNDLL32 PRINTUI.DLL,PrintUIEntry /Sr /n"%~2" /a %~1 m f g p echo. done! call :dots EXIT /B :dots REM just echoing dots in a Function instead of copy pasting them so that it's consistent echo ...................................................................... EXIT /B :funcHead REM A simple function for displaying a consistent header at the start of functions call :dots echo. %~1 call :dots EXIT /B
I would rather use the fog print management with the added ability to import printer config files, as it is the only thing it doesn’t do that my scripting method does. Granted I could just set this idea up as a snapin, but I don’t have the remove printer functionality in my script as is. So What can I do to add this functionality in.
-
RE: FOG/Powershell not copying to Win32/GroupPolicy/Adm
So this is an idea unrelated to your script syntax
Do you have access to your active directory central store and are all the computers involved in AD?
Based on what you have written you’re using the adm policy templates for applying chrome policies via group policy that you had set at the AD level.If you copy the admx files to the central store they’ll get copied down to each AD joined computer automatically. Is that an option for you?
I believe that the folder you’re copying to has some extra security built into it or something. I remember reading that once upon a time. You can use the chrome.admx file and the googleUpdate.admx files from where you got the adm files and copy them to c:\windows\policyDefinitions and that will work fine. I used to do it that way before I started just including them in the domain central store which can be accessed (read\write) remotely via
\\domainControllerHostname\C$\Windows\SYSVOL\sysvol\domainFqdn\Policies\PolicyDefinitions
You may have to login to the domain controller and find the local folder of that share.
I think you can copy adm files to either the central store or local store too, but I’ve read that admx files are the better option. I can’t remember why but I recall it being convincing.I hope that helps.
-
RE: Copy ipxe.efi to uefi partition?
@greg-plamondon Sorry I’ve been rather busy and hadn’t checked the forums in a bit.
Firstly a sidenote on what @Sebastian-Roth posted last. My understanding (from lots of trial and error, testing, and reading of microsoft docs) bootmgfw.efi is the bootmgr at the firmware level for windows. It uses the bcd entries (that you can modify with
bcdedit
to then load the specified efi file to boot the OS, which I think is something like bootx64.efi.So, I have a lot of information in my brain on this so let’s see if I can simplify.
TL;DR
Perhaps the quick answer to your question is
- make a symlink on the fog server to be able to download the ipxe.efi file
ln -s /tftpboot/ipxe.efi /var/www/html/ipxe.efi
- Mount the efi partition to drive letter A in windows
mountvol A: /S
- Download the ipxe file using powershell
Invoke-WebRequest -Uri "http://fogserver/ipxe.efi" -OutFile "A:\EFI\ipxe-latest.efi";
- (untested bit, but would probably work) Set the bcd to use ipxe as a bootmanager
bcdedit /set "{bootmgr}" path "\EFI\ipxe-latest.efi"
- You can revert this back to default with
bcdedit /set "{bootmgr}" path "\efi\Microsoft\Boot\bootmgfw.efi"
- You can revert this back to default with
- Dismount the efi partition
Mountvol A: /D
Brain dump of detailed info
I used to use rEFInd as my bootloader for my machines, but it has compatibility issues on some hardware so I found a different solution. I now use grub2win. But I still utilize Refind sometimes manually because it has a uefi shell, so when it is compatible it’s useful.
So first let me explain a wee bit on uefi shells from my understanding.
Basically, uefi has a shell, but not all computers have one built in. If you can boot to refind from a usb then you can access the shell.
The syntax for changing directories in the shell isfs#:
where # is the disk/partition number seen by uefi 0-(number of partitions -1).
You can then usels
andcd
to navigate and you can execute.efi
boot files and load efi drivers i.e.load driverName.efi
.
Playing with the uefi shells is how I figured out that if you pop ipxe.efi on to a usb or somewhere on the local disk, you can run it from the efi shell and it boots to fog (provided your network is already configured for pxe booting to fog). Some Bios/uefi firmwares also have options for ‘booting to file’ or other custom boot options where you can achive the same idea of navigating to an efi file and booting to it.So here’s a rundown of how I automate that process.
- I use chocolatey package manager and have a package made for installing grub2win
- I have a custom powershell module provisioning system that’s started via firstlogoncommands of my unattend.xml
- Within some of the first steps of provisioning I have it install my custom grub2win package (I have also tried to embed it in the image, but I believe sysprep/windows install changes the boot order on you, so I just make sure it runs, you could also do this with a setupcomplete.cmd system or whatever you use the run scripts after an image is completed)
So here’s what my custom package does, it looks like a lot here but it’s basically just installing a boot manager, copying some files, and editing the bcd.
Install grub2win
You can get a grub2win installer here https://sourceforge.net/projects/grub2win/
You download and extract the zip file. The setup.exe from the zip will then download the latest install files to%LocalAppData%\temp\grub2win.setup.exe.{buildNumber}\install
It will auto start a gui setup, but I leave that be and go copy the install folder from the temp folder to be a part of my package. Once I have the install folder out of the local appdata temp directory, I close the install wizard that popped up.Configure grub
In that install folder, you’ll need to edit the file at
winsource\basic.cfg
You can also use the built in gui tools to edit this after installing, but I find it easier to just make the config changes beforehand.Here’s what my custom menu entries look like, you’ll at least need the windows and fog menu entries.
# # Menu Entry 0 Windows 10 # # ** Grub will boot this entry by default ** # menuentry 'Windows 10 Hotkey=w' --hotkey=w --class windows --class icon-arrowwin { set gfxpayload=auto set efibootmgr=/efi/Microsoft/Boot/bootmgfw.efi getpartition file $efibootmgr root if [ ! -z $reviewpause ] ; then echo GNU Grub will load the Windows EFI Boot Manager at disk address $root g2wsleep echo fi chainloader $efibootmgr savelast 0 'Windows 10' echo GNU Grub is now loading Windows 10 } # # Menu Entry 1 FOG # menuentry 'FOG Hotkey=f' --hotkey=f --class chainfile --class icon-fog { set gfxpayload=auto set chainbootmgr=/efi/ipxe-latest.efi getpartition file $chainbootmgr root chainloader $chainbootmgr savelast 1 'FOG' echo GNU Grub is now loading FOG via ipxe } # # Menu Entry 2 Boot to your EFI firmware setup # menuentry 'Boot to your EFI firmware setup Hotkey=b' --hotkey=b --class bootfirmware --class icon-bootfirmware { g2wutil fwsetup } # # Menu Entry 3 Boot Information and Utilities # menuentry 'Boot Information and Utilities Hotkey=i' --hotkey=i --class bootinfo --class icon-bootinfo { clear set pager=0 set grub2win_chosen='0 - Windows Boot Manager' set grub2win_lastbooted=no export gfxmode export grub2part export grub2win_chosen export grub2win_lastbooted export grub2win_version export grub2win_procbits export grub2win_bootmode export grub2win_efiboot export grub2win_efilevel configfile $prefix/g2bootmgr/gnugrub.bootinfo.cfg } # # Menu Entry 65 Shutdown the system # menuentry 'Shutdown the system Hotkey=s' --hotkey=s --class shutdown --class icon-shutdown { clear set pager=1 echo echo Grub is shutting down your machine echo sleep -i -v 2 halt # If halt fails, display an error message echo Grub Shutdown is not supported by your firmware }
I put all that at the bottom, that’s my entire menuentries section.
Then at the top of the basic.cfg file (as in the very first uncommented line) I have
Set default=0
to default to the windows bootloader.Packaging and silent install
Then I make a chocolatey package (if you don’t have chocolatey you could probably achieve the same idea with a fog snapin pack). Basically you need all the files from the install folder, for a quick example we’ll pretend I copied the install files to
C:\install
To install grub2win silently I would runC:\install\winsource\grub2win.exe Autoinstall Quiet EFIAccess Shortcut=no Drive=C: RunFromEFI=yes SetAsDefault
This will extract some files to
C:\grub2win
and copy neccesarry files to the EFI partition.I also do some theme customization and add the refind efi shell tools, but I’m not going to get into that here right now.
Mount The EFI drive and copy down the ipxe.efi file
I have a powershell function called Mount-Efi that does this with some other functions that help it too with some error checking and making sure it’s not already mounted. But the most important bit is this bit
$mountLtr='A:' $mountVol = "C:\Windows\System32\mountvol.exe"; Start-Process -FilePath $mountVol -Wait -NoNewWindow -ArgumentList @($mountLtr, '/S');
That’s all to make it pretty in powershell, you can also just run the command natively
mountvol A: /S
where the/S
is telling it to mount your efi partion, and theA:
is saying to use A: as your path. This isn’t exposed to the gui file explorer, but you can thencd A:\
and you’re in the efi partion in powershell/cmd and can do whatever you want.Getting ipxe.efi
To simplify this process and always have the latest version. I have a symlink on my fogserver to be able to grab the ipxe.efi file with a quick download.
On the fogserver I create this withln -s /tftpboot/ipxe.efi /var/www/html/ipxe.efi
I can then download from http://fogserver/ipxe.efi. So after I’ve installed grub2win and then mounted the efi partition. I run this powershell command to download the ipxe file to efi and have it be namedipxe-latest.efi
Invoke-WebRequest -Uri "http://fogserver/ipxe.efi" -OutFile "A:\EFI\ipxe-latest.efi";
Now it is where my grub config will look for it if I choose to boot to fog.
Test that grub2win installed correct
I do a check in the efi partition that the kernel and binary files for grub2win are in the right place.
You should ssee all the files that were in the folderg2bootmgr
from the grub2win install folder at (assuming you mounted efi to A)A:\EFI\Grub2Win\g2bootmgr
particularly you want to see thegnugrub.kernel*.efi
boot file.Edit the windows bcd
This is the series of steps I run through to edit the bcd. (I have powershell functions for each to keep it simple to run internally, but I’ll just share the basic commands to make it less confusing to read through). Essentially I have an end result of pointing the default windows bootmgr bcd entry to the grub efi boot file.
Remove boot entry added by grub2win
Grub2win adds its own entry to bcd and it does often work. But I have a handful of devices that it doesn’t work as expected on, so I remove it and edit the default windows one, which helps with devices that don’t let you change the boot order within windows.
First you need to get the bcd entry for grub2win
$searchString = "Grub2Win EFI - 64 Bit"; $grubEntry = ($bcdEntry.ToString().split([Environment]::NewLine) | Where-Object { $_ -match 'id' }).Replace("identifier","").trim();
Then you need the guid of that entry
$guid = ($grubEntry.ToString().split([Environment]::NewLine) | Where-Object { $_ -match 'id' }).Replace("identifier","").trim();
Now you can remove the entry
bcdedit /set "{fwbootmgr}" displayorder $guid /remove
# you can also view/confirm its removal before and after with bcdedit /enum "{fwbootmgr}"
Edit where the bootmgr points
This is where we change the default bcd entry to use grub instead of the windows bootloader. Theoretically you could also use this to always boot to pxe, but I wouldn’t recommend that.
$path = "\EFI\Grub2Win\g2bootmgr\gnugrub.kernel64.efi" bcdedit /set "{bootmgr}" path $path
The code above is just using string manipulation to get the guid out of the output of the above enum command. If doing it manually you could highlight, copy, paste.
Make sure the altered boot manager is the first boot option
I’m pretty sure this is the command windows uses during sysprep to reset the boot order to boot to windows first instead of whatever you had set in the bios for install (i.e. pxeboot)
bcdedit /set "{fwbootmgr}" displayorder "{bootmgr}" /addfirst
Remove runOnce boot options
Sometimes grub2win or windows bcd or something else during this process adds a runOnce option. Theoretically you could use the runOnce option to force the computer to boot to the network on next reboot but it’ll go back to normal after that.
However, since I’m creating a default here and want to see it work as it always will, I remove any entries if the exist.bcdedit /deletevalue "{fwbootmgr}" bootsequence
Dismount efi partition and you’re done
Lastly you can dismount the efi partition with this command. Next time you restart you’ll have grub as a bootmgr with options for booting to fog or windows.
mountvol A: /D
Putting it all together.
Here’s what my chocolatey package looks like
- parent folder named custom-grub
- custom-grub.nuspec
<?xml version="1.0" encoding="utf-8"?> <package xmlns="http://schemas.microsoft.com/packaging/2015/06/nuspec.xsd"> <metadata> <id>custom-grub</id> <version>2004.2.207.5</version> <title>custom-grub</title> <authors>jfullmer</authors> <copyright>2019</copyright> <tags>custom-grub admin</tags> <description> Installs the customized arrowhead grub bootloader for easy booting to fog bios setup or a uefi shell when needed To update the config that gets installed, edit the sources\winsource\basic.cfg file The basic theme is overridden with the customized theme complete with company logo background the boot options are to boot to windows 10, fog via ipxe, firmware/bios setup, or the refind boot manager for when a uefi shell is needed. In the future options for windows 10 safe mode and other boot modes should be added as a submenu. </description> </metadata> <files> <file src="tools\**" target="tools" /> </files> </package>
-
- tools folder
- chocolateyinstall.ps1
- tools folder
$packageName = 'custom-grub' $toolsDir = "$(Split-Path -parent $MyInvocation.MyCommand.Definition)" $sources = "$toolsDir\sources"; $fileLocation = "$sources\winsource\grub2win.exe" $packageArgs = @{ packageName = $packageName softwareName = 'custom-grub*' file = $fileLocation fileType = 'exe' silentArgs = "Autoinstall Quiet EFIAccess Shortcut=no Drive=C: RunFromEFI=yes SetAsDefault " validExitCodes= @(0) url = "" destination = $toolsDir } Import-Module "$toolsDir\Functions.psm1" -force; Set-Location "C:\" Mount-EFI; $EfiMnt = Get-EfiMountLetter; Remove-OldGrubFiles -EfiMnt $EfiMnt; Add-EfiTools -sources $sources -EfiMnt $EfiMnt Dismount-EFI; Install-ChocolateyInstallPackage @packageArgs Mount-EFI; $EfiMnt = Get-EfiMountLetter; Test-BootMgrBinary -sources $sources -EfiMnt $EfiMnt Add-AdlGrubTheme -sources $sources -EfiMnt $EfiMnt; Write-Verbose "adding grub boot manager to bios boot order and fixing built-in bootmgr to use grub boot manager" Remove-FwBootEntry; Set-BcdBootMgrPath; Set-FirstFwBootOption; Remove-RunOnceBootOptions; Dismount-EFI; Remove-Item -Force -Recurse $sources; return;
-
-
- functions.psm1
-
function Remove-OldGrubFiles { [CmdletBinding()] param ( $EfiMnt ) process { Write-Verbose "removing any current grub files for fresh install" if ((Test-Path "C:\grub2")) { #grub2 path already exists remove it "Removing C:\grub2" | OUt-HOst; Remove-Item -Force -Recurse C:\grub2; } if ((Test-Path "$EfiMnt\EFI\grub2win")) { "Removing old grub2 EFI Files" | Out-host; Remove-Item -Force -Recurse "$EfiMnt\EFI\grub2win"; } } } function Add-AdlGrubTheme { [CmdletBinding()] param ( $sources, $EfiMnt ) process { Copy-Item "$sources\themes\*" "C:\grub2\themes\" -force -recurse; Copy-Item "$sources\themes\*" "$EfiMnt\EFI\Grub2win\themes\" -force -recurse; } } function Add-EFITools { [CmdletBinding()] param ( $Sources, $EfiMnt ) process { Write-Verbose "Adding efi binary tools and drivers" New-Dir "$EfiMnt\EFI\Tools\"; New-Dir "$EfiMnt\EFI\boot\"; Copy-Item "$sources\refind\tools\*" "$EfiMnt\EFI\Tools\" -Force; Copy-Item "$sources\refind\boot\*" "$EfiMnt\EFI\boot\" -Force -Recurse; Write-Verbose "downloading latest fog ipxe file" Invoke-WebRequest -Uri "http://arrowfog/ipxe.efi" -OutFile "$EfiMnt\EFI\ipxe-latest.efi"; } } function Test-BootMgrBinary { [CmdletBinding()] param ( $Sources, $EfiMnt ) process { if (!(Test-Path "$EfiMnt\EFI\Grub2Win\g2bootmgr\gnugrub.kernel*.efi")) { Write-Verbose "boot manager binary is missing, re-copying the grub boot binary files"; Copy-Item "$sources\g2bootmgr\*" "$EfiMnt\EFI\Grub2Win\g2bootmgr\" -force; } } } function Get-BCDEntry { [CmdletBinding()] param ( $searchString = "Grub2Win EFI - 64 Bit" ) process { return (bcdedit /enum all | select-string $searchString -Context 5,1); #get the grub bootmgr entry from all bcd options } } function Get-BcdGUID { [CmdletBinding()] param ( $bcdEntry = (Get-BCDEntry) ) process { return ($bcdEntry.ToString().split([Environment]::NewLine) | ? { $_ -match 'id' }).Replace("identifier","").trim(); #get the guid of the grub bootmgr entry } } function Remove-FwBootEntry { [CmdletBinding()] param ( $bcdEntry = (Get-BCDEntry) ) process { $guid = Get-BcdGUID -bcdEntry $bcdEntry; $fwboot = bcdedit /enum "{fwbootmgr}" if ($null -ne $guid) { if ($fwboot -match $guid) { return (bcdedit /set "{fwbootmgr}" displayorder $grubID /remove); #remove the grub boot manager created by the installer from boot order as it isn't universally compatible } else { "guid was not in {fwbootmgr}" | OUt-Host; } } else { "guid not found" | OUt-Host; return $null; } } } function Set-BcdBootMgrPath { [CmdletBinding()] param ( $path = "\EFI\Grub2Win\g2bootmgr\gnugrub.kernel64.efi" ) process { return (bcdedit /set "{bootmgr}" path $path) #set the default bootmanager to the grub efi file path } } function Set-FirstFwBootOption { [CmdletBinding()] param ( $bootOptionName = "{bootmgr}" ) process { return (bcdedit /set "{fwbootmgr}" displayorder $bootOptionName /addfirst); #set the edited bootmanager to the first boot option } } function Remove-RunOnceBootOptions { [CmdletBinding()] param ( ) process { $fwboot = bcdedit /enum "{fwbootmgr}" if ($fwboot -match "bootsequence") { $result = (bcdedit /deletevalue "{fwbootmgr}" bootsequence); #remove any run once boot options } else { $result = "bootsequence value not present"; } return $result; } } function Dismount-Efi { <# .SYNOPSIS Dismounts the EFI system partition if it is currently mounted .DESCRIPTION Gets the efi partition mount letter and dismounts it with the mountvol tool #> [CmdletBinding()] param () process { $mountLtr=(Get-EfiMountLetter) if ($null -eq $mountLtr) { Write-Debug "EFI Partition is not mounted"; return $null } else { $mountVol = "C:\Windows\System32\mountvol.exe"; return Start-Process -FilePath $mountVol -Wait -NoNewWindow -ArgumentList @($mountLtr, '/D'); } } } function Get-EfiMountLetter { <# .SYNOPSIS If the EFI partition is mounted this returns the current drive letter .DESCRIPTION Runs the mountvol.exe tool and parses out the string at the end of the output that states if and where the EFI system partition is mounted #> [CmdletBinding()] [Alias('Get-EfiMountLtr','Get-EfiMountPath')] param ( ) process { $mountVol = "C:\Windows\System32\mountvol.exe"; #test if mountvol already has mounted a EFI partition somewhere and dismount it $mountVolStr = (& $mountVol) $currentEfiMountStr = ($mountVolStr | Select-String "EFI System Partition is mounted at"); if ($null -ne $currentEfiMountStr) { #get the substring starting at the index of the character before ':' in the drive name $currentEfiMountLtr = $currentEfiMountStr.ToString().Substring(($currentEfiMountStr.ToString().indexOf(':'))-1,2); if ($null -ne $currentEfiMountLtr) { return $currentEfiMountLtr; } } Write-Debug "EFI partition is not currently mounted"; return $null } }
-
-
- sources folder
- Contents of install folder with altered basic.cfg file from the install grub2win step. I also have customizations to the theme (like a fog icon) and have some other customizations, but the ones I described here are all you need to make it function.
- sources folder
-
Hopefully that is helpful information. Probably more information than you ever wanted.
- make a symlink on the fog server to be able to download the ipxe.efi file
-
RE: FOG 1.3 persistent groups
@Sebastian-Roth
Ok let me try to explain at least my idea in a simpler way. I tend to use too many words.So lets say you have a department like accounting. This department all needs access to the same printers, software, and needs to be in the same OU.
I want to be able to add a host to the accounting group that already has all those settings saved.
So when I add a host to the accounting group I can then apply all the saved printers, OU settings, snapins, and image with a single action.Does that make sense?
I think @george1421’s desires are a little more complex then mind, but a similar idea.
-
RE: FOG/Powershell not copying to Win32/GroupPolicy/Adm
@victorkrazan6267 I just read this part after making my domain central store reccomendations.
We have some non-domain computers and I utilized copying the admx files to C:\Windows\PolicyDefinitions for setting the policies in local group policies. You could theoretically embed them in your image as well.You can also use the policyfileeditor module https://www.powershellgallery.com/packages/PolicyFileEditor/3.0.1
to edit the local group policy as part of that script.i.e. to set chrome to always open pdfs externally you could do
$machinePol = "C:\WINDOWS\system32\grouppolicy\machine\Registry.pol"; $chromeKey= "Software\policies\google\chrome"; Set-PolicyFileEntry $machinePol -key $chromeKey -ValueName "AlwaysOpenPdfExernally" -Data 1 -Type DWord;
It takes a little time to learn that module. But it’s pretty useful to have a way to script changes to local group policies.
-
RE: Printer mapping wont work
@RTOadmin Can you provide
some examples of what you see working on the fog side and what you see not ?
The log of what’s broken ?
Version of fog and fog client ? -
RE: ZSTD Compression
@Junkhacker Well deploy is where speed is more important to me.
I gave 19 a go with the split and it actually had some weird error on the first deploy, I was in a meeting in my office so I didn’t really get to see the whole thing, but then it auto-retried the task and worked proper the second time. 2 minutes 18 seconds. The image size on the server seems to still be bigger than pigz was with 7.1 GB for a 15 GB image instead of 6.7 G for the old 18 GB image. But, don’t need to be too picky about it.@Tom-Elliott Two minor issues I noticed. The first time (the slow deploy) I queued the image after doing a full host inventory via the pxe boot on the host. I had not specified any snapins and it randomly added like 10 of them. The second time I queued it from the gui and deleted the snapins and the problem didn’t repeat itself. However in both instances the drive didn’t resize itself.
-
RE: Tablet PC hangs on bzImage
@Zerpie You can also try booting from the ipxe shell, which if isn’t built in to the tablet as a boot option (sometimes it is sometimes it isn’t) then you can make a rEFInd usb disk and add all the ipxe efi boot options. Then you can create a startup.nsh script that will switch to the fs#: of the usb drive and then boot to whichever 32 bit ipxe file ends up working. It would be tricky and still involve usb drives but you could in theory make it work.
Another possibility would be to customize fog’s built in refind for those tablets if that happens to be booted to successfully (i.e. if boot to hard drive from the fog menu is working). You could change the default boot settings, I believe you can add some conditions to it, I know you can do it to have different times of the day have different default boot options. So one possibility would be to add the refind efi shell to the fog refind.conf boot options and make it the default during some time slot you are going to image and just also find a way to link a startup.nsh script. I haven’t actually tested this idea, it’s just another possibility if you want network boot to work. But all of that is nill if none of the ipxe efi boot files get you through bzimage32 boot.
-
RE: failed to import module
@Sebastian-Roth said in failed to import module:
@kalafina The fog-client is a 32 bit application as far as I know. So you might get around by installing the 32-bit Dell Command | PowerShell Provider v2.7.0 found here: https://www.dell.com/support/kbdoc/en-us/000177240/dell-command-powershell-provider?lwp=rt
If switching to the 32 bit module doesn’t work like @Sebastian-Roth suggests, you could also try changing to the alternate version of powershell in the snapinrun with path
"%SYSTEMROOT%\SYSWOW64\windowspowershell\v1.0\powershell.exe"
-
RE: ZSTD Compression
@JJ-Fullmer Well it wasn’t actually phpipam that was slowing it down.
I had some ssl logs running for a website running on that server. It was tracking access logs for every access of the ssl cert and site. Which was also adding up to over 400 GB of logs. I changed the apache configuration of the site to log much less. That solved the problem. So again, nothing wrong with zstd. Just wanted to have the right answer in case someone else happens to see a constant 5-8 Mbps transmit and receive on a storage node. -
RE: Disable snapin hashing
Here is the code I use to create a snapin after publishing a chocolatey package to my repo.
I added the hashes after the problem started and it sometimes helps but it seems the behavior is slightly unpredictable and the hash record on fog still changes somehow.Write-Verbose "making sure package $global:packageName exists as fog snapin"; if ( (Invoke-FogApi -uriPath "snapin/search/$global:packageName" -Method GET).count -eq 0){ Write-Verbose "snapin does not exist, creating new snapin"; $snapinScript = Get-Item "path\to\chocoPkgSnapin.ps1"; $hash = ($snapinScript | Get-FileHash -Algorithm SHA512).Hash; $fileSize = $snapinScript.Length; $json = @{ "name"="$global:packageName" "file"="chocoPkgSnapin.ps1" "args"="-pkgname $global:packageName" "reboot"="" "shutdown"="" "runwith"="powershell.exe" "runwithArgs"="-ExecutionPolicy Bypass -NoProfile -File" "protected"="0" "isEnabled"="1" "toReplicate"="1" "hide"="0" "timeout"="0" "packtype"="0" "storagegroupname"="default" "hash"="$hash" "size"="$fileSize" } | ConvertTo-Json; Invoke-FogApiChocoSnapin -uriPath 'snapin/new' -Method POST -jsonData $json -verbose; } else { Write-Verbose "Snapin already exists"; } Write-Verbose "Updating hases for all snapins"; $snapinScript = Get-Item "path\to\chocoPkgSnapin.ps1"; $hash = ($snapinScript | Get-FileHash -Algorithm SHA512).Hash; $fileSize = $snapinScript.Length; $snapins = Get-FogObject -type object -coreObject snapin; $snapins.snapins | Where-Object file -match 'choco' | ForEach-Object { $data = @{ "id" = "$($_.id)"; "name" = "$($_.name)"; "file" = "$($_.file)"; "runwith"="powershell.exe"; "runwithArgs"="-ExecutionPolicy Bypass -NoProfile -File"; "args" = "$($_.args)"; "protected"="0"; "isEnabled"="1"; "toReplicate"="1"; "hide"="0"; "timeout"="0"; "packtype"="0"; "reboot"=""; "shutdown"=""; "size"="$fileSize" "hash" = "$hash"; } | convertto-json; Update-FogObject -type object -coreObject 'snapin' -IDofObject $_.id -jsonData $data -uri "snapin/$($_.ID)/ Write-Verbose 'Done!'; return;
Some of the snapins return 500 errors when I attempt to loop through them all and update their hash records.
Since that isn’t working I’m really hoping there’s some way to disable the hashing function, even if it’s some hackish way in the database or something.