Welcome to Rants and Raves!
I kept hearing that I needed to write, so here is the blog that I ended up starting.
It is mostly an accounting of my progression through creating a web site, nuances with code, and tips about what I did to make things work.
In there you will find sprinkled about some gems of life, and letting loose fun.
Enjoy!
Using PowerShell To Help Organize Music
2023-06-01
I had a bunch of music that I had collected over the years, transferred from computer to computer in hap-hazardous ways. Due to that the collection was a mess of folders and repeats with varying formats, bit rates, and naming conventions. I've tried a few times to organize and figure out the placement of a song, but it has been a daunting task with over 70,000 items to look through. One thing that has giving me trouble was trying to organize by artist. Don't get me wrong, that does seem to be the intuitive way to organize songs, but it actually creates an additional complication with so many songs being joint projects or part of some compilation. If, though, everything were organized by the albums instead it would provide a better initial way to make sure songs were in the right place, if all were present, and that they are all properly cleaned up. I figured the easiest way to do this was to go through each artist's folder and move everything in there into a single folder, so that all the album folders and individual songs were together regardless of artist. This was fairly easy to do by hand with some down, up, enter, ctrl+a, ctrl+x, alt+tab, ctrl+v, alt+tab, alt+up, delete, and repeat. I said some, I meant a lot. But it went rather quick, merged albums together, and if there was a conflict I just saved a copy of each to deal with later. With that done I now had everything grouped by album or individual songs. From here I was just going to sort the individual songs by album and move them into any albums they "belonged", however explorer.exe really didn't like to attempt to sort like that on 17,000 items. It stalled and never really seemed to get it done. I was not particularly thrilled with the idea of the extra work it would cause to go through that many songs if they weren't already sorted by album, so I looked into plan B (which should have been plan A), PowerShell. Windows knows how to access the metadata of songs to show and manipulate, so I looked to see if there was a way to access the metadata easily with PowerShell. The short answer, there's not a built in cmdlet to do so. Long answer short, it can be done. I found a page that gave me the base I needed here:
https://stackoverflow.com/questions/49214905/get-attributes-listed-in-the-details-tab-with-powershell
In there it references a blog post that creates a cmdlet to pretty much do exactly what I was hoping for, unfortunately it seems it was for Windows Vista and no longer works as is.
https://devblogs.microsoft.com/scripting/list-music-file-metadata-in-a-csv-and-open-in-excel-with-powershell/
Also, the original cmdlet that was referenced in the post is apparently gone, however it seems to be available on another site. The cmdlet that was made:
https://www.powershellgallery.com/packages/FC_SysAdmin/5.0.0/Content/public%5CGet-FileMetaData.ps1
It did not work for me as is, and I did not feel knowledgeable enough to want to troubleshoot and fix it. A good portion of that was due to one of posts in the original page having mentioned the issues with the blog's cmdlet and having provided their own updated version of a function.
https://stackoverflow.com/questions/49214905/get-attributes-listed-in-the-details-tab-with-powershell/#73527527
I am not exactly sure of the details, but I think they are turning the folder into an object, which will make the songs objects by inheritance, and accessing the metadata using '.getDetailsOf()'. They are just looping through all of the possible properties and writing them to the console, which isn't quite what I needed but close enough that I could manipulate it. One thing to note about '.getDetailsOf()' is that it takes 2 arguments, the first being the folder item you want the details of, the second being a integer representing the parameter you are interested in.
https://learn.microsoft.com/en-us/windows/win32/shell/folder-getdetailsof
That being said, you might need to do some work to figure out which integer you want to use. Luckily you can pass 'null' or '0' (or rather any non folder item) as the first argument and it will return the property name, which there are a lot of.
https://stackoverflow.com/questions/22382010/what-options-are-available-for-shell32-folder-getdetailsof
For me, I was just interested in the album info this time, which seems to be parameter 14.
I should note before going too far that this program made use of PowerShell 'param()' to pre-define the source file location, which I think can accept an array of locations and loop through them. I Added a destination parameter and had trouble with the syntax, even though I'm pretty sure I had it right the first time. Anyway, you should be able to separate parameters with commas, and assign a value to them in the param() declaration.
https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_functions_advanced_parameters?view=powershell-7.3
Once we pull the album name from the song it might need a little cleaning, as folders are limited in which characters they can have, while the album metadata does not seem to be.
https://stackoverflow.com/questions/1976007/what-characters-are-forbidden-in-windows-and-linux-directory-names
To start I removed or replaced those specific characters using the '.replace()' function.
https://shellgeek.com/powershell-replace-multiple-characters-in-string/
I had some songs that for some reason had a bunch of spaces as the album, and windows does not allow strictly whitespace as a folder name. This meant as part of my checks I needed to remove all of the spaces that would result in a blank album name. Since spaces are generally desired in names we couldn't simple replace all spaces with blanks. Instead, I opted to replace any double spaces with a single space, and since there were an unknown amount of spaces I thought it would be best to throw it inside a while() loop. For the condition I did a check to see if the album name contained double spaces using the '.contains()' function.
https://ss64.com/ps/contains.html
This gets us most of the way there, but it will still leave a single space as the album name. That's okay, since the album name is now going to be in a known state we will use it as a condition for one last check. The last check assigns a default album if the song did not provide something suitable for this rough pass. Basically, if the album is a single space or doesn't have any value, then use 'Unknown Album' as its album. I did need a little refresher on proper syntax for the if conditionals; I used the not operator (!), the or operator (-or), and the equals operator (-eq).
https://www.computerperformance.co.uk/powershell/if-and/
With a hopefully appropriately formatted album name we need to make sure it exists in the destination, because the Move-Item cmdlet won't create a destination folder. To check if something exists we use the Test-Path -Path cmdlet. However, our conditional doesn't really need to do anything if the folder exists, so we need to include the not (!) operator to the check. This is going to require your Test-Path cmdlet to be wrapped in parenthesis otherwise PowerShell throws a fit and assume that the ! belongs to some kind of other expression. You need it to check the path first by being in the parenthesis, and then PowerShell will understand to flip the Boolean using the ! operator.
https://devblogs.microsoft.com/powershell-community/determine-if-a-folder-exists/
If we don't find a folder then we need to make one using the Make-Item cmdlet, which is pretty straight forward. You provide a value for the -Path parameter, and an -ItemType of Directory.
https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.management/new-item?view=powershell-7.3
For this particular program I wanted to keep all of the songs and deal with culling duplicates later. Which means at this point I needed to check to see if the filename was already in use in an album folder, and adjust the name so that both files would be present. To start with I decided to split the name and extension of the song into individual parts so that I could append a copy count to the end of the name. Because of the variable nature of how the names could be made I decided to simply use the .substring() function and using the break point of .length-4. A fun tidbit about .substring() is that if don't specify the second ending parameter then it will return the complete end of the string past where you started.
https://adamtheautomator.com/powershell-substring/
I did find potentially useful functions that should do the same thing, but the don't seem to work in this context, .basename and .extension.
https://stackoverflow.com/questions/12503871/removing-path-and-extension-from-filename-in-powershell/#32634452
There is also -split.
https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_split?view=powershell-7.3
And Split-Path, although it seems you will need a later version of PowerShell, if not the latest, to be able to make use of the -LeafBase and -Extension parameters.
https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.management/split-path?view=powershell-7.3
You can check your version of PowerShell by checking the environment variable $PSVersionTable in PowerShell.
https://learn.microsoft.com/en-us/powershell/scripting/windows-powershell/install/installing-windows-powershell?view=powershell-7.3
I now initialized a counter, and ran a while loop. the condition of the while loop was a Test-Path of the filename in the destination. If that returned true, meaning the file already exists in the destination, then I would increase the counter, rewrite the destination name, and insert a string before the extension that indicated the copy number. The while loop would check the new destination name, and repeat as necessary.
https://www.pdq.com/blog/copy-individual-files-and-rename-duplicates/
With the destination filename figured out so I wouldn't be overwriting any existing files, I could finally actually move them with Move-Item. Because a number of the songs had some weird naming formats I did end up having the use the -LiteralPath parameter instead of the -Path parameter.
https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.management/move-item?view=powershell-7.3
Ultimately I had a .ps1 script that looked a bit like this:
param( $folder = "C:\source folder", $dest = "C:\destination folder" )
function funMetaData {
foreach($sFolder in $folder){
$objShell = New-Object -ComObject Shell.Application
$objFolder = $objShell.namespace($sFolder)
foreach ($strFileName in $objFolder.items()) {
$album = $objFolder.getDetailsOf($strFileName, 14)
$album = $album.replace('\','_').replace('/','_').replace('|','_').replace('?','_').replace('*','_').replace('"',"'").replace(':','_').replace('<','[').replace('>',']')
while($album.Contains(' ')) {
$album = $album.Replace(' ',' ')
}
if(!$album -or $album -eq ' ') {
$album = 'Unknown Album'
}
$destPath = "$dest\$album"
if(!(Test-Path -Path $destPath)) {
New-Item -Path $destPath -ItemType Directory
}
$name = $strFileName.name.substring(0,$strFileName.name.length-4)
$ext = $strFileName.name.substring($strFileName.name.length-4)
$src = "$sfolder\$name$ext"
$des = "$destPath\$name$ext"
$i=0
while(Test-Path $des) {
$i += 1
$des = "$destPath\$name - Copy $i$ext"
}
Write-Host $src
Write-Host $des
Move-Item -LiteralPath $src -Destination $des
Write-Host ""
}
}
}
funMetaData
With the 'for's and 'while's remember that you can use break to exit them before they would otherwise complete, great for troubleshooting and stopping when you want it.
https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_break?view=powershell-7.3
In this project I did run into some minor annoyances with folders that only contained pictures, or were completely empty. I found a really nice script to quickly eliminate any unwanted filetypes:
Get-ChildItem -Include *.ext -Recurse | Remove-Item -force
https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.management/remove-item?view=powershell-7.3#example-4-delete-files-in-subfolders-recursively
And another to properly check for and remove empty folders:
Get-ChildItem $tdc -Recurse -Force -Directory | Sort-Object -Property FullName -Descending | Where-Object { $($_ | Get-ChildItem -Force | Select-Object -First 1).Count -eq 0 } | Remove-Item -Verbose
https://stackoverflow.com/questions/28631419/how-to-recursively-remove-all-empty-folders-in-powershell/#54619752
I know it should go without saying but be cautious of code like this. Things like this do a lot really quickly and if the setup is wrong it could cause a lot of damage real fast. This processed 17,000 songs in a matter of a few of minutes. Be sure to test this out in a small replica of your data before releasing it on all of it. And be sure have a good idea of what it's trying to accomplish first.
Web-NFC MakeReadOnly() Freezing On Android
2023-05-19
Ran into an issue when trying to make an NFC tag read only, it locks up NFC related stuff on my phone. The web browser stop responding. The quick panel to try and toggle the NFC feature on my phone. The settings when going into the Connections section. NFC won't show in a settings search. Possibly more. This seems to happen if the 'makeReadOnly()' function in Web-NFC sees a tag. If it doesn't see a tag then things don't lock up and I can still use the scan and write buttons that I made. Even the abort controller doesn't seem to work with the 'makeReadOnly()' function either. So far my search results have not proven fruitful, it seems this has not been a problem that has stirred up any troubleshooting documenting. I might look a little bit more into proper 'makeReadOnly()' implementation, and the failing abort controller, before letting it sit for a while.
JavaScript Variables And Switches
2023-05-18
I was running into some issues testing out some new NFC code, which prompted the previous post. My initial issue was just a syntax mess up, using a ':' instead of a ';'. After that it was failing to define a new variable I had put in to concatenate the NFC records, 'var records;'. The issue that caused me more headache than it should have and led me down some extra learning of JavaScript was that I had placed the logic for my concatenation in the wrong spot in regards to my for loop and switch statement. What I initially had was:
for(){
var message = '';
switch () {
message += 'add to previous';
case '1':
...
Two big issues here, the message would get reset on each for loop which I didn't want, and things aren't suppose to happen before the cases of the switch statement. What I needed was this:
var message = '';
for(){
message += 'add to previous';
switch () {
case '1':
...
While figuring out my variable placement in a switch statement blunder I did run across some good resources about switches and variable scopes.
https://code-basics.com/languages/javascript/lessons/switch
https://stackoverflow.com/questions/40999025/javascript-scope-variable-to-switch-case
https://stackoverflow.com/questions/43669765/unexpected-identifier-with-switch-statement
Some of the things I learned while I was at it were things like including a new line in a string:
var foo = "Hello.\nHow are you?";
https://www.simplilearn.com/tutorials/javascript-tutorial/javascript-new-line#:~:text=The%20newline%20character%20is%20%5Cn,new%20line%20to%20a%20string.
How to include a variable in a string using the back-tick "`", not to be confused with the single quote "'":
var foo = `Include ${bar}`;
https://stackoverflow.com/questions/3304014/how-to-interpolate-variables-in-strings-in-javascript-without-concatenation
On a similar note, there are several ways to go about concatenating strings, like just adding them together:
var foo = "Include " + bar;
https://developer.mozilla.org/en-US/docs/Learn/JavaScript/First_steps/Strings#concatenating_strings
Also, appending strings. two basic ways there:
var foo = "one";
var foo = foo + " two";
var foo += " two";
https://stackoverflow.com/questions/1288095/append-to-string-variable
Android Chrome Dev Tools
2023-05-17
When testing NFC code it has to be on the phone, which is a bit problematic because there's no built in Developer Tools. For Chrome and Android there is a work around which requires a separate computer, not really a problem for me since that's where I do my coding anyway. First to setup the Android:
Enable Developer options:
Menu
About Phone
Software Information
Tap 'Build Number' 7 times
https://developer.android.com/studio/debug/dev-options.html
Enable USB debugging on Android:
Menu
Developer options
Enable 'USB debugging'
Connect phone and computer with USB cable
Accept permissions (whenever they show)
Open Chrome page to inspect
Setup on Chrome:
Open Chrome
Navigate to 'chrome://inspect/#devices'
Enable 'Discover USB devices'
Wait for phone to show up
Wait for phone tabs to populate/use 'Open tab with url' text box
Select 'inspect'
https://developer.chrome.com/docs/devtools/remote-debugging/
From there you get a new window that shows and allows you to interact with the page the phone is viewing, with the Chrome Development Tools at the ready. They did note that the dev tools will match the version of Chrome on the phone. Also note that the phone will also need to be open and on the web page that the computer has requested to use with the dev tools. This was my first time using it and it made identifying my trouble JavaScript code super easy.
Bitbucket SSH Disruption
2023-05-16
Bitbucket ran into an issue where it's SSH key was stolen. It was encrypted so there isn't an immediate threat, but they are adjusting their SSH keys to avoid a future threat.
https://bitbucket.org/blog/ssh-host-key-changes?utm_source=alert-email&utm_medium=email&utm_campaign=ssh-key-rotation_EML-15878&jobid=106067432&subid=1726726670
Luckily it seems that my local machine and Forge will automatically update with Bitbucket's new keys. This did seem like a good opportunity to make some notes on SSH with Bitbucket. Running through their documentation on checking the state of the keys they wanted you to run a command on the client that connects to Bitbucket (i.e. my computer):
ssh git@bitbucket.org host_key_info
When I tried that I received the following error:
git@bitbucket.org: Permission denied (publickey).
Later in the document they had another command to see what remotes a repository is using, SSH or HTTPS:
git remote -v
That came back in my project as HTTPS, so I don't really need to worry about this SSH issue. I did want to see about having SSH access anyway so I found another troubleshooting article.
https://confluence.atlassian.com/bbkb/permission-denied-publickey-302811860.html
I ran their more verbose connection command:
ssh -t -vvv git@bitbucket.org
And it came back with so many errors, some of which matched the "debug3: no such identity: <path_to_your_key>: No such file or directory" that they were looking for. This indicates that MY SSH key is not added to THEIR system. The document is a little outdated on where to go, for me it was:
Bitbucket ->
click the gear from the menu bar ->
click "Personal Bitbucket settings" ->
click "SSH keys" in the Security section ->
click "Add key" ->
give it an informative name ->
paste in your id_rsa.pub key, every part of it ->
click "Add key"
Now I was able to go back to my console window and run the command:
ssh git@bitbucket.org host_key_info
This time I received the expected response:
You are using host key with fingerprint:
ssh-rsa SHA256:*******************************************
WARNING: The host key your client is using will be removed in the near future.
Your client supports learning new host keys. Please run this command
again to see if your client has automatically moved to the new host keys.
If you continue to see this message please manually configure your client
to trust a new host key.
See https://bitbucket.org/blog/ssh-host-key-changes for more details.
I ran the command again and received the best response:
You are using host key with fingerprint:
ssh-rsa SHA256:*******************************************
See https://bitbucket.org/blog/ssh-host-key-changes for more details.
Now I have SSH setup between my computer and Bitbucket, and it is the appropriate SSH key to prevent disruptions in the immediate future.
NFC MACs From JavaScript To DB
2023-05-15
With the JS at the ready the rest needs setup. Starting with the DB a new field needs entered, as a basic implementation of Laravel migrations to update a table:
Schema::table('table', function (Blueprint $table) {
$table->string('column')->nullable();
});
https://laravel.com/docs/10.x/migrations
Since I am creating a new DB for each organization, I have a section in my controllers that will do some checks and clean up each of the replicated DBs. One of the things I found that isn't part of Laravel's normal migration documentation is a function that checks for a column in a table, and then performs a closure if the table does or doesn't exist (depending on which you choose). So you can end up with something like this:
Schema::whenTableDoesntHaveColumn('table', 'column', function (Blueprint $table) {
$table->string('column');
});
https://laravel.com/api/10.x/Illuminate/Database/Schema/
If you want to check for a column type you can if you have Doctrine/DBAL already installed:
DB::getSchemaBuilder()->getColumnType($tableName, $colName)
https://stackoverflow.com/questions/18562684/how-to-get-database-field-type-in-laravel
You might also want to consult the Doctrine/DBAL types list if you want to initiate a '->change()':
https://www.doctrine-project.org/projects/doctrine-dbal/en/current/reference/types.html#types
I did run into issues with placing the NFC data into my newly created form element. While they all probably work just fine, they won't if the element does contain an 'id' attribute.
<input id='nfc_id'>
Here are some ways to set the value of such an element:
element.setAttribute("class", "democlass");
https://www.w3schools.com/jsref/met_element_setattribute.asp
document.getElementById("nameofid").value = "My value";
https://stackoverflow.com/questions/7609130/set-the-default-value-of-an-input-field
I ended up using this one:
document.querySelector('#nfc_id').value = 'newContent';
The NFC scan button also had an issue where pressing it would also submit the form, which meant scanning was ineffective. I opted for the solution of defining the type as a button, instead of the default of submit:
<button id="id" type="button">Scan</button>
https://gomakethings.com/how-to-prevent-buttons-from-causing-a-form-to-submit-with-html/
I did try setting a blank 'formaction' attribute, but that was not successful.
https://stackoverflow.com/a/40484002
I have a status area and the scan button under the form element that they are for, with status first and then scan. I wanted the scan button to stay on the right side of the screen using Bootstrap's 'row' and 'col' classes, which I found two ways to potentially easily accomplish. If all of the elements under the 'row' are good with being to the sides and evenly spaced you can just add the 'justify-content-between' class to the 'row'. Otherwise, if that one 'col' needs to the far right regardless of the rest then add the 'ms-auto' class to that 'col'.
https://getbootstrap.com/docs/5.0/layout/columns/#horizontal-alignment
https://www.w3schools.com/bootstrap5/bootstrap_flex.php
Now we just need to get the data from the browser to the DB. This is easy enough with a simple addition to the 'store()' and 'update()' methods in the controller, something like:
$item->db_col = $request->input_name;
Before sending the data to the DB I decided to apply a Laravel mutator to the model to strip out anything that's not an appropriate hex character. This is because I am saving the MAC address of the NFCs rather than any other data on it, that way i can guarantee that the entry will most likely be unique and untampered with. Then it uppercases everything so that way the only thing saved to the DB is the hex characters:
public function setMacAddressAttribute($value)
{
$this->attributes['mac_address'] = Str::upper(preg_filter('/[^A-F0-9]/i', '',$value));
}
This is the Laravel 8 version of a mutator, with a rexeg filter that takes any character that is not ([^]) either a number (0-9) or a hex letter (A-F) while being case insensitive (i), and replaces them with nothing ('').
https://laravel.com/docs/8.x/eloquent-mutators
https://laravel.com/docs/10.x/helpers#method-str-upper
https://www.w3schools.com/php/func_regex_preg_filter.asp
https://www.w3schools.com/php/php_ref_regex.asp
https://stackoverflow.com/questions/13726429/regex-string-replace
Ruby Gloom
2023-05-12
10/10. Do recommend.
Web NFC Scan Ready
2023-05-11
Some basics for setting up a Web NFC reader.
https://w3c.github.io/web-nfc/
As mentioned before the feature is limited to secure browsing contexts, so you will need to have your site encrypted.
https://stackoverflow.com/questions/65271299/how-do-you-obtain-permissions-from-web-nfc-api
Also, likely due to general hardware configurations, the feature is generally only available in phone browsers.
https://developer.mozilla.org/en-US/docs/Web/API/NDEFReader#browser_compatibility
After that a good place to start is doing some checks to make sure NFC is capable and give some feedback about that. To start with most do a check to see if the browser is even capable of running Web-NFC:
"NDEFReader" in window
https://w3c.github.io/web-nfc/#feature-support
NFCs do potentially have read and write capabilities, however it seems that the checks/permissions for those individual capabilities are being wrapped as a single item, i.e. 'NDEFReader'
https://github.com/w3c/web-nfc/issues/434#issuecomment-556971265
I did try try to check for permissions using: const nfcPermissionStatus = await navigator.permissions.query({ name: "nfc" }); as https://developer.chrome.com/articles/nfc/#check-for-permission stated, however there seems to be an issue with 'await' and actually assigning the value to the constant. Instead I ended up using:
navigator.permissions.query({ name: "nfc" }).then((permissionStatus) => {});
https://developer.mozilla.org/en-US/docs/Web/API/PermissionStatus
From there it might be good to run through a switch case to determine the status so you can give better feedback:
switch(permissionStatus.state){}
https://www.w3.org/TR/permissions/#examples
If everything is good then go ahead and add the button event with a try and catch for error handling:
scanButton.addEventListener("click", async () => {
try{
} catch{
}
});
https://googlechrome.github.io/samples/web-nfc/
To prevent the scanner from continually scanning after the button event it is good to put in a timeout inside the event:
const ctrl = new AbortController();
await ndef.scan({ signal: ctrl.signal });
ctrl.signal.onabort = () => {};
setTimeout(() => ctrl.abort(), 3_000);
https://w3c.github.io/web-nfc/#scheduling-a-write-with-a-timeout
Also to help prevent multiple reads include the abort command after a read:
ctrl.abort();
https://developer.chrome.com/articles/nfc/#abort-nfc-operations
Ultimately you can use something similar to this:
<script>
if (!("NDEFReader" in window)){
//State handle
} else {
navigator.permissions.query({ name: "nfc" }).then((permissionStatus) => {
switch(permissionStatus.state){
case "granted":
//State handle
break;
case "prompt":
//State handle
break;
case "denied":
//State handle
break;
default:
//State handle
}
});
}
nfcScanButton.addEventListener("click", async () => {
try {
const ndef = new NDEFReader();
const ctrl = new AbortController();
await ndef.scan({ signal: ctrl.signal });
ndef.addEventListener("readingerror", () => {
//State handle
});
ndef.addEventListener("reading", ({ message }) => {
//State handle
ctrl.abort();
});
ctrl.signal.onabort = () => {
//State handle
};
setTimeout(() => ctrl.abort(), 3_000);
} catch (error) {
//State handle
}
});
</script>
Finch For Mental Health
2023-05-10
McKendra and I have been trying out this wellness app called Finch. It's sort of like the old Tamagotchi pets, but it rewards simple tasks with crystals to customize your finch's wardrobe and place. The tasks also give your finch energy to go adventuring and speed up its return, where it will tell you about the adventure. We have also added each other to our little trees and our finches can hang out together. The makers are using legit research to build the environment and help peoples' mental state. They understand that sometimes "Literally survive the day" is a worthy task to complete, and is an option to use. It has been helpful enough already that I think it's worth everyone giving it a go.
More Updates, More Breaking
2023-05-09
After a windows update something broke. Big surprise, right? My homestead machine kept erroring out about the network and not launching. One of the errors was this:
Stderr: VBoxManage.exe: error: A NAT rule of this name already exists
That one only seemed to pop up when I would clear the NAT network adapter in VirtualBox and Vagrant would need to reinstate it.
The biggest hang-up was this one:
Stderr: VBoxManage.exe: error: Failed to open/create the internal network 'HostInterfaceNetworking-VirtualBox Host-Only Ethernet Adapter' (VERR_INTNET_FLT_IF_NOT_FOUND).
Even after clearing the networks out of VirtualBox, and subsequently out of Windows, resetting all of the network adapter settings, uninstalling VirtualBox and Installing the next version, PC restarts, nothing seemed to work. After getting back to the closest point of being able to start Homestead I DISABLED/ENABLED the host only network adapter that was associated with homestead in Windows. Tada! Suddenly it works and Vagrant can launch Homestead. Not sure I how long it would have been before I would have tried that if it weren't for this thread:
https://forums.virtualbox.org/viewtopic.php?t=94277