Script to Fix For Folders Not Refreshing on older NAS drives (SMBv1)


BLzNFuN

Active member
Local time
8:00 PM
Posts
20
OS
Windows 11 Pro x3
Hey all,

I have an older NAS drive and with Windows 11 changes to SMB and configurations, you're most likely frustrated like me. One of the more frustrating things was when you loaded folders on an older NAS drive, the contents would show empty unless you manually refreshed them.

Well with the help of ChatGPT and Gemini, I created this script that does all the work for you so you don't have to search for the solution. Keep in mind, Windows implemented the changes that cause the above issues because they are less secure. So keep in mind when you run this script, it defeats the protections put in place by Windows. But if you know what you are doing or are aware of your internet surroundings, you should be fine.

The script will also do a few more things for you like let you add devices to the "Trusted Intranet Zone" so when you try to run executible files, it won't prompt you with security warnings about "This might not be safe". All you need to know is the device's IP address or Domain/NetBIOS name.

The script will also help you enable SMBv1 (as a last resort if you device is still causing you issues) but keep in mind enabling SMBv1 is an extreme risk and should not be enabled without knowing the risks.

I recommend Notepad++ to copy and paste the following code into a blank text document for each section of code.
Step 1- Create a new folder on your desktop (or where ever you want it) to store your files your going to create.

Step 2 - Inside the new folder you just created, right click and create a new text document using Notepad++. Open the new text file and copy the batch code to blank Notepad++, then click File > Save As and name it what you want and select the dropdown file type, "Batch". Now click "Save".

Step 3 - Inside the new folder you just created, right click and create another new text document using Notepad++. Open the new text file and copy powershell script code to the blank Notepad++, then click File > Save As and name it NAS_SMB_Settings. Click the dropdown file type to save it as a Windows Powershell File. Now click save. You can rename this file to anything you want as well, but then you'll have to update the batch file code to reflect what you called the powershell file.

You should now have four files in the new folder. One is a batch file, one is a powerscript file and the other two were the blank notepad++ files you used to get started. You can safely delete the two Notepad++ text files so you only have the batch file and the powershell script file.

Now run the batch file. It will load the Powershell script elevated so it can control the SMB functions and settings. Upon first run, it will automatically create a "log" folder inside the folder you created. This logs all actions by the script so you should be able to see exactly what the script did.

Once you have this folder with your files on, you can move the folder where ever you want (like a USB Flash Drive) so you can do this on all your PCs and devices that are having issues on your home network or over VPN.

I hope this helps!

Below you'll find the batch file (which elevates the script so you don't have elevate your global script policy) and the script to get you up and running again with your devices.

Batch:
@echo off
:: -----------------------------
:: Launch NAS_SMB_Settings.ps1 with admin rights
:: -----------------------------
set ScriptDir=%~dp0
powershell -NoProfile -ExecutionPolicy Bypass -Command "Start-Process powershell -ArgumentList '-NoProfile -ExecutionPolicy Bypass -File \"%ScriptDir%NAS_SMB_Settings.ps1\"' -Verb RunAs"
exit

Powershell:
# ====================================================
# NAS / SMB Configuration Script - Portable
# Console Tracking
# Created using ChatGPT & Gemini by Jeremy / BLzNFuN
# [email protected]
# ====================================================

# Force all errors to be terminating to ensure they are caught
$ErrorActionPreference = "Stop"

# --- Global Variables ---
# This file is used to persist the reboot state across script sessions.
$RebootTrackerFile = Join-Path (Join-Path $PSScriptRoot "log") "reboot_required.txt"
$LastPCFile = Join-Path (Join-Path $PSScriptRoot "log") "last_run_pc.txt"

# --- Functions ---

function Write-Log { param([string]$Message)
    $timestamp = Get-Date -Format "yyyy-MM-dd hh:mm:ss tt"
    $computerName = $env:COMPUTERNAME
    "[INFO] $timestamp [$computerName] - $Message" | Out-File -FilePath $LogFile -Append -Encoding UTF8
}

function Show-Message { param([string]$Message,[ValidateSet("Info","Warning","Error","Success")][string]$Type="Info")
    switch ($Type) {
        "Info"    { Write-Host $Message -ForegroundColor White -BackgroundColor Blue }
        "Warning" { Write-Host $Message -ForegroundColor Yellow -BackgroundColor Blue }
        "Error"   { Write-Host $Message -ForegroundColor Red -BackgroundColor Blue }
        "Success" { Write-Host $Message -ForegroundColor Green -BackgroundColor Blue }
    }
}

function Get-IntranetRegPaths {
    # We will always use the HKCU drive as it is the most reliable.
    # When run as an administrator, it points to the administrator's registry hive.
    $paths = @{
        Domains = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMap\Domains"
        Ranges = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMap\Ranges"
    }
    return $paths
}

# --- Local Intranet Functions ---
function Get-AllIntranetEntries {
    $entries = @()
    $regPaths = Get-IntranetRegPaths
    try {
        # Check for existence of the Domains key before trying to get child items
        if (Test-Path $regPaths.Domains) {
            $domainKeys = Get-ChildItem -Path $regPaths.Domains -ErrorAction SilentlyContinue
            foreach ($key in $domainKeys) {
                # Use PSChildName to get just the domain name, not the full path
                $entries += $key.PSChildName.ToLower()
            }
        }
       
        # Check for existence of the Ranges key before trying to get child items
        if (Test-Path $regPaths.Ranges) {
            $rangeKeys = Get-ChildItem -Path $regPaths.Ranges -ErrorAction SilentlyContinue
            foreach ($key in $rangeKeys) {
                try {
                    $props = Get-ItemProperty -Path $key.PSPath -ErrorAction Stop
                    # Check for the correct ":Range" key first
                    if ($props.PSObject.Properties.Name -contains ":Range") {
                        $entries += ([string]$props.":Range").Trim().ToLower()
                    }
                    # Also check for the old "URL" key for backward compatibility
                    elseif ($props.PSObject.Properties.Name -contains "URL") {
                        $entries += ([string]$props.URL).Trim().ToLower()
                    }
                } catch {
                    Write-Log "ERROR: Failed to retrieve range entry from $($key.PSPath). $($_.Exception.Message)"
                }
            }
        }
    } catch {
        Write-Log "ERROR: Failed to retrieve all intranet entries. $($_.Exception.Message)"
    }
    return $entries
}

function Validate-NASDevice { param([string]$Device)
    # Check for IP address format. If it matches, it's a valid IP.
    if ($Device -match "^\d{1,3}(\.\d{1,3}){3}$") {
        return $true
    }
    # Check for hostname format. This now excludes pure numerical strings.
    elseif ($Device -notmatch "^[\d.]+$" -and $Device -match "^[A-Za-z0-9\-_.]+$") {
        return $true
    }
    else {
        Show-Message "Invalid Local Intranet entry format: $Device" "Error"
        return $false
    }
}

function Add-LocalIntranetEntry { param([string]$device)
    try {
        $normalizedDevice = $device.Trim().ToLower()
       
        # Check if entry already exists in either location
        $existingEntries = Get-AllIntranetEntries
        if ($existingEntries -contains $normalizedDevice) {
            Show-Message "$device already exists." "Info"
            return
        }
        $regPaths = Get-IntranetRegPaths

        if ($normalizedDevice -match "^\d{1,3}(\.\d{1,3}){3}$") { # IP Address
            $regPath = $regPaths.Ranges

            # Find the highest existing Range number and add one
            $nextRangeNumber = 0
            $existingRanges = Get-ChildItem -Path $regPath -ErrorAction SilentlyContinue | Where-Object { $_.PSChildName -match '^Range\d+$' }
            if ($existingRanges) {
                $numbers = $existingRanges | ForEach-Object { [int]($_.PSChildName -replace '^Range') }
                $nextRangeNumber = ($numbers | Measure-Object -Maximum).Maximum + 1
            }

            $rangeKey = Join-Path -Path $regPath -ChildPath "Range$nextRangeNumber"
           
            if (-not (Test-Path $rangeKey)) { New-Item -Path $rangeKey -Force | Out-Null }
            # Use the correct ":Range" property name as per Windows GUI.
            New-ItemProperty -Path $rangeKey -Name ":Range" -Value $device -Force | Out-Null
            # Add the "*" dword value with data 1 to match the GUI behavior.
            New-ItemProperty -Path $rangeKey -Name "*" -Value 1 -Type DWORD -Force | Out-Null
        } else { # Domain Name
            $regPath = $regPaths.Domains
            $domainKey = Join-Path -Path $regPath -ChildPath $normalizedDevice
            # Simply creating the key is sufficient.
            if (-not (Test-Path $domainKey)) { New-Item -Path $domainKey -Force | Out-Null }
            # Add the "*" dword value with data 1 to match the GUI behavior.
            New-ItemProperty -Path $domainKey -Name "*" -Value 1 -Type DWORD -Force | Out-Null
        }
       
        Write-Log "Local Intranet entry added: $device"
        Show-Message "$device successfully added." "Success"
    } catch {
        Show-Message "Failed to add $device. Check log for details." "Error"
        Write-Log "ERROR: Failed to add $device - $($_.Exception.Message)"
    }
}

function Remove-LocalIntranetEntry { param([string]$device)
    $found = $false
    $normalizedDevice = $device.Trim().ToLower()
    $regPaths = Get-IntranetRegPaths
   
    try {
        # Check Domains
        if ($normalizedDevice -notmatch "^\d{1,3}(\.\d{1,3}){3}$") {
            $domainPath = Join-Path -Path $regPaths.Domains -ChildPath $normalizedDevice
            if (Test-Path $domainPath) {
                Remove-Item -Path $domainPath -Recurse -Force -ErrorAction Stop
                $found = $true
                Show-Message "$device successfully removed." "Success"
                Write-Log "Removed Local Intranet entry: $device"
            }
        }
       
        # Check Ranges
        $rangeKeys = Get-ChildItem -Path $regPaths.Ranges -ErrorAction SilentlyContinue
        foreach ($key in $rangeKeys) {
            try {
                $props = Get-ItemProperty -Path $key.PSPath -ErrorAction Stop
                # Check for the correct ":Range" property first
                if ($props.PSObject.Properties.Name -contains ":Range" -and $props.":Range".Trim().ToLower() -eq $normalizedDevice) {
                    Remove-Item -Path $key.PSPath -Recurse -Force -ErrorAction Stop
                    $found = $true
                    Show-Message "$device successfully removed." "Success"
                    Write-Log "Removed Local Intranet entry: $device"
                }
                # Also check for the old "URL" property for backward compatibility
                elseif ($props.PSObject.Properties.Name -contains "URL" -and $props.URL.Trim().ToLower() -eq $normalizedDevice) {
                    Remove-Item -Path $key.PSPath -Recurse -Force -ErrorAction Stop
                    $found = $true
                    Show-Message "$device successfully removed." "Success"
                    Write-Log "Removed Local Intranet entry: $device"
                }
            } catch {
                Write-Log "ERROR: Failed to remove entry - $($_.Exception.Message)"
            }
        }
       
        if (-not $found) { Show-Message "$device not found." "Error" }
    } catch {
        Write-Log "ERROR: Failed to remove intranet entries - $($_.Exception.Message)"
    }
}

function Remove-AllIntranetEntries {
    Clear-Host
    Show-Message "--- Remove ALL Trusted Local Intranet Devices From This PC ---" "Info"
    Write-Host ""
   
    $currentEntries = Get-AllIntranetEntries
   
    Show-Message "The following devices will be removed:" "Info"
    Write-Host ""
    if ($currentEntries.Count -gt 0) {
        foreach ($d in $currentEntries) { Show-Message "  - $d" "Warning" }
    } else {
        Show-Message "  No trusted devices found." "Info"
        Read-Host "`nPress Enter to return to main menu..." | Out-Null
        return
    }
   
    Write-Host ""
    $confirm = Read-Host "Are you sure you want to remove ALL listed devices? This includes devices added from other sources. (Y/N)"
    if ($confirm -match "^[Yy]$") {
        try {
            $regPaths = Get-IntranetRegPaths

            if (Test-Path $regPaths.Domains) {
                Remove-Item -Path $regPaths.Domains -Recurse -Force -ErrorAction Stop
                Show-Message "All Domain/NetBIOS devices successfully removed." "Success"
                Write-Log "All domain entries removed from Local Intranet."
            } else {
                Show-Message "No domain entries to remove." "Info"
            }

            if (Test-Path $regPaths.Ranges) {
                Remove-Item -Path $regPaths.Ranges -Recurse -Force -ErrorAction Stop
                Show-Message "All IP Devices successfully removed." "Success"
                Write-Log "All IP range entries removed from Local Intranet."
            } else {
                Show-Message "No IP range entries to remove." "Info"
            }

        } catch {
            Show-Message "An error occurred while removing devices. Check log for details." "Error"
            Write-Log "ERROR: Failed to remove all intranet entries - $($_.Exception.Message)"
        }
    } else {
        Show-Message "No devices were removed." "Info"
    }
   
    Read-Host "`nPress Enter to return to main menu..." | Out-Null
}

