Cannot find the type for custom attribute 'byte[]'. Make sure that the assembly that contains this type is loaded.
At C:\Users\kioskuser2\Documents\Disable_FTDI_Selective_Suspend.ps1:41 char:17
+ $desiredBytes = [byte[](0x01,0x00,0x3F,0x3F)]
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: ([byte[](0x01,0x00,0x3F,0x3F)]:AttributeAst) [], RuntimeException
+ FullyQualifiedErrorId : CustomAttributeTypeNotFound
Cannot index into a null array.
At C:\Users\kioskuser2\Documents\Disable_FTDI_Selective_Suspend.ps1:189 char:13
+ if ($bytes[$i] -ne $desiredBytes[$i]) { $needCfgWrite = $true ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation:

) [], RuntimeException
+ FullyQualifiedErrorId : NullArray
Cannot index into a null array.
At C:\Users\kioskuser2\Documents\Disable_FTDI_Selective_Suspend.ps1:189 char:13
+ if ($bytes[$i] -ne $desiredBytes[$i]) { $needCfgWrite = $true ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation:

) [], RuntimeException
+ FullyQualifiedErrorId : NullArray
Cannot index into a null array.
At C:\Users\kioskuser2\Documents\Disable_FTDI_Selective_Suspend.ps1:189 char:13
+ if ($bytes[$i] -ne $desiredBytes[$i]) { $needCfgWrite = $true ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation:

) [], RuntimeException
+ FullyQualifiedErrorId : NullArray
Cannot index into a null array.
At C:\Users\kioskuser2\Documents\Disable_FTDI_Selective_Suspend.ps1:189 char:13
+ if ($bytes[$i] -ne $desiredBytes[$i]) { $needCfgWrite = $true ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation:

) [], RuntimeException
+ FullyQualifiedErrorId : NullArray
<#
Disable_FTDI_Selective_Suspend.ps1
- Force-overwrite selective-suspend properties (DeviceIdleEnabled, DefaultIdleState, UserSetDeviceIdleEnabled, SSIdleTimeout)
- Ensure ConfigData first 4 bytes are 01 00 3F 3F (modify only those bytes)
- Keep PortName behavior (write only if missing)
- Launch pnputil /scan-devices in background and optionally schedule reboot
- Supports -WhatIf for dry-run
Run as Administrator.
#>
param(
[switch]$WhatIf,
[switch]$NoReboot
)
# require elevation
if (-not ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator)) {
Write-Error "This script must be run as Administrator. Exiting."
exit 1
}
$timestamp = (Get-Date).ToString('yyyyMMdd_HHmmss')
$logFile = Join-Path $env:USERPROFILE ("Desktop\Disable_Selective_Suspend_$timestamp.log")
"Started: $(Get-Date -Format u)" | Out-File -FilePath $logFile -Encoding UTF8
function Get-ComForInstance {
param([string]$instanceId)
try {
$sp = Get-CimInstance -ClassName Win32_SerialPort -ErrorAction SilentlyContinue | Where-Object { $_.PNPDeviceID -eq $instanceId }
if ($sp) { return $sp.DeviceID }
$tail = ($instanceId -split '\\')[-1]
if ($tail) {
$sp = Get-CimInstance -ClassName Win32_SerialPort -ErrorAction SilentlyContinue | Where-Object { $_.PNPDeviceID -like "*$tail*" }
if ($sp) { return $sp.DeviceID }
}
} catch { }
return $null
}
# desired first 4 bytes (01 00 3F 3F)
$desiredBytes = [byte[](0x01,0x00,0x3F,0x3F)]
# corresponding little-endian DWORD
$desiredDword = [uint32]0x3F3F0001
# Find 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
$createdCount = 0
$errors = @()
$processedDp = @{} # avoid reprocessing same DP
foreach ($p in $ports) {
"----" | Tee-Object -FilePath $logFile -Append
"Device 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; continue }
$regPathBase = "HKLM:\SYSTEM\CurrentControlSet\Enum\$inst"
$dpCandidates = @("$regPathBase\Device Parameters","$regPathBase\0000\Device Parameters")
$dpFoundForInstance = $false
foreach ($dp in $dpCandidates) {
$dpStr = [string]$dp
"Checking: $dpStr" | Tee-Object -FilePath $logFile -Append
if ($processedDp.ContainsKey($dpStr)) {
"Already processed $dpStr this run - skipping." | Tee-Object -FilePath $logFile -Append
$dpFoundForInstance = $true
break
}
if (Test-Path $dpStr) {
$dpFoundForInstance = $true
"Using Device Parameters: $($dpStr)" | Tee-Object -FilePath $logFile -Append
$processedDp[$dpStr] = $true
# Read existing properties
try {
$item = Get-ItemProperty -Path $dpStr -ErrorAction SilentlyContinue
$existingProps = if ($item) { $item.PSObject.Properties | ForEach-Object { $_.Name } } else { @() }
} catch {
$existingProps = @()
}
# PortName: write only if missing
if (-not ($existingProps -contains 'PortName')) {
$friendly = $p.FriendlyName
$detectedCom = $null
if ($friendly -and ($friendly -match '\(COM(\d+)\)')) {
$detectedCom = "COM$($matches[1])"
"Detected COM from FriendlyName: $($detectedCom)" | Tee-Object -FilePath $logFile -Append
} else {
$detectedCom = Get-ComForInstance -instanceId $inst
if ($detectedCom) { "Detected COM via WMI: $($detectedCom)" | Tee-Object -FilePath $logFile -Append }
}
if ($detectedCom) {
if ($WhatIf) {
"WhatIf: would write PortName = $($detectedCom) at $($dpStr)" | Tee-Object -FilePath $logFile -Append
} else {
try {
New-Item -Path $dpStr -Force | Out-Null
New-ItemProperty -Path $dpStr -Name 'PortName' -PropertyType String -Value $detectedCom -Force -ErrorAction Stop | Out-Null
"WROTE PortName = $($detectedCom) at $($dpStr)" | Tee-Object -FilePath $logFile -Append
$createdCount++
} catch {
"ERROR writing PortName at $($dpStr) : $($_.Exception.Message)" | Tee-Object -FilePath $logFile -Append
$errors += "PortName write error for $inst : $($_.Exception.Message)"
}
}
} else {
"Could not detect COM for $inst; PortName not written." | Tee-Object -FilePath $logFile -Append
}
} else {
$currPort = (Get-ItemProperty -Path $dpStr -Name 'PortName' -ErrorAction SilentlyContinue).PortName
"PortName already present at $($dpStr): $($currPort) - not changed" | Tee-Object -FilePath $logFile -Append
}
# Force-selective-suspend writes if missing or not 0
$toForce = @{ DeviceIdleEnabled = 0; DefaultIdleState = 0; UserSetDeviceIdleEnabled = 0; SSIdleTimeout = 0 }
foreach ($kv in $toForce.GetEnumerator()) {
$name = $kv.Key; $desired = [int]$kv.Value
try { $existingVal = (Get-ItemProperty -Path $dpStr -Name $name -ErrorAction SilentlyContinue).$name } catch { $existingVal = $null }
$needWrite = $false
if ($existingVal -eq $null) { $needWrite = $true }
else { try { if ([int]$existingVal -ne $desired) { $needWrite = $true } } catch { $needWrite = $true } }
if ($needWrite) {
if ($WhatIf) { "WhatIf: would set $($name) = $desired at $($dpStr)" | Tee-Object -FilePath $logFile -Append }
else {
try {
New-Item -Path $dpStr -Force | Out-Null
New-ItemProperty -Path $dpStr -Name $name -PropertyType DWord -Value $desired -Force -ErrorAction Stop | Out-Null
"WROTE $($name) = $desired at $($dpStr)" | Tee-Object -FilePath $logFile -Append
$createdCount++
} catch {
"ERROR writing $($name) at $($dpStr) : $($_.Exception.Message)" | Tee-Object -FilePath $logFile -Append
$errors += "Write $($name) error for $inst : $($_.Exception.Message)"
}
}
} else {
"$($name) already = $existingVal at $($dpStr) - not changed" | Tee-Object -FilePath $logFile -Append
}
}
# ConfigData: ensure first 4 bytes are 01 00 3F 3F
# Read raw value (may be binary or dword)
$cfgRaw = $null
try { $cfgRaw = (Get-ItemProperty -Path $dpStr -Name 'ConfigData' -ErrorAction SilentlyContinue).ConfigData } catch { $cfgRaw = $null }
# Normalize to a byte[] safely
$bytes = $null
$origType = 'Missing'
if ($cfgRaw -ne $null) {
if ($cfgRaw -is [byte[]]) {
$bytes = [byte[]]$cfgRaw
$origType = 'Binary'
} elseif ($cfgRaw -is [int] -or $cfgRaw -is [uint32] -or $cfgRaw -is [long]) {
$bytes = [BitConverter]::GetBytes([uint32]$cfgRaw)
$origType = 'DWord'
} else {
try { $bytes = [byte[]]$cfgRaw; $origType='Binary' } catch { $bytes = New-Object byte[] 0; $origType='Unknown' }
}
} else {
$bytes = New-Object byte[] 0
$origType = 'Missing'
}
# Ensure we have at least 4 bytes (pad with zeros if necessary)
if ($null -eq $bytes) { $bytes = New-Object byte[] 4 }
if ($bytes.Length -lt 4) {
$newBytes = New-Object byte[] 4
if ($bytes.Length -gt 0) { [System.Array]::Copy($bytes, 0, $newBytes, 0, $bytes.Length) }
$bytes = $newBytes
}
$needCfgWrite = $false
for ($i=0; $i -lt 4; $i++) {
if ($bytes[$i] -ne $desiredBytes[$i]) { $needCfgWrite = $true; break }
}
if ($needCfgWrite) {
for ($i=0; $i -lt 4; $i++) { $bytes[$i] = $desiredBytes[$i] }
if ($WhatIf) {
"WhatIf: would update ConfigData first 4 bytes at $($dpStr) (orig type: $origType)" | Tee-Object -FilePath $logFile -Append
} else {
try {
if ($origType -eq 'DWord') {
$newDword = [BitConverter]::ToUInt32($bytes,0)
New-Item -Path $dpStr -Force | Out-Null
New-ItemProperty -Path $dpStr -Name 'ConfigData' -PropertyType DWord -Value $newDword -Force -ErrorAction Stop | Out-Null
"WROTE ConfigData (DWORD) = 0x$([Convert]::ToString($newDword,16).ToUpper()) at $($dpStr)" | Tee-Object -FilePath $logFile -Append
} else {
New-Item -Path $dpStr -Force | Out-Null
Set-ItemProperty -Path $dpStr -Name 'ConfigData' -Value $bytes -ErrorAction Stop
"WROTE ConfigData (Binary) first 4 bytes updated at $($dpStr)" | Tee-Object -FilePath $logFile -Append
}
$createdCount++
} catch {
"ERROR writing ConfigData at $($dpStr) : $($_.Exception.Message)" | Tee-Object -FilePath $logFile -Append
$errors += "ConfigData write error for $inst : $($_.Exception.Message)"
}
}
} else {
"ConfigData first 4 bytes already match desired pattern at $($dpStr) (no change)." | Tee-Object -FilePath $logFile -Append
}
break
} else {
"Not found: $($dpStr)" | Tee-Object -FilePath $logFile -Append
}
}
if (-not $dpFoundForInstance) {
"No Device Parameters found for instance $inst (expected path: $regPathBase). Skipping." | Tee-Object -FilePath $logFile -Append
}
} # end foreach ports
"Created/changed count: $createdCount" | Tee-Object -FilePath $logFile -Append
if ($errors.Count -gt 0) {
"Errors: $($errors.Count)" | Tee-Object -FilePath $logFile -Append
$errors | Tee-Object -FilePath $logFile -Append
}
# Launch pnputil asynchronously so script ends quickly
try {
"Launching device rescan: pnputil /scan-devices (background)" | Tee-Object -FilePath $logFile -Append
$proc = Start-Process -FilePath 'pnputil.exe' -ArgumentList '/scan-devices' -NoNewWindow -PassThru
"pnputil started (PID $($proc.Id))" | Tee-Object -FilePath $logFile -Append
} catch {
"pnputil failed to start: $($_.Exception.Message)" | Tee-Object -FilePath $logFile -Append
}
if (($createdCount -gt 0) -and (-not $WhatIf) -and (-not $NoReboot)) {
"Scheduling reboot in 15 seconds so changes take effect (abort with 'shutdown /a')." | Tee-Object -FilePath $logFile -Append
Start-Process -FilePath 'shutdown.exe' -ArgumentList @('/r','/t','15','/c','Applying FTDI Device Parameter changes') -NoNewWindow
} else {
"No reboot scheduled. If you created properties and want immediate recognition, run: pnputil /scan-devices or reboot manually." | Tee-Object -FilePath $logFile -Append
}
"Completed: $(Get-Date -Format u)" | Tee-Object -FilePath $logFile -Append
Write-Output "Done. Log saved to: $logFile"