• Recent
    • Unsolved
    • Tags
    • Popular
    • Users
    • Groups
    • Search
    • Register
    • Login
    1. Home
    2. JJ Fullmer
    3. Posts
    • Profile
    • Following 5
    • Followers 4
    • Topics 55
    • Posts 963
    • Groups 3

    Posts

    Recent Best Controversial
    • RE: Adapt MBR images to GPT

      @oscarvc https://learn.microsoft.com/en-us/windows-server/storage/disk-management/change-an-mbr-disk-into-a-gpt-disk
      This might help? Not sure you can convert the actual image files on fog without a recapture, that would be difficult if not impossible. But you could automate a conversion to gpt after imaging perhaps

      posted in General
      JJ FullmerJ
      JJ Fullmer
    • RE: How to use unattended script to complete oobe without loading a new image

      @rogerdodger wait, I just read this bit, not reimaging it makes it difficult. You still could use snapins and the fog client, but fully automating it would require reimaging.

      posted in General
      JJ FullmerJ
      JJ Fullmer
    • RE: How to use unattended script to complete oobe without loading a new image

      @rogerdodger If all your SD card is doing is running ppkg files, those can be applied with powershell in a snapin, in some instances you can embed such in the image but usually best to do it after, during we’ll provisioning.

      So you can probably make a simple snapin that uses powershell and the install-provisioningpackage command that references each ppkg file which you upload as the snapin file. There are some other ways you can go about it, it won’t work out of the box, but you can build a pretty robust automation solution with fog at the core.

      You could also embed the ppkgs or a script that downloads the most up to date version from an internal source and have it as part of a setupcomplete.cmd or synchronous commands in an unattend xml

      I’m on a phone at the moment, but if you want to go down this road I will gladly help you get started

      posted in General
      JJ FullmerJ
      JJ Fullmer
    • RE: fog install ubuntu problem

      @theyikes Why do you need to reset it to the original installation state repeatedly?
      How to do that is in the wiki here https://wiki.fogproject.org/wiki/index.php/Uninstall_FOG (that doc isn’t yet migrated to the new docs site)

      I’m not sure why you’re wanting to start the server side fresh though.

      The general idea is

      • Create Fog Server on a linux vm/machine that has enough storage for the OS images (not isos, captures of install states)
      • Setup a different VM with the OS as ‘golden image’ (With windows you need to utilize sysprep)
      • Register that VM as a host in FOG and capture the image.
      • Deploy the image to as many other hosts as you desire

      See also :

      https://docs.fogproject.org/en/latest/capture-an-image
      https://docs.fogproject.org/en/latest/deploy-an-image
      https://docs.fogproject.org/en/latest/intro

      posted in General Problems
      JJ FullmerJ
      JJ Fullmer
    • RE: Scheduled Tasks - New Image with Task/current-Date

      @Tom-Elliott @paranoid64
      Just to offer another use case for this, if I’m understanding it right. We currently maintain a ‘prev’ version of our image as a separate image.
      The idea being if something is wrong with the new ‘stable’ image we can quickly revert to using the ‘prev’ image and continue on.
      If when capturing it automatically kept the previous version, we wouldn’t need to manually do that. We don’t actually capture to the prev image, we just created the image definition and manually do a copy of the image on the server before capturing a new stable version.
      We typically align this with the windows YYH2 releases.

      We could probably do away with our prev image step if the stable image had an automatic history. I mean sure we have snapshot backups of our fog server too if we need it, but it’s always nice to have it at the file level for a quicker restore.

      I could see other users wanting that built-in backup copy. But even still I would make it an optional setting to turn on and off, not everyone will have the storage space for 2-3 versions of their image.

      posted in Feature Request
      JJ FullmerJ
      JJ Fullmer
    • RE: FOG Post Install, Sysprep, unattend file

      @HorizonG Short answer to both, yes.

      There’s a bit of work to do to make it work but you can.
      The first thing to know to help in full is what phase of sysprep you captured at?

      If you captured right after the generalize phase (best practice) and specialize is what starts you can indeed update the unattend file dynamically with computer name, domain, ou, etc.
      You can only effect the phases that haven’t happened yet. So you can add things to the specialize and oobe phases. Specialize does things before windows fully loads, it’s essentially a winpe environment, and oobe is the full windows where you can have a setupcomplete run. I have it kick off a series of powershell scripts (essentially).

      Windows also moves the unattend file around across the phases, when I update the unattend file in a post install script I just update it in all these places. i.e. in the context of fog having mounted 😄 at /ntfs
      "/ntfs/Windows/System32/Sysprep/Unattend.xml" "/ntfs/Windows/Panther/unattend.xml" "/ntfs/Windows/Panther/Unattend.xml"

      I also have one at C:\Unattend.xml you’ll see in my example below.

      Also note that it’s case sensitive, which is why I have 2 in the same spot as I’ve seen it both ways.

      I don’t have time to dig into too much detail right now but here’s an example of injecting some stuff into the unattend files. I also included my bit where I can just patch in an updated Unattend.xml file, though this wouldn’t scale for every host I just use it for another option before recapturing a whole image to test an unattend change.

      One very important bit for this to work as it does in the example is I have this bit in my specialize phase, which I replace with computername and AD info, replace NETBIOSDOMAINNAME with your short domain name that you use for this format logon string domain\username

      <component name="Microsoft-Windows-UnattendedJoin" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
                  <Identification>
                      <JoinWorkgroup>NETBIOSDOMAINNAME</JoinWorkgroup>
                  </Identification>
              </component>
      

      I also have <ComputerName></ComputerName> in the specialize phase under my "Microsoft-Windows-Shell-Setup" component i.e. the end of this has that. I took out my company info from this example, you don’t need all of this the same, just a contextual example. The product key is the GVLK for windows 10/11 publicly available.

      <component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
                  <DesktopOptimization>
                      <GoToDesktopOnSignIn>true</GoToDesktopOnSignIn>
                      <ShowWindowsStoreAppsOnTaskbar>true</ShowWindowsStoreAppsOnTaskbar>
                  </DesktopOptimization>
                  <BluetoothTaskbarIconEnabled>true</BluetoothTaskbarIconEnabled>
                  <ConvertibleSlateModePromptPreference>1</ConvertibleSlateModePromptPreference>
                  <CopyProfile>false</CopyProfile>
                  <DisableAutoDaylightTimeSet>false</DisableAutoDaylightTimeSet>
                  <EnableStartMenu>true</EnableStartMenu>
                  <OEMName>Company Name</OEMName>
                  <RegisteredOrganization>Company Name</RegisteredOrganization>
                  <ShowPowerButtonOnStartScreen>true</ShowPowerButtonOnStartScreen>
                  <RegisteredOwner>Company Name</RegisteredOwner>
                  <SignInMode>2</SignInMode>
                  <TimeZone>Mountain Standard Time</TimeZone>
                  <OEMInformation>
                      <SupportURL>http://helpme.company.tld</SupportURL>
                      <Logo>C:\img\company-logo.bmp</Logo>
                      <SupportPhone>555-5555</SupportPhone>
                      <SupportProvider>String that shows up in sys info</SupportProvider>
                      <Manufacturer>string that shows up in sys info</Manufacturer>
                  </OEMInformation>
                  <Themes>
                      <BrandIcon>C:\img\company-logo.png</BrandIcon>
                      <ThemeName>Company Theme</ThemeName>
                      <DesktopBackground>%WINDIR%\web\Wallpaper\some-injected-background.jpg</DesktopBackground>
                      <WindowColor>Automatic</WindowColor>
                      <DefaultThemesOff>false</DefaultThemesOff>
                  </Themes>
                  <DoNotCleanTaskBar>true</DoNotCleanTaskBar>
                  <AutoLogon>
                      <Password>
                          <Value>supersecretencryptedpassword</Value>
                          <PlainText>false</PlainText>
                      </Password>
                      <Enabled>true</Enabled>
                      <Username>Administrator</Username>
                      <LogonCount>99</LogonCount>
                  </AutoLogon>
                  <ProductKey>NPPR9-FWDCX-D2C8J-H872K-2YT43</ProductKey>
                  <ComputerName></ComputerName>
              </component>
      

      The fog post download examples. I also do something with the device form setting but I tried to just take that out for this example. Device form is mildly helpful for configuring the tablet vs desktop user experience if you have a mix of such devices.

      unattends=("/ntfs/Unattend.xml" "/ntfs/Windows/System32/Sysprep/Unattend.xml" "/ntfs/Windows/Panther/unattend.xml" "/ntfs/Windows/Panther/Unattend.xml")
      for unattend in ${unattends[@]}; do
          [[ ! -f $unattend ]] && break
          #as a failsafe, reload the funcs.sh from fog
          . /usr/share/fog/lib/funcs.sh
          dots "Preparing Sysprep File at $unattend"
          #update unattend files if an Unattend.xml file is present to replace current file
          if [[ -f "/images/drivers/Unattend.xml" ]]; then
              echo -en "\n\nUnattend.xml patch file detected, updating the Unattend.xml file baseline\n\n";
              echo -en "\n\nUnattend.xml patch file detected, updating the Unattend.xml file baseline\n\n" >> $updateUnattendLog
              rsync -aqzz "/images/drivers/Unattend.xml" $unattend;
          else
              echo -en "\n\nNo Unattend.xml patch file detected, skipping update of unattend.xml file baseline and just updating contents\n\n";
              echo -en "\n\nNo Unattend.xml patch file detected, skipping update of unattend.xml file baseline and just updating contents\n\n" >> $updateUnattendLog
          fi
          #echo "File update Done"
          debugPause
          if [[ $adon=="1" ]]; then 
          cp $unattend $unattend.old
          
                  domainJoinStr="<JoinDomain></JoinDomain>\n\t\t<MachineObjectOU></MachineObjectOU>\n\t\t<Credentials>\n\t\t\t<Domain></Domain>\n\t\t\t<Password></Password>\n\t\t\t<Username></Username>\n\t\t</Credentials>"
          
                  echo -en "\n\nInjecting Unattend Join fields into unattend for Dynamic update....\n"
          
                  echo -en "\n\nInjecting Unattend Join fields into unattend for Dynamic update....\n" >> $updateUnattendLog
          
                  # get the value of the workgroup to set as the netbios domain for the domain login
          
                  netbiosdomain=`sed -n '/JoinWorkgroup/{s/.*<JoinWorkgroup>//;s/<\/JoinWorkgroup.*//;p;}' $unattend`
          
                  #replace the workgroup join string with the domain tags to be updated
          
                  sed -i -e "s|<JoinWorkgroup>${netbiosdomain}</JoinWorkgroup>|${domainJoinStr}|g" $unattend >/dev/null 2>&1
          
          
          
                  echo -en "\n\nSetting Dynamic Unattend fields - \n\nComputer Name: ${hostname}\nJoining Domain: ${addomain}\nWill be in OU: ${adou}\n"
          
                  echo -en "\n\nSetting Dynamic Unattend fields - \n\nComputer Name: ${hostname}\nJoining Domain: ${addomain}\nWill be in OU: ${adou}\n" >> $updateUnattendLog
          
                  sed -i \
          
          
                      -e "s|<ComputerName></ComputerName>|<ComputerName>${hostname}</ComputerName>|g" \
          
                      -e "s|<Name>\*</Name>|<Name>${hostname}</Name>|g" \
          
                      -e "s|<Password></Password>|<Password>${adpass}</Password>|g" \
          
                      -e "s|<Username></Username>|<Username>${aduser}</Username>|g" \
          
                      -e "s|<Domain></Domain>|<Domain>${netbiosdomain}</Domain>|g" \
          
                      -e "s|<MachineObjectOU></MachineObjectOU>|<MachineObjectOU>${adou}</MachineObjectOU>|g" \
          
                      -e "s|<JoinDomain></JoinDomain>|<JoinDomain>${addomain}</JoinDomain>|g" $unattend >/dev/null 2>&1
          
                  if [[ ! $? -eq 0 ]]; then
          
                      echo -en "\n\nFailed to update user, pass, ou, and domain setter, set just computername and deviceform instead and using simplified unattend file\n"
          
                      echo -en "\n\nFailed to update user, pass, ou, and domain setter, set just computername and deviceform instead and using simplified unattend file\n" >> $updateUnattendLog
          
                      echo -en "\n\Restoring unattend file from before domain join attempt\n"
          
                      echo -en "\n\Restoring unattend file from before domain join attempt\n" >> $updateUnattendLog
          
                      mv $unattend.old $unattend -f
          
                      echo -en "\n\nSetting Dynamic Unattend fields - \n\nDeviceForm: ${DeviceForm}\nComputer Name: ${hostname}"
          
                      echo -en "\n\nSetting Dynamic Unattend fields - \n\nDeviceForm: ${DeviceForm}\nComputer Name: ${hostname}" >> $updateUnattendLog
                      debugPause
                      sed -i \
                          -e "s|<ComputerName></ComputerName>|<ComputerName>${hostname}</ComputerName>|g" \
          
                          -e "s|<Name>\*</Name>|<Name>${hostname}</Name>|g" $unattend >/dev/null 2>&1
          
                      if [[ ! $? -eq 0 ]]; then
          
                          echo -en "\nFailed again after using failsafe unattend\n"
          
                          echo -en "\nFailed again after using failsafe unattend\n" >> $updateUnattendLog
          
                          debugPause
          
                          handleError "Failed to update user, pass, ou, and domain setter and then failed the failsafe with no domain"
          
                      fi
          
                  else
          
                      echo -en "\n\nRemoving Workgroup join section and backup unattend as adding domain join was a success...\n"
          
                      echo -en "\n\nRemoving Workgroup join section and backup unattend as adding domain join was a success...\n" >> $updateUnattendLog
          
                      rm -f $unattend.old
          
                      sed -i "/<JoinWorkgroup>/d" $unattend >/dev/null 2>&1
          
                      sed -i "/<MachinePassword>/d" $unattend >/dev/null 2>&1
          
                      if [[ ! $? -eq 0 ]]; then
          
                          echo "Failed"
          
                          debugPause
          
                          handleError "Failed to remove the Workgroup setter"
          
                      fi
          
                  fi
                  echo -en "\n\nDone updating $unattend\n"
                  echo -en "\n\nDone updating $unattend\n" >> $updateUnattendLog
                  debugPause
              else
                  echo -en "\n\nNo domain to join variable present, just setting deviceform and computer name and using simplified unattend file\n"
                  echo -en "\n\nNo domain to join variable present, just setting deviceform and computer name and using simplified unattend file\n" >> $updateUnattendLog
                  echo -en "\n\nSetting Dynamic Unattend fields - \n\nDeviceForm: ${DeviceForm}\nComputer Name: ${hostname}"
                  echo -en "\n\nSetting Dynamic Unattend fields - \n\nDeviceForm: ${DeviceForm}\nComputer Name: ${hostname}" >> $updateUnattendLog
                  debugPause
                  sed -i \
                      -e "s|<ComputerName></ComputerName>|<ComputerName>${hostname}</ComputerName>|g" \
                      -e "s|<Name>\*</Name>|<Name>${hostname}</Name>|g" $unattend >/dev/null 2>&1
                  if [[ ! $? -eq 0 ]]; then
                      echo "Failed"
                      debugPause
                      handleError "Failed to set workgroup join fields"
                  fi        
              fi
          done
      posted in General
      JJ FullmerJ
      JJ Fullmer
    • RE: 1.6.0-alpha.1377 not showing available images on host

      @Tom-Elliott @sideone @MatMurdock
      I can confirm this is fixed in the latest 🙂

      posted in Bug Reports
      JJ FullmerJ
      JJ Fullmer
    • RE: 1.6.0-alpha.1377 not showing available images on host

      @sideone @MatMurdock @Tom-Elliott
      I just tested this and I’m getting the same thing too. This was working previously, we’ll work it out.

      posted in Bug Reports
      JJ FullmerJ
      JJ Fullmer
    • RE: 1.6.0-alpha.1377 not showing available images on host

      @MatMurdock

      First I would ask you to check the php error log
      cat /var/log/php-fpm/www-error.log
      And post any relevant errors or warnings occurring at the same time this happens.

      Then 2 things I would try

      I’d start with trying ipxe.efi instead of snponly.efi. I don’t remember if the kernel is loaded at that point so a different pxe boot file could help.

      The other thing to do is update the kernel and Init to the latest “experimental” versions. There’s a wizard to do it in the gui for both under the configuration menu. Then give it another go.

      posted in Bug Reports
      JJ FullmerJ
      JJ Fullmer
    • RE: Restrict access to web management UI?

      @fogcloud Pxe boot has to get to the boot.php file. It does this over port 80 or 443 if you have https enforced. When you enforce https ipxe is compiled with the fog ca and the certificate generated by said ca as trusted certs within your local version of ipxe.
      I’m not quite sure what you mean by restricting access only to the web UI. Do you mean close all other ports? Because that will likely break tftp and nfs as they use other ports and imaging and pxe boot will be broken. ipxe itself will be fine if you’ve booted to it outside of native pxe boot where the ipxe boot file (i.e. ipxe.efi or snponly.efi) is downloaded via tftp. ipxe then downloads the boot.php file from the fog web server and boots to it to get to the fog pxe menu.

      posted in General Problems
      JJ FullmerJ
      JJ Fullmer
    • RE: Group Management Settings not saving

      @MatMurdock You can also do a full host registration and that allows you to set the group and the snapin associations at registration and kick off the image from there.

      I use the API powershell module (see my signature) and have created custom functions and powershell tools to manage most my assignments. That takes a bit more work to get setup at scale but gives you more customization options.

      Starting fresh, well depends on how fresh, the best answer depends on how you’re going to use Fog. Like if these are all brand new computers that aren’t in any other system yet, then doing quick reg on them all might be best.
      I myself do full registration and inventory for new hosts. If all your computers already exist on the network or in Active Directory you could get the host information and import. Many moons ago I made this host scanner example https://forums.fogproject.org/topic/9560/creating-a-csv-host-import-from-a-network-scan?_=1721413305258 that will create a csv of all hosts and their macs on your network in the provided subnets.
      If you can get them all in before hand, then mass-setting the snapins would be much easier.

      posted in FOG Problems
      JJ FullmerJ
      JJ Fullmer
    • RE: Group Management Settings not saving

      @MatMurdock A newly imaged machine will automatically deploy any assigned snapins.

      The design is flexible and you can do it in many different ways but here’s a general example that would utilize a group.

      • You have a group named ‘Group A’ with computers you want to image with the same image and join the domain in the same ou and have them use the same bunch of snapins
      • You assign the image via group management, they all now have the same image
      • You assign the AD information, they all now have the same AD info
      • You assign some snapins, they all now have those snapins assigned (in addition to anything else those hosts already have assigned, you could also do a group remove of all snapins first if desired)
      • You push the task to deploy or multicast deploy on the group
      • All the machines in that group now have a deploy task for the image and a deploy task for the snapins associated
      posted in FOG Problems
      JJ FullmerJ
      JJ Fullmer
    • RE: Fog Client replaced powershell script with "Please update your FOG Client, this is old and insecure"

      @MatMurdock That is correct.
      If git pull gives you trouble (sometimes happens on upgrades) then do this within your git folder (i.e. /root/fogproject)

      git fetch --all
      git checkout working-1.6
      git reset --hard origin/working-1.6
      git pull
      

      Then the cd bin and installfog.sh are good.

      Also lols to CrowdStrike

      posted in Windows Problems
      JJ FullmerJ
      JJ Fullmer
    • RE: Fog Client replaced powershell script with "Please update your FOG Client, this is old and insecure"

      @sideone https://forums.fogproject.org/topic/17575/snapins-not-downloading-to-client-hash-check-error just linking to your other post.

      posted in Windows Problems
      JJ FullmerJ
      JJ Fullmer
    • RE: Group Management Settings not saving

      @MatMurdock Are you using the persistent groups plugin? When you set something in group management I believe it doesn’t save persistently unless you’re using that plugin. The idea is that you’re setting that settings on all hosts in that group the one time. I might be remembering that wrong, but that’s what I recall.

      posted in FOG Problems
      JJ FullmerJ
      JJ Fullmer
    • RE: NVMe PCIe : BSOD after imaging "INACCESSIBLE_BOOT_DEVICE"

      @nathan67 That sounds like the image doesn’t have the nvme driver.
      There’s a potential easy solution, first check the bios settings on the nvme machine, if there are settings for intel VMD or intel optane make sure those are off. They require a different storage driver that isn’t including by default in windows.

      You could also try recapturing the image from the nvme based machine

      The more complicated solution involves recapturing the image and ensuring you use sysprep and add a set of basic storage drivers that don’t get wiped so they’re embedded and at the ready for multiple use cases. If the other options don’t work I can find some time to help with that. If it requires the intel vmd driver though, I’ve had experiences where that driver makes older non-vmd intel chipsets fail to boot. So I eventually gave up on having VMD enabled, it’s a pretty sweet feature and can add some performance, but not enough to matter for the operational complexity within a controlled and mixed business environment (at least that’s what I went with for me).

      posted in Windows Problems
      JJ FullmerJ
      JJ Fullmer
    • RE: My drivers can't install

      @IT-MAN
      Where are you capturing your image and are you using sysprep to generalize the image without any drivers?

      The only way for driver injection to work on the windows side automatically is to use sysprep via an unattend.xml. Well I guess technically setupcomplete.cmd may run after setup without it according to https://learn.microsoft.com/en-us/windows-hardware/manufacture/desktop/add-a-custom-script-to-windows-setup?view=windows-11 but utilize sysprep and an unattend.xml is far more robust.

      It is possible to inject just the driver files into the disk in a post download script but without sysprep to kick it off, you can run into issues.

      This requires capturing your image with sysprep and an unattend.xml. One thing you can do with unattend.xml is remove the drivers from the image so that conflicting drivers don’t exist, then you can add the pnputil portion in the specialize phase of sysprep.

      This post is what I used and I added some of what I’ve done on top of it that may be of help.

      https://forums.fogproject.org/topic/8889/fog-post-install-script-for-win-driver-injection
      Also this one
      https://forums.fogproject.org/topic/7740/the-magical-mystical-fog-post-download-script

      At a high level, driver injection being dynamic per model has some assumptions

      • You captured an image that doesn’t have model specific drivers (this is easiest when capturing from a VM and using sysprep)
      • You have drivers organized within your /images nfs share
      • You have a postdownload script that detects the model, finds the drivers, mounts the windows disk, and then injects them into a known path
      • You have a method to kick off a script that installs the drivers into windows
        • For example, I have a synchronouscommand in my specialize phase of my unattend that runs pnputil against the injected path, so drivers are loaded as early as possible in the process
      posted in FOG Problems
      JJ FullmerJ
      JJ Fullmer
    • RE: Management images problem

      @alexpolytech94 I’m still a bit confused. So have you had working images with fog in the past and they suddenly stopped working?

      posted in FOG Problems
      JJ FullmerJ
      JJ Fullmer
    • RE: Host not registered" appears again and again

      @paranoid64 Technically the menu is just ipxe, but when capturing or deploying images, getting hardware inventory, stuff like that you’re booting into fos which is in the kernel and init.
      You can manually make a backup of the old kernel and init that can be just as easily restored. I believe in working-1.6 this happens automatically but to be safe you can just run this on your fog server linux terminal

      sudo mv /var/www/html/fog/service/ipxe/bzImage /var/www/html/fog/service/ipxe/bzImage.old
      sudo mv /var/www/html/fog/service/ipxe/init.xz /var/www/html/fog/service/ipxe/init.xz.old
      

      To revert you can simply reverse those like this

      sudo mv -f /var/www/html/fog/service/ipxe/bzImage.old /var/www/html/fog/service/ipxe/bzImage
      sudo mv -f /var/www/html/fog/service/ipxe/init.xz.old /var/www/html/fog/service/ipxe/init.xz
      

      You can also name the new kernels different and specify a different kernel per host, but since this is happening before registration is recognized, it’ll be better to update globally to test it out. I am currently using the ‘experimental’ kernels in production with 0 issues.

      Another thing to look at is some log files.
      See if you have anything helpful in /var/log/php-fpm/www-error.log and post it here

      posted in FOG Problems
      JJ FullmerJ
      JJ Fullmer
    • RE: HP Z8 Fury G5 Workstation Desktop PXE boot

      @alessandro19884 Is that working-1.6? I would update your fog server, that error should be fixed in the latest version.

      posted in FOG Problems
      JJ FullmerJ
      JJ Fullmer
    • 1 / 1