# --- Menu Functions ---
function Show-CurrentStatus {
    Clear-Host
    Show-Message "--- Current Status ---" "Info"
    Write-Host ""
    try {
        $smbConfig = Get-SmbClientConfiguration
        $smb1Status = Get-WindowsOptionalFeature -Online -FeatureName SMB1Protocol
        # Use string formatting for justified output
        Show-Message ("{0,-28}: {1}" -f "RequireSecuritySignature", $smbConfig.RequireSecuritySignature) "Info"
        if ($smbConfig.RequireSecuritySignature -eq $false) { Show-Message "(DISABLED - Low security!)" "Warning" }
        Show-Message ("{0,-28}: {1}" -f "EnableInsecureGuestLogons", $smbConfig.EnableInsecureGuestLogons) "Info"
        if ($smbConfig.EnableInsecureGuestLogons -eq $true) { Show-Message "(ENABLED - Insecure!)" "Warning" }
        Show-Message ("{0,-28}: {1}" -f "SMBv1 Status", $smb1Status.State) "Info"
        if ($smb1Status.State -eq 'Enabled') { Show-Message "(ENABLED - Insecure!)" "Warning" }

    } catch { Show-Message "SMB config not accessible or requires admin." "Warning" }
   
    $allIntranetEntries = Get-AllIntranetEntries
   
    Show-Message "`nTrusted Local Intranet Devices:" "Info"
    Write-Host ""
    if ($allIntranetEntries.Count -gt 0) {
        foreach ($d in $allIntranetEntries) { Show-Message "  - $d" "Success" }
    } else {
        Show-Message "  No trusted devices found." "Info"
    }
   
    Write-Host "`nPress any key to return to menu..."
    $null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
}

function Configure-Option2 {
    Clear-Host
    Show-Message "--- Current SMB Status ---" "Info"
    Write-Host ""
    try {
        $smbConfig = Get-SmbClientConfiguration
        # Use string formatting for justified output
        Show-Message ("{0,-28}: {1}" -f "RequireSecuritySignature", $smbConfig.RequireSecuritySignature) "Info"
        if ($smbConfig.RequireSecuritySignature -eq $false) { Show-Message "(DISABLED - Low security!)" "Warning" }
        Show-Message ("{0,-28}: {1}" -f "EnableInsecureGuestLogons", $smbConfig.EnableInsecureGuestLogons) "Info"
        if ($smbConfig.EnableInsecureGuestLogons -eq $true) { Show-Message "(ENABLED - Insecure!)" "Warning" }
    } catch { Show-Message "SMB config not accessible or requires admin." "Warning" }
    Write-Host "`n-------------------------------------`n"
    Show-Message "--- SMB Configuration Options ---" "Info"
    Write-Host ""
    Show-Message "1) Apply Less Secure Settings" "Info"
    Write-Host
    Show-Message "    - WARNING: This will make SMB less secure!" "Warning"
    Show-Message "    - ENABLE guest logins (may allow unauthenticated access to shares)" "Warning"
    Show-Message "    - DISABLE security signature (reduces protection against man-in-the-middle attacks)" "Warning"
    Write-Host
    Show-Message "2) Revert to Windows Default" "Info"
    Write-Host
    Show-Message "    - Restore default, secure settings" "Success"
    Show-Message "    - DISABLE guest logins" "Success"
    Show-Message "    - ENABLE security signature" "Success"
    Write-Host
    while ($true) {
        $selection = Read-Host "Select an option (1 or 2, or leave blank and press Enter to return to main menu)"
        # Check for empty input (user just pressed Enter)
        if ([string]::IsNullOrWhiteSpace($selection)) {
            break # Exit the loop and the function returns to the main menu
        }
       
        switch ($selection) {
            "1" {
                if ($smbConfig.EnableInsecureGuestLogons -eq $true -and $smbConfig.RequireSecuritySignature -eq $false) {
                    Show-Message "Less secure settings are already in effect." "Warning"
                } else {
                    $confirm = Read-Host "Are you sure you wish to apply LESS SECURE settings? (Y/N)"
                    if ($confirm -match "^[Yy]$") {
                        try {
                            Set-SmbClientConfiguration -EnableInsecureGuestLogons $true -RequireSecuritySignature $false -Force | Out-Null
                            Show-Message "SMB configuration updated: guest logins enabled, security signature disabled" "Warning"
                            Write-Log "SMB configuration updated via Option 2 (Less Secure) - REBOOT REQUIRED"
                            Set-Content -Path $RebootTrackerFile -Value "Reboot Required"
                            Show-Message "`nA reboot is required to apply these changes." "Warning"
                        } catch {
                            Show-Message "Failed to update SMB configuration. Check log for details." "Error"
                            Write-Log "ERROR: Option 2 (Less Secure) failed - $($_.Exception.Message)"
                        }
                    } else { Show-Message "No changes applied." "Info" }
                }
                break # Exit the loop after a valid selection is made
            }
            "2" {
                if ($smbConfig.EnableInsecureGuestLogons -eq $false -and $smbConfig.RequireSecuritySignature -eq $true) {
                    Show-Message "Windows Default settings are already in effect." "Info"
                } else {
                    $confirm = Read-Host "Are you sure you wish to REVERT to Windows Default settings? (Y/N)"
                    if ($confirm -match "^[Yy]$") {
                        try {
                            Set-SmbClientConfiguration -EnableInsecureGuestLogons $false -RequireSecuritySignature $true -Force | Out-Null
                            Show-Message "SMB configuration reverted to Windows Default." "Success"
                            Write-Log "SMB configuration reverted to Windows Default - REBOOT REQUIRED"
                            Set-Content -Path $RebootTrackerFile -Value "Reboot Required"
                            Show-Message "`nA reboot is required to apply these changes." "Warning"
                        } catch {
                            Show-Message "Failed to revert SMB configuration. Check log for details." "Error"
                            Write-Log "ERROR: Option 2 (Windows Default) failed - $($_.Exception.Message)"
                        }
                    } else { Show-Message "No changes applied." "Info" }
                }
                break # Exit the loop after a valid selection is made
            }
            Default { Show-Message "Invalid selection." "Warning"; Start-Sleep 0 } # Stays in the loop on invalid input
        }
    }
}

function Configure-Smb1 {
    Clear-Host
    Show-Message "--- Configure SMBv1 ---" "Info"
    Write-Host ""
   
    try {
        $smb1Status = Get-WindowsOptionalFeature -Online -FeatureName SMB1Protocol
        Show-Message ("Current SMBv1 Status: {0}" -f $smb1Status.State) "Info"
        if ($smb1Status.State -eq 'Enabled') { Show-Message "(SMBv1 is a legacy, insecure protocol. Use with caution!)" "Warning" }
        Write-Host ""
    } catch {
        Show-Message "Failed to check SMBv1 status. Check log for details." "Error"
        Write-Log "ERROR: Failed to get SMBv1 status - $($_.Exception.Message)"
    }
   
    Show-Message "`n-------------------------------------`n"
    Show-Message "Enabling SMBv1 is a LAST RESORT for connecting to very old NAS devices." "Warning"
    Show-Message "It is highly insecure and can expose your network to threats like WannaCry." "Warning"
    Show-Message "`nA reboot is required to apply these changes.`n" "Warning"
   
    Show-Message "1) Enable SMBv1 (Insecure)" "Warning"
    Show-Message "2) Disable SMBv1 (Recommended)" "Info"
    Write-Host ""
    while ($true) {
        $selection = Read-Host "Select an option (1 or 2, or leave blank and press Enter to return to main menu)"
        if ([string]::IsNullOrWhiteSpace($selection)) {
            break
        }
   
        switch ($selection) {
            "1" {
                try {
                    if ($smb1Status.State -eq 'Enabled') {
                        Show-Message "SMBv1 is already enabled." "Warning"
                    } else {
                        $confirm = Read-Host "Are you sure you want to ENABLE the insecure SMBv1 protocol? (Y/N)"
                        if ($confirm -match "^[Yy]$") {
                            Enable-WindowsOptionalFeature -Online -FeatureName "SMB1Protocol" -NoRestart -ErrorAction Stop | Out-Null
                            Show-Message "SMBv1 is now enabled. A reboot is required." "Warning"
                            Write-Log "SMBv1 enabled - REBOOT REQUIRED"
                            Set-Content -Path $RebootTrackerFile -Value "Reboot Required"
                        } else { Show-Message "No changes applied." "Info" }
                    }
                } catch {
                    Show-Message "Failed to enable SMBv1. Check log for details." "Error"
                    Write-Log "ERROR: Failed to enable SMBv1 - $($_.Exception.Message)"
                }
                break
            }
            "2" {
                try {
                    if ($smb1Status.State -eq 'Disabled') {
                        Show-Message "SMBv1 is already disabled." "Info"
                    } else {
                        $confirm = Read-Host "Are you sure you want to DISABLE SMBv1? (Y/N)"
                        if ($confirm -match "^[Yy]$") {
                            Disable-WindowsOptionalFeature -Online -FeatureName "SMB1Protocol" -NoRestart -ErrorAction Stop | Out-Null
                            Show-Message "SMBv1 is now disabled. A reboot is required." "Success"
                            Write-Log "SMBv1 disabled - REBOOT REQUIRED"
                            Set-Content -Path $RebootTrackerFile -Value "Reboot Required"
                        } else { Show-Message "No changes applied." "Info" }
                    }
                } catch {
                    Show-Message "Failed to disable SMBv1. Check log for details." "Error"
                    Write-Log "ERROR: Failed to disable SMBv1 - $($_.Exception.Message)"
                }
                break
            }
            Default { Show-Message "Invalid selection." "Warning"; Start-Sleep 0 }
        }
    }
}

function Add-LocalIntranetEntries {
    Clear-Host
    Show-Message "--- Add Trusted Local Intranet Devices To This PC ---" "Info"
    Write-Host ""
    Show-Message "Current trusted devices are:" "Info"
    Write-Host ""
    $currentEntries = Get-AllIntranetEntries
    if ($currentEntries.Count -gt 0) {
        foreach ($d in $currentEntries) { Show-Message "  - $d" "Success" }
    } else {
        Show-Message "  No trusted devices found." "Info"
    }
    Show-Message "`nEnter IP addresses or NAS/NetBIOS names below." "Info"
    Show-Message "Separate multiple entries by commas or hit Enter for each device." "Info"
    Show-Message "Leave blank and press Enter to return to main menu." "Info"
    while ($true) {
        Write-Host ""
        $inputDevices = Read-Host "Enter device(s)"
        if ([string]::IsNullOrWhiteSpace($inputDevices)) { break }
        $devices = $inputDevices -split ","
        foreach ($d in $devices) {
            $d = $d.Trim()
            if ($d -ne "") {
                if (Validate-NASDevice $d) { Add-LocalIntranetEntry $d }
            }
        }
    }
}

function Remove-LocalIntranetEntries {
    Clear-Host
    Show-Message "--- Remove Trusted Local Intranet Devices From This PC ---" "Info"
    Write-Host ""
    Show-Message "Current trusted devices are:" "Info"
    Write-Host ""
    $currentEntries = Get-AllIntranetEntries
    if ($currentEntries.Count -gt 0) {
        foreach ($d in $currentEntries) { Show-Message "  - $d" "Success" }
    } else {
        Show-Message "  No trusted devices found." "Info"
    }
    Show-Message "`nEnter IP addresses or NAS/NetBIOS names below to remove." "Info"
    Show-Message "Separate multiple entries by commas or hit Enter for each device." "Info"
    Show-Message "Leave blank and press Enter to return to main menu." "Info"
    Write-Host ""
    while ($true) {
        $inputDevices = Read-Host "Enter device(s)"
        if ([string]::IsNullOrWhiteSpace($inputDevices)) { break }
        $devices = $inputDevices -split ","
        foreach ($d in $devices) {
            $d = $d.Trim()
            if ($d -ne "") { Remove-LocalIntranetEntry $d }
            }
        }
    }

