sjbesenski
Member
- Joined
- Nov 21, 2025
- Messages
- 71
- Thread Author
-
- #1
I am looking for a way to programmatically Uncheck Enable Selective Suspend on all USB Serial Ports in device manager. I changed the value of DeviceSelectiveSuspend to 0 in the registry manager but the change doesn't persist over a reboot. I have also changed my power settings to disable USB selective suspend. I cannot get this change to persist any way other than opening device manager going to advanced settings and actually unchecking Enable Selective Suspend in each COM port device. I have a large number of devices and PCs I need to do this for and do not want to manually uncheck this box on every device on every PC. Happy to share photos of everything I have tried in the registry editor that has not worked yet. This is specifically for FTDI devices if that help. Windows 11 Desktop PC.
- Joined
- Mar 14, 2023
- Messages
- 97,513
Got it — I edited your script so it will set the PortName registry value when it is missing (and only then), using the system mapping so Device Manager’s Advanced page will show the COM port instead of blank. If the script can’t discover a COM name it will NOT write a blank PortName. It still obeys your existing rules: only create properties that are missing, only touch existing Serial‑Enumerator‑like properties if they already exist, logs everything, and reboots if changes were applied (unless you used -WhatIf or -NoReboot).
Save this file as Disable-FTDI-SelectiveSuspend-ApplyIfMissing-WithPortName.ps1 and run elevated.
Changes:
How this ensures Device Manager shows the COM:
Save this file as Disable-FTDI-SelectiveSuspend-ApplyIfMissing-WithPortName.ps1 and run elevated.
Changes:
- New logic after selective‑suspend writes: if PortName is missing/empty, try to discover the assigned COM via Win32_SerialPort (PNPDeviceID or the instance tail) and create PortName = "COMn".
- Does not overwrite an existing PortName.
- If PortName could not be discovered, it does nothing (no blank value).
- All writes respect -WhatIf and -NoReboot.
Code:
<#
Disable-FTDI-SelectiveSuspend-ApplyIfMissing-WithPortName.ps1
- Only creates selective-suspend properties if they do not already exist.
- If any changes are made (and not -WhatIf), reboots the PC (15s countdown) so Windows picks up changes.
- If PortName is missing, attempts to detect the assigned COM (via Win32_SerialPort) and writes PortName so Device Manager Advanced shows the COM. Run as Administrator.
#> param( [switch]$WhatIf, # dry run: show what would change, do not write or reboot [switch]$NoReboot # if specified, do not reboot even when changes were made) # Ensure elevated
if (-not ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent.IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator) { Write-Error "Run this script in an elevated PowerShell (Run as Administrator). Exiting." exit 1
} $timestamp = (Get-Date).ToString('yyyyMMdd_HHmmss')
$logFile = Join-Path $env:USERPROFILE "Desktop\FTDI_ApplyIfMissing_$timestamp.log"
"Started: $(Get-Date -Format u)" | Out-File -FilePath $logFile -Encoding UTF8 # Regex for detecting existing serial-enumerator-like properties (we only touch existing ones)
$serialEnumRegex = '(serial.*enum|enum.*serial|serialenumerator|enable.*serial)' # Trackers
$changedDevices = @
$skippedDevices = @
$errors = @ # Discover FTDI COM ports
$ports = Get-PnpDevice -Class Ports -PresentOnly -ErrorAction SilentlyContinue | Where-Object { ($_.Manufacturer -and $_.Manufacturer -like '*FTDI*') -or ($_.InstanceId -and $_.InstanceId -match 'VID_0403') } if (-not $ports -or $ports.Count -eq 0) { "No FTDI COM ports found." | Tee-Object -FilePath $logFile -Append Write-Output "No FTDI COM ports found. See log: $logFile" exit 0
} "Found $($ports.Count) FTDI COM port(s)." | Tee-Object -FilePath $logFile -Append # helper: find COM assigned to a PnP instance (tries exact match then tail-match)
function Get-ComForInstance { param($instanceId) # Try exact PNPDeviceID match in Win32_SerialPort try { $sp = Get-CimInstance -ClassName Win32_SerialPort -ErrorAction SilentlyContinue | Where-Object { $_.PNPDeviceID -eq $instanceId } if ($sp) { return $sp.DeviceID } # returns "COM3" etc. } catch { } # If exact match failed, try matching the last segment of InstanceId $tail = $instanceId.Split('\')[-1] try { $sp2 = Get-CimInstance -ClassName Win32_SerialPort -ErrorAction SilentlyContinue | Where-Object { $_.PNPDeviceID -like "*$tail*" } if ($sp2) { return $sp2[0].DeviceID } } catch { } # Fallback: try HARDWARE\DEVICEMAP\SERIALCOMM mapping (attempt to find a value that contains the tail) try { $map = Get-Item -Path 'HKLM:\HARDWARE\DEVICEMAP\SERIALCOMM' -ErrorAction SilentlyContinue if ($map) { $values = Get-ItemProperty -Path 'HKLM:\HARDWARE\DEVICEMAP\SERIALCOMM' -ErrorAction SilentlyContinue foreach ($name in ($values.PSObject.Properties | Where-Object { $_.Name -ne 'PSPath' -and $_.Name -ne 'PSParentPath' -and $_.Name -ne 'PSChildName' -and $_.Name -ne 'PSDrive' -and $_.Name -ne 'PSProvider' } | Select-Object -ExpandProperty Name) { $val = (Get-ItemProperty -Path 'HKLM:\HARDWARE\DEVICEMAP\SERIALCOMM' -Name $name -ErrorAction SilentlyContinue).$name if ($name -like "*$tail*" -or $val -like "COM*") { # best-effort: return the value found return $val } } } } catch { } return $null
} foreach ($p in $ports) { "----" | Tee-Object -FilePath $logFile -Append "FriendlyName: $($p.FriendlyName)" | Tee-Object -FilePath $logFile -Append "InstanceId: $($p.InstanceId)" | Tee-Object -FilePath $logFile -Append $inst = $p.InstanceId if ([string]::IsNullOrWhiteSpace($inst) { "InstanceId empty; skipping." | Tee-Object -FilePath $logFile -Append $skippedDevices += $inst continue } $base = "HKLM:\SYSTEM\CurrentControlSet\Enum\$inst" $dpCandidates = @( "$base\Device Parameters", "$base\0000\Device Parameters") $foundDP = $false $deviceWasChanged = $false foreach ($dp in $dpCandidates) { "Checking: $dp" | Tee-Object -FilePath $logFile -Append if (Test-Path $dp) { $foundDP = $true "Found Device Parameters: $dp" | Tee-Object -FilePath $logFile -Append # helper: check existence of a named property function Property-Exists { param($Path, $Name) try { $val = Get-ItemProperty -Path $Path -Name $Name -ErrorAction SilentlyContinue return ($null -ne $val) } catch { return $false } } # Only create if property does NOT exist $propsToEnsure = @{ 'DeviceIdleEnabled' = 0 'DefaultIdleState' = 0 'UserSetDeviceIdleEnabled' = 0 'SSIdleTimeout' = 0 } foreach ($kv in $propsToEnsure.GetEnumerator { $name = $kv.Key $desired = $kv.Value $exists = Property-Exists -Path $dp -Name $name if ($exists) { "$name already exists at $dp (skipping creation)." | Tee-Object -FilePath $logFile -Append } else { if ($WhatIf) { "WhatIf: would create $name = $desired at $dp" | Tee-Object -FilePath $logFile -Append $deviceWasChanged = $true } else { try { New-Item -Path $dp -Force | Out-Null New-ItemProperty -Path $dp -Name $name -PropertyType DWord -Value $desired -Force -ErrorAction Stop | Out-Null "Created $name = $desired at $dp" | Tee-Object -FilePath $logFile -Append $deviceWasChanged = $true } catch { "ERROR creating $name at $dp : $($_.Exception.Message)" | Tee-Object -FilePath $logFile -Append $errors += "ERROR creating $name at $dp : $($_.Exception.Message)" } } } } # Disable any existing Serial Enumerator-like properties (only if they exist) try { $existingProps = (Get-ItemProperty -Path $dp -ErrorAction SilentlyContinue).PSObject.Properties | ForEach-Object { $_.Name } } catch { $existingProps = @ } foreach ($propName in $existingProps) { if ($propName -match $serialEnumRegex) { # read current value try { $curVal = Get-ItemProperty -Path $dp -Name $propName -ErrorAction SilentlyContinue | Select-Object -ExpandProperty $propName -ErrorAction SilentlyContinue } catch { $curVal = $null } if ($null -eq $curVal) { $curVal = $null } # treat missing as null if ($null -eq $curVal) { # property exists but no value? create as 0 if ($WhatIf) { "WhatIf: would set existing $propName = 0 at $dp (regex matched)" | Tee-Object -FilePath $logFile -Append $deviceWasChanged = $true } else { try { New-ItemProperty -Path $dp -Name $propName -PropertyType DWord -Value 0 -Force -ErrorAction Stop | Out-Null "Set existing $propName = 0 at $dp (regex matched)" | Tee-Object -FilePath $logFile -Append $deviceWasChanged = $true } catch { "ERROR writing $propName at $dp : $($_.Exception.Message)" | Tee-Object -FilePath $logFile -Append $errors += "ERROR writing $propName at $dp : $($_.Exception.Message)" } } } else { # existing numeric value: only change if it does not exist (user requested only create-if-missing), # so we will NOT overwrite. Log it and skip. "$propName exists with value $curVal at $dp (no overwrite per policy)." | Tee-Object -FilePath $logFile -Append } } } # --- PortName logic: ensure PortName exists and is not blank in Device Manager --- # Only create PortName if it does not exist or is empty, and if we can discover the COM $portExists = Property-Exists -Path $dp -Name 'PortName' $currentPortName = $null if ($portExists) { try { $currentPortName = (Get-ItemProperty -Path $dp -Name 'PortName' -ErrorAction SilentlyContinue).PortName } catch { $currentPortName = $null } } if (-not $portExists -or [string]::IsNullOrWhiteSpace($currentPortName) { # Try to discover COM assigned to this instance $detectedCOM = Get-ComForInstance -instanceId $inst if ($detectedCOM) { if ($WhatIf) { "WhatIf: would create PortName = $detectedCOM at $dp" | Tee-Object -FilePath $logFile -Append $deviceWasChanged = $true } else { try { New-Item -Path $dp -Force | Out-Null New-ItemProperty -Path $dp -Name 'PortName' -PropertyType String -Value $detectedCOM -Force -ErrorAction Stop | Out-Null "Created PortName = $detectedCOM at $dp (so Device Manager will show COM)" | Tee-Object -FilePath $logFile -Append $deviceWasChanged = $true } catch { "ERROR writing PortName at $dp : $($_.Exception.Message)" | Tee-Object -FilePath $logFile -Append $errors += "ERROR writing PortName at $dp : $($_.Exception.Message)" } } } else { "Could not detect COM for instance $inst; will NOT write blank PortName." | Tee-Object -FilePath $logFile -Append } } else { "PortName already present ('$currentPortName') at $dp (no change)." | Tee-Object -FilePath $logFile -Append } break # exit candidates loop for this device } else { "Not found: $dp" | Tee-Object -FilePath $logFile -Append } } if (-not $foundDP) { "Device Parameters not found for instance $inst. Skipping." | Tee-Object -FilePath $logFile -Append $skippedDevices += $inst } else { if ($deviceWasChanged) { $changedDevices += $inst } else { $skippedDevices += $inst } }
} # Summary logging
"=== Summary ===" | Tee-Object -FilePath $logFile -Append
"Devices changed: $($changedDevices.Count)" | Tee-Object -FilePath $logFile -Append
if ($changedDevices.Count -gt 0) { $changedDevices | Tee-Object -FilePath $logFile -Append } "Devices skipped/already-compliant: $($skippedDevices.Count)" | Tee-Object -FilePath $logFile -Append
if ($skippedDevices.Count -gt 0) { $skippedDevices | Tee-Object -FilePath $logFile -Append } if ($errors.Count -gt 0) { "Errors encountered: $($errors.Count)" | Tee-Object -FilePath $logFile -Append $errors | Tee-Object -FilePath $logFile -Append
} # Reboot if changes were made and not a dry run and not suppressed
if (($changedDevices.Count -gt 0) -and (-not $WhatIf) -and (-not $NoReboot) { "Changes applied. Rebooting in 15 seconds to apply changes..." | Tee-Object -FilePath $logFile -Append Write-Output "Changes applied. Rebooting in 15 seconds to apply changes..." Start-Process -FilePath "shutdown.exe" -ArgumentList "/r /t 15 /c `"`"Applying FTDI Device Parameter changes`"`"" -NoNewWindow
} else { if ($changedDevices.Count -eq 0) { "No updates were necessary. No reboot will be performed." | Tee-Object -FilePath $logFile -Append Write-Output "No updates were necessary." } else { "No reboot requested (NoReboot specified or WhatIf). Review log: $logFile" | Tee-Object -FilePath $logFile -Append Write-Output "Changes applied but reboot suppressed. Review log: $logFile" }
} "Completed: $(Get-Date -Format u)" | Tee-Object -FilePath $logFile -Append
Write-Output "Done. Log saved to: $logFile"
- Device Manager reads the PortName value under the device’s Device Parameters to populate the Advanced → COM Port dropdown/display. By creating PortName with the actual COM (COM3/COM4/etc. the Advanced dialog will show that COM instead of a blank field (after a rescan/reboot).
- Joined
- Mar 14, 2023
- Messages
- 97,513
Thanks — the screenshot helps. That “Serial Enumerator” checkbox is a per‑device property stored under the device’s Device Parameters key (HKLM\SYSTEM\CurrentControlSet\Enum\<device‑instance>\Device Parameters). Before I change anything for every device I want to identify the exact registry value your FTDI driver uses when you toggle that checkbox on this machine — then I’ll add that exact name to the script so it only touches the correct property.
Please run this short, elevated PowerShell diagnostic. It:
if (-not $inst) { Write-Error 'No FTDI COM port found. Run Get-PnpDevice -Class Ports to confirm.'; break }
$enumBase = 'HKLM:\SYSTEM\CurrentControlSet\Enum'
$regPath = Join-Path $enumBase ($inst -replace '\','\')
$dp = Join-Path $regPath 'Device Parameters'
Write-Output "Using instance: $inst"
Write-Output "Device Parameters path: $dp"
$before = @{}
if (Test-Path $dp) { $before = Get-ItemProperty -Path $dp | Select-Object -Property | ConvertTo-Json -Depth 4 } else { Write-Output "Device Parameters key not found." ; break }
$beforeFile = "$env:USERPROFILE\Desktop\FTDI_before.json"
$afterFile = "$env:USERPROFILE\Desktop\FTDI_after.json"
$before | Out-File -FilePath $beforeFile -Encoding utf8
Write-Output "Saved before state to $beforeFile"
Write-Output "Now open Device Manager → Ports → (your COM) → Properties → Advanced, toggle Serial Enumerator, click OK, then come back here and press Enter."
Read-Host -Prompt "Press Enter after toggling Serial Enumerator"
$after = Get-ItemProperty -Path $dp | Select-Object -Property | ConvertTo-Json -Depth 4
$after | Out-File -FilePath $afterFile -Encoding utf8
Write-Output "Saved after state to $afterFile"
$a = (Get-Content $afterFile -Raw | ConvertFrom-Json)
$changed = @
foreach ($name in ($b | Get-Member -MemberType NoteProperty | Select-Object -Expand Name) {
$bv = $b.$name
$av = $a.$name
if ($bv -ne $av) { $changed += [pscustomobject]@{ Property = $name; Before = $bv; After = $av } }
}
if ($changed.Count -eq 0) { Write-Output "No property values changed. Paste the two JSON files if you want me to inspect further." } else { $changed | Format-Table -AutoSize; $changed | Out-File -FilePath "$env:USERPROFILE\Desktop\FTDI_changed_props.txt" ; Write-Output "Changed properties saved to FTDI_changed_props.txt on your Desktop." }
What I need from you
Please run this short, elevated PowerShell diagnostic. It:
- finds one FTDI COM port,
- saves the Device Parameters state to a file,
- prompts you to toggle the Serial Enumerator checkbox in Device Manager for that COM port (open Advanced settings → change the checkbox then click OK),
- then captures the after state and prints the properties that changed.
Run this in an elevated PowerShell
$inst = (Get-PnpDevice -Class Ports -PresentOnly | Where-Object { ($.Manufacturer -and $.Manufacturer -like 'FTDI') -or ($_.InstanceId -match 'VID_0403') } | Select-Object -First 1).InstanceIdif (-not $inst) { Write-Error 'No FTDI COM port found. Run Get-PnpDevice -Class Ports to confirm.'; break }
$enumBase = 'HKLM:\SYSTEM\CurrentControlSet\Enum'
$regPath = Join-Path $enumBase ($inst -replace '\','\')
$dp = Join-Path $regPath 'Device Parameters'
Write-Output "Using instance: $inst"
Write-Output "Device Parameters path: $dp"
$before = @{}
if (Test-Path $dp) { $before = Get-ItemProperty -Path $dp | Select-Object -Property | ConvertTo-Json -Depth 4 } else { Write-Output "Device Parameters key not found." ; break }
$beforeFile = "$env:USERPROFILE\Desktop\FTDI_before.json"
$afterFile = "$env:USERPROFILE\Desktop\FTDI_after.json"
$before | Out-File -FilePath $beforeFile -Encoding utf8
Write-Output "Saved before state to $beforeFile"
Write-Output "Now open Device Manager → Ports → (your COM) → Properties → Advanced, toggle Serial Enumerator, click OK, then come back here and press Enter."
Read-Host -Prompt "Press Enter after toggling Serial Enumerator"
$after = Get-ItemProperty -Path $dp | Select-Object -Property | ConvertTo-Json -Depth 4
$after | Out-File -FilePath $afterFile -Encoding utf8
Write-Output "Saved after state to $afterFile"
compute diff of property names/values
$b = (Get-Content $beforeFile -Raw | ConvertFrom-Json)$a = (Get-Content $afterFile -Raw | ConvertFrom-Json)
$changed = @
foreach ($name in ($b | Get-Member -MemberType NoteProperty | Select-Object -Expand Name) {
$bv = $b.$name
$av = $a.$name
if ($bv -ne $av) { $changed += [pscustomobject]@{ Property = $name; Before = $bv; After = $av } }
}
if ($changed.Count -eq 0) { Write-Output "No property values changed. Paste the two JSON files if you want me to inspect further." } else { $changed | Format-Table -AutoSize; $changed | Out-File -FilePath "$env:USERPROFILE\Desktop\FTDI_changed_props.txt" ; Write-Output "Changed properties saved to FTDI_changed_props.txt on your Desktop." }
What I need from you
- Run the diagnostic above (elevated), toggle the Serial Enumerator checkbox for that COM port when prompted, then paste the output (or attach the FTDI_changed_props.txt from your Desktop).
- If the diagnostic shows a property name that changed (for example SerialEnumerator or a vendor name), I will:
- update the main script so it only sets that exact property if missing (or clears it if you prefer),
- and (if you want) run the change across all FTDI devices and automatically reboot the PC if any changes were made.
- On some systems the GUI toggles a property that’s created only after the device is installed by the INF. My script can either create the property (if desired) or only set it if it already exists — tell me which behavior you prefer.
- INF-based AddReg is the persistent, supported way to make the change survive driver updates/replugs. If the GUI-created property reappears after driver reinstall, I’ll give the INF AddReg snippet to deploy.
sjbesenski
Member
- Joined
- Nov 21, 2025
- Messages
- 71
- Thread Author
-
- #44
PS C:\Users\kioskuser2\Documents> Usage: C:\WINDOWS\system32\shutdown.exe [/i | /l | /s | /sg | /r | /g | /a | /p | /h | /e | /o] [/hybrid] [/soft] [/fw] [/f]
[/m \\computer][/t xxx][/d [p|u:]xx:yy [/c "comment"]]
No args Display help. This is the same as typing /?.
/? Display help. This is the same as not typing any options.
/i Display the graphical user interface (GUI).
This must be the first option.
/l Log off. This cannot be used with /m or /d options.
/s Shutdown the computer.
/sg Shutdown the computer. On the next boot, if Automatic Restart Sign-On
is enabled, automatically sign in and lock last interactive user.
After sign in, restart any registered applications.
/r Full shutdown and restart the computer.
/g Full shutdown and restart the computer. After the system is rebooted,
if Automatic Restart Sign-On is enabled, automatically sign in and
lock last interactive user.
After sign in, restart any registered applications.
/a Abort a system shutdown.
This can only be used during the time-out period.
Combine with /fw to clear any pending boots to firmware.
/p Turn off the local computer with no time-out or warning.
Can be used with /d and /f options.
/h Hibernate the local computer.
Can be used with the /f option.
/hybrid Performs a shutdown of the computer and prepares it for fast startup.
Must be used with /s option.
/fw Combine with a shutdown option to cause the next boot to go to the
firmware user interface.
/e Document the reason for an unexpected shutdown of a computer.
/o Go to the advanced boot options menu and restart the computer.
Must be used with /r option.
/m \\computer Specify the target computer.
/t xxx Set the time-out period before shutdown to xxx seconds.
The valid range is 0-315360000 (10 years), with a default of 30.
If the timeout period is greater than 0, the /f parameter is
implied.
/c "comment" Comment on the reason for the restart or shutdown.
Maximum of 512 characters allowed.
/f Force running applications to close without forewarning users.
The /f parameter is implied when a value greater than 0 is
specified for the /t parameter.
/d [p|u:]xx:yy Provide the reason for the restart or shutdown.
p indicates that the restart or shutdown is planned.
u indicates that the reason is user defined.
If neither p nor u is specified the restart or shutdown is
unplanned.
xx is the major reason number (positive integer less than 256).
yy is the minor reason number (positive integer less than 65536).
Reasons on this computer:
(E = Expected U = Unexpected P = planned, C = customer defined)
Type Major Minor Title
U 0 0 Other (Unplanned)
E 0 0 Other (Unplanned)
E P 0 0 Other (Planned)
U 0 5 Other Failure: System Unresponsive
E 1 1 Hardware: Maintenance (Unplanned)
E P 1 1 Hardware: Maintenance (Planned)
E 1 2 Hardware: Installation (Unplanned)
E P 1 2 Hardware: Installation (Planned)
E 2 2 Operating System: Recovery (Unplanned)
E P 2 2 Operating System: Recovery (Planned)
P 2 3 Operating System: Upgrade (Planned)
E 2 4 Operating System: Reconfiguration (Unplanned)
E P 2 4 Operating System: Reconfiguration (Planned)
P 2 16 Operating System: Service pack (Planned)
2 17 Operating System: Hot fix (Unplanned)
P 2 17 Operating System: Hot fix (Planned)
2 18 Operating System: Security fix (Unplanned)
P 2 18 Operating System: Security fix (Planned)
E 4 1 Application: Maintenance (Unplanned)
E P 4 1 Application: Maintenance (Planned)
E P 4 2 Application: Installation (Planned)
E 4 5 Application: Unresponsive
E 4 6 Application: Unstable
U 5 15 System Failure: Stop error
U 5 19 Security issue (Unplanned)
E 5 19 Security issue (Unplanned)
E P 5 19 Security issue (Planned)
E 5 20 Loss of network connectivity (Unplanned)
U 6 11 Power Failure: Cord Unplugged
U 6 12 Power Failure: Environment
P 7 0 Legacy API shutdown
[/m \\computer][/t xxx][/d [p|u:]xx:yy [/c "comment"]]
No args Display help. This is the same as typing /?.
/? Display help. This is the same as not typing any options.
/i Display the graphical user interface (GUI).
This must be the first option.
/l Log off. This cannot be used with /m or /d options.
/s Shutdown the computer.
/sg Shutdown the computer. On the next boot, if Automatic Restart Sign-On
is enabled, automatically sign in and lock last interactive user.
After sign in, restart any registered applications.
/r Full shutdown and restart the computer.
/g Full shutdown and restart the computer. After the system is rebooted,
if Automatic Restart Sign-On is enabled, automatically sign in and
lock last interactive user.
After sign in, restart any registered applications.
/a Abort a system shutdown.
This can only be used during the time-out period.
Combine with /fw to clear any pending boots to firmware.
/p Turn off the local computer with no time-out or warning.
Can be used with /d and /f options.
/h Hibernate the local computer.
Can be used with the /f option.
/hybrid Performs a shutdown of the computer and prepares it for fast startup.
Must be used with /s option.
/fw Combine with a shutdown option to cause the next boot to go to the
firmware user interface.
/e Document the reason for an unexpected shutdown of a computer.
/o Go to the advanced boot options menu and restart the computer.
Must be used with /r option.
/m \\computer Specify the target computer.
/t xxx Set the time-out period before shutdown to xxx seconds.
The valid range is 0-315360000 (10 years), with a default of 30.
If the timeout period is greater than 0, the /f parameter is
implied.
/c "comment" Comment on the reason for the restart or shutdown.
Maximum of 512 characters allowed.
/f Force running applications to close without forewarning users.
The /f parameter is implied when a value greater than 0 is
specified for the /t parameter.
/d [p|u:]xx:yy Provide the reason for the restart or shutdown.
p indicates that the restart or shutdown is planned.
u indicates that the reason is user defined.
If neither p nor u is specified the restart or shutdown is
unplanned.
xx is the major reason number (positive integer less than 256).
yy is the minor reason number (positive integer less than 65536).
Reasons on this computer:
(E = Expected U = Unexpected P = planned, C = customer defined)
Type Major Minor Title
U 0 0 Other (Unplanned)
E 0 0 Other (Unplanned)
E P 0 0 Other (Planned)
U 0 5 Other Failure: System Unresponsive
E 1 1 Hardware: Maintenance (Unplanned)
E P 1 1 Hardware: Maintenance (Planned)
E 1 2 Hardware: Installation (Unplanned)
E P 1 2 Hardware: Installation (Planned)
E 2 2 Operating System: Recovery (Unplanned)
E P 2 2 Operating System: Recovery (Planned)
P 2 3 Operating System: Upgrade (Planned)
E 2 4 Operating System: Reconfiguration (Unplanned)
E P 2 4 Operating System: Reconfiguration (Planned)
P 2 16 Operating System: Service pack (Planned)
2 17 Operating System: Hot fix (Unplanned)
P 2 17 Operating System: Hot fix (Planned)
2 18 Operating System: Security fix (Unplanned)
P 2 18 Operating System: Security fix (Planned)
E 4 1 Application: Maintenance (Unplanned)
E P 4 1 Application: Maintenance (Planned)
E P 4 2 Application: Installation (Planned)
E 4 5 Application: Unresponsive
E 4 6 Application: Unstable
U 5 15 System Failure: Stop error
U 5 19 Security issue (Unplanned)
E 5 19 Security issue (Unplanned)
E P 5 19 Security issue (Planned)
E 5 20 Loss of network connectivity (Unplanned)
U 6 11 Power Failure: Cord Unplugged
U 6 12 Power Failure: Environment
P 7 0 Legacy API shutdown
- Joined
- Mar 14, 2023
- Messages
- 97,513
Thanks — that output is the shutdown help because shutdown.exe was called with a bad/ malformed argument string. The fix is to call shutdown with properly separated arguments (avoid embedding extra quotes in a single ArgumentList string).
Recommended change (safe, works in PowerShell)
Replace the Start-Process line in the script with this:
Start-Process -FilePath 'shutdown.exe' -ArgumentList @('/r','/t','15','/c','Applying FTDI Device Parameter changes') -NoNewWindow
What that does
Run (from an elevated prompt):
shutdown /a
Alternative: immediate reboot without countdown
If you prefer an immediate restart (no countdown), use:
Restart-Computer -Force
(That restarts instantly and cannot be aborted.
What to do now
Recommended change (safe, works in PowerShell)
Replace the Start-Process line in the script with this:
Start-Process -FilePath 'shutdown.exe' -ArgumentList @('/r','/t','15','/c','Applying FTDI Device Parameter changes') -NoNewWindow
What that does
- /r = restart
- /t 15 = wait 15 seconds before restarting (gives you a chance to abort)
- /c "Applying FTDI Device Parameter changes" = comment shown in event log
- Using an ArgumentList array avoids quoting/escaping problems that produced the usage output you saw.
Run (from an elevated prompt):
shutdown /a
Alternative: immediate reboot without countdown
If you prefer an immediate restart (no countdown), use:
Restart-Computer -Force
(That restarts instantly and cannot be aborted.
What to do now
- Replace the shutdown call in the script with the Start-Process line above and re-run the script (with -WhatIf first if you want to test).
- If you want I can patch the script and paste the full corrected script block (with the fixed shutdown call) for you to copy/paste. Do you want me to do that?
sjbesenski
Member
- Joined
- Nov 21, 2025
- Messages
- 71
- Thread Author
-
- #46
can you write the command for an immediate shutdown with the previous argument list
- Joined
- Mar 14, 2023
- Messages
- 97,513
Use this PowerShell one‑liner to restart immediately and force-close apps, while supplying the same comment text as before:
Start-Process -FilePath 'shutdown.exe' -ArgumentList @('/r','/t','0','/f','/c','Applying FTDI Device Parameter changes') -NoNewWindow
Notes:
Start-Process -FilePath 'shutdown.exe' -ArgumentList @('/r','/t','0','/f','/c','Applying FTDI Device Parameter changes') -NoNewWindow
Notes:
- /r = restart, /t 0 = no timeout (immediate), /f = force applications to close, /c = comment (appears in event log).
- Because /t 0 is immediate, you cannot abort it with shutdown /a. If you want a short countdown to allow aborting, replace '0' with e.g. '15'.
- Alternative (PowerShell native): Restart-Computer -Force (no comment support).
sjbesenski
Member
- Joined
- Nov 21, 2025
- Messages
- 71
- Thread Author
-
- #48
yes please paste the full corrected script block
- Joined
- Mar 14, 2023
- Messages
- 97,513
Code:
<#
Disable-FTDI-SelectiveSuspend-ApplyIfMissing.ps1
- Only creates selective-suspend properties if they do not already exist.
- If any changes are made (and not -WhatIf and not -NoReboot), reboots the PC with a 15s countdown so Windows picks up changes. Run as Administrator.
#> param( [switch]$WhatIf, # dry run: show what would change, do not write or reboot [switch]$NoReboot # if specified, do not reboot even when changes were made) # Ensure elevated
if (-not ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent.IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator) { Write-Error "Run this script in an elevated PowerShell (Run as Administrator). Exiting." exit 1
} $timestamp = (Get-Date).ToString('yyyyMMdd_HHmmss')
$logFile = Join-Path $env:USERPROFILE "Desktop\FTDI_ApplyIfMissing_$timestamp.log"
"Started: $(Get-Date -Format u)" | Out-File -FilePath $logFile -Encoding UTF8 # Regex for detecting existing serial-enumerator-like properties (we only touch existing ones)
$serialEnumRegex = '(serial.*enum|enum.*serial|serialenumerator|enable.*serial)' # Trackers
$changedDevices = @
$skippedDevices = @
$errors = @ # Discover FTDI COM ports
$ports = Get-PnpDevice -Class Ports -PresentOnly -ErrorAction SilentlyContinue | Where-Object { ($_.Manufacturer -and $_.Manufacturer -like '*FTDI*') -or ($_.InstanceId -and $_.InstanceId -match 'VID_0403') } if (-not $ports -or $ports.Count -eq 0) { "No FTDI COM ports found." | Tee-Object -FilePath $logFile -Append Write-Output "No FTDI COM ports found. See log: $logFile" exit 0
} "Found $($ports.Count) FTDI COM port(s)." | Tee-Object -FilePath $logFile -Append foreach ($p in $ports) { "----" | Tee-Object -FilePath $logFile -Append "FriendlyName: $($p.FriendlyName)" | Tee-Object -FilePath $logFile -Append "InstanceId: $($p.InstanceId)" | Tee-Object -FilePath $logFile -Append $inst = $p.InstanceId if ([string]::IsNullOrWhiteSpace($inst) { "InstanceId empty; skipping." | Tee-Object -FilePath $logFile -Append $skippedDevices += $inst continue } # Build registry paths (safe direct interpolation) $base = "HKLM:\SYSTEM\CurrentControlSet\Enum\$inst" $dpCandidates = @( "$base\Device Parameters", "$base\0000\Device Parameters") $foundDP = $false $deviceWasChanged = $false foreach ($dp in $dpCandidates) { "Checking: $dp" | Tee-Object -FilePath $logFile -Append if (Test-Path $dp) { $foundDP = $true "Found Device Parameters: $dp" | Tee-Object -FilePath $logFile -Append # helper: check existence of a named property function Property-Exists { param($Path, $Name) try { $val = Get-ItemProperty -Path $Path -Name $Name -ErrorAction SilentlyContinue return ($null -ne $val) } catch { return $false } } # Only create if property does NOT exist $propsToEnsure = @{ 'DeviceIdleEnabled' = 0 'DefaultIdleState' = 0 'UserSetDeviceIdleEnabled' = 0 'SSIdleTimeout' = 0 } foreach ($kv in $propsToEnsure.GetEnumerator { $name = $kv.Key $desired = $kv.Value $exists = Property-Exists -Path $dp -Name $name if ($exists) { "$name already exists at $dp (skipping creation)." | Tee-Object -FilePath $logFile -Append } else { if ($WhatIf) { "WhatIf: would create $name = $desired at $dp" | Tee-Object -FilePath $logFile -Append $deviceWasChanged = $true } else { try { New-Item -Path $dp -Force | Out-Null New-ItemProperty -Path $dp -Name $name -PropertyType DWord -Value $desired -Force -ErrorAction Stop | Out-Null "Created $name = $desired at $dp" | Tee-Object -FilePath $logFile -Append $deviceWasChanged = $true } catch { "ERROR creating $name at $dp : $($_.Exception.Message)" | Tee-Object -FilePath $logFile -Append $errors += "ERROR creating $name at $dp : $($_.Exception.Message)" } } } } # Disable any existing Serial Enumerator-like properties (only if they exist) try { $existingProps = (Get-ItemProperty -Path $dp -ErrorAction SilentlyContinue).PSObject.Properties | ForEach-Object { $_.Name } } catch { $existingProps = @ } foreach ($propName in $existingProps) { if ($propName -match $serialEnumRegex) { # read current value try { $curVal = Get-ItemProperty -Path $dp -Name $propName -ErrorAction SilentlyContinue | Select-Object -ExpandProperty $propName -ErrorAction SilentlyContinue } catch { $curVal = $null } if ($null -eq $curVal) { $curVal = $null } # treat missing as null if ($null -eq $curVal) { # property exists but no value? create as 0 if ($WhatIf) { "WhatIf: would set existing $propName = 0 at $dp (regex matched)" | Tee-Object -FilePath $logFile -Append $deviceWasChanged = $true } else { try { New-ItemProperty -Path $dp -Name $propName -PropertyType DWord -Value 0 -Force -ErrorAction Stop | Out-Null "Set existing $propName = 0 at $dp (regex matched)" | Tee-Object -FilePath $logFile -Append $deviceWasChanged = $true } catch { "ERROR writing $propName at $dp : $($_.Exception.Message)" | Tee-Object -FilePath $logFile -Append $errors += "ERROR writing $propName at $dp : $($_.Exception.Message)" } } } else { # existing numeric value: do NOT overwrite per policy; log and skip "$propName exists with value $curVal at $dp (no overwrite per policy)." | Tee-Object -FilePath $logFile -Append } } } break # exit candidates loop for this device } else { "Not found: $dp" | Tee-Object -FilePath $logFile -Append } } if (-not $foundDP) { "Device Parameters not found for instance $inst. Skipping." | Tee-Object -FilePath $logFile -Append $skippedDevices += $inst } else { if ($deviceWasChanged) { $changedDevices += $inst } else { $skippedDevices += $inst } }
} # Summary logging
"=== Summary ===" | Tee-Object -FilePath $logFile -Append
"Devices changed: $($changedDevices.Count)" | Tee-Object -FilePath $logFile -Append
if ($changedDevices.Count -gt 0) { $changedDevices | Tee-Object -FilePath $logFile -Append } "Devices skipped/already-compliant: $($skippedDevices.Count)" | Tee-Object -FilePath $logFile -Append
if ($skippedDevices.Count -gt 0) { $skippedDevices | Tee-Object -FilePath $logFile -Append } if ($errors.Count -gt 0) { "Errors encountered: $($errors.Count)" | Tee-Object -FilePath $logFile -Append $errors | Tee-Object -FilePath $logFile -Append
} # Reboot if changes were made and not a dry run and not suppressed
if (($changedDevices.Count -gt 0) -and (-not $WhatIf) -and (-not $NoReboot) { "Changes applied. Rebooting in 15 seconds to apply changes..." | Tee-Object -FilePath $logFile -Append Write-Output "Changes applied. Rebooting in 15 seconds to apply changes..." Start-Process -FilePath 'shutdown.exe' -ArgumentList @('/r','/t','15','/c','Applying FTDI Device Parameter changes') -NoNewWindow
} else { if ($changedDevices.Count -eq 0) { "No updates were necessary. No reboot will be performed." | Tee-Object -FilePath $logFile -Append Write-Output "No updates were necessary." } else { "No reboot requested (NoReboot specified or WhatIf). Review log: $logFile" | Tee-Object -FilePath $logFile -Append Write-Output "Changes applied but reboot suppressed. Review log: $logFile" }
} "Completed: $(Get-Date -Format u)" | Tee-Object -FilePath $logFile -Append
Write-Output "Done. Log saved to: $logFile"
if (-not $WhatIf) { Write-Output "If you wrote values, Windows will pick them up after reboot (or run: pnputil /scan-devices)." }
- The corrected reboot call uses Start-Process with an ArgumentList array to avoid malformed shutdown arguments.
- You can change the countdown (15) to 0 for immediate restart or to a longer value if you want time to abort.
- Abort the scheduled reboot during the countdown with: shutdown /a (run elevated).
sjbesenski
Member
- Joined
- Nov 21, 2025
- Messages
- 71
- Thread Author
-
- #50
Getting this output
<#
Disable-FTDI-SelectiveSuspend-ApplyIfMissing.ps1
- Only creates selective-suspend properties if they do not already exist.
- If any changes are made (and not -WhatIf and not -NoReboot), reboots the PC with a 15s countdown so Windows picks up changes.
Run as Administrator.
#>
param(
[switch]$WhatIf, # dry run: show what would change, do not write or reboot
[switch]$NoReboot # if specified, do not reboot even when changes were made
)
# Ensure elevated
if (-not ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator)) {
Write-Error "Run this script in an elevated PowerShell (Run as Administrator). Exiting."
exit 1
}
$timestamp = (Get-Date).ToString('yyyyMMdd_HHmmss')
$logFile = Join-Path $env:USERPROFILE "Desktop\FTDI_ApplyIfMissing_$timestamp.log"
"Started: $(Get-Date -Format u)" | Out-File -FilePath $logFile -Encoding UTF8
# Regex for detecting existing serial-enumerator-like properties (we only touch existing ones)
$serialEnumRegex = '(serial.*enum|enum.*serial|serialenumerator|enable.*serial)'
# Trackers
$changedDevices = @()
$skippedDevices = @()
$errors = @()
# Discover FTDI COM ports
$ports = Get-PnpDevice -Class Ports -PresentOnly -ErrorAction SilentlyContinue |
Where-Object { ($_.Manufacturer -and $_.Manufacturer -like '*FTDI*') -or ($_.InstanceId -and $_.InstanceId -match 'VID_0403') }
if (-not $ports -or $ports.Count -eq 0) {
"No FTDI COM ports found." | Tee-Object -FilePath $logFile -Append
Write-Output "No FTDI COM ports found. See log: $logFile"
exit 0
}
"Found $($ports.Count) FTDI COM port(s)." | Tee-Object -FilePath $logFile -Append
foreach ($p in $ports) {
"----" | Tee-Object -FilePath $logFile -Append
"FriendlyName: $($p.FriendlyName)" | Tee-Object -FilePath $logFile -Append
"InstanceId: $($p.InstanceId)" | Tee-Object -FilePath $logFile -Append
$inst = $p.InstanceId
if ([string]::IsNullOrWhiteSpace($inst)) {
"InstanceId empty; skipping." | Tee-Object -FilePath $logFile -Append
$skippedDevices += $inst
continue
}
# Build registry paths (safe direct interpolation)
$base = "HKLM:\SYSTEM\CurrentControlSet\Enum\$inst"
$dpCandidates = @(
"$base\Device Parameters",
"$base\0000\Device Parameters"
)
$foundDP = $false
$deviceWasChanged = $false
foreach ($dp in $dpCandidates) {
"Checking: $dp" | Tee-Object -FilePath $logFile -Append
if (Test-Path $dp) {
$foundDP = $true
"Found Device Parameters: $dp" | Tee-Object -FilePath $logFile -Append
# helper: check existence of a named property
function Property-Exists {
param($Path, $Name)
try {
$val = Get-ItemProperty -Path $Path -Name $Name -ErrorAction SilentlyContinue
return ($null -ne $val)
} catch {
return $false
}
}
# Only create if property does NOT exist
$propsToEnsure = @{
'DeviceIdleEnabled' = 0
'DefaultIdleState' = 0
'UserSetDeviceIdleEnabled' = 0
'SSIdleTimeout' = 0
}
foreach ($kv in $propsToEnsure.GetEnumerator()) {
$name = $kv.Key
$desired = $kv.Value
$exists = Property-Exists -Path $dp -Name $name
if ($exists) {
"$name already exists at $dp (skipping creation)." | Tee-Object -FilePath $logFile -Append
} else {
if ($WhatIf) {
"WhatIf: would create $name = $desired at $dp" | Tee-Object -FilePath $logFile -Append
$deviceWasChanged = $true
} else {
try {
New-Item -Path $dp -Force | Out-Null
New-ItemProperty -Path $dp -Name $name -PropertyType DWord -Value $desired -Force -ErrorAction Stop | Out-Null
"Created $name = $desired at $dp" | Tee-Object -FilePath $logFile -Append
$deviceWasChanged = $true
} catch {
"ERROR creating $name at $dp : $($_.Exception.Message)" | Tee-Object -FilePath $logFile -Append
$errors += "ERROR creating $name at $dp : $($_.Exception.Message)"
}
}
}
}
# Disable any existing Serial Enumerator-like properties (only if they exist)
try {
$existingProps = (Get-ItemProperty -Path $dp -ErrorAction SilentlyContinue).PSObject.Properties | ForEach-Object { $_.Name }
} catch {
$existingProps = @()
}
foreach ($propName in $existingProps) {
if ($propName -match $serialEnumRegex) {
# read current value
try {
$curVal = Get-ItemProperty -Path $dp -Name $propName -ErrorAction SilentlyContinue | Select-Object -ExpandProperty $propName -ErrorAction SilentlyContinue
} catch { $curVal = $null }
if ($null -eq $curVal) { $curVal = $null } # treat missing as null
if ($null -eq $curVal) {
# property exists but no value? create as 0
if ($WhatIf) {
"WhatIf: would set existing $propName = 0 at $dp (regex matched)" | Tee-Object -FilePath $logFile -Append
$deviceWasChanged = $true
} else {
try {
New-ItemProperty -Path $dp -Name $propName -PropertyType DWord -Value 0 -Force -ErrorAction Stop | Out-Null
"Set existing $propName = 0 at $dp (regex matched)" | Tee-Object -FilePath $logFile -Append
$deviceWasChanged = $true
} catch {
"ERROR writing $propName at $dp : $($_.Exception.Message)" | Tee-Object -FilePath $logFile -Append
$errors += "ERROR writing $propName at $dp : $($_.Exception.Message)"
}
}
} else {
# existing numeric value: do NOT overwrite per policy; log and skip
"$propName exists with value $curVal at $dp (no overwrite per policy)." | Tee-Object -FilePath $logFile -Append
}
}
}
break # exit candidates loop for this device
} else {
"Not found: $dp" | Tee-Object -FilePath $logFile -Append
}
}
if (-not $foundDP) {
"Device Parameters not found for instance $inst. Skipping." | Tee-Object -FilePath $logFile -Append
$skippedDevices += $inst
} else {
if ($deviceWasChanged) {
$changedDevices += $inst
} else {
$skippedDevices += $inst
}
}
}
# Summary logging
"=== Summary ===" | Tee-Object -FilePath $logFile -Append
"Devices changed: $($changedDevices.Count)" | Tee-Object -FilePath $logFile -Append
if ($changedDevices.Count -gt 0) { $changedDevices | Tee-Object -FilePath $logFile -Append }
"Devices skipped/already-compliant: $($skippedDevices.Count)" | Tee-Object -FilePath $logFile -Append
if ($skippedDevices.Count -gt 0) { $skippedDevices | Tee-Object -FilePath $logFile -Append }
if ($errors.Count -gt 0) {
"Errors encountered: $($errors.Count)" | Tee-Object -FilePath $logFile -Append
$errors | Tee-Object -FilePath $logFile -Append
}
# Reboot if changes were made and not a dry run and not suppressed
if (($changedDevices.Count -gt 0) -and (-not $WhatIf) -and (-not $NoReboot)) {
"Changes applied. Rebooting in 15 seconds to apply changes..." | Tee-Object -FilePath $logFile -Append
Write-Output "Changes applied. Rebooting in 15 seconds to apply changes..."
Start-Process -FilePath 'shutdown.exe' -ArgumentList @('/r','/t','15','/c','Applying FTDI Device Parameter changes') -NoNewWindow
} else {
if ($changedDevices.Count -eq 0) {
"No updates were necessary. No reboot will be performed." | Tee-Object -FilePath $logFile -Append
Write-Output "No updates were necessary."
} else {
"No reboot requested (NoReboot specified or WhatIf). Review log: $logFile" | Tee-Object -FilePath $logFile -Append
Write-Output "Changes applied but reboot suppressed. Review log: $logFile"
}
}
"Completed: $(Get-Date -Format u)" | Tee-Object -FilePath $logFile -Append
Write-Output "Done. Log saved to: $logFile"
if (-not $WhatIf) { Write-Output "If you wrote values, Windows will pick them up after reboot (or run: pnputil /scan-devices)." }
<#
Disable-FTDI-SelectiveSuspend-ApplyIfMissing.ps1
- Only creates selective-suspend properties if they do not already exist.
- If any changes are made (and not -WhatIf and not -NoReboot), reboots the PC with a 15s countdown so Windows picks up changes.
Run as Administrator.
#>
param(
[switch]$WhatIf, # dry run: show what would change, do not write or reboot
[switch]$NoReboot # if specified, do not reboot even when changes were made
)
# Ensure elevated
if (-not ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator)) {
Write-Error "Run this script in an elevated PowerShell (Run as Administrator). Exiting."
exit 1
}
$timestamp = (Get-Date).ToString('yyyyMMdd_HHmmss')
$logFile = Join-Path $env:USERPROFILE "Desktop\FTDI_ApplyIfMissing_$timestamp.log"
"Started: $(Get-Date -Format u)" | Out-File -FilePath $logFile -Encoding UTF8
# Regex for detecting existing serial-enumerator-like properties (we only touch existing ones)
$serialEnumRegex = '(serial.*enum|enum.*serial|serialenumerator|enable.*serial)'
# Trackers
$changedDevices = @()
$skippedDevices = @()
$errors = @()
# Discover FTDI COM ports
$ports = Get-PnpDevice -Class Ports -PresentOnly -ErrorAction SilentlyContinue |
Where-Object { ($_.Manufacturer -and $_.Manufacturer -like '*FTDI*') -or ($_.InstanceId -and $_.InstanceId -match 'VID_0403') }
if (-not $ports -or $ports.Count -eq 0) {
"No FTDI COM ports found." | Tee-Object -FilePath $logFile -Append
Write-Output "No FTDI COM ports found. See log: $logFile"
exit 0
}
"Found $($ports.Count) FTDI COM port(s)." | Tee-Object -FilePath $logFile -Append
foreach ($p in $ports) {
"----" | Tee-Object -FilePath $logFile -Append
"FriendlyName: $($p.FriendlyName)" | Tee-Object -FilePath $logFile -Append
"InstanceId: $($p.InstanceId)" | Tee-Object -FilePath $logFile -Append
$inst = $p.InstanceId
if ([string]::IsNullOrWhiteSpace($inst)) {
"InstanceId empty; skipping." | Tee-Object -FilePath $logFile -Append
$skippedDevices += $inst
continue
}
# Build registry paths (safe direct interpolation)
$base = "HKLM:\SYSTEM\CurrentControlSet\Enum\$inst"
$dpCandidates = @(
"$base\Device Parameters",
"$base\0000\Device Parameters"
)
$foundDP = $false
$deviceWasChanged = $false
foreach ($dp in $dpCandidates) {
"Checking: $dp" | Tee-Object -FilePath $logFile -Append
if (Test-Path $dp) {
$foundDP = $true
"Found Device Parameters: $dp" | Tee-Object -FilePath $logFile -Append
# helper: check existence of a named property
function Property-Exists {
param($Path, $Name)
try {
$val = Get-ItemProperty -Path $Path -Name $Name -ErrorAction SilentlyContinue
return ($null -ne $val)
} catch {
return $false
}
}
# Only create if property does NOT exist
$propsToEnsure = @{
'DeviceIdleEnabled' = 0
'DefaultIdleState' = 0
'UserSetDeviceIdleEnabled' = 0
'SSIdleTimeout' = 0
}
foreach ($kv in $propsToEnsure.GetEnumerator()) {
$name = $kv.Key
$desired = $kv.Value
$exists = Property-Exists -Path $dp -Name $name
if ($exists) {
"$name already exists at $dp (skipping creation)." | Tee-Object -FilePath $logFile -Append
} else {
if ($WhatIf) {
"WhatIf: would create $name = $desired at $dp" | Tee-Object -FilePath $logFile -Append
$deviceWasChanged = $true
} else {
try {
New-Item -Path $dp -Force | Out-Null
New-ItemProperty -Path $dp -Name $name -PropertyType DWord -Value $desired -Force -ErrorAction Stop | Out-Null
"Created $name = $desired at $dp" | Tee-Object -FilePath $logFile -Append
$deviceWasChanged = $true
} catch {
"ERROR creating $name at $dp : $($_.Exception.Message)" | Tee-Object -FilePath $logFile -Append
$errors += "ERROR creating $name at $dp : $($_.Exception.Message)"
}
}
}
}
# Disable any existing Serial Enumerator-like properties (only if they exist)
try {
$existingProps = (Get-ItemProperty -Path $dp -ErrorAction SilentlyContinue).PSObject.Properties | ForEach-Object { $_.Name }
} catch {
$existingProps = @()
}
foreach ($propName in $existingProps) {
if ($propName -match $serialEnumRegex) {
# read current value
try {
$curVal = Get-ItemProperty -Path $dp -Name $propName -ErrorAction SilentlyContinue | Select-Object -ExpandProperty $propName -ErrorAction SilentlyContinue
} catch { $curVal = $null }
if ($null -eq $curVal) { $curVal = $null } # treat missing as null
if ($null -eq $curVal) {
# property exists but no value? create as 0
if ($WhatIf) {
"WhatIf: would set existing $propName = 0 at $dp (regex matched)" | Tee-Object -FilePath $logFile -Append
$deviceWasChanged = $true
} else {
try {
New-ItemProperty -Path $dp -Name $propName -PropertyType DWord -Value 0 -Force -ErrorAction Stop | Out-Null
"Set existing $propName = 0 at $dp (regex matched)" | Tee-Object -FilePath $logFile -Append
$deviceWasChanged = $true
} catch {
"ERROR writing $propName at $dp : $($_.Exception.Message)" | Tee-Object -FilePath $logFile -Append
$errors += "ERROR writing $propName at $dp : $($_.Exception.Message)"
}
}
} else {
# existing numeric value: do NOT overwrite per policy; log and skip
"$propName exists with value $curVal at $dp (no overwrite per policy)." | Tee-Object -FilePath $logFile -Append
}
}
}
break # exit candidates loop for this device
} else {
"Not found: $dp" | Tee-Object -FilePath $logFile -Append
}
}
if (-not $foundDP) {
"Device Parameters not found for instance $inst. Skipping." | Tee-Object -FilePath $logFile -Append
$skippedDevices += $inst
} else {
if ($deviceWasChanged) {
$changedDevices += $inst
} else {
$skippedDevices += $inst
}
}
}
# Summary logging
"=== Summary ===" | Tee-Object -FilePath $logFile -Append
"Devices changed: $($changedDevices.Count)" | Tee-Object -FilePath $logFile -Append
if ($changedDevices.Count -gt 0) { $changedDevices | Tee-Object -FilePath $logFile -Append }
"Devices skipped/already-compliant: $($skippedDevices.Count)" | Tee-Object -FilePath $logFile -Append
if ($skippedDevices.Count -gt 0) { $skippedDevices | Tee-Object -FilePath $logFile -Append }
if ($errors.Count -gt 0) {
"Errors encountered: $($errors.Count)" | Tee-Object -FilePath $logFile -Append
$errors | Tee-Object -FilePath $logFile -Append
}
# Reboot if changes were made and not a dry run and not suppressed
if (($changedDevices.Count -gt 0) -and (-not $WhatIf) -and (-not $NoReboot)) {
"Changes applied. Rebooting in 15 seconds to apply changes..." | Tee-Object -FilePath $logFile -Append
Write-Output "Changes applied. Rebooting in 15 seconds to apply changes..."
Start-Process -FilePath 'shutdown.exe' -ArgumentList @('/r','/t','15','/c','Applying FTDI Device Parameter changes') -NoNewWindow
} else {
if ($changedDevices.Count -eq 0) {
"No updates were necessary. No reboot will be performed." | Tee-Object -FilePath $logFile -Append
Write-Output "No updates were necessary."
} else {
"No reboot requested (NoReboot specified or WhatIf). Review log: $logFile" | Tee-Object -FilePath $logFile -Append
Write-Output "Changes applied but reboot suppressed. Review log: $logFile"
}
}
"Completed: $(Get-Date -Format u)" | Tee-Object -FilePath $logFile -Append
Write-Output "Done. Log saved to: $logFile"
if (-not $WhatIf) { Write-Output "If you wrote values, Windows will pick them up after reboot (or run: pnputil /scan-devices)." }
- Joined
- Mar 14, 2023
- Messages
- 97,513
Thanks — that looks like the script text printed back to you. That usually happens when you paste the script into an interactive shell instead of saving it to a .ps1 file and running it. Here are the exact, safe steps to save, test (dry run), run, and inspect the log — plus commands to cancel the reboot if needed.
1) Save the script to a file
Paste the script into Notepad, save and close.
2) Dry run first (no writes, no reboot)
This will log what WOULD be changed without making changes.
3) Inspect the log file the script writes to your Desktop
Or open the most recent log in Notepad:
notepad (Get-ChildItem "$env:USERPROFILE\Desktop\FTDIApplyIfMissing*.log" | Sort-Object LastWriteTime -Descending | Select-Object -First 1).FullName
4) Run for real (apply changes)
5) Abort a pending reboot (if you change your mind in the countdown)
6) If you see errors or nothing changed
Test-Path $dp; Get-ItemProperty -Path $dp -ErrorAction SilentlyContinue | Format-List
(Use the exact InstanceId from the previous command; some nodes use the extra 0000 subkey and some don’t — the script handles both.
If you want I can:
1) Save the script to a file
- Open an elevated PowerShell window (right‑click Start → Windows Terminal (Admin) or PowerShell (Admin).
- Create the file and paste the script contents into it (recommended):
Paste the script into Notepad, save and close.
2) Dry run first (no writes, no reboot)
- In the elevated PowerShell run:
This will log what WOULD be changed without making changes.
3) Inspect the log file the script writes to your Desktop
- To view the most recent log quickly:
Or open the most recent log in Notepad:
notepad (Get-ChildItem "$env:USERPROFILE\Desktop\FTDIApplyIfMissing*.log" | Sort-Object LastWriteTime -Descending | Select-Object -First 1).FullName
4) Run for real (apply changes)
- When you’re ready and the dry run looks correct, run (this will create missing properties and reboot after 15s if changes occurred):
- To apply changes but suppress reboot:
5) Abort a pending reboot (if you change your mind in the countdown)
- Run (elevated):
6) If you see errors or nothing changed
- Paste the contents of the most recent log file here (use the Get-Content or open in Notepad commands above) and I’ll read it and tell you exactly what happened (Access denied, path not found, etc..
- If you get “Access denied” writing under HKLM\SYSTEM\CurrentControlSet\Enum the script can’t proceed on that machine without changing ACLs or running in SYSTEM context — I’ll recommend the safe next steps (INF/AddReg persistent approach or running the script as SYSTEM via psexec / scheduled task).
- List matched FTDI ports the script will act on:
- Check one device’s Device Parameters (replace <INSTANCEID> with the InstanceId string):
Test-Path $dp; Get-ItemProperty -Path $dp -ErrorAction SilentlyContinue | Format-List
(Use the exact InstanceId from the previous command; some nodes use the extra 0000 subkey and some don’t — the script handles both.
If you want I can:
- Paste a corrected script that logs more details (already done), or
- Modify the script to force-create a particular serial‑enumerator property name you found on your machine, or
- Give you the INF AddReg snippet for a persistent change (recommended for enterprise).
sjbesenski
Member
- Joined
- Nov 21, 2025
- Messages
- 71
- Thread Author
-
- #52
I ran the script and it is not resetting my pc
- Joined
- Mar 14, 2023
- Messages
- 97,513
Thanks — that helps. Most likely reason: the script didn’t actually make any new registry writes, so it never triggered the reboot. The script only creates the selective‑suspend / serial‑enumerator values if they do not already exist and only restarts when it has made at least one change (that behavior is in the version you ran).
Let’s verify quickly and either trigger the reboot or apply the writes (overwrite) if you want.
1) Check the script log (fast)
Open the most recent log the script wrote to your Desktop and show the summary lines:
Sort-Object LastWriteTime -Descending |
Select-Object -First 1 |
ForEach-Object { Get-Content -Path $_.FullName -Tail 200 }
Look for the summary block near the end:
That means all those registry values already existed (or the script could not write because of ACLs). To confirm for one device, run (replace <INSTANCEID> with one from Get-PnpDevice output):
Where-Object { ($.Manufacturer -like 'FTDI') -or ($.InstanceId -match 'VID_0403') } |
Format-List FriendlyName,InstanceId
Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Enum\$($inst -replace '\','\')\Device Parameters" | Format-List *
You’re looking for any of these names: DeviceIdleEnabled, DefaultIdleState, UserSetDeviceIdleEnabled, SSIdleTimeout (and any serial‑enumerator property the device might have). If they already exist, the script correctly skipped them.
3) If you want the script to overwrite (force) the values so a reboot will happen
You can either:
A) Re-run a one‑line command that force‑writes the four values for every FTDI device (immediate, but requires admin):
Where-Object { ($.Manufacturer -like 'FTDI') -or ($.InstanceId -match 'VID0403') } |
ForEach-Object {
$inst = $.InstanceId
$regPath = "HKLM:\SYSTEM\CurrentControlSet\Enum\$inst\Device Parameters"
}
After running that, either reboot manually or let the script reboot. To reboot immediately (no countdown):
Or to reboot with 15s countdown (abortable via shutdown /a):
Start-Process -FilePath 'shutdown.exe' -ArgumentList @('/r','/t','15','/c','Applying FTDI Device Parameter changes') -NoNewWindow
4) If changes were made but the script still didn’t reboot
Let’s verify quickly and either trigger the reboot or apply the writes (overwrite) if you want.
1) Check the script log (fast)
Open the most recent log the script wrote to your Desktop and show the summary lines:
in an elevated PowerShell window
Get-ChildItem "$env:USERPROFILE\Desktop\FTDIApplyIfMissing*.log" |Sort-Object LastWriteTime -Descending |
Select-Object -First 1 |
ForEach-Object { Get-Content -Path $_.FullName -Tail 200 }
Look for the summary block near the end:
- "Devices changed: N"
If N is 0 then no changes were needed and the script will not reboot. If N > 0 the reboot should have been scheduled (or suppressed by -NoReboot / -WhatIf).
That means all those registry values already existed (or the script could not write because of ACLs). To confirm for one device, run (replace <INSTANCEID> with one from Get-PnpDevice output):
find a device instance first (run elevated)
Get-PnpDevice -Class Ports -PresentOnly |Where-Object { ($.Manufacturer -like 'FTDI') -or ($.InstanceId -match 'VID_0403') } |
Format-List FriendlyName,InstanceId
then inspect its Device Parameters (example)
$inst = 'FTDIBUS\VID_0403+PID_6001+XXXXXXXX\0000' # paste InstanceIdGet-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Enum\$($inst -replace '\','\')\Device Parameters" | Format-List *
You’re looking for any of these names: DeviceIdleEnabled, DefaultIdleState, UserSetDeviceIdleEnabled, SSIdleTimeout (and any serial‑enumerator property the device might have). If they already exist, the script correctly skipped them.
3) If you want the script to overwrite (force) the values so a reboot will happen
You can either:
A) Re-run a one‑line command that force‑writes the four values for every FTDI device (immediate, but requires admin):
Run elevated
Get-PnpDevice -Class Ports -PresentOnly |Where-Object { ($.Manufacturer -like 'FTDI') -or ($.InstanceId -match 'VID0403') } |
ForEach-Object {
$inst = $.InstanceId
$regPath = "HKLM:\SYSTEM\CurrentControlSet\Enum\$inst\Device Parameters"
create Device Parameters if missing
Code:
if (-not (Test-Path $regPath) { New-Item -Path $regPath -Force | Out-Null }
New-ItemProperty -Path $regPath -Name 'DeviceIdleEnabled' -PropertyType DWord -Value 0 -Force
New-ItemProperty -Path $regPath -Name 'DefaultIdleState' -PropertyType DWord -Value 0 -Force
New-ItemProperty -Path $regPath -Name 'UserSetDeviceIdleEnabled' -PropertyType DWord -Value 0 -Force
New-ItemProperty -Path $regPath -Name 'SSIdleTimeout' -PropertyType DWord -Value 0 -Force
Write-Output "Wrote values for $inst"
After running that, either reboot manually or let the script reboot. To reboot immediately (no countdown):
immediate forced restart (cannot be aborted)
Start-Process -FilePath 'shutdown.exe' -ArgumentList @('/r','/t','0','/f','/c','Applying FTDI Device Parameter changes') -NoNewWindowOr to reboot with 15s countdown (abortable via shutdown /a):
Start-Process -FilePath 'shutdown.exe' -ArgumentList @('/r','/t','15','/c','Applying FTDI Device Parameter changes') -NoNewWindow
4) If changes were made but the script still didn’t reboot
- Confirm you didn’t run with -WhatIf or -NoReboot. If you ran from a scheduled task or different account the reboot may be blocked.
- Check the log for any “ERROR creating …” messages — those indicate ACL / Access Denied. If you see Access Denied the script could not write and therefore would not reboot; paste the error lines and I’ll show the safest next step (INF AddReg or running as SYSTEM).
- Post a short variant of the script that FORCE‑writes only if you explicitly request overwrite (safer), then reboots; OR
- Walk you through the one‑liner to force writes + immediate reboot (I gave it above), OR
- Inspect the log for you if you paste the last 50 lines (or attach the log file).
- Run the first Log command I pasted, copy the final summary lines and paste them here (or attach the log). I’ll tell you exactly why no reboot happened and the safest command to run to apply or force the change and reboot.
sjbesenski
Member
- Joined
- Nov 21, 2025
- Messages
- 71
- Thread Author
-
- #54
The com port number in advanced settings is still being set as a blank value
sjbesenski
Member
- Joined
- Nov 21, 2025
- Messages
- 71
- Thread Author
-
- #55
Showing as advanced settings for comx
sjbesenski
Member
- Joined
- Nov 21, 2025
- Messages
- 71
- Thread Author
-
- #56
Do not want to change the com port number want it to stay the same
- Joined
- Mar 14, 2023
- Messages
- 97,513
Thanks — let’s diagnose why Device Manager’s Advanced dialog still shows an empty COM Port field and fix it.
Run the short diagnostic (requires Administrator). It will:
Diagnostic script (run elevated)
$log = Join-Path $env:USERPROFILE ("Desktop\FTDIPortDiag{0}.log" -f (Get-Date -Format yyyyMMdd_HHmmss)
"Start: $(Get-Date)" | Out-File $log
if (-not $ports) { "No FTDI ports found." | Tee-Object -FilePath $log -Append; exit }
"Found $($ports.Count) FTDI device(s)" | Tee-Object -FilePath $log -Append
try {
Get-ItemProperty -Path 'HKLM:\HARDWARE\DEVICEMAP\SERIALCOMM' -ErrorAction Stop | ForEach-Object {
$.PSObject.Properties | ForEach-Object { "$($.Name) = $($.Value)" | Tee-Object -FilePath $log -Append }
}
} catch { "No SERIALCOMM key or cannot read it: $($.Exception.Message)" | Tee-Object -FilePath $log -Append }
"----" | Tee-Object -FilePath $log -Append
"FriendlyName: $($p.FriendlyName)" | Tee-Object -FilePath $log -Append
"InstanceId: $($p.InstanceId)" | Tee-Object -FilePath $log -Append
$inst = $p.InstanceId
$enumBase = 'HKLM:\SYSTEM\CurrentControlSet\Enum'
$basePath = Join-Path $enumBase ($inst -replace '\','\')
$cands = @(
Join-Path $basePath 'Device Parameters',
Join-Path (Join-Path $basePath '0000') 'Device Parameters')
foreach ($dp in $cands) {
"Checking registry path: $dp" | Tee-Object -FilePath $log -Append
if (Test-Path $dp) {
"Path exists" | Tee-Object -FilePath $log -Append
try {
$props = Get-ItemProperty -Path $dp -ErrorAction Stop
if ($props.PSObject.Properties.Name -contains 'PortName') {
"PortName (registry) = $($props.PortName)" | Tee-Object -FilePath $log -Append
} else {
"PortName not present at this key" | Tee-Object -FilePath $log -Append
}
"Other properties: " + (($props.PSObject.Properties | ForEach-Object { $.Name }) -join ', ') | Tee-Object -FilePath $log -Append
} catch {
"Failed reading props: $($.Exception.Message)" | Tee-Object -FilePath $log -Append
}
} else {
"Path not present" | Tee-Object -FilePath $log -Append
}
}
try {
$portsWin = Get-CimInstance -ClassName Win32SerialPort -ErrorAction SilentlyContinue
$matchExact = $portsWin | Where-Object { $.PNPDeviceID -eq $inst }
if ($matchExact) {
$matchExact | ForEach-Object { "Win32 SerialPort: DeviceID=$($.DeviceID) PNPDeviceID=$($.PNPDeviceID)" | Tee-Object -FilePath $log -Append }
} else {
} catch {
"Failed to query Win32SerialPort: $($.Exception.Message)" | Tee-Object -FilePath $log -Append
}
}
"Completed: $(Get-Date)" | Tee-Object -FilePath $log -Append
Write-Output "Diagnostic complete. Log saved to: $log"
— After running, paste the log contents or upload it.
Quick probable fixes (if diagnostics show PortName missing)
$com = 'COM3' # replace with the COM shown by Win32_SerialPort
$base = "HKLM:\SYSTEM\CurrentControlSet\Enum\$inst"
$dp1 = "$base\Device Parameters"
$dp2 = "$base\0000\Device Parameters"
if (Test-Path $dp1) { New-ItemProperty -Path $dp1 -Name 'PortName' -PropertyType String -Value $com -Force }
if (Test-Path $dp2) { New-ItemProperty -Path $dp2 -Name 'PortName' -PropertyType String -Value $com -Force }
1) Run the diagnostic script (Admin) and paste the log or the relevant lines for one device (the Device Parameters paths and the Win32_SerialPort matching line).
2) I’ll provide the exact PowerShell command to write PortName to the correct registry location and either rescan or reboot so the Advanced dialog shows the COM number.
Run the short diagnostic (requires Administrator). It will:
- list each FTDI device InstanceId,
- show whether PortName exists under both possible Device Parameters locations (…\Device Parameters and …\0000\Device Parameters),
- show the Win32_SerialPort mapping (PNPDeviceID and DeviceID like "COM3"),
- show current HARDWARE\DEVICEMAP\SERIALCOMM entries.
Diagnostic script (run elevated)
$log = Join-Path $env:USERPROFILE ("Desktop\FTDIPortDiag{0}.log" -f (Get-Date -Format yyyyMMdd_HHmmss)
"Start: $(Get-Date)" | Out-File $log
Find FTDI ports
$ports = Get-PnpDevice -Class Ports -PresentOnly | Where-Object { ($.Manufacturer -and $.Manufacturer -like 'FTDI') -or ($_.InstanceId -match 'VID_0403') }if (-not $ports) { "No FTDI ports found." | Tee-Object -FilePath $log -Append; exit }
"Found $($ports.Count) FTDI device(s)" | Tee-Object -FilePath $log -Append
List SerialComm map
"--- HARDWARE\DEVICEMAP\SERIALCOMM entries ---" | Tee-Object -FilePath $log -Appendtry {
Get-ItemProperty -Path 'HKLM:\HARDWARE\DEVICEMAP\SERIALCOMM' -ErrorAction Stop | ForEach-Object {
$.PSObject.Properties | ForEach-Object { "$($.Name) = $($.Value)" | Tee-Object -FilePath $log -Append }
}
} catch { "No SERIALCOMM key or cannot read it: $($.Exception.Message)" | Tee-Object -FilePath $log -Append }
For each FTDI instance, check candidate Device Parameters and Win32 mapping
foreach ($p in $ports) {"----" | Tee-Object -FilePath $log -Append
"FriendlyName: $($p.FriendlyName)" | Tee-Object -FilePath $log -Append
"InstanceId: $($p.InstanceId)" | Tee-Object -FilePath $log -Append
$inst = $p.InstanceId
$enumBase = 'HKLM:\SYSTEM\CurrentControlSet\Enum'
$basePath = Join-Path $enumBase ($inst -replace '\','\')
$cands = @(
Join-Path $basePath 'Device Parameters',
Join-Path (Join-Path $basePath '0000') 'Device Parameters')
foreach ($dp in $cands) {
"Checking registry path: $dp" | Tee-Object -FilePath $log -Append
if (Test-Path $dp) {
"Path exists" | Tee-Object -FilePath $log -Append
try {
$props = Get-ItemProperty -Path $dp -ErrorAction Stop
if ($props.PSObject.Properties.Name -contains 'PortName') {
"PortName (registry) = $($props.PortName)" | Tee-Object -FilePath $log -Append
} else {
"PortName not present at this key" | Tee-Object -FilePath $log -Append
}
"Other properties: " + (($props.PSObject.Properties | ForEach-Object { $.Name }) -join ', ') | Tee-Object -FilePath $log -Append
} catch {
"Failed reading props: $($.Exception.Message)" | Tee-Object -FilePath $log -Append
}
} else {
"Path not present" | Tee-Object -FilePath $log -Append
}
}
Check Win32_SerialPort for a mapping (PNPDeviceID or tail-match)
"Checking Win32_SerialPort mappings..." | Tee-Object -FilePath $log -Appendtry {
$portsWin = Get-CimInstance -ClassName Win32SerialPort -ErrorAction SilentlyContinue
$matchExact = $portsWin | Where-Object { $.PNPDeviceID -eq $inst }
if ($matchExact) {
$matchExact | ForEach-Object { "Win32 SerialPort: DeviceID=$($.DeviceID) PNPDeviceID=$($.PNPDeviceID)" | Tee-Object -FilePath $log -Append }
} else {
try tail match (last segment of instance)
Code:
$tail = ($inst -split '\\')[-1] $matchTail = $portsWin | Where-Object { $_.PNPDeviceID -like "*$tail*" } if ($matchTail) { $matchTail | ForEach-Object { "Win32 SerialPort (tail match): DeviceID=$($_.DeviceID) PNPDeviceID=$($_.PNPDeviceID)" | Tee-Object -FilePath $log -Append } } else { "No Win32_SerialPort entry matched this instance." | Tee-Object -FilePath $log -Append }
}
"Failed to query Win32SerialPort: $($.Exception.Message)" | Tee-Object -FilePath $log -Append
}
}
"Completed: $(Get-Date)" | Tee-Object -FilePath $log -Append
Write-Output "Diagnostic complete. Log saved to: $log"
— After running, paste the log contents or upload it.
Quick probable fixes (if diagnostics show PortName missing)
- If Win32_SerialPort shows DeviceID = COMn for that instance (tail match), but the device’s Device Parameters PortName is missing, set PortName under the matching registry key (both candidates) to the COM found and rescan/reboot.
Example (run elevated — replace variables with the actual InstanceId and COM string if you already know them):
set PortName at both candidate locations (force)
$inst = 'FTDIBUS\VID_0403+PID_6001+XXXXXXXX\0000' # replace$com = 'COM3' # replace with the COM shown by Win32_SerialPort
$base = "HKLM:\SYSTEM\CurrentControlSet\Enum\$inst"
$dp1 = "$base\Device Parameters"
$dp2 = "$base\0000\Device Parameters"
if (Test-Path $dp1) { New-ItemProperty -Path $dp1 -Name 'PortName' -PropertyType String -Value $com -Force }
if (Test-Path $dp2) { New-ItemProperty -Path $dp2 -Name 'PortName' -PropertyType String -Value $com -Force }
rescan devices
pnputil /scan-devicesor reboot
Start-Process -FilePath 'shutdown.exe' -ArgumentList @('/r','/t','15','/c','Applying FTDI PortName') -NoNewWindow- If Win32_SerialPort shows no mapping (no COM assigned), you can assign a COM by setting PortName (as above) to a free COM name then rescan/reboot — Windows should register it in HARDWARE\DEVICEMAP\SERIALCOMM. If Device Manager still shows blank, try reboot.
- give one command that force-writes PortName for all FTDI instances to the COM currently shown in Win32_SerialPort (or to the same COM if you want), or
- write a script that sets PortName only where PortName is missing and Win32 shows a COM (safe).
1) Run the diagnostic script (Admin) and paste the log or the relevant lines for one device (the Device Parameters paths and the Win32_SerialPort matching line).
2) I’ll provide the exact PowerShell command to write PortName to the correct registry location and either rescan or reboot so the Advanced dialog shows the COM number.
- Joined
- Mar 14, 2023
- Messages
- 97,513
Thanks — good progress. If Device Manager already shows “Advanced settings for COMx” that means Windows has a PortName for that instance. The remaining problem is the script either found nothing to change (so it correctly didn’t reboot) or it failed to write (ACL). Let’s confirm and — if you want — force the missing PortName / device properties and then restart.
Run these commands in an elevated PowerShell (copy/paste). They will:
1) show per‑device PortName and the four selective‑suspend properties,
2) create the missing properties (only if they do NOT exist), and
3) immediately restart the machine if at least one device was changed.
Step A — inspect FTDI devices and Device Parameters (no changes)
Run as Administrator:
Where-Object { ($.Manufacturer -and $.Manufacturer -like 'FTDI') -or ($_.InstanceId -match 'VID_0403') } |
Format-Table FriendlyName, InstanceId -AutoSize
$dp = "HKLM:\SYSTEM\CurrentControlSet\Enum\$($inst -replace '\','\')\Device Parameters"
Test-Path $dp; if (Test-Path $dp) { Get-ItemProperty -Path $dp | Select-Object PortName, DeviceIdleEnabled, DefaultIdleState, UserSetDeviceIdleEnabled, SSIdleTimeout | Format-List } else { "Device Parameters key not found: $dp" }
This tells us whether PortName is present and whether the selective‑suspend values already exist.
Step B — apply missing values and set PortName if missing, then restart if anything changed
Run this whole block (elevated). It only CREATES properties that are missing (does not overwrite existing values). If any changes are made it will immediately restart the PC (no countdown). If you want a countdown instead, change the shutdown /t 0 to /t 15.
Where-Object { ($.Manufacturer -and $.Manufacturer -like 'FTDI') -or ($_.InstanceId -match 'VID_0403') }
foreach ($p in $ports) {
$inst = $p.InstanceId
$dp = "HKLM:\SYSTEM\CurrentControlSet\Enum\$($inst -replace '\','\')\Device Parameters"
if (-not (Test-Path $dp) { New-Item -Path $dp -Force | Out-Null }
param($Path,$Name,$Type,$Value)
try {
$exists = Get-ItemProperty -Path $Path -Name $Name -ErrorAction SilentlyContinue
if ($null -eq $exists) {
if ($Type -eq 'DWord') { New-ItemProperty -Path $Path -Name $Name -PropertyType DWord -Value $Value -Force | Out-Null }
else { New-ItemProperty -Path $Path -Name $Name -PropertyType String -Value $Value -Force | Out-Null }
"$Name created at $Path"
$script:changed = $true
} else {
"$Name exists at $Path (no change)"
}
} catch {
"ERROR ensuring $Name at $Path : $($_.Exception.Message)"
}
}
Ensure-Prop -Path $dp -Name 'DefaultIdleState' -Type 'DWord' -Value 0
Ensure-Prop -Path $dp -Name 'UserSetDeviceIdleEnabled' -Type 'DWord' -Value 0
Ensure-Prop -Path $dp -Name 'SSIdleTimeout' -Type 'DWord' -Value 0
$portName = (Get-ItemProperty -Path $dp -ErrorAction SilentlyContinue).PortName
} catch { $portName = $null }
if (-not $portName) {
} else {
"$inst already has PortName = $portName"
}
}
Write-Output "Changes made; restarting now..."
Start-Process -FilePath 'shutdown.exe' -ArgumentList @('/r','/t','0','/f','/c','Applying FTDI Device Parameter changes') -NoNewWindow
} else {
Write-Output "No changes were necessary."
}
Important notes and troubleshooting
Run these commands in an elevated PowerShell (copy/paste). They will:
1) show per‑device PortName and the four selective‑suspend properties,
2) create the missing properties (only if they do NOT exist), and
3) immediately restart the machine if at least one device was changed.
Step A — inspect FTDI devices and Device Parameters (no changes)
Run as Administrator:
list FTDI COM devices and their InstanceIds
Get-PnpDevice -Class Ports -PresentOnly |Where-Object { ($.Manufacturer -and $.Manufacturer -like 'FTDI') -or ($_.InstanceId -match 'VID_0403') } |
Format-Table FriendlyName, InstanceId -AutoSize
pick one InstanceId from the output and run (replace <INSTANCE> with it)
$inst = '<PASTE_InstanceId_HERE>'$dp = "HKLM:\SYSTEM\CurrentControlSet\Enum\$($inst -replace '\','\')\Device Parameters"
Test-Path $dp; if (Test-Path $dp) { Get-ItemProperty -Path $dp | Select-Object PortName, DeviceIdleEnabled, DefaultIdleState, UserSetDeviceIdleEnabled, SSIdleTimeout | Format-List } else { "Device Parameters key not found: $dp" }
This tells us whether PortName is present and whether the selective‑suspend values already exist.
Step B — apply missing values and set PortName if missing, then restart if anything changed
Run this whole block (elevated). It only CREATES properties that are missing (does not overwrite existing values). If any changes are made it will immediately restart the PC (no countdown). If you want a countdown instead, change the shutdown /t 0 to /t 15.
Run as Administrator
$changed = $falsefind FTDI COM ports
$ports = Get-PnpDevice -Class Ports -PresentOnly |Where-Object { ($.Manufacturer -and $.Manufacturer -like 'FTDI') -or ($_.InstanceId -match 'VID_0403') }
foreach ($p in $ports) {
$inst = $p.InstanceId
$dp = "HKLM:\SYSTEM\CurrentControlSet\Enum\$($inst -replace '\','\')\Device Parameters"
if (-not (Test-Path $dp) { New-Item -Path $dp -Force | Out-Null }
helper: only create if missing
function Ensure-Prop {param($Path,$Name,$Type,$Value)
try {
$exists = Get-ItemProperty -Path $Path -Name $Name -ErrorAction SilentlyContinue
if ($null -eq $exists) {
if ($Type -eq 'DWord') { New-ItemProperty -Path $Path -Name $Name -PropertyType DWord -Value $Value -Force | Out-Null }
else { New-ItemProperty -Path $Path -Name $Name -PropertyType String -Value $Value -Force | Out-Null }
"$Name created at $Path"
$script:changed = $true
} else {
"$Name exists at $Path (no change)"
}
} catch {
"ERROR ensuring $Name at $Path : $($_.Exception.Message)"
}
}
ensure the 4 selective-suspend values exist (create only if missing)
Ensure-Prop -Path $dp -Name 'DeviceIdleEnabled' -Type 'DWord' -Value 0Ensure-Prop -Path $dp -Name 'DefaultIdleState' -Type 'DWord' -Value 0
Ensure-Prop -Path $dp -Name 'UserSetDeviceIdleEnabled' -Type 'DWord' -Value 0
Ensure-Prop -Path $dp -Name 'SSIdleTimeout' -Type 'DWord' -Value 0
if PortName is missing, try to discover COM from Win32_SerialPort and write it
try {$portName = (Get-ItemProperty -Path $dp -ErrorAction SilentlyContinue).PortName
} catch { $portName = $null }
if (-not $portName) {
try to find matching Win32_SerialPort by PNPDeviceID or tail
Code:
$foundCom = $null
try { $sp = Get-CimInstance Win32_SerialPort -ErrorAction SilentlyContinue | Where-Object { $_.PNPDeviceID -eq $inst } if ($sp) { $foundCom = $sp.DeviceID } else { # try tail match $tail = $inst.Split('\')[-1] $sp2 = Get-CimInstance Win32_SerialPort -ErrorAction SilentlyContinue | Where-Object { $_.PNPDeviceID -like "*$tail*" } if ($sp2) { $foundCom = $sp2.DeviceID } }
} catch {}
if ($foundCom) { Ensure-Prop -Path $dp -Name 'PortName' -Type 'String' -Value $foundCom if ($changed) { "$inst -> PortName set to $foundCom" }
} else { "Could not detect COM for $inst; skipping PortName create."
}
"$inst already has PortName = $portName"
}
}
if any changes were made, restart immediately
if ($changed) {Write-Output "Changes made; restarting now..."
Start-Process -FilePath 'shutdown.exe' -ArgumentList @('/r','/t','0','/f','/c','Applying FTDI Device Parameter changes') -NoNewWindow
} else {
Write-Output "No changes were necessary."
}
Important notes and troubleshooting
- Must run elevated (Admin). If the script cannot write because of ACL/AccessDenied it will log errors; paste those lines and I’ll advise how to proceed safely. Writing under HKLM...\Enum sometimes requires SYSTEM or changing ACLs — INF AddReg is the recommended long‑term approach if ACLs block you. See Microsoft guidance about per‑device Device Parameters and WinUSB/driver behavior.
- If PortName is created, Device Manager’s Advanced page will show that COM number after a reboot/rescan. If the driver later overwrites this value (driver reinstall/re‑enumeration), consider adding AddReg entries in the driver INF so Windows writes the defaults at install (I can provide the exact AddReg snippet for your oem167.inf).
- To abort a scheduled reboot (if you choose a countdown later): shutdown /a (run elevated).
- Joined
- Mar 14, 2023
- Messages
- 97,513
Thanks — understood: you want the script to never change PortName (COM number) and only create the selective‑suspend / serial‑enumerator values if they’re missing, and to reboot only if the script actually created something.
Below are (A) quick checks to confirm what happened on your run, (B) a corrected idempotent script that does NOT touch PortName at all and WILL reboot only if it created at least one property, and (C) short one‑liner alternatives you can run immediately. Run everything in an elevated PowerShell session.
A — Quick checks (run elevated)
1) Show the last script log (so we can confirm whether the script reported any changes):
Get-ChildItem "$env:USERPROFILE\Desktop\FTDIApplyIfMissing*.log" |
Sort-Object LastWriteTime -Descending |
Select-Object -First 1 |
ForEach-Object { Get-Content -Path $_.FullName -Tail 200 }
Paste the summary lines here if you want me to read them.
2) Confirm one device’s Device Parameters and existing keys (replace <INSTANCE> with a real InstanceId returned by Get-PnpDevice):
Where-Object { ($.Manufacturer -like 'FTDI') -or ($.InstanceId -match 'VID_0403') } |
Format-List FriendlyName,InstanceId
Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Enum\$($inst -replace '\','\')\Device Parameters" -ErrorAction SilentlyContinue | Format-List
Look for DeviceIdleEnabled, DefaultIdleState, UserSetDeviceIdleEnabled, SSIdleTimeout and any Serial‑Enumerator property names. If the four selective‑suspend values already exist, the script correctly skipped them and therefore did not reboot.
B — Idempotent script (DOES NOT touch PortName)
Save this exact script as Disable-FTDI-SelectiveSuspend-OnlyIfMissing-NoPortName.ps1 and run elevated.
What it does: for each FTDI COM port it will create DeviceIdleEnabled, DefaultIdleState, UserSetDeviceIdleEnabled and SSIdleTimeout = 0 only if the property does not already exist. It will set existing serial‑enumerator properties to 0 only if the property exists (it will NOT create new vendor serial names). It will NOT touch PortName. If it created at least one value (and you did not run -WhatIf), it will reboot after 15s. Use -WhatIf to dry run.
Script:
param(
[switch]$WhatIf,
[switch]$NoReboot)
Write-Error "Run as Administrator"; exit 1
}
$log = Join-Path $env:USERPROFILE ("Desktop\FTDIApplyIfMissing{0}.log" -f (Get-Date -Format yyyyMMdd_HHmmss)
"Started: $(Get-Date)" | Out-File $log
$serialEnumRegex = '(serial.enum|enum.serial|serialenumerator|enable.*serial)'
$changedCount = 0
$ports = Get-PnpDevice -Class Ports -PresentOnly -ErrorAction SilentlyContinue |
Where-Object { ($.Manufacturer -and $.Manufacturer -like 'FTDI') -or ($.InstanceId -and $.InstanceId -match 'VID_0403') }
if (-not $ports) {
"No FTDI ports found." | Tee-Object -FilePath $log -Append
Write-Output "No FTDI ports found. See $log"
exit 0
}
foreach ($p in $ports) {
"----" | Tee-Object -FilePath $log -Append
"Device: $($p.FriendlyName) [$($p.InstanceId)]" | Tee-Object -FilePath $log -Append
$inst = $p.InstanceId
$base = "HKLM:\SYSTEM\CurrentControlSet\Enum\$inst"
$candidates = @("$base\Device Parameters", "$base\0000\Device Parameters")
$dpFound = $false
foreach ($dp in $candidates) {
if (Test-Path $dp) {
$dpFound = $true
"Using $dp" | Tee-Object -FilePath $log -Append
} # candidates
if (-not $dpFound) { "No Device Parameters key found for $inst" | Tee-Object -FilePath $log -Append }
} # foreach ports
"Created/updated properties count: $changedCount" | Tee-Object -FilePath $log -Append
if (($changedCount -gt 0) -and (-not $WhatIf) -and (-not $NoReboot) {
"Rebooting in 15s..." | Tee-Object -FilePath $log -Append
Start-Process -FilePath 'shutdown.exe' -ArgumentList @('/r','/t','15','/c','Applying FTDI Device Parameter changes') -NoNewWindow
} else {
"No reboot scheduled." | Tee-Object -FilePath $log -Append
}
"Done" | Tee-Object -FilePath $log -Append
C — One‑line to create missing selective‑suspend properties (no PortName) and reboot if anything created
Run elevated. This is equivalent to the script but inline:
$made=0; Get-PnpDevice -Class Ports -PresentOnly | Where-Object { ($.Manufacturer -like 'FTDI') -or ($.InstanceId -match 'VID0403') } |
ForEach-Object {
$inst=$.InstanceId; $dp1="HKLM:\SYSTEM\CurrentControlSet\Enum\$inst\Device Parameters"; $dp2="HKLM:\SYSTEM\CurrentControlSet\Enum\$inst\0000\Device Parameters";
foreach($dp in @($dp1,$dp2){ if(Test-Path $dp) {
foreach($kv in @('DeviceIdleEnabled','DefaultIdleState','UserSetDeviceIdleEnabled','SSIdleTimeout'){
if(-not (Get-ItemProperty -Path $dp -Name $kv -ErrorAction SilentlyContinue) {
New-Item -Path $dp -Force | Out-Null; New-ItemProperty -Path $dp -Name $kv -PropertyType DWord -Value 0 -Force | Out-Null; $made++;
}
}
break
} }
}; if($made -gt 0){ Start-Process -FilePath 'shutdown.exe' -ArgumentList @('/r','/t','15','/c','Applying FTDI Device Parameter changes') -NoNewWindow } else { Write-Output "No changes were necessary." }
D — Abort countdown
If you see the 15s reboot countdown and change your mind, run (elevated):
shutdown /a
Tell me which you want to do now:
Below are (A) quick checks to confirm what happened on your run, (B) a corrected idempotent script that does NOT touch PortName at all and WILL reboot only if it created at least one property, and (C) short one‑liner alternatives you can run immediately. Run everything in an elevated PowerShell session.
A — Quick checks (run elevated)
1) Show the last script log (so we can confirm whether the script reported any changes):
Get-ChildItem "$env:USERPROFILE\Desktop\FTDIApplyIfMissing*.log" |
Sort-Object LastWriteTime -Descending |
Select-Object -First 1 |
ForEach-Object { Get-Content -Path $_.FullName -Tail 200 }
Paste the summary lines here if you want me to read them.
2) Confirm one device’s Device Parameters and existing keys (replace <INSTANCE> with a real InstanceId returned by Get-PnpDevice):
list FTDI ports
Get-PnpDevice -Class Ports -PresentOnly |Where-Object { ($.Manufacturer -like 'FTDI') -or ($.InstanceId -match 'VID_0403') } |
Format-List FriendlyName,InstanceId
inspect one instance (paste the InstanceId from previous command)
$inst = '<PASTE_INSTANCEID_HERE>'Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Enum\$($inst -replace '\','\')\Device Parameters" -ErrorAction SilentlyContinue | Format-List
Look for DeviceIdleEnabled, DefaultIdleState, UserSetDeviceIdleEnabled, SSIdleTimeout and any Serial‑Enumerator property names. If the four selective‑suspend values already exist, the script correctly skipped them and therefore did not reboot.
B — Idempotent script (DOES NOT touch PortName)
Save this exact script as Disable-FTDI-SelectiveSuspend-OnlyIfMissing-NoPortName.ps1 and run elevated.
What it does: for each FTDI COM port it will create DeviceIdleEnabled, DefaultIdleState, UserSetDeviceIdleEnabled and SSIdleTimeout = 0 only if the property does not already exist. It will set existing serial‑enumerator properties to 0 only if the property exists (it will NOT create new vendor serial names). It will NOT touch PortName. If it created at least one value (and you did not run -WhatIf), it will reboot after 15s. Use -WhatIf to dry run.
Script:
param(
[switch]$WhatIf,
[switch]$NoReboot)
require elevation
if (-not ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent.IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator) {Write-Error "Run as Administrator"; exit 1
}
$log = Join-Path $env:USERPROFILE ("Desktop\FTDIApplyIfMissing{0}.log" -f (Get-Date -Format yyyyMMdd_HHmmss)
"Started: $(Get-Date)" | Out-File $log
$serialEnumRegex = '(serial.enum|enum.serial|serialenumerator|enable.*serial)'
$changedCount = 0
$ports = Get-PnpDevice -Class Ports -PresentOnly -ErrorAction SilentlyContinue |
Where-Object { ($.Manufacturer -and $.Manufacturer -like 'FTDI') -or ($.InstanceId -and $.InstanceId -match 'VID_0403') }
if (-not $ports) {
"No FTDI ports found." | Tee-Object -FilePath $log -Append
Write-Output "No FTDI ports found. See $log"
exit 0
}
foreach ($p in $ports) {
"----" | Tee-Object -FilePath $log -Append
"Device: $($p.FriendlyName) [$($p.InstanceId)]" | Tee-Object -FilePath $log -Append
$inst = $p.InstanceId
$base = "HKLM:\SYSTEM\CurrentControlSet\Enum\$inst"
$candidates = @("$base\Device Parameters", "$base\0000\Device Parameters")
$dpFound = $false
foreach ($dp in $candidates) {
if (Test-Path $dp) {
$dpFound = $true
"Using $dp" | Tee-Object -FilePath $log -Append
Code:
# Only create if missing $props = @{ 'DeviceIdleEnabled' = 0 'DefaultIdleState' = 0 'UserSetDeviceIdleEnabled' = 0 'SSIdleTimeout' = 0 } foreach ($kv in $props.GetEnumerator { $name = $kv.Key; $val = $kv.Value $exists = $false try { $exists = (Get-ItemProperty -Path $dp -Name $name -ErrorAction SilentlyContinue) -ne $null } catch { $exists = $false } if ($exists) { "$name exists — skipping" | Tee-Object -FilePath $log -Append } else { if ($WhatIf) { "WhatIf: would create $name = $val at $dp" | Tee-Object -FilePath $log -Append $changedCount++ } else { try { New-Item -Path $dp -Force | Out-Null New-ItemProperty -Path $dp -Name $name -PropertyType DWord -Value $val -Force -ErrorAction Stop | Out-Null "Created $name = $val" | Tee-Object -FilePath $log -Append $changedCount++ } catch { "ERROR creating $name at $dp: $($_.Exception.Message)" | Tee-Object -FilePath $log -Append } } } } # If serial-enum props exist, set them to 0 (but do NOT create new unknown names) try { $existing = (Get-ItemProperty -Path $dp -ErrorAction SilentlyContinue).PSObject.Properties | ForEach-Object { $_.Name } } catch { $existing = @ } foreach ($nm in $existing) { if ($nm -match $serialEnumRegex) { # read current try { $cur = (Get-ItemProperty -Path $dp -Name $nm -ErrorAction SilentlyContinue).$nm } catch { $cur = $null } if ($null -eq $cur) { if ($WhatIf) { "WhatIf: would set existing $nm = 0 at $dp" | Tee-Object -FilePath $log -Append $changedCount++ } else { try { New-ItemProperty -Path $dp -Name $nm -PropertyType DWord -Value 0 -Force -ErrorAction Stop | Out-Null "Set $nm = 0" | Tee-Object -FilePath $log -Append $changedCount++ } catch { "ERROR writing $nm at $dp: $($_.Exception.Message)" | Tee-Object -FilePath $log -Append } } } else { "$nm exists with value $cur — not overwriting" | Tee-Object -FilePath $log -Append } } } break
} # Test-Path
if (-not $dpFound) { "No Device Parameters key found for $inst" | Tee-Object -FilePath $log -Append }
} # foreach ports
"Created/updated properties count: $changedCount" | Tee-Object -FilePath $log -Append
if (($changedCount -gt 0) -and (-not $WhatIf) -and (-not $NoReboot) {
"Rebooting in 15s..." | Tee-Object -FilePath $log -Append
Start-Process -FilePath 'shutdown.exe' -ArgumentList @('/r','/t','15','/c','Applying FTDI Device Parameter changes') -NoNewWindow
} else {
"No reboot scheduled." | Tee-Object -FilePath $log -Append
}
"Done" | Tee-Object -FilePath $log -Append
C — One‑line to create missing selective‑suspend properties (no PortName) and reboot if anything created
Run elevated. This is equivalent to the script but inline:
$made=0; Get-PnpDevice -Class Ports -PresentOnly | Where-Object { ($.Manufacturer -like 'FTDI') -or ($.InstanceId -match 'VID0403') } |
ForEach-Object {
$inst=$.InstanceId; $dp1="HKLM:\SYSTEM\CurrentControlSet\Enum\$inst\Device Parameters"; $dp2="HKLM:\SYSTEM\CurrentControlSet\Enum\$inst\0000\Device Parameters";
foreach($dp in @($dp1,$dp2){ if(Test-Path $dp) {
foreach($kv in @('DeviceIdleEnabled','DefaultIdleState','UserSetDeviceIdleEnabled','SSIdleTimeout'){
if(-not (Get-ItemProperty -Path $dp -Name $kv -ErrorAction SilentlyContinue) {
New-Item -Path $dp -Force | Out-Null; New-ItemProperty -Path $dp -Name $kv -PropertyType DWord -Value 0 -Force | Out-Null; $made++;
}
}
break
} }
}; if($made -gt 0){ Start-Process -FilePath 'shutdown.exe' -ArgumentList @('/r','/t','15','/c','Applying FTDI Device Parameter changes') -NoNewWindow } else { Write-Output "No changes were necessary." }
D — Abort countdown
If you see the 15s reboot countdown and change your mind, run (elevated):
shutdown /a
Tell me which you want to do now:
- I’ll inspect the log for you (paste the log summary or run the log command and paste output), or
- You want me to run (i.e., you want the exact command) the idempotent one‑liner above to create any missing properties (it does not touch PortName) and then reboot, or
- You want the saved script file pasted for copying (I included it above).
sjbesenski
Member
- Joined
- Nov 21, 2025
- Messages
- 71
- Thread Author
-
- #60
give me the script to run
Similar threads
- Article
- Replies
- 0
- Views
- 19
- Article
- Replies
- 0
- Views
- 32
- Article
- Replies
- 0
- Views
- 113
- Replies
- 0
- Views
- 50
- Article
- Replies
- 0
- Views
- 43