Navigation

    FOG Project

    • Register
    • Login
    • Search
    • Recent
    • Unsolved
    • Tags
    • Popular
    • Users
    • Groups
    • Search
    1. Home
    2. JJ Fullmer
    • Profile
    • Following
    • Followers
    • Topics
    • Posts
    • Best
    • Groups

    JJ Fullmer

    @JJ Fullmer

    Testers

    Been using FOG since 2013.
    Powershell developer and enthusiast
    Avid Tester of new technologies with Fog.

    300
    Reputation
    705
    Posts
    4524
    Profile views
    4
    Followers
    5
    Following
    Joined Last Online
    Website arrowheaddental.com Location Sandy UT Age 32

    JJ Fullmer Follow
    FOG Hangouts Testers Moderator

    Best posts made by JJ Fullmer

    • Creating a csv host import from a network scan

      Run the following code in powershell (after editing it with your network’s subnets) to create a csv that will import all hosts on your network.

      # examples, just gotta put subnets minus the final .x in a string array
      # Could also be params if this was a function
      $subnets = @("192.168.1", "192.168.2", "10.2.114", "192.168.0"); 
      $subnets | ForEach-Object { # loop through each subnet
      	for ($i=0; $i -lt 255; $i++) { # loop through 0 to 255 of the subnet
      		$hn = nslookup "$_.$i"; # run nslookup on the current ip in the loop
      		if ($hn[3] -ne $null -AND $hn[3] -ne "") { # does the ip have a dns entry
      			$hostN = $hn[3].Replace("Name:","").Trim(); # parse the nslookup output into a fqdn host name
      			$mac = getMac /S $hostN; # does the hostname have a mac addr. Can also add /U and /P for user and password if not running from a administrative account
      			if ($mac -ne $null) { # was there a mac for the host?
      				$macAddr = $mac[3].Split(' ')[0]; # use the first found mac address and parse it
      				"$hostN,$macAddr" | Out-File C:\hosts.csv -Append -Encoding UTF8; # add the hostname,macaddress to the csv
      			}
      		}
      	}
      }
      
      posted in Tutorials
      JJ Fullmer
      JJ Fullmer
    • RE: Can't Edit Exisiting Snapins or Create New ones

      @Arrowhead-IT Scratch that, it totally worked after a restart. So if you go breaking your permissions just run the script posted and restart and violia!

      posted in Bug Reports
      JJ Fullmer
      JJ Fullmer
    • RE: New Inits

      Everything is working for me now! hooray for the new inits!

      posted in General
      JJ Fullmer
      JJ Fullmer
    • RE: Cortana/Windows Search breaks in default profile

      @Lee-Rowlett I think you are somewhat correct there. In all my testing I found that it relates to when a user first logs in it installs all the metro apps for that user including cortana. And when you do a profile copy in the system advanced settings control panel it ends up copying some of those installed apps to the default profile which causes the installation of metro apps on a new profile to fail, but there’s no error because the installs think they succeed since the files are already there.
      At least I think that has some to do with it. My new script system seems to work flawlessly and it is much easier than my old way of having to change the registry everytime and such.

      I would still test your theory for you, just for funzies, but I don’t actually use an unattend.xml. I don’t like sysprep. It breaks my default profile sometimes, and I’ve seen it break other things and it forces you to go back to oobe which messes with my computer naming system. I’ve kinda found it to not be necessary. Yes it resets some security id’s for activation this and that but if you are using windows enterprise volume licensing, that doesn’t cause any problems. In windows 7 I figured out the registry key to change and then just re-inputting the windows key and reactivating gave it a new sid. Windows 8 and 10 just work without issue without doing that. As for drivers, I make my images on a vm so they’re already hardware independent and I use the terminal tool devcon (included in the windows wdk 8.1, I just copy the devcon.exe over to my image vm after installing the wdk on my workstation) to uninstall all the devices in the device manager before rebooting with devcon -r remove *
      It goes through the uninstalling of devices much much faster than sysprep does too.

      So thank you sir for your help, but I think I got it figured out.

      posted in Windows Problems
      JJ Fullmer
      JJ Fullmer
    • Powershell API Module

      I created a powershell module for using the Fog API

      https://www.powershellgallery.com/packages/FogApi

      Install instructions are found at that link.

      You can also use powershellget https://www.powershellgallery.com/packages/PowerShellGet the command Install-Module -Name FogApi;*

      Importing that module will help you to set up a quick and easy and crossplatform way to manage fog from a powershell prompt.

      It is structured based on the api documentation found here https://news.fogproject.org/simplified-api-documentation/
      It even autocompletes the parameter options based on that documentation.

      So if you read that documentation and see that you can get an ‘object’ you can then take that to the command by saying Get-FogObject -type object -CoreObject objecttype that object type validates/autocompletes to the list of available core objects found in the documentation.

      If you install the module and run help Invoke-FogApi it will display a bit more verbose help and documentation on how it all works.

      There are a few main functions to use that all make calling the Invoke-FogApi function a bit easier with autocompletion fun times

      • For GET api calls : Get-FogObject
      • For POST api calls : New-FogObject
      • For PUT api calls : Update-FogObject
      • For DELETE api calls : Remove-FogObject

      Each of these return powershell objects. If you’re unfamiliar with powershell and powershell objects, then this is a good way to learn.
      They make it so you can take information and easily find and manipulate their properties.
      i.e. if you did a $hosts = Get-FogObject - type Object -CoreObject host $hosts would contain 2 properties, a count of returned objects and an array of all your fog hosts, each with all the information fog has on them. So lets say you want to see all your hosts that have a intel cpu, you can search all the hosts for where the inventory’s cpu manufacturer has ‘intel’ in its value. $intelPCs = $hosts.hosts | ? { $_.inventory.cpuman -match 'intel' } Then maybe you just want the hostids, names, and mac addresses. $intelPCList = $intelPCs | Select-Object id,name,primac; $intelPCList;

      PS Objects can also easily be turned into json by piping them into a ConvertTo-Json command. Meaning that you can just change the values of an object’s properties, such as a host’s name, image, etc. And then convert that to json to use as the jsondata in any other command.

      I also included a Install-FogService function in the module for good measure that downloads the latest version of the client msi installer from your server and then silently installs it. In theory, you could use Invoke-Command to run that command on remote computers (though you would also have to import the module on each computer).

      There is a settings.json file that the module pulls from to get your api keys and servername. It needs to be set manually, but automatically opens in an appropriate editor for your OS if it finds that the settings are still set to default. The default settings are explanations of where to find the values on your server.

      Help Info from function code Will be updated overtime, putting here as it is the help info uri listed in module manifest
      Invoke-FogApi

      <#
              .SYNOPSIS
                 a cmdlet function for making fogAPI calls via powershell
              
              .DESCRIPTION
                  Takes a few parameters with some pulled from settings.json and others are put in from the wrapper cmdlets
                  Makes a call to the api of a fog server and returns the results of the call
                  The returned value is an object that can then be easily filtered, processed,
                   and otherwise manipulated in poweshell.
                  The defaults for each setting explain how to find or a description of the property needed.
                  fogApiToken = "fog API token found at https://fog-server/fog/management/index.php?node=about&sub=settings under API System";
                  fogUserToken = "your fog user api token found in the user settings https://fog-server/fog/management/index.php?node=user&sub=list select your api enabled used and view the api tab";
                  fogServer = "your fog server hostname or ip address to be used for created the url used in api calls default is fog-server or fogServer";
                          
              .PARAMETER serverSettings
                  this variable pulls the values from settings.json and assigns the values to 
                  the associated params. The defaults explain how to get the needed settings
                  fogApiToken = "fog API token found at https://fog-server/fog/management/index.php?node=about&sub=settings under API System";
                  fogUserToken = "your fog user api token found in the user settings https://fog-server/fog/management/index.php?node=user&sub=list select your api enabled used and view the api tab";
                  fogServer = "your fog server hostname or ip address to be used for created the url used in api calls default is fog-server or fogServer";
      
              .PARAMETER fogApiToken
                  a string of your fogApiToken gotten from the fog web ui. 
                  this value is pulled from the settings.json file
              
              .PARAMETER fogUserToken
                 a string of your fog user token gotten from the fog web ui in the user section.
                 this value is pulled from the settings.json file
              
              .PARAMETER fogServer
                  The hostname or ip address of your fogserver, 
                  defaults to the default name fog-server
                  this value is pulled from the settings.json file
              
              .PARAMETER uriPath
                  Put in the path of the apicall that would follow http://fog-server/fog/
                  i.e. 'host/1234' would access the host with an id of 1234
                  This is filled by the wrapper commands using parameter validation to 
                  help ensure using the proper object names for the url 
                  
              .PARAMETER Method
                Defaults to 'Get' can also be Post, put, or delete, this param is handled better
                by the wrapper functions
                get is Get-fogObject
                post is New-fogObject
                delete is Remove-fogObject
                put is Update-fogObject
              
              .PARAMETER jsonData
                  The jsondata string for including data in the body of a request
              
              .EXAMPLE
                  #if you had the api tokens set as default values and wanted to get all hosts and info you could run this, assuming your fogserver is accessible on http://fog-server
                  Invoke-FogApi;
      
              .Example
                  #if your fogserver was named rawr and you wanted to put rename host 123 to meow
                  Invoke-FogApi -fogServer "rawr" -uriPath "host/123" -Method "Put" -jsonData "{ `"name`": meow }";
      
              .Link
                  https://news.fogproject.org/simplified-api-documentation/
              
              .NOTES
                  The online version of this help takes you to the fog project api help page
                  
          #>
      
      posted in Tutorials
      JJ Fullmer
      JJ Fullmer
    • RE: executing batch file from snapin

      I would suggest using the full path of the file in your batch script instead of changing the directory.
      And when I say full path, I mean the true full path, not the mounted S:\ drive.
      Even if S:\ is being mounted by active directory or is a mapped drive as part of your image, I would still suggest using the full network/unc path.
      I would also suggest mounting it with net use and a username and password. This will ensure the system account that the Fog Service uses has access to the files you want
      I would also add some logging and other error preventions.

      i.e. if S:\ was mapped to \FileServer\Share …

      @ECHO off
      
      echo. Create variables to make scripting easier
      set sharePath=\\FileServer\Share\Pat
      
      echo. Mount S drive path, replace username and password with share credentials. 
      echo. If share is public omit the /USER parameter and everything after it
      
      
      net use %sharePath% /USER:username password
      
      echo. make sure destination exists, create it if it doesn't
      if not exist C:\temp mkdir C:\temp
      
      echo. copy each file, add /Y to overwrite without any prompt
      echo. copying tdpunt...
      copy /Y %sharePath%\tdpunt.bat C:\temp\ > C:\temp\tdpunt-bat-Copy.log
      echo. copying tundpt.exe...
      copy /Y %sharePath%\tundpt.exe C:\temp\ > C:\temp\tundpt-exe-Copy.log
      
      echo. Done!
      
      exit
      
      

      Use that and then see if the .log files show up after deploying the snapin.

      Also, in the web gui snapin config, you should take out the /qn that does nothing.
      The snapin arguments section is for custom arguments that you have in your script. Your script doesn’t do anything with the /qn and it could cause issues. The /c parameter is passed to the cmd.exe command which tells cmd.exe to open a prompt, run the command, and then close.
      If you had a line in your script like this

      if "%1" == "/qn" (
          echo. hey look a parameter, lets do something since it's there!
      )
      

      then the /qn would have a point.

      Hope that helps a bit.

      Thanks,
      -JJ

      posted in General
      JJ Fullmer
      JJ Fullmer
    • RE: Powershell API Module

      New Module Version Published

      Just wanted to let people know that there’s a new version of the API yay!
      It’s been published to the psgallery here https://www.powershellgallery.com/packages/FogApi/1903.0.0.22 and it is awaiting a pull request to show up in the fog community scripts git.
      It has new functions to help do some common tasks, particularly with snapins. Here’s a list of the current functions.

      Add-FogSnapins
      Set-FogObject
      Get-FogAssociatedSnapins
      Get-FogGroup
      Get-FogHost
      Get-FogHosts
      Get-FogInventory
      Get-FogLog
      Get-FogObject
      Get-FogServerSettings
      Get-FogSnapins
      Install-FogService
      Invoke-FogApi
      New-FogObject
      Remove-FogObject
      Remove-UsbMac
      Set-FogInventory
      Set-FogServerSettings
      Set-FogSnapins
      Start-FogSnapins
      Update-FogObject
      
      posted in Tutorials
      JJ Fullmer
      JJ Fullmer
    • RE: Installation woes: dhcp...Failed!

      @kbramhall said:

      @Tom-Elliott I attempted to go through the installer and saying no to DHCP and DNS but if failed to install tftp-server this time. Attached is the foginstall.log file.0_1450298881023_foginstall.log

      I took a look at the install log and noticed this bit

      ../lib/redhat/functions.sh: line 1: n#: command not found
      

      I’ve seen that before. You need to both make sure that you’re running as the root user and make sure you’re running the install script from the bin folder.
      i.e. cd into where you downloaded/untarred the fog installer and then

      cd bin
      ./installfog.sh
      

      I figured out when making the automated update scripts that you can’t run it with the full path like
      /home/fog/installFoder/bin/installfog.sh
      because it use the trailing … to get to some included scripts. So you have to start the script from its happy home.

      Also, what happens when you try to install the packages that failed manually?
      I would try them one at a time. It looks like these ones…

      yum install tftp-server
      yum install xinetd
      yum install vsftpd
      yum install gcc
      yum install gcc-c++
      yum install lftp
      

      And I just had another thought, are you sure the firewall is completely disabled? I just remembered a recent experience where a fresh install cent OS wouldn’t do internet things until I flushed the iptables.
      Which if memory serves is

      iptables -F
      or
      iptables -f
      

      Hopefully something there helps

      posted in FOG Problems
      JJ Fullmer
      JJ Fullmer
    • Automating Git Updates for FOG

      In the past I made a script for automating svn updates. Since sourceforge has been making a habit of crashing lately, I decided to start using the git repo instead and adjusted my script to work with git.
      I figured others might benefit from it so why not share…

      #!/bin/bash
      clear
      # -------------------------------------------
      # Fog Git Updater
      # -------------------------------------------
      # -------------------------------------------
      # Script Purpose
      # -------------------------------------------
      # This script is designed to run an automated update of the latest FOG Git dev build and it's cron friendly
      # -------------------------------------------
      # -------------------------------------------
      # Some prereqs for this script
      # -------------------------------------------
      # 1. Already have an existing working install/configuration of FOG 1.0 or later
      #
      # 2. Have git installed and setup. You can do that by doing....
      # 	sudo apt-get install git
      #  	mkdir /home/fog/fogInstalls/git
      #	git clone https://github.com/FOGProject/fogproject.git /home/fog/fogInstalls/git
      #
      # 3. A script to echo the encrypted version of your sudo password, create one with this function
      #	just put in your password into the following in place of your_super_secret_password (leave the quotes)
      #	and then uncomment and copy paste the function into a terminal and then run it with just the name of the function pw
      	# pw(){
      	# 	touch /home/fog/fogInstalls/.~
      	# 	ossl=`echo "your_super_secret_password" | openssl enc -des -a -e -pass pass:PASSWORD`
      	# 	echo 'echo "$(echo '$ossl' | openssl enc -des -a -d -pass pass:PASSWORD)"' >> /home/fog/fogInstalls/.~
      	# 	sudo chown fog.root /home/fog/fogInstalls/.~
      	# 	sudo chmod 700 /home/fog/fogInstalls/.~ 
      	# }
      # -------------------------------------------
      # -------------------------------------------
      # Variables
      # -------------------------------------------
      # -------------------------------------------
      echo "Creating Script variables..."
      fogInstalls='/home/fog/fogInstalls'
      gitPath="$fogInstalls/git"
      backup="$fogInstalls/backups"
      pw=`sh $fogInstalls/.~` 
      # -------------------------------------------
      # -------------------------------------------
      # Functions
      # -------------------------------------------
      # -------------------------------------------
      perms(){
      	sudo chmod -R 775 $1
      	sudo chown -R fog.fog $1
      }
      
      srvUpdate(){
      	# Enter sudo mode aand do some quick server maintenance update fun times
      	# First, enter sudo mode by echoing the output of decrypting your encrypted password and pipe that into an apt-get update
      	#	Don't worry, it doesn't output the password into the terminal
      	#	Now that the password is in once the terminal will keep it stored for the next bunch of sudo commands
      	echo "Running Sever updates!..."
      	echo $pw | sudo -S apt-get update -y
      	sudo apt-get upgrade -y # install any upgrades you just downloaded
      }
      
      backupConfig(){
      	# Backup custom config and other files
      	# Copy the latest versions of any files you've changed that will be overwritten by the update and backup the database just in case.
      	# For example you may want to back up...
      	# Config.php
      	# 	To be on the safe side your config file in the /opt folder that has may have a corrected webroot for ubuntu 14.04 and may have stored encrypted credentials (i.e mysql)
      	# 		I think that the installer uses this file and keeps it anyway, but I like to be careful
      	# Exports file
      	#	Because this runs the installer with a yes pipe, it ends up telling it that the image path is "y",
      	# 		simply backing up and restoring your current one avoids the issue of fog not finding your precious images. 
      	# Custom pxe boot background
      	# 	If you have a custom background for the pxe menu, the bg.png file
      	# Mysql database dump
      	#	It would be rather troublesome if something went horribly wrong in the update and your database goes kaboom, it's unlikely but backups are a good thing 
      	# Just a note, It's a good policy to also have backups of these outside of your server, which you could add to this script with an scp command or something like that
      	# -------------------------------------------
      	echo "make sure backup dir exists..."
      	if [ ! -d $backup ]; then
      		mkdir $backup
      	fi
      	echo "Dumping the database..."
      	mysqldump -u root --all-databases --events > $backup/DatabaseBeforeLastUpdate.sql #backup database
      	echo "Backing up config and custom files..."
      	echo "config.php..."
      	sudo cp /opt/fog/service/etc/config.php $backup/config.php
      	echo "fog settings..."
      	sudo cp /opt/fog/.fogsettings $backup/.fogsettings
      	echo "nfs exports..."
      	sudo cp /etc/exports $backup/exports
      	echo "custom pxe background..."
      	sudo cp /var/www/html/fog/service/ipxe/bg.png $backup/bg.png 
      }
      
      gitP(){
              perms $gitPath
      	echo "git pull...."
      	cd $gitPath
      	git pull
      }
      
      updateFOG(){
      	echo "running FOG installer..."
      	cd $gitPath/bin
      	sudo bash installfog.sh -Y
      }
      
      restoreConfig(){
      	# Restore backed up files
      	# Restore the backed up files to their proper places and make sure they're formatted correct too.
      	echo "restoring custom pxe background..."
      	sudo cp $backup/bg.png /var/www/html/fog/service/ipxe # Restore Custom Background 
      	# I found that I needed to do this in some configurations, but it may no longer be neccesarry...
      	echo "Creating undionly for iPxe boot in ipxe folder, just in case..." 
      	sudo cp /tftpboot/undionly.kpxe /tftpboot/undionly.0 # backup original then rename undionly 
      	sudo cp /tftpboot/undionly.0 /var/www/html/fog/service/ipxe/undionly.0
      	sudo cp /var/www/html/fog/service/ipxe/undionly.0 /var/www/html/fog/service/ipxe/undionly.kpxe
      }
      
      fixPerms(){
      	echo "Changing Permissions of webroot..."
      	perms '/var/www/html/fog'
      	echo "Changing permissions of images...."
      	perms '/images'
      	echo "Changing permissions of tftpboot...."
      	perms '/tftpboot'
      }
      
      # -------------------------------------------
      # -------------------------------------------
      # Run the script
      # -------------------------------------------
      # -------------------------------------------
      srvUpdate
      backupConfig
      gitP
      updateFOG
      restoreConfig
      fixPerms
      echo "Done!"
      
      posted in General
      JJ Fullmer
      JJ Fullmer
    • RE: Active directory Join issue

      @anthonyglamis Fogcrypt is essentially obsolete, yes. You can still put the fogcrypt output into the legacy input but I find the new auto-encrypt to work better. But yes I’m pretty sure that the fogcrypt tool is still there

      I hadn’t noticed that the hashes were different before, so I checked mine and they are different. I haven’t had any problems though, so I would say it shouldn’t be an issue.

      posted in Windows Problems
      JJ Fullmer
      JJ Fullmer

    Latest posts made by JJ Fullmer

    • RE: Lenovo L13 yoga 'Maybe the usb cable is bad' error when trying to register

      @sebastian-roth Well yes I see that now. It just felt like a familiar problem from whenever I change kernels. Should have just restarted and tried again before assuming something was broken though.

      posted in Hardware Compatibility
      JJ Fullmer
      JJ Fullmer
    • RE: Lenovo L13 yoga 'Maybe the usb cable is bad' error when trying to register

      @george1421 Well, perhaps it was a one time glitch or updating the bios solves the issue.

      After surfaces image I have them install the latest driver pack that includes a bios update. After that happened and I tried to re-create the problem, the problem didn’t happen. I can share the video with all the log output if you still want it.

      posted in Hardware Compatibility
      JJ Fullmer
      JJ Fullmer
    • RE: Lenovo L13 yoga 'Maybe the usb cable is bad' error when trying to register

      @george1421 I will got my log level to 7 and scheduled it to do an inventory task, I’ll take a video and we’ll see if it does it again on this 5.10.12 kernel

      posted in Hardware Compatibility
      JJ Fullmer
      JJ Fullmer
    • RE: Lenovo L13 yoga 'Maybe the usb cable is bad' error when trying to register

      @george1421 well it got to

      bzImage....1%
      

      I actually had it sitting for a couple of hours. I just manually added the host in the gui and got it started imaging with the kernel you made here.
      I’ll put it back to the default kernel and see what I can do.

      posted in Hardware Compatibility
      JJ Fullmer
      JJ Fullmer
    • 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.

      posted in Windows Problems
      JJ Fullmer
      JJ Fullmer
    • RE: Lenovo L13 yoga 'Maybe the usb cable is bad' error when trying to register

      @george1421 @Tom-Elliott
      Just as an fyi related to this post. I just updated to the latest kernel from Tom (5.10.12 64bit) and it does not load up on a surface. Trying to get it just to go to the full inventory screen from the pxe menu it gets to 1% after about 15 minutes and just sits there. The kernel has been fine for all other machines just the surfaces have an issue (thus far in my testing anyway). Perhaps we can add whatever George did to the default kernel build to make sure surface’s stay supported?

      posted in Hardware Compatibility
      JJ Fullmer
      JJ Fullmer
    • 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"
      • 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 is fs#: where # is the disk/partition number seen by uefi 0-(number of partitions -1).
      You can then use ls and cd 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 run

      C:\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 the A: is saying to use A: as your path. This isn’t exposed to the gui file explorer, but you can then cd 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 with ln -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 named ipxe-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 folder g2bootmgr from the grub2win install folder at (assuming you mounted efi to A) A:\EFI\Grub2Win\g2bootmgr particularly you want to see the gnugrub.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
      $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.

      Hopefully that is helpful information. Probably more information than you ever wanted.

      posted in Windows Problems
      JJ Fullmer
      JJ Fullmer
    • RE: Move partitions on GPT layouts - need people to test

      @btoffolon Does this machine image fine with the original init?
      You can also try a different bzImage. I’m using 5.618RT3 made by @george1421 found here https://forums.fogproject.org/topic/15017/lenovo-l13-yoga-maybe-the-usb-cable-is-bad-error-when-trying-to-register/18?_=1610731427661

      I may have forgotten that I was using a different bzImage kernel when I started testing for this…

      posted in General
      JJ Fullmer
      JJ Fullmer
    • RE: How to delete images from FOG

      @sebastian-roth I will probably put this in https://docs.fogproject.org/en/latest/management/image-management.html# in a new subsection for deleting images.

      posted in FOG Problems
      JJ Fullmer
      JJ Fullmer
    • RE: Move partitions on GPT layouts - need people to test

      @sebastian-roth

      Windows 8.1

      Image captured and deployed with new init
      Did deploy test from larger 128 GB source VM and it had no problem deploying to 60 GB VM

      d1.partitions

      label: gpt
      label-id: 68156B04-B4FE-40EF-96CC-747C33F75E54
      device: /dev/nvme0n1
      unit: sectors
      first-lba: 34
      last-lba: 268435422
      sector-size: 512
      
      /dev/nvme0n1p1 : start=        2048, size=      614400, type=DE94BBA4-06D1-4D40-A16A-BFD50179D6AC, uuid=6D92B4A9-E0B4-4DED-8C4C-E271AA36B06F, name="Basic data partition", attrs="RequiredPartition GUID:63"
      /dev/nvme0n1p2 : start=      616448, size=      204800, type=C12A7328-F81F-11D2-BA4B-00A0C93EC93B, uuid=2410B705-A7CB-4CE5-A393-8B3919C909D1, name="EFI system partition", attrs="GUID:63"
      /dev/nvme0n1p3 : start=      821248, size=      262144, type=E3C9E316-0B5C-4DB8-817D-F92DF00215AE, uuid=58F556FE-7D3B-44EA-A846-C0848DB743CB, name="Microsoft reserved partition", attrs="GUID:63"
      /dev/nvme0n1p4 : start=     1083392, size=   267350016, type=EBD0A0A2-B9E5-4433-87C0-68B6B72699C7, uuid=364F4B4F-4D49-4955-A5EB-9CDE151EEBF7, name="Basic data partition"
      

      d1.minimum.partitions

      label: gpt
      label-id: 68156B04-B4FE-40EF-96CC-747C33F75E54
      device: /dev/nvme0n1
      unit: sectors
      first-lba: 34
      last-lba: 268435422
      sector-size: 512
      
      /dev/nvme0n1p1 : start=        2048, size=      614400, type=DE94BBA4-06D1-4D40-A16A-BFD50179D6AC, uuid=6D92B4A9-E0B4-4DED-8C4C-E271AA36B06F, name="Basic data partition", attrs="RequiredPartition GUID:63"
      /dev/nvme0n1p2 : start=      616448, size=      204800, type=C12A7328-F81F-11D2-BA4B-00A0C93EC93B, uuid=2410B705-A7CB-4CE5-A393-8B3919C909D1, name="EFI system partition", attrs="GUID:63"
      /dev/nvme0n1p3 : start=      821248, size=      262144, type=E3C9E316-0B5C-4DB8-817D-F92DF00215AE, uuid=58F556FE-7D3B-44EA-A846-C0848DB743CB, name="Microsoft reserved partition", attrs="GUID:63"
      /dev/nvme0n1p4 : start=     1083392, size=    17806622, type=EBD0A0A2-B9E5-4433-87C0-68B6B72699C7, uuid=364F4B4F-4D49-4955-A5EB-9CDE151EEBF7, name="Basic data partition"
      
      posted in General
      JJ Fullmer
      JJ Fullmer