function List-AllIntranetEntries {
    Clear-Host
    Show-Message "--- All Trusted Local Intranet Entries ---" "Info"
    Write-Host ""
    Show-Message "Current trusted devices are:" "Info"
    Write-Host ""
    $allEntries = Get-AllIntranetEntries
    if ($allEntries.Count -gt 0) {
        foreach ($entry in $allEntries) { Show-Message "  - $entry" "Success" }
    } else { Show-Message "  No trusted devices found." "Info" }
    Write-Host "`nPress any key to return to menu..."
    $null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
}

function Revert-ToWindowsDefaults {
    Clear-Host
    Show-Message "--- Revert All SMB Configuration Settings and SMBv1 Settings to Windows Defaults ---" "Info"
    Write-Host ""
   
    # Show current status before asking for confirmation
    try {
        $smbConfig = Get-SmbClientConfiguration
        $smb1Status = Get-WindowsOptionalFeature -Online -FeatureName SMB1Protocol
        Show-Message "Current SMB and SMBv1 Status:" "Info"
        Write-Host ""
        Show-Message ("{0,-28}: {1}" -f "RequireSecuritySignature", $smbConfig.RequireSecuritySignature) "Info"
        Show-Message ("{0,-28}: {1}" -f "EnableInsecureGuestLogons", $smbConfig.EnableInsecureGuestLogons) "Info"
        Show-Message ("{0,-28}: {1}" -f "SMBv1 Status", $smb1Status.State) "Info"
    } catch {
        Show-Message "Failed to retrieve current status. Check log for details." "Error"
        Write-Log "ERROR: Failed to get current status in Revert-ToWindowsDefaults - $($_.Exception.Message)"
    }

    Write-Host "`n-------------------------------------`n"
    Show-Message "This will revert your system to the default, more secure settings." "Success"
    Show-Message "This includes disabling insecure guest logins, enabling security signatures, and disabling SMBv1." "Success"
    Write-Host ""

    $confirm = ""
    do {
        $confirm = Read-Host "Are you sure you want to revert all SMB settings to Windows defaults? (Y/N)"
        if ($confirm -notmatch "^[YyNn]$") {
            Show-Message "Invalid selection. Please enter Y or N." "Warning"
        }
    } while ($confirm -notmatch "^[YyNn]$")
   
    if ($confirm -match "^[Yy]$") {
        $changesMade = $false
       
        try {
            # Revert less secure settings
            if ($smbConfig.EnableInsecureGuestLogons -eq $true -or $smbConfig.RequireSecuritySignature -eq $false) {
                Set-SmbClientConfiguration -EnableInsecureGuestLogons $false -RequireSecuritySignature $true -Force | Out-Null
                Show-Message "`nSMB configuration reverted to Windows Default." "Success"
                $changesMade = $true
            } else {
                Show-Message "`nSMB client settings are already at Windows defaults." "Info"
            }
           
            # Revert SMBv1
            if ($smb1Status.State -eq 'Enabled') {
                Disable-WindowsOptionalFeature -Online -FeatureName "SMB1Protocol" -NoRestart -ErrorAction Stop | Out-Null
                Show-Message "SMBv1 is now disabled." "Success"
                $changesMade = $true
            } else {
                Show-Message "SMBv1 is already disabled." "Info"
            }
        } catch {
            Show-Message "Failed to revert settings. Check log for details." "Error"
            Write-Log "ERROR: Failed to revert to Windows defaults - $($_.Exception.Message)"
        }
       
        if ($changesMade) {
            Set-Content -Path $RebootTrackerFile -Value "Reboot Required"
            Show-Message "`nA reboot is required to apply these changes." "Warning"
        }
    } else {
        Show-Message "`nReversion cancelled. No changes were made." "Info"
    }
   
    Read-Host "`nPress Enter to return to main menu..." | Out-Null
}

# --- Main Script Logic ---
try {
    # --- Setup ---
    chcp 65001 >$null
    [Console]::OutputEncoding = [System.Text.Encoding]::UTF8
    [Console]::InputEncoding = [System.Text.Encoding]::UTF8
    If (-NOT ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) {
        Write-Host "ERROR: Script must be run as Administrator!" -ForegroundColor Red -BackgroundColor Blue
        Read-Host "Press Enter to exit..." | Out-Null
        Exit
    }
    $exitRequested = $false
    $Host.UI.RawUI.BackgroundColor = "Blue"
    $Host.UI.RawUI.ForegroundColor = "White"
    Clear-Host
    $logFolder = Join-Path $PSScriptRoot "log"
    if (-not (Test-Path $logFolder)) { New-Item -ItemType Directory -Path $logFolder | Out-Null }
   
    $LogFile = Join-Path $logFolder "NAS_Script.log"

    # --- New PC Logging Check ---
    $currentComputerName = $env:COMPUTERNAME
    $lastKnownComputerName = ""
    if (Test-Path $LastPCFile) {
        $lastKnownComputerName = Get-Content $LastPCFile
    }

    if ($lastKnownComputerName -ne $currentComputerName) {
        " " | Out-File -FilePath $LogFile -Append -Encoding UTF8
        " " | Out-File -FilePath $LogFile -Append -Encoding UTF8
        " " | Out-File -FilePath $LogFile -Append -Encoding UTF8
        Write-Log "New PC detected. Starting new log session."
        Set-Content -Path $LastPCFile -Value $currentComputerName
    }

    # --- Reboot Check ---
    if (Test-Path $RebootTrackerFile) {
        $fileCreationTime = (Get-Item $RebootTrackerFile).LastWriteTime
        $currentBootTime = (Get-CimInstance -ClassName Win32_OperatingSystem).LastBootUpTime
       
        # Compare last boot time to the file's last write time.
        if ($currentBootTime -gt $fileCreationTime) {
            Remove-Item -Path $RebootTrackerFile -ErrorAction SilentlyContinue
        } else {
            Write-Host ""
            Show-Message "WARNING: A reboot is still required to apply a previous change. Main menu is loading, please wait." "Warning"
            Write-Log "WARNING: A previous change was made that requires a reboot."
            Start-Sleep -Seconds 6
        }
    }

    # --- Main Menu Loop ---
    while (-not $exitRequested) {
        Clear-Host
        if (Test-Path $RebootTrackerFile) {
            Show-Message "WARNING: A REBOOT IS REQUIRED" "Warning"
            Write-Host ""
        }
        Show-Message "--- NAS / SMB Configuration Script ---" "Success"
        Write-Host ""
        Show-Message "IMPORTANT: Some changes will require a reboot. Please save all your work before proceeding." "Warning"
        Write-Host ""
        Show-Message ("{0,2}) {1}" -f 1, "Show current SMB and Trusted Local Intranet status.") "Info"
        Show-Message ("{0,2}) {1}" -f 2, "Configure SMB (Fixes folder refresh, etc.)") "Info"
        Show-Message ("{0,2}) {1}" -f 3, "Configure SMBv1 (Final resort for legacy devices)") "Info"
        Write-Host ""
        Show-Message ("{0,2}) {1}" -f 4, "List All Trusted Local Intranet Entries On This PC") "Info"
        Show-Message ("{0,2}) {1}" -f 5, "Add Trusted Local Intranet Entries To This PC (Helps Prevent Security Warnings)") "Info"
        Show-Message ("{0,2}) {1}" -f 6, "Remove Trusted Local Intranet Entries From This PC") "Info"
        Write-Host ""
        Show-Message ("{0,2}) {1}" -f 7, "Remove ALL Trusted Devices From This PC") "Info"
        Write-Host ""
        Show-Message ("{0,2}) {1}" -f 8, "Revert All SMB Configuration Settings and SMBv1 Settings to Windows Defaults.") "Info"
        Write-Host ""
        Show-Message ("{0,2}) {1}" -f 9, "Exit (Reboot Manually If Required)") "Info"
        Show-Message ("{0,2}) {1}" -f 10, "Exit and Reboot (If Required)") "Info"
        Write-Host ""
        $selection = Read-Host "`nSelect an option (1-10)"
        switch ($selection) {
            "1" { Show-CurrentStatus }
            "2" { Configure-Option2 }
            "3" { Configure-Smb1 }
            "4" { List-AllIntranetEntries }
            "5" { Add-LocalIntranetEntries }
            "6" { Remove-LocalIntranetEntries }
            "7" { Remove-AllIntranetEntries }
            "8" { Revert-ToWindowsDefaults }
            "9" {
                if (Test-Path $RebootTrackerFile) {
                    Show-Message "`n--- REBOOT REQUIRED ---`n" "Warning"
                    Show-Message "A reboot is required to apply the changes you made to SMB settings.`n" "Warning"
                    Show-Message "Please save all your work before manually rebooting your computer.`n" "Warning"
                    $confirm = Read-Host "Do you wish to exit the script? (Y/N)"
                    if ($confirm -match "^[Yy]$") {
                        $exitRequested = $true
                    }
                } else {
                    Show-Message "`nNo reboot is required. No SMB changes were made that need a reboot.`n" "Success"
                    $confirm = Read-Host "Do you wish to exit the script? (Y/N)"
                    if ($confirm -match "^[Yy]$") {
                        $exitRequested = $true
                    }
                }
            }
            "10" {
                if (Test-Path $RebootTrackerFile) {
                    Show-Message "`n--- REBOOTING TO APPLY CHANGES ---`n" "Warning"
                    Show-Message "A reboot is required to apply the changes you made to SMB settings.`n" "Warning"
                    Show-Message "You will lose any unsaved work if you proceed now! Please save your work now!`n" "Warning"
                    $confirm = Read-Host "Are you sure you wish to reboot now? (Y/N)"
                    if ($confirm -match "^[Yy]$") {
                        Show-Message "Press Enter to reboot..." "Info"
                        Read-Host | Out-Null
                        Restart-Computer
                        $exitRequested = $true
                    } else {
                        Show-Message "Reboot cancelled." "Info"
                        $confirmExit = Read-Host "Do you still wish to exit the script? (Y/N)"
                        if ($confirmExit -match "^[Yy]$") {
                            $exitRequested = $true
                        }
                    }
                } else {
                    Show-Message "`nNo reboot is required. No SMB changes were made that need a reboot.`n" "Success"
                    $confirm = Read-Host "Do you wish to exit the script? (Y/N)"
                    if ($confirm -match "^[Yy]$") {
                        $exitRequested = $true
                    }
                }
            }
            Default { Show-Message "Invalid selection." "Warning"; Start-Sleep 1 }
        }
    }
} catch {
    Clear-Host
    Write-Host "FATAL ERROR: A critical error occurred and the script was forced to exit." -ForegroundColor Red -BackgroundColor Blue
    Write-Host "`nError Details:" -ForegroundColor Yellow -BackgroundColor Blue
    Write-Host $_ -ForegroundColor Yellow -BackgroundColor Blue
    Write-Host "`nThis indicates a problem with the system's PowerShell environment or a Windows component." -ForegroundColor White -BackgroundColor Blue
    Read-Host "`nPress Enter to exit..." | Out-Null
}
 
Last edited:

My Computer My Computer

At a glance

Windows 11 Pro x3i9-14900K / i9-14900HX / AMD Z1E64 GSkill / 64 Gskill / 24EVGA 3080 Ultra FTW 3 / 4070 Mobile / Z1E
OS
Windows 11 Pro x3
Computer type
PC/Desktop
Manufacturer/Model
Asus / Asus / Asus
CPU
i9-14900K / i9-14900HX / AMD Z1E
Motherboard
Asus Apex Encore / Asus G16 (2024) / ROG Ally X
Memory
64 GSkill / 64 Gskill / 24
Graphics Card(s)
EVGA 3080 Ultra FTW 3 / 4070 Mobile / Z1E
Sound Card
Logitech G Pro
Screen Resolution
2560 x 1080 / 2560 x 1600 / 1920 x 1080
Hard Drives
990 pro 4 TB, 4x 980 1TB, 980 pro 2TB
If you find any errors, or broken functionality, please let me know.
 

My Computer My Computer

At a glance

Windows 11 Pro x3i9-14900K / i9-14900HX / AMD Z1E64 GSkill / 64 Gskill / 24EVGA 3080 Ultra FTW 3 / 4070 Mobile / Z1E
OS
Windows 11 Pro x3
Computer type
PC/Desktop
Manufacturer/Model
Asus / Asus / Asus
CPU
i9-14900K / i9-14900HX / AMD Z1E
Motherboard
Asus Apex Encore / Asus G16 (2024) / ROG Ally X
Memory
64 GSkill / 64 Gskill / 24
Graphics Card(s)
EVGA 3080 Ultra FTW 3 / 4070 Mobile / Z1E
Sound Card
Logitech G Pro
Screen Resolution
2560 x 1080 / 2560 x 1600 / 1920 x 1080
Hard Drives
990 pro 4 TB, 4x 980 1TB, 980 pro 2TB
I made a few tweeks to the script.
 

My Computer My Computer

At a glance

Windows 11 Pro x3i9-14900K / i9-14900HX / AMD Z1E64 GSkill / 64 Gskill / 24EVGA 3080 Ultra FTW 3 / 4070 Mobile / Z1E
OS
Windows 11 Pro x3
Computer type
PC/Desktop
Manufacturer/Model
Asus / Asus / Asus
CPU
i9-14900K / i9-14900HX / AMD Z1E
Motherboard
Asus Apex Encore / Asus G16 (2024) / ROG Ally X
Memory
64 GSkill / 64 Gskill / 24
Graphics Card(s)
EVGA 3080 Ultra FTW 3 / 4070 Mobile / Z1E
Sound Card
Logitech G Pro
Screen Resolution
2560 x 1080 / 2560 x 1600 / 1920 x 1080
Hard Drives
990 pro 4 TB, 4x 980 1TB, 980 pro 2TB
Updated the powefshell script code for some visual effects, to add some functionality and changed how the script handled some functions.

Latest version 1.1.0

Powershell:
# ====================================================
# NAS / SMB Configuration Script - Portable
# Console Tracking
# Created using ChatGPT & Gemini by Jeremy / BLzNFuN
# email: [email protected]
# v 1.1.0
# ====================================================

# Force all errors to be terminating to ensure they are caught by the TRY/CATCH
$ErrorActionPreference = "Stop"

# --- Global Variables ---
# Variables defining paths for logs and tracking files, and registry keys for SMB settings.
$logFolder = Join-Path $PSScriptRoot "log"
$LogFile = Join-Path $logFolder "script_log.log"

# This file is used to persist the reboot state across script sessions.
$RebootTrackerFile = Join-Path $env:TEMP "nas_smb_reboot_required.txt"
# Tracking file for portability/migration. Maintained in log folder.
$LastPCFile = Join-Path $logFolder "last_run_pc.txt"

# Registry key for SMBv1 Automatic Removal setting (AutoDeactivated)
$smb1RegPath = "HKLM:\SYSTEM\CurrentControlSet\Services\LanmanServer\Parameters"

# --- Functions (MUST be defined before main logic) ---

# This function is available for logging high-level errors and for runtime errors.
# It includes error suppression in case the log file becomes inaccessible.
function Write-Log {
    param(
        [string]$Message,
        [string]$Type="INFO"
    )
    $timestamp = Get-Date -Format "yyyy-MM-dd hh:mm:ss tt"
    $computerName = $env:COMPUTERNAME
    # This function now relies on the $LogFile variable being present in its scope.
    $logEntry = "[$Type] $timestamp [$computerName] - $Message"
    Add-Content -Path $LogFile -Value $logEntry -Encoding UTF8 -ErrorAction SilentlyContinue
}

# Displays colored messages to the console based on message type.
function Show-Message { param([string]$Message,[ValidateSet("Info","Warning","Error","Success")][string]$Type="Info")
    # Note: Using default console colors
    switch ($Type) {
        "Info"    { Write-Host $Message -ForegroundColor White }
        "Warning" { Write-Host $Message -ForegroundColor Yellow }
        "Error"   { Write-Host $Message -ForegroundColor Red }
        "Success" { Write-Host $Message -ForegroundColor Green }
    }
}

# Returns the HKCU registry paths used for Local Intranet Zone mapping.
function Get-IntranetRegPaths {
    # We will always use the HKCU drive as it is the most reliable.
    $paths = @{
        Domains = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMap\Domains"
        Ranges = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMap\Ranges"
    }
    return $paths
}

# --- Local Intranet Functions ---
# This section contains functions for managing the Local Intranet security zone settings
# in the Windows Registry (HKCU). This allows NAS/SMB devices to be treated as local,
# preventing unnecessary security prompts.
function Get-AllIntranetEntries {
    $entries = @()
    $regPaths = Get-IntranetRegPaths
  
    if (Test-Path $regPaths.Domains) {
        $domainKeys = Get-ChildItem -Path $regPaths.Domains -ErrorAction SilentlyContinue
        foreach ($key in $domainKeys) {
            $entries += $key.PSChildName.ToLower()
        }
    }
  
    if (Test-Path $regPaths.Ranges) {
        $rangeKeys = Get-ChildItem -Path $regPaths.Ranges -ErrorAction SilentlyContinue
        foreach ($key in $rangeKeys) {
            $props = Get-ItemProperty -Path $key.PSPath -ErrorAction SilentlyContinue
            if ($props.PSObject.Properties.Name -contains ":Range") {
                $entries += ([string]$props.":Range").Trim().ToLower()
            }
            elseif ($props.PSObject.Properties.Name -contains "URL") {
                $entries += ([string]$props.URL).Trim().ToLower()
            }
        }
    }
    return $entries
}

function Validate-NASDevice { param([string]$Device)
    if ($Device -match "^\d{1,3}(\.\d{1,3}){3}$") {
        return $true
    }
    elseif ($Device -notmatch "^[\d.]+$" -and $Device -match "^[A-Za-z0-9\-_.]+$") {
        return $true
    }
    else {
        Show-Message "Invalid Local Intranet entry format: $Device" "Error"
        return $false
    }
}

function Add-LocalIntranetEntry { param([string]$device)
    $normalizedDevice = $device.Trim().ToLower()
    $existingEntries = Get-AllIntranetEntries
    if ($existingEntries -contains $normalizedDevice) {
        Show-Message "$device already exists." "Info"
        return
    }
    $regPaths = Get-IntranetRegPaths

    if ($normalizedDevice -match "^\d{1,3}(\.\d{1,3}){3}$") { # IP Address
        $regPath = $regPaths.Ranges
        $nextRangeNumber = 0
        $existingRanges = Get-ChildItem -Path $regPath -ErrorAction SilentlyContinue | Where-Object { $_.PSChildName -match '^Range\d+$' }
        if ($existingRanges) {
            $numbers = $existingRanges | ForEach-Object { [int]($_.PSChildName -replace '^Range') }
            $nextRangeNumber = ($numbers | Measure-Object -Maximum).Maximum + 1
        }

        $rangeKey = Join-Path -Path $regPath -ChildPath "Range$nextRangeNumber"
      
        if (-not (Test-Path $rangeKey)) { New-Item -Path $rangeKey -Force | Out-Null }
        New-ItemProperty -Path $rangeKey -Name ":Range" -Value $device -Type String -Force | Out-Null
        New-ItemProperty -Path $rangeKey -Name "*" -Value 1 -Type DWORD -Force | Out-Null
    } else { # Domain Name
        $regPath = $regPaths.Domains
        $domainKey = Join-Path -Path $regPaths.Domains -ChildPath $normalizedDevice
        if (-not (Test-Path $domainKey)) { New-Item -Path $domainKey -Force | Out-Null }
        New-ItemProperty -Path $domainKey -Name "*" -Value 1 -Type DWORD -Force | Out-Null
    }
  
    Write-Log "Local Intranet entry added: $device"
    Show-Message "$device successfully added." "Success"
    Show-Message " " "Info"
}

function Remove-LocalIntranetEntry { param([string]$device)
    $found = $false
    $normalizedDevice = $device.Trim().ToLower()
    $regPaths = Get-IntranetRegPaths
  
    # Check Domains
    if ($normalizedDevice -notmatch "^\d{1,3}(\.\d{1,3}){3}$") {
        $domainPath = Join-Path -Path $regPaths.Domains -ChildPath $normalizedDevice
        if (Test-Path $domainPath) {
            Remove-Item -Path $domainPath -Recurse -Force -ErrorAction SilentlyContinue | Out-Null
            $found = $true
            Show-Message "$device successfully removed." "Success"
            Write-Log "Removed Local Intranet entry: $device"
        }
    }
  
    # Check Ranges
    $rangeKeys = Get-ChildItem -Path $regPaths.Ranges -ErrorAction SilentlyContinue
    foreach ($key in $rangeKeys) {
        $props = Get-ItemProperty -Path $key.PSPath -ErrorAction SilentlyContinue
        if ($props.PSObject.Properties.Name -contains ":Range" -and $props.":Range".Trim().ToLower() -eq $normalizedDevice) {
            Remove-Item -Path $key.PSPath -Recurse -Force -ErrorAction SilentlyContinue | Out-Null
            $found = $true
            Show-Message "$device successfully removed." "Success"
            Write-Log "Removed Local Intranet entry: $device"
        }
        elseif ($props.PSObject.Properties.Name -contains "URL" -and $props.URL.Trim().ToLower() -eq $normalizedDevice) {
            Remove-Item -Path $key.PSPath -Recurse -Force -ErrorAction SilentlyContinue | Out-Null
            $found = $true
            Show-Message "$device successfully removed." "Success"
            Write-Log "Removed Local Intranet entry: $device"
        }
    }
  
    if (-not $found) {
        Show-Message "$device not found." "Error"
    }
    Show-Message " " "Info"
}

function Remove-AllIntranetEntries {
    Write-Log "User selected Option 7: Removing ALL Trusted Local Intranet Devices."
    Clear-Host
    Show-Message "=====================================================================" "Info"
    Show-Message "   Menu 7 - Remove ALL Trusted Local Intranet Devices From This PC   " "Info"
    Show-Message "=====================================================================" "Info"
    Show-Message " " "Info"
  
    $currentEntries = Get-AllIntranetEntries
  
    Show-Message "The following devices found on this PC will be removed:" "Info"
    Show-Message " " "Info"
    if ($currentEntries.Count -gt 0) {
        foreach ($d in $currentEntries) { Show-Message "  - $d" "Warning" }
    } else {
        Show-Message "  No trusted devices found." "Info"
        Show-Message " " "Info"
        Read-Host "Press Enter to return to main menu..." | Out-Null
        return
    }
  
    Show-Message " " "Info"
  
    $confirm = ""
    do {
        $confirm = Read-Host "Are you sure you want to remove ALL listed devices? This includes devices added from other sources. (Y/N)"
        Show-Message " " "Info"
        if ($confirm -notmatch "^[YyNn]$") {
            Show-Message "Invalid selection. Please enter Y or N." "Warning"
        }
    } while ($confirm -notmatch "^[YyNn]$")
  
    if ($confirm -match "^[Yy]$") {
        $regPaths = Get-IntranetRegPaths

        # Log each device removed before actual deletion (Per User Request)
        foreach ($device in $currentEntries) {
            Write-Log "Removed Local Intranet entry (Bulk Removal): $device"
        }

        if (Test-Path $regPaths.Domains) {
            Remove-Item -Path $regPaths.Domains -Recurse -Force -ErrorAction SilentlyContinue | Out-Null
            Show-Message "All Domain/NetBIOS devices successfully removed." "Success"
            Show-Message " " "Info"
            Write-Log "All domain entries removed from Local Intranet."
        } else {
            Show-Message "No domain entries to remove." "Info"
            Show-Message " " "Info"
        }

        if (Test-Path $regPaths.Ranges) {
            Remove-Item -Path $regPaths.Ranges -Recurse -Force -ErrorAction SilentlyContinue | Out-Null
            Show-Message "All IP Devices successfully removed." "Success"
            Show-Message " " "Info"
            Write-Log "All IP range entries removed from Local Intranet."
        } else {
            Show-Message "No IP range entries to remove." "Info"
            Show-Message " " "Info"
        }
    } else {
        Show-Message "No devices were removed." "Info"
        Write-Log "Removal of all Local Intranet entries cancelled by user."
    }
  
    Show-Message " " "Info"
    Read-Host "Press Enter to return to main menu..." | Out-Null
}


# --- SMB Helper Functions ---
# These functions abstract the retrieval and setting of SMB client configuration and
# the status of the legacy SMBv1 protocol features, including robust error handling.
function Get-SmbClientConfiguration {
    # Returns the configuration object for the SMB client
    try {
        # Force a stop if the cmdlet itself fails, preventing hangs/silent failure
        return Get-SmbClientConfiguration -ErrorAction Stop
    } catch {
        # Use more stable error reporting property
        Write-Log "ERROR: Get-SmbClientConfiguration failed to execute. (Error Type: $($_.CategoryInfo.Reason))" "ERROR"
        # Return a mock object with default safe settings and a tag for explicit error handling
        return @{
            RequireSecuritySignature = $true;
            EnableInsecureGuestLogons = $false;
            _IsMockObject = $true;
        }
    }
}

function Get-Smb1ClientStatus {
    # Returns the status object for the SMB1Protocol-Client feature
    try {
        return Get-WindowsOptionalFeature -Online -FeatureName SMB1Protocol-Client -ErrorAction Stop
    } catch {
        # Use more stable error reporting property
        Write-Log "ERROR: Get-WindowsOptionalFeature (Client) failed to execute. (Error Type: $($_.CategoryInfo.Reason))" "ERROR"
        # Return a mock object with the safest state ('Removed') and a tag for explicit error handling
        return @{State = 'Removed'; PSObject = @{}; _IsMockObject = $true}
    }
}

function Get-Smb1ServerStatus {
    # Returns the status object for the SMB1Protocol-Server feature
    try {
        return Get-WindowsOptionalFeature -Online -FeatureName SMB1Protocol-Server -ErrorAction Stop
    } catch {
        # Use more stable error reporting property (Line 231)
        Write-Log "ERROR: Get-WindowsOptionalFeature (Server) failed to execute. (Error Type: $($_.CategoryInfo.Reason))" "ERROR"
        # Return a mock object with the safest state ('Removed') and a tag for explicit error handling (Line 233)
        return @{State = 'Removed'; PSObject = @{}; _IsMockObject = $true}
    }
}

function Get-Smb1AutoRemovalStatus {
    # Returns a hashtable with Status (bool), Text (string), and Color (string) based ONLY on registry value
  
    # The default/missing value (or 1) means 'Auto Removal IS ON' (AutoDeactivated IS active/on).
    # The value 0 means 'Auto Removal IS OFF' (AutoDeactivated IS NOT active/off).

    $autoDeactivatedRegValue = Get-ItemProperty -Path $smb1RegPath -Name AutoDeactivated -ErrorAction SilentlyContinue
  
    if ($autoDeactivatedRegValue -eq $null -or $autoDeactivatedRegValue.AutoDeactivated -eq 1) {
        return @{
            Status = $true
            Text = "Enabled (Default/Key Missing)"
            Color = "Warning"
        }
    } else { # Value is 0
        return @{
            Status = $false
            Text = "Disabled (Prevents Auto-Uninstall)"
            Color = "Success"
        }
    }
}

function Set-Smb1AutoRemoval { param([bool]$Enable)
    $regPath = $smb1RegPath
    $valueName = "AutoDeactivated"
    $value = if ($Enable) { 1 } else { 0 }
    $statusText = if ($Enable) { "Enabled" } else { "Disabled" }

    try {
        if (-not (Test-Path $regPath)) {
            New-Item -Path $regPath -Force | Out-Null
        }
      
        # Set the DWORD value. | Out-Null to suppress unwanted 'True' output.
        New-ItemProperty -Path $regPath -Name $valueName -Value $value -Type DWORD -Force | Out-Null
        Write-Log "SMBv1 Automatic Removal set to: $statusText (Registry value $valueName = $value)."
        Show-Message "SMBv1 Automatic Removal successfully $statusText." "Success"
        return $true
    } catch {
        Write-Log "ERROR setting SMBv1 Automatic Removal registry key: $($_.Exception.Message)" "ERROR"
        Show-Message "ERROR: Could not set SMBv1 Automatic Removal registry key." "Error"
        return $false
    }
}

function Remove-Smb1AutoRemovalRegKey {
    $regPath = $smb1RegPath
    $valueName = "AutoDeactivated"
    try {
        # Check for existence of the value before trying to remove
        if (Get-ItemProperty -Path $regPath -Name $valueName -ErrorAction SilentlyContinue) {
            # Use Out-Null to suppress any output from the removal process
            Remove-ItemProperty -Path $regPath -Name $valueName -Force -ErrorAction Stop | Out-Null
            Write-Log "SMBv1 Automatic Removal registry value removed."
            return $true
        }
        return $true
    } catch {
        Write-Log "ERROR removing SMBv1 Automatic Removal registry key: $($_.Exception.Message)" "ERROR"
        Show-Message "ERROR: Could not remove SMBv1 Automatic Removal registry key." "Error"
        return $false
    }
}


# --- Menu Functions ---
function Show-CurrentStatus {
    Write-Log "User selected Option 1: Viewing current SMB and Trusted Local Intranet status."
    Clear-Host
    Show-Message "===========================================================" "Info"
    Show-Message "   Menu 1 - Current Status of all Script Tracked Options   " "Info"
    Show-Message "===========================================================" "Info"
    Show-Message " " "Info"
  
    $smbConfig = Get-SmbClientConfiguration
    # Get specific SMBv1 feature statuses
    $smb1ClientStatus = Get-Smb1ClientStatus
    $smb1ServerStatus = Get-Smb1ServerStatus
    $clientState = $smb1ClientStatus.State
    $serverState = $smb1ServerStatus.State
  
    # Check if Get-SmbClientConfiguration failed and returned a mock object
    if ($smbConfig._IsMockObject -eq $true) {
        Show-Message "WARNING: Could not retrieve current SMB Configuration. Check logs for WMI/CIM errors." "Error"
    }
  
    # Use string formatting for justified output
    Show-Message ("{0,-28}: {1}" -f "RequireSecuritySignature", $smbConfig.RequireSecuritySignature) "Info"
    if ($smbConfig.RequireSecuritySignature -eq $false) { Show-Message "(DISABLED - Low security!)" "Warning" }
    Show-Message ("{0,-28}: {1}" -f "EnableInsecureGuestLogons", $smbConfig.EnableInsecureGuestLogons) "Info"
    if ($smbConfig.EnableInsecureGuestLogons -eq $true) { Show-Message "(ENABLED - Insecure!)" "Warning" }

    # SMBv1 Status Display with Color Logic
    Show-Message " " "Info"
    Show-Message "--- SMBv1 Status ---" "Info"
    Show-Message " " "Info"
  
    $clientColor = if ($clientState -eq 'Enabled') { "Warning" } else { "Success" }
    if ($clientState -eq 'Unknown' -or $smb1ClientStatus._IsMockObject -eq $true) { $clientColor = "Error" }
    Show-Message ("{0,-28}: {1}" -f "SMBv1 Client Status", $clientState) $clientColor
  
    $serverColor = if ($serverState -eq 'Enabled') { "Warning" } else { "Success" }
    if ($serverState -eq 'Unknown' -or $smb1ServerStatus._IsMockObject -eq $true) { $serverColor = "Error" }
    Show-Message ("{0,-28}: {1}" -f "SMBv1 Server Status", $serverState) $serverColor
    Show-Message "(Server component is kept DISABLED by this script.  If needed, please enable via the Windows Features GUI.)" "Warning"

    # Automatic Removal Status Check Logic
    Show-Message " " "Info"
    $autoRemovalRegStatus = Get-Smb1AutoRemovalStatus
  
    if ($clientState -eq 'Disabled' -or $clientState -eq 'Removed' -or $clientState -eq 'DisablePending' -or $smb1ClientStatus._IsMockObject -eq $true) {
        # If the feature is not installed or is being removed, auto removal is irrelevant.
        $autoRemovalText = "Disabled"
        $autoRemovalColor = "Success"
        if ($autoRemovalRegStatus.Status -eq $false) {
            $autoRemovalText = "Key Present/Disabled (Feature is Disabled/Removed)"
            $autoRemovalColor = "Info"
        }
        if ($smb1ClientStatus._IsMockObject -eq $true) {
            $autoRemovalText = "Status Unknown (SMBv1 Client Status Error)"
            $autoRemovalColor = "Error"
        }
    } else {
        # SMBv1 Client is installed or InstallPending, so we check the registry for active status.
        $autoRemovalText = $autoRemovalRegStatus.Text
        $autoRemovalColor = $autoRemovalRegStatus.Color
    }
  
    Show-Message ("{0,-28}: {1}" -f "Automatic Removal", $autoRemovalText) $autoRemovalColor
    Show-Message "NOTE: The Windows Optional Features GUI may incorrectly show 'Automatic Removal' as checked even when the registry key indicates it is DISABLED. The status displayed above is the definitive status." "Warning"
  
    $allIntranetEntries = Get-AllIntranetEntries
  
    Show-Message " " "Info"
    Show-Message "Trusted Local Intranet Devices:" "Info"
    Show-Message " " "Info"
    if ($allIntranetEntries.Count -gt 0) {
        foreach ($d in $allIntranetEntries) { Show-Message "  - $d" "Success" }
    } else {
        Show-Message "  No trusted devices found." "Info"
    }
  
    Show-Message " " "Info"
    Read-Host "Press Enter to return to the main menu..." | Out-Null
}

function Configure-Option2 {
    Write-Log "User selected Option 2: Entered SMB Configuration Menu."
    Clear-Host
    Show-Message "=================================" "Info"
    Show-Message "   Menu 2 - Current SMB Status   " "Info"
    Show-Message "=================================" "Info"
    Show-Message " " "Info"
    $smbConfig = Get-SmbClientConfiguration
    # Use string formatting for justified output
    Show-Message ("{0,-28}: {1}" -f "RequireSecuritySignature", $smbConfig.RequireSecuritySignature) "Info"
    if ($smbConfig.RequireSecuritySignature -eq $false) { Show-Message "(DISABLED - Low security!)" "Warning" }
    Show-Message ("{0,-28}: {1}" -f "EnableInsecureGuestLogons", $smbConfig.EnableInsecureGuestLogons) "Info"
    if ($smbConfig.EnableInsecureGuestLogons -eq $true) { Show-Message "(ENABLED - Insecure!)" "Warning" }
  
    Show-Message " " "Info"
    Show-Message "-------------------------------------" "Info"
    Show-Message " " "Info"
    Show-Message "--- SMB Configuration Options ---" "Info"
    Show-Message " " "Info"
    Show-Message "1) Apply Less Secure Settings" "Info"
    Show-Message " " "Info"
    Show-Message "    - WARNING: This will make SMB less secure!" "Warning"
    Show-Message "    - ENABLE guest logins (may allow unauthenticated access to shares)" "Warning"
    Show-Message "    - DISABLE security signature (reduces protection against man-in-the-middle attacks)" "Warning"
    Show-Message " " "Info"
    Show-Message "2) Revert to Windows Default" "Info"
    Show-Message " " "Info"
    Show-Message "    - Restore default, secure settings" "Success"
    Show-Message "    - DISABLE guest logins" "Success"
    Show-Message "    - ENABLE security signature" "Success"
    Show-Message " " "Info"
    Show-Message "ATTENTION: A Logoff will be **REQUIRED** after you change these settings!  Be sure to do this" "Error"
    Show-Message "           to test if access is restored before enabling SMBv1 which is an EXTREME RISK!" "Error"
    Show-Message " " "Info"
    while ($true) {
        $selection = Read-Host "Select an option (1 or 2, or leave blank and press Enter to return to main menu)"
        # Check for empty input (user just pressed Enter)
        if ([string]::IsNullOrWhiteSpace($selection)) {
            break # Exit the loop and the function returns to the main menu
        }
      
        switch ($selection) {
            "1" {
                if ($smbConfig.EnableInsecureGuestLogons -eq $true -and $smbConfig.RequireSecuritySignature -eq $false) {
                    Show-Message "Less secure settings are already in effect." "Warning"
                } else {
                    $confirm = ""
                    do {
                        $confirm = Read-Host "Are you sure you wish to apply LESS SECURE settings? (Y/N)"
                        if ($confirm -notmatch "^[YyNn]$") {
                            Show-Message "Invalid selection. Please enter Y or N." "Warning"
                        }
                    } while ($confirm -notmatch "^[YyNn]$")
                  
                    if ($confirm -match "^[Yy]$") {
                        Set-SmbClientConfiguration -EnableInsecureGuestLogons $true -RequireSecuritySignature $false -Force | Out-Null
                        Show-Message "SMB configuration updated: guest logins enabled, security signature disabled" "Warning"
                        Write-Log "SMB configuration updated via Option 2 (Less Secure) - LOGOFF REQUIRED" # Log change
                        # Removed Set-Content -Path $RebootTrackerFile...
                        Show-Message " " "Info"
                        Show-Message "A Logoff is **REQUIRED** to apply these changes!" "Error" # Updated message
                    } else {
                        Show-Message "No changes applied." "Info"
                    }
                }
                break # Exit the loop after a valid selection is made
            }
            "2" {
                if ($smbConfig.EnableInsecureGuestLogons -eq $false -and $smbConfig.RequireSecuritySignature -eq $true) {
                    Show-Message "Windows Default settings are already in effect." "Info"
                } else {
                    $confirm = ""
                    do {
                        $confirm = Read-Host "Are you sure you wish to REVERT to Windows Default settings? (Y/N)"
                        if ($confirm -notmatch "^[YyNn]$") {
                            Show-Message "Invalid selection. Please enter Y or N." "Warning"
                        }
                    } while ($confirm -notmatch "^[YyNn]$")
                  
                    if ($confirm -match "^[Yy]$") {
                        Set-SmbClientConfiguration -EnableInsecureGuestLogons $false -RequireSecuritySignature $true -Force | Out-Null
                        Show-Message "SMB configuration reverted to Windows Default." "Success"
                        Write-Log "SMB configuration reverted to Windows Default - LOGOFF REQUIRED" # Log change
                        # Removed Set-Content -Path $RebootTrackerFile...
                        Show-Message " " "Info"
                        Show-Message "A Logoff is **REQUIRED** to apply these changes!" "Error"
                    } else {
                        Show-Message "No changes applied." "Info"
                    }
                }
                break # Exit the loop after a valid selection is made
            }
            Default { Show-Message "Invalid selection." "Warning"; Start-Sleep 0 } # Stays in the loop on invalid input
        }
    }
}

function Configure-Smb1 {
    Write-Log "User selected Option 3: Entered SMBv1 Configuration Menu."
    Clear-Host
  
    # Check current status first
    $smb1ClientStatus = Get-Smb1ClientStatus
    $smb1ServerStatus = Get-Smb1ServerStatus
    $clientState = $smb1ClientStatus.State
    $serverState = $smb1ServerStatus.State
  
    # Apply conditional display logic for Auto Removal based on client status
    $autoRemovalRegStatus = Get-Smb1AutoRemovalStatus
  
    if ($clientState -eq 'Disabled' -or $clientState -eq 'Removed' -or $clientState -eq 'DisablePending' -or $smb1ClientStatus._IsMockObject -eq $true) {
        # If the feature is not installed or is being removed, auto removal is irrelevant.
        $autoRemovalText = "Disabled"
        $autoRemovalColor = "Success"
        if ($autoRemovalRegStatus.Status -eq $false) {
            $autoRemovalText = "Disabled"
            $autoRemovalColor = "Info"
        }
        if ($smb1ClientStatus._IsMockObject -eq $true) {
            $autoRemovalText = "Status Unknown (SMBv1 Client Status Error)"
            $autoRemovalColor = "Error"
        }
    } else {
        # SMBv1 Client is installed or InstallPending, so we check the registry for active status.
        $autoRemovalText = $autoRemovalRegStatus.Text
        $autoRemovalColor = $autoRemovalRegStatus.Color
    }

    Show-Message "==============================" "Info"
    Show-Message "   Menu 3 - Configure SMBv1   " "Info"
    Show-Message "==============================" "Info"
    Show-Message " " "Info"
  
    $clientColor = if ($clientState -eq 'Enabled') { "Warning" } else { "Success" }
    if ($smb1ClientStatus._IsMockObject -eq $true) { $clientColor = "Error" }
    Show-Message ("Current SMBv1 Client Status: {0}" -f $clientState) $clientColor
  
    $serverColor = if ($serverState -eq 'Enabled') { "Warning" } else { "Success" }
    if ($smb1ServerStatus._IsMockObject -eq $true) { $serverColor = "Error" }
    Show-Message ("Current SMBv1 Server Status: {0}" -f $serverState) $serverColor
    Show-Message ("Automatic Removal Status   : {0}" -f $autoRemovalText) $autoRemovalColor

    Show-Message " " "Info"
  
    Show-Message "-------------------------------------" "Info"
    Show-Message "Enabling SMBv1 is a LAST RESORT for connecting to very old NAS devices." "Warning"
    Show-Message "It is highly insecure and can expose your network to threats like WannaCry." "Warning"
    Show-Message " " "Info"
    Show-Message "This script WILL NOT ENABLE SMBv1 Server Feature.  Please use the Windows Features GUI to enable it if needed." "Success"
    Show-Message " " "Info"
  
    Show-Message "A reboot is required to apply these changes." "Warning"
    Show-Message " " "Info"  
    Show-Message "    1) Enable SMBv1 Client Only (Insecure) and Configure Automatic Removal" "Warning"
    Show-Message " " "Info"
    Show-Message "    2) Disable ALL SMBv1 Components (Recommended)" "Success"
    Show-Message " " "Info"
    while ($true) {
        $selection = Read-Host "Select an option (1 or 2, or leave blank and press Enter to return to main menu)"
        if ([string]::IsNullOrWhiteSpace($selection)) {
            break
        }
  
        switch ($selection) {
            "1" {
                # --- Enable SMBv1 Client Only and Configure Automatic Removal ---
                $changesMade = $false
                $clientState = (Get-Smb1ClientStatus).State
              
                if ($clientState -eq 'Enabled') {
                    Show-Message "SMBv1 Client is already enabled. Only modifying Automatic Removal setting." "Warning"
                } else {
                    $confirm = ""
                    do {
                        $confirm = Read-Host "Are you sure you want to ENABLE the insecure SMBv1 CLIENT protocol? (Y/N)"
                        if ($confirm -notmatch "^[YyNn]$") {
                            Show-Message "Invalid selection. Please enter Y or N." "Warning"
                        }
                    } while ($confirm -notmatch "^[YyNn]$")
                  
                    if ($confirm -match "^[Yy]$") {
                        try {
                            # 1. Enable the SMB1Protocol parent feature
                            Enable-WindowsOptionalFeature -Online -FeatureName "SMB1Protocol" -NoRestart 3>$null -ErrorAction Stop | Out-Null
                            Show-Message "SMBv1 Client successfully enabled." "Success"
                            $changesMade = $true

                            # 2. Disable/Uninstall the unwanted SMBv1 Server component.
                            $serverStatusNew = Get-Smb1ServerStatus
                            if ($serverStatusNew.State -eq 'Enabled') {
                                try {
                                    # Suppress -NoRestart warning messages
                                    Disable-WindowsOptionalFeature -Online -FeatureName "SMB1Protocol-Server" -NoRestart 3>$null -ErrorAction Stop | Out-Null
                                    Show-Message "SMBv1 Server component successfully disabled." "Success"
                                } catch {
                                    Show-Message "WARNING: Could not disable SMBv1 Server feature. Manual check may be required." "Warning"
                                    Write-Log "WARNING disabling SMBv1 Server: $($_.Exception.Message)" "WARNING"
                                }
                            }
                        } catch {
                            Show-Message "ERROR: Could not complete SMBv1 Client enablement. $($_.Exception.Message)" "Error"
                            Write-Log "FATAL ERROR enabling SMBv1 Parent: $($_.Exception.Message)" "ERROR"
                            break
                        }
                    } else {
                        Show-Message "No changes applied." "Info"
                        break
                    }
                }
              
                # 3. Configure Automatic Removal (Runs for both "already enabled" and "just enabled")
                Show-Message " " "Info"
                Show-Message "--- Automatic Removal Configuration ---" "Info"
                Show-Message "SMBv1 Client has an 'Automatic Removal' feature. When enabled (default), Windows will automatically remove the Client if it detects 30 days of inactivity." "Info"
                Show-Message " " "Info"
                # Re-check status in case it was just enabled
                $autoRemovalRegStatus = Get-Smb1AutoRemovalStatus
                $autoRemovalText = $autoRemovalRegStatus.Text
                Show-Message "Current Registry Status: $autoRemovalText" $autoRemovalRegStatus.Color
                Show-Message " " "Info"
                Show-Message "1) Keep Automatic Removal Enabled (Default - Recommended for security)" "Info"
                Show-Message "2) Disable Automatic Removal (Client will stay installed permanently)" "Warning"
                Show-Message " " "Info"
              
                $autoRemovalSelection = Read-Host "Select an option (1 or 2, or leave blank to skip)"
                Show-Message " " "Info"
              
                if ([string]::IsNullOrWhiteSpace($autoRemovalSelection)) {
                    Show-Message "Automatic Removal setting was not changed." "Info"
                    Write-Log "Skipped Automatic Removal configuration."
                } else {
                    switch ($autoRemovalSelection) {
                        "1" {
                            if ($autoRemovalRegStatus.Status -eq $false) { # Only change if currently disabled (0)
                                Set-Smb1AutoRemoval $true | Out-Null
                                Write-Log "User selected to Enable SMBv1 Automatic Removal."
                                $changesMade = $true
                            } else {
                                Show-Message "Automatic Removal is already enabled." "Info"
                            }
                        }
                        "2" {
                            if ($autoRemovalRegStatus.Status -eq $true) { # Only change if currently enabled (1 or missing)
                                Set-Smb1AutoRemoval $false | Out-Null
                                Write-Log "User selected to Disable SMBv1 Automatic Removal."
                                $changesMade = $true
                            } else {
                                Show-Message "Automatic Removal is already disabled." "Info"
                            }
                        }
                        Default {
                            Show-Message "Invalid selection. Automatic Removal setting was not changed." "Warning"
                        }
                    }
                }

                # Final steps
                if ($changesMade) {
                    Write-Log "SMBv1 Client configuration complete - REBOOT REQUIRED"
                    Set-Content -Path $RebootTrackerFile -Value "Reboot Required - This file is created by the NAS / SMB Configuration Script to indicate that a system reboot is necessary to finalize SMB configuration or SMBv1 changes."
                    Show-Message " " "Info"
                    Show-Message "A reboot is required to apply these changes." "Warning"
                }
              
                break
            }
            "2" {
                # --- Disable ALL SMBv1 ---
                if ($clientState -eq 'Disabled' -or $clientState -eq 'Removed') {
                    Show-Message "SMBv1 is already disabled/removed." "Success"
                    Show-Message " " "Info"
                } else {
                    $confirm = ""
                    do {
                        $confirm = Read-Host "Are you sure you want to DISABLE ALL SMBv1 components? (Y/N)"
                        Show-Message " " "Info"
                        if ($confirm -notmatch "^[YyNn]$") {
                            Show-Message "Invalid selection. Please enter Y or N." "Warning"
                        }
                    } while ($confirm -notmatch "^[YyNn]$")
                  
                    if ($confirm -match "^[Yy]$") {
                        Show-Message "Disabling all SMBv1 components..." "Info"
                        Show-Message " " "Info"
                        try {
                            # Disable the parent feature to remove all components
                            Disable-WindowsOptionalFeature -Online -FeatureName "SMB1Protocol" -NoRestart 3>$null -ErrorAction Stop | Out-Null
                          
                            Show-Message "All SMBv1 components are now disabled." "Success"
                            Write-Log "All SMBv1 components disabled - REBOOT REQUIRED"
                          
                            # Remove the registry key as the component is gone.
                            Remove-Smb1AutoRemovalRegKey | Out-Null

                            Set-Content -Path $RebootTrackerFile -Value "Reboot Required - This file is created by the NAS / SMB Configuration Script to indicate that a system reboot is necessary to finalize SMB configuration or SMBv1 changes."
                            Show-Message " " "Info"
                            Show-Message "A reboot is required to apply these changes." "Warning"
                        } catch {
                            Show-Message "ERROR: Could not disable all SMBv1 features. Manual check may be required. $($_.Exception.Message)" "Error"
                            Write-Log "ERROR disabling all SMBv1 features: $($_.Exception.Message)" "ERROR"
                        }
                    } else {
                        Show-Message "No changes applied." "Info"
                        Write-Log "User cancelled disabling SMBv1."
                    }
                }
                break
            }
            Default { Show-Message "Invalid selection." "Warning"; Start-Sleep 0 }
        }
    }
}

function Add-LocalIntranetEntries {
    Write-Log "User selected Option 5: Entered Add Trusted Local Intranet Entries menu."
    Clear-Host
    Show-Message "============================================================" "Info"
    Show-Message "   Menu 5 - Add Trusted Local Intranet Devices To This PC   " "Info"
    Show-Message "============================================================" "Info"
    Show-Message " " "Info"
    Show-Message "Current trusted devices found on this PC:" "Info"
    Show-Message " " "Info"
    $currentEntries = Get-AllIntranetEntries
    if ($currentEntries.Count -gt 0) {
        foreach ($d in $currentEntries) { Show-Message "  - $d" "Success" }
    } else {
        Show-Message "  No trusted devices found." "Info"
    }
    Show-Message " " "Info"
    Show-Message "- Enter IP addresses or NAS/NetBIOS names below." "Info"
    Show-Message " " "Info"
    Show-Message "- Separate multiple entries by commas or hit Enter for each device." "Info"
    Show-Message " " "Info"
    Show-Message "- Leave blank and press Enter to return to main menu." "Info"
    Show-Message " " "Info"
    Show-Message "- NOTE: Some windows configurations may require a user to logoff and logon to clear security warnings" "Warning"
    Show-Message "  even though adding a device to the trusted intranet zone doesn't normally require a full reboot." "Warning"
    Show-Message " " "Info"
    Show-Message "- NOTE: If using a VPN and you are trying to access a device by its NetBIOS name or Domain/Device name, it will fail." "Warning"
    Show-Message "  You'll have to edit your Hosts File to get this work properly.  You can do this easily with Windows PowerToys." "Warning"
    $devicesAddedCount = 0
    while ($true) {
        Show-Message " " "Info"
        $inputDevices = Read-Host "Enter device(s)"
        if ([string]::IsNullOrWhiteSpace($inputDevices)) { break }
        $devices = $inputDevices -split ","
        foreach ($d in $devices) {
            $d = $d.Trim()
            if ($d -ne "") {
                if (Validate-NASDevice $d) {
                    Add-LocalIntranetEntry $d
                    $devicesAddedCount++
                }
            }
        }
    }
}

function Remove-LocalIntranetEntries {
    Write-Log "User selected Option 6: Entered Remove Trusted Local Intranet Entries menu."
    Clear-Host
    Show-Message "=================================================================" "Info"
    Show-Message "   Menu 6 - Remove Trusted Local Intranet Devices From This PC   " "Info"
    Show-Message "=================================================================" "Info"
    Show-Message " " "Info"
    Show-Message "Current trusted devices found on this PC:" "Info"
    Show-Message " " "Info"
    $currentEntries = Get-AllIntranetEntries
    if ($currentEntries.Count -gt 0) {
        foreach ($d in $currentEntries) { Show-Message "  - $d" "Success" }
    } else {
        Show-Message "  No trusted devices found." "Info"
    }
    Show-Message " " "Info"
    Show-Message "- Enter IP addresses or NAS/NetBIOS names below to remove." "Info"
    Show-Message " " "Info"
    Show-Message "- Separate multiple entries by commas or hit Enter for each device." "Info"
    Show-Message " " "Info"
    Show-Message "- Leave blank and press Enter to return to main menu." "Info"
    Show-Message " " "Info"
    $devicesRemovedCount = 0
    while ($true) {
        $inputDevices = Read-Host "Enter device(s)"
        if ([string]::IsNullOrWhiteSpace($inputDevices)) { break }
        $devices = $inputDevices -split ","
        foreach ($d in $devices) {
            $d = $d.Trim()
            if ($d -ne "") {
                Remove-LocalIntranetEntry $d
                $devicesRemovedCount++
            }
            }
        }
    }

function List-AllIntranetEntries {
    Write-Log "User selected Option 4: Listing all trusted Local Intranet entries."
    Clear-Host
    Show-Message "=================================================" "Info"
    Show-Message "   Menu 4 - All Trusted Local Intranet Entries   " "Info"
    Show-Message "=================================================" "Info"

    Show-Message " " "Info"
    Show-Message "Current trusted devices found on this PC:" "Info"
    Show-Message " " "Info"
    $allEntries = Get-AllIntranetEntries
    if ($allEntries.Count -gt 0) {
        foreach ($entry in $allEntries) { Show-Message "  - $entry" "Success" }
    } else { Show-Message "  No trusted devices found." "Info" }
    Show-Message " " "Info"
    Read-Host "Press Enter to return to menu..." | Out-Null
}

function Revert-ToWindowsDefaults {
    Write-Log "User selected Option 8: Entered Revert All SMB and SMBv1 Settings to Windows Defaults."
    Clear-Host
    Show-Message "===========================================================================================" "Info"
    Show-Message "   Menu 8 - Revert All SMB Configuration Settings and SMBv1 Settings to Windows Defaults   " "Info"
    Show-Message "===========================================================================================" "Info"
    Show-Message " " "Info"
  
    # Show current status before asking for confirmation
    $smbConfig = Get-SmbClientConfiguration
    $smb1ClientStatus = Get-Smb1ClientStatus
    $smb1ServerStatus = Get-Smb1ServerStatus
    $clientState = $smb1ClientStatus.State
  
    # Apply conditional display logic for Auto Removal based on client status
    $autoRemovalRegStatus = Get-Smb1AutoRemovalStatus
  
    if ($clientState -eq 'Disabled' -or $clientState -eq 'Removed' -or $clientState -eq 'DisablePending' -or $smb1ClientStatus._IsMockObject -eq $true) {
        # If the feature is not installed or is being removed, auto removal is irrelevant.
        $autoRemovalText = "Disabled"
        $autoRemovalColor = "Success"
        if ($autoRemovalRegStatus.Status -eq $false) {
            $autoRemovalText = "Key Present/Disabled (Feature is Disabled/Removed)"
            $autoRemovalColor = "Info"
        }
        if ($smb1ClientStatus._IsMockObject -eq $true) {
            $autoRemovalText = "Status Unknown (SMBv1 Client Status Error)"
            $autoRemovalColor = "Error"
        }
    } else {
        # SMBv1 Client is installed or InstallPending, so we check the registry for active status.
        $autoRemovalText = $autoRemovalRegStatus.Text
        $autoRemovalColor = $autoRemovalRegStatus.Color
    }
  
    Show-Message "Current SMB Client Configuration and SMBv1 Status:" "Info"
    Show-Message " " "Info"
    Show-Message ("{0,-28}: {1}" -f "RequireSecuritySignature", $smbConfig.RequireSecuritySignature) "Info"
    Show-Message ("{0,-28}: {1}" -f "EnableInsecureGuestLogons", $smbConfig.EnableInsecureGuestLogons) "Info"
    Show-Message ("{0,-28}: {1}" -f "SMBv1 Client Status", $clientState) "Info"
    Show-Message ("{0,-28}: {1}" -f "SMBv1 Server Status", $smb1ServerStatus.State) "Info"
    Show-Message ("{0,-28}: {1}" -f "SMBv1 Auto Removal", $autoRemovalText) "Info"


    Show-Message " " "Info"
    Show-Message "-------------------------------------" "Info"
    Show-Message " " "Info"
    Show-Message "This will revert your system to the default, more secure settings." "Success"
    Show-Message "This includes disabling insecure guest logins, enabling security signatures, and disabling SMBv1." "Success"
    Show-Message " " "Info"

    $confirm = ""
    do {
        $confirm = Read-Host "Are you sure you want to revert all SMB settings to Windows defaults? (Y/N)"
        Show-Message " " "Info"
        if ($confirm -notmatch "^[YyNn]$") {
            Show-Message "Invalid selection. Please enter Y or N." "Warning"
        }
    } while ($confirm -notmatch "^[YyNn]$")
  
    if ($confirm -match "^[Yy]$") {
        $changesMade = $false
      
        # Revert less secure settings
        if ($smbConfig.EnableInsecureGuestLogons -eq $true -or $smbConfig.RequireSecuritySignature -eq $false) {
            Set-SmbClientConfiguration -EnableInsecureGuestLogons $false -RequireSecuritySignature $true -Force | Out-Null
            Show-Message "SMB configuration reverted to Windows Default." "Success"
            Show-Message " " "Info"
            $changesMade = $true
            Write-Log "SMB client configuration reverted to Windows defaults."
        } else {
            Show-Message "SMB client settings are already at Windows defaults." "Info"
            Show-Message " " "Info"
        }
      
        # Revert SMBv1
        if ($smb1ClientStatus.State -eq 'Enabled' -or $smb1ServerStatus.State -eq 'Enabled') {
            # Disable the parent feature to remove all components
            Disable-WindowsOptionalFeature -Online -FeatureName "SMB1Protocol" -NoRestart 3>$null | Out-Null
            Show-Message "SMBv1 is now disabled (Client and Server)." "Success"
            Show-Message " " "Info"
            Remove-Smb1AutoRemovalRegKey | Out-Null # Remove registry key on full disable
            $changesMade = $true
            Write-Log "SMBv1 disabled and registry key removed."
        } else {
            Show-Message "SMBv1 is already uninstalled or unavailable." "Info"
            Show-Message " " "Info"
        }
      
        if ($changesMade) {
            Set-Content -Path $RebootTrackerFile -Value "Reboot Required - This file is created by the NAS / SMB Configuration Script to indicate that a system reboot is necessary to finalize SMB configuration or SMBv1 changes."
            Show-Message " " "Info"
            Show-Message "A reboot is required to apply these changes." "Warning"
            Write-Log "Reversion completed - REBOOT REQUIRED."
        } else {
            Write-Log "Reversion confirmed, but no changes were necessary as settings were already at default."
        }
    } else {
        Show-Message "Reversion cancelled. No changes were made." "Info"
        Write-Log "Reversion of all SMB and SMBv1 settings cancelled by user."
    }
  
    Show-Message " " "Info"
    Read-Host "Press Enter to return to main menu..." | Out-Null
}

function View-LogFile {
    Write-Log "User selected Option 9: Viewing script log file."
    Clear-Host
    Show-Message "--- Viewing Log File: $LogFile ---" "Info"
    Show-Message " " "Info"
  
    if (Test-Path $LogFile) {
        try {
            Get-Content $LogFile | Out-Host -Paging
        } catch {
        }
    } else {
        Show-Message "Log file not found." "Error"
        Write-Log "Attempted to view log file, but it was not found." "ERROR"
    }

    Show-Message " " "Info"
    Read-Host "Press Enter to return to menu..." | Out-Null
}


# ===============================================
# --- BOOTSTRAP / INITIALIZATION ---
# This section sets up the logging environment, checks for Administrator privileges,
# and configures console encoding.
# ===============================================

# 1. Create log folder and write session separator.
if (-not (Test-Path $logFolder)) { New-Item -ItemType Directory -Path $logFolder | Out-Null -ErrorAction Stop }

# Log script start and session separation. This ensures blank lines precede the session start log.
if (Test-Path $LogFile) {
    # Add two blank lines for session separation
    " " | Out-File -FilePath $LogFile -Append -Encoding UTF8
    " " | Out-File -FilePath $LogFile -Append -Encoding UTF8
}
Write-Log "------------------- NEW SCRIPT SESSION STARTED -------------------"

# 2. Check for Administrator privileges
If (-NOT ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) {
  
    Write-Host "ERROR: Script must be run as Administrator!" -ForegroundColor Red
    Read-Host "Press Enter to exit..." | Out-Null
    Exit 1
}

# 3. Set encoding for proper display of all characters
chcp 65001 >$null
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
[Console]::InputEncoding = [System.Text.Encoding]::UTF8

Write-Log "Script execution started."


# ===============================================
# --- MAIN SCRIPT LOGIC ---
# This is the main execution loop, responsible for module loading,
# checking for pending reboots, and displaying the interactive menu.
# It is wrapped in a TRY/CATCH block to handle fatal runtime errors.
# ===============================================
try {
    $exitRequested = $false
  
    # --- Import Required Modules ---
    Write-Log "Attempting to import required PowerShell modules (SmbShare and Dism)."
    Import-Module SmbShare -ErrorAction SilentlyContinue | Out-Null
    Import-Module Dism -ErrorAction SilentlyContinue | Out-Null
    Write-Log "Module import attempted."

    # --- New PC Logging Check ---
    $currentComputerName = $env:COMPUTERNAME
    $lastKnownComputerName = ""
    if (Test-Path $LastPCFile) {
        $lastKnownComputerName = Get-Content $LastPCFile
    }

    if ($lastKnownComputerName -ne $currentComputerName) {
        Write-Log "WARNING: Computer name changed from '$lastKnownComputerName' to '$currentComputerName'. Resetting LastPC tracker." "WARNING"
        # Only reset the tracker, the session separation lines are already written above.
        Set-Content -Path $LastPCFile -Value $currentComputerName
    }

    # --- Reboot Check ---
    if (Test-Path $RebootTrackerFile) {
        $fileCreationTime = (Get-Item $RebootTrackerFile).LastWriteTime
        $currentBootTime = (Get-CimInstance -ClassName Win32_OperatingSystem).LastBootUpTime
      
        # Compare last boot time to the file's last write time.
        if ($currentBootTime -gt $fileCreationTime) {
            Remove-Item -Path $RebootTrackerFile -ErrorAction SilentlyContinue
        } else {
            Clear-Host # Add clear host to make the prompt stand out
            Show-Message " " "Info"
            Show-Message "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" "Error"
            Show-Message "!!!                  REBOOT REQUIRED                  !!!" "Error"
            Show-Message "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" "Error"
            Show-Message " " "Info"
            Show-Message "A REBOOT IS REQUIRED to finalize a previous configuration change." "Warning"
            Show-Message "*** Please save all your work before proceeding with the reboot. ***" "Warning"
            Show-Message " " "Info"
          
            Write-Log "PROMPT: Reboot required. Asking user to Continue or Exit."

            # Present Options
            Show-Message "------------------------------------------------- " "Info"
            Show-Message " " "Info"
            Show-Message "1) Continue to Main Menu (You can reboot from inside the script or reboot manually later)" "Info"
            Show-Message " " "Info"
            Show-Message "2) Exit Script (To reboot now manually)" "Info"
            Show-Message " " "Info"
            Show-Message "------------------------------------------------- " "Info"
            Show-Message " " "Info"
          
            $rebootSelection = ""
            do {
                $rebootSelection = Read-Host "Select 1 or 2"
                if ($rebootSelection -notmatch "^[12]$") {
                    Show-Message "Invalid selection. Please enter 1 or 2." "Warning"
                }
            } while ($rebootSelection -notmatch "^[12]$")

            if ($rebootSelection -eq "2") {
                Write-Log "User chose to exit script to perform manual reboot."
                Clear-Host
                Show-Message "Script exiting." "Success"
                Show-Message " " "Info"
                Show-Message "Please save all your work." "Warning"
                Show-Message "Then, reboot your computer MANUALLY now to apply the changes." "Warning"
                Show-Message " " "Info"
                Read-Host "Press Enter to exit..." | Out-Null
                exit 0 # Terminate the script cleanly
            } else {
                Write-Log "User chose to continue to main menu despite pending reboot."
                Show-Message "Continuing to Main Menu..." "Success"
                Start-Sleep 1 # A brief pause for confirmation
            }
        }
    }
  
    # --- Main Menu Loop ---
    while (-not $exitRequested) {
        Clear-Host
        if (Test-Path $RebootTrackerFile) {
            Show-Message "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" "Warning"
            Show-Message "!!!     WARNING: A REBOOT IS REQUIRED TO APPY PREVIOUS CHANGES    !!!" "Warning"
            Show-Message "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" "Warning"
            Show-Message " " "Info"
        }
        Show-Message "===================================================================================================================" "Success"
        Show-Message "                  Main Menu - Portable NAS / SMB Configuration & SMBv1 Client Configuration Script                 " "Success"
        Show-Message "                           by Jeremy / BLzNFuN using Gemini  email: [email protected]                            " "Success"
        Show-Message "                                                     v 1.1.0                                                       " "Info"
        Show-Message "===================================================================================================================" "Success"
        Show-Message " " "Info"
        Show-Message "IMPORTANT: Some changes will require a reboot or logoff. Please save all your work before proceeding." "Warning"
        Show-Message " " "Info"
        Show-Message "NOTE: A 'nas_smb_reboot_required.txt' file will be created in the %temp% directory for the reboot tracking logic." "Warning"
        Show-Message "      It will be permantly deleted upon a successful reboot if the script is ran again." "Warning"
        Show-Message " " "Info"
        Show-Message "NOTE: A 'last_run_pc.txt' file will be created in the 'logs' folder for logging purposes when it comes to running" "Warning"
        Show-Message "      the script between multiple PCs (Portable). This is so the user can see logged functions across multiple PCs." "Warning"
        Show-Message " " "Info"
        Show-Message ("{0,2}) {1}" -f 1, "Show current SMB and Trusted Local Intranet Status") "Info"
        Show-Message ("{0,2}) {1}" -f 2, "Configure SMB (Applies Common Fixes For Folder Refresh & Access, etc.)") "Info"
        Show-Message ("{0,2}) {1}" -f 3, "Configure SMBv1 Client (Last Resort AFTER Applying Option 2 For Connecting to Legacy Devices) (EXTREME RISK!)") "Error"
        Show-Message " " "Info"
        Show-Message ("{0,2}) {1}" -f 4, "List All Trusted Local Intranet Entries On This PC") "Info"
        Show-Message ("{0,2}) {1}" -f 5, "Add Trusted Local Intranet Entries To This PC (Helps Prevent Security Warnings)") "Info"
        Show-Message ("{0,2}) {1}" -f 6, "Remove Trusted Local Intranet Entries From This PC") "Info"
        Show-Message ("{0,2}) {1}" -f 7, "Remove ALL Trusted Devices From This PC") "Info"
        Show-Message " " "Info"
        Show-Message ("{0,2}) {1}" -f 8, "Revert All SMB Configuration Settings and SMBv1 Settings To Windows Defaults.") "Info"
        Show-Message " " "Info"
        Show-Message ("{0,2}) {1}" -f 9, "View Script Log File (Stored In 'logs' folder)") "Info"
        Show-Message " " "Info"
        Show-Message ("{0,2}) {1}" -f 10, "Exit (You Must Manually Reboot If Required)") "Info"
        Show-Message ("{0,2}) {1}" -f 11, "Exit and Reboot (If Required)") "Info"
        Show-Message " " "Info"
        $selection = Read-Host "Select an option (1-11)"
        switch ($selection) {
            "1" { Show-CurrentStatus }
            "2" { Configure-Option2 }
            "3" { Configure-Smb1 }
            "4" { List-AllIntranetEntries }
            "5" { Add-LocalIntranetEntries }
            "6" { Remove-LocalIntranetEntries }
            "7" { Remove-AllIntranetEntries }
            "8" { Revert-ToWindowsDefaults }
            "9" { View-LogFile }
            "10" {
                Write-Log "User selected Option 10: Exit (Reboot Manually If Required)."
                if (Test-Path $RebootTrackerFile) {
                    Show-Message " " "Info"
                    Show-Message "--- REBOOT REQUIRED ---" "Warning"
                    Show-Message "A reboot is required to apply the changes you made to SMB settings." "Warning"
                    Show-Message "Please save all your work before manually rebooting your computer." "Warning"
                    Show-Message " " "Info"
                  
                    $confirm = ""
                    do {
                        $confirm = Read-Host "Do you wish to exit the script? (Y/N)"
                        if ($confirm -notmatch "^[YyNn]$") {
                            Show-Message "Invalid selection. Please enter Y or N." "Warning"
                        }
                    } while ($confirm -notmatch "^[YyNn]$")
                  
                    if ($confirm -match "^[Yy]$") {
                        Write-Log "Exiting script while reboot is pending."
                        $exitRequested = $true
                    }
                } else {
                    Show-Message " " "Info"
                    Show-Message "No reboot is required. No SMB changes were made that need a reboot." "Success"
                    Show-Message " " "Info"
                  
                    $confirm = ""
                    do {
                        $confirm = Read-Host "Do you wish to exit the script? (Y/N)"
                        if ($confirm -notmatch "^[YyNn]$") {
                            Show-Message "Invalid selection. Please enter Y or N." "Warning"
                        }
                    } while ($confirm -notmatch "^[YyNn]$")
                  
                    if ($confirm -match "^[Yy]$") {
                        Write-Log "Exiting script gracefully."
                        $exitRequested = $true
                    }
                }
            }
            "11" {
                Write-Log "User selected Option 11: Exit and Reboot (If Required)."
                if (Test-Path $RebootTrackerFile) {
                    Show-Message " " "Info"
                    Show-Message "--- REBOOTING TO APPLY CHANGES ---" "Warning"
                    Show-Message "A reboot is required to apply the changes you made to SMB settings." "Warning"
                    Show-Message "You will lose any unsaved work if you proceed now! Please save your work now!" "Warning"
                    Show-Message " " "Info"
                  
                    $confirm = ""
                    do {
                        $confirm = Read-Host "Are you sure you wish to reboot now? (Y/N)"
                        if ($confirm -notmatch "^[YyNn]$") {
                            Show-Message "Invalid selection. Please enter Y or N." "Warning"
                        }
                    } while ($confirm -notmatch "^[YyNn]$")
                  
                    if ($confirm -match "^[Yy]$") {
                        Write-Log "Confirmed immediate system reboot."
                        Show-Message "Press Enter to reboot..." "Info"
                        Read-Host | Out-Null
                        Restart-Computer
                        $exitRequested = $true
                    } else {
                        Show-Message "Reboot cancelled." "Info"
                        Write-Log "Immediate system reboot cancelled by user."
                      
                        $confirmExit = ""
                        do {
                            $confirmExit = Read-Host "Do you still wish to exit the script? (Y/N)"
                            if ($confirmExit -notmatch "^[YyNn]$") {
                                Show-Message "Invalid selection. Please enter Y or N." "Warning"
                            }
                        } while ($confirmExit -notmatch "^[YyNn]$")
                      
                        if ($confirmExit -match "^[Yy]$") {
                            $exitRequested = $true
                        }
                    }
                } else {
                    Show-Message " " "Info"
                    Show-Message "No reboot is required. No SMB changes were made that need a reboot." "Success"
                    Show-Message " " "Info"
                  
                    $confirm = ""
                    do {
                        $confirm = Read-Host "Do you wish to exit the script? (Y/N)"
                        if ($confirm -notmatch "^[YyNn]$") {
                            Show-Message "Invalid selection. Please enter Y or N." "Warning"
                        }
                    } while ($confirm -notmatch "^[YyNn]$")
                  
                    if ($confirm -match "^[Yy]$") {
                        Write-Log "Exiting script gracefully."
                        $exitRequested = $true
                    }
                }
            }
            Default {
                Show-Message "Invalid selection." "Warning";
                Start-Sleep 1
            }
        }
    }
} catch {
    # === CRITICAL FINAL CATCH BLOCK (To attempt logging under fatal script errors) ===
  
    # 1. Attempt to log the error information directly for maximum stability.
    # We bypass the Write-Log function here to ensure this final log attempt is as simple as possible.
    $timestamp = Get-Date -Format "yyyy-MM-dd hh:mm:ss tt"
    $computerName = $env:COMPUTERNAME
  
    # Capture the error message and full details (including stack trace)
    $errorMessage = $_.Exception.Message
    $errorDetails = $_ | Out-String
  
    # Format the final log entry. Use SilentlyContinue to prevent a crash if the log file is locked.
    $logEntry = "`n[FATAL_CRASH] $timestamp [$computerName] - Unhandled Script Crash: $errorMessage`n$errorDetails`n"
    Add-Content -Path $LogFile -Value $logEntry -Encoding UTF8 -ErrorAction SilentlyContinue | Out-Null
  
    Clear-Host
  
    Write-Host "=======================================================" -ForegroundColor Red
    Write-Host "         FATAL SCRIPT ERROR - EXECUTION HALTED         " -ForegroundColor Red
    Write-Host "=======================================================" -ForegroundColor Red
  
    Write-Host "`n"
    Write-Host "A CRITICAL, UNHANDLED ERROR occurred during script execution." -ForegroundColor Yellow
  
    # Display message is updated to confirm that logging was attempted.
    Write-Host "An attempt was made to log the crash details to 'script_log.log'." -ForegroundColor Yellow
    Write-Host "Please check the log file for the **FATAL_CRASH** entry." -ForegroundColor Yellow
  
    # CRITICAL: The one and only action to keep the console open.
    Read-Host "`nPress Enter to exit..." | Out-Null
}

# IMPORTANT: Final logging on manual exit
Write-Log "Script exited normally."
 
Last edited:

My Computer My Computer

At a glance

Windows 11 Pro x3i9-14900K / i9-14900HX / AMD Z1E64 GSkill / 64 Gskill / 24EVGA 3080 Ultra FTW 3 / 4070 Mobile / Z1E
OS
Windows 11 Pro x3
Computer type
PC/Desktop
Manufacturer/Model
Asus / Asus / Asus
CPU
i9-14900K / i9-14900HX / AMD Z1E
Motherboard
Asus Apex Encore / Asus G16 (2024) / ROG Ally X
Memory
64 GSkill / 64 Gskill / 24
Graphics Card(s)
EVGA 3080 Ultra FTW 3 / 4070 Mobile / Z1E
Sound Card
Logitech G Pro
Screen Resolution
2560 x 1080 / 2560 x 1600 / 1920 x 1080
Hard Drives
990 pro 4 TB, 4x 980 1TB, 980 pro 2TB
Back
Top Bottom