# DISCLAIMER: # THIS SCRIPT IS WORK IN PROGRESS AND HAS NOT UNDERGONE VALIDATION TESTING. # FOR USE BY =S= SUPPORT PERSONNEL ONLY, NOT FOR DISTRIBUTION. # # Usage: Copy this file to the desktop, then copy/paste the following into an Admin PowerShell: # $savedPolicy = $(Get-ExecutionPolicy); Set-ExecutionPolicy -Force RemoteSigned; . "$home\Desktop\Release-PerUserDrivers.ps1" # # If you want to really clean up, then add the "--no-dry-run" option. # # Note that setting the execution policy can be a security risk, hence the example given above saves the previous setting and the script restores it immediately: if ($savedPolicy -in "AllSigned", "Bypass", "Default", "Restricted", "Undefined", "Unrestricted") { Set-ExecutionPolicy -Force $savedPolicy } $dryrun = $true $includeCurrentUser = $false $includePerMachine = $false $args | ForEach-Object { # Don't do anything, just show what would be done $dryrun = $dryrun -and $_ -notin "-n", "--no-dry-run" # Process drivers installed for the currently logged-on user in addition to those installed for other users $includeCurrentUser = $includeCurrentUser -or $_ -in "-u", "--include-current-user" # Process 14.14+ drivers (installed per-machine) in addition to the older ones (installed per-user) $includePerMachine = $includePerMachine -or $_ -in "-m", "--include-per-machine" } # input: "ABCDEFGH-IJKL-MNOP-QRST-UVWXYZ123456" # output: "HGFEDCBALKJIPONMRQTSVUXWZY214365" function ScrambleGuid { param ($guid) $scrambled = "" $parts = $guid.Split('-') # "ABCDEFGH-IJKL-MNOP" -> "HGFEDCBALKJIPONM" for ($i = 0; $i -lt 3; ++$i) { $charArray = $parts[$i].ToCharArray() [array]::Reverse($charArray) $scrambled += -join($charArray) } # "QRST-UVWXYZ123456" -> "RQTSVUXWZY214365" for ($i = 3; $i -lt 5; ++$i) { $part = $parts[$i] for ($j = 0; $j -lt $part.Length; $j += 2) { $scrambled += $part[$j + 1] + $part[$j] } } return $scrambled } # Product names (predefined - do not change) $DriverManager32 = "Driver Manager" $DriverManager64 = "DriverManager x64" $ModbusDriver32 = "Modbus Driver" $ModbusDriver64 = "Modbus Driver X64" $UnitelwayDriver32 = "Unitelway Driver" $UnitelwayDriver64 = "Unitelway Driver X64" $UsbDriver32 = "PLC Usb Driver" $UsbDriver64 = "PLCUsb Driver X64" $XipDriver32 = "Xip Driver" $XipDriver64 = "Xip Driver X64" # Setup reference files. These are used by the suite setup to determine # whether or not the installed version is older than the one to be installed. $ReferenceFiles = @{} $ReferenceFiles[$DriverManager32] = $ReferenceFiles[$DriverManager64] = "NA_Service.exe" $ReferenceFiles[$ModbusDriver32] = $ReferenceFiles[$ModbusDriver64] = "ModbusDrvSys.exe" $ReferenceFiles[$UnitelwayDriver32] = $ReferenceFiles[$UnitelwayDriver64] = "Unitelw.dll" $ReferenceFiles[$UsbDriver32] = $ReferenceFiles[$UsbDriver64] = "UsbConnect.exe" $ReferenceFiles[$XipDriver32] = $ReferenceFiles[$XipDriver64] = "XipDrvSys.exe" $ProductNames = $ReferenceFiles.Keys $SuiteVersionsByDriverVersion = @{ $DriverManager32 = @{ "003.031.00000" = "14.15.2" "003.030.00000" = "14.15.1" "003.029.00000" = "14.15" "003.028.00000" = "14.14" "003.027.00000" = "14.13" "003.026.00000" = "14.12 or 14.12.1" "003.025.00000" = "14.11" "003.024.00000" = "14.10" } $DriverManager64 = @{ "004.031.00000" = "14.15.2" "004.030.00000" = "14.15.1" "004.029.00000" = "14.15" "004.028.00000" = "14.14" "004.027.00000" = "14.13" "004.026.00000" = "14.12 or 14.12.1" "004.025.00000" = "14.11" "004.024.00000" = "14.10" } $ModbusDriver32 = @{ "002.031.00000" = "14.15.1" "002.030.00000" = "14.15" "002.029.00000" = "14.14" "002.028.00000" = "14.13" "002.027.00000" = "14.12.1" "002.026.00000" = "14.12" "002.025.00000" = "14.11" "002.024.00000" = "14.10" } $ModbusDriver64 = @{ "003.031.00000" = "14.15.1" "003.030.00000" = "14.15" "003.029.00000" = "14.14" "003.028.00000" = "14.13" "003.027.00000" = "14.12.1" "003.026.00000" = "14.12" "003.025.00000" = "14.11" "003.024.00000" = "14.10" } $UnitelwayDriver32 = @{ "002.025.00000" = "14.15" "002.024.00000" = "14.14" "002.023.00000" = "14.13" "002.022.00000" = "14.12 or 14.12.1" "002.021.00000" = "14.11" "002.020.00000" = "14.10" } $UnitelwayDriver64 = @{ "003.025.00000" = "14.15" "003.024.00000" = "14.14" "003.023.00000" = "14.13" "003.022.00000" = "14.12 or 14.12.1" "003.021.00000" = "14.11" "003.020.00000" = "14.10" } $UsbDriver32 = @{ "002.028.00000" = "14.15" "002.027.00000" = "14.14" "002.026.00000" = "14.13" "002.025.00000" = "14.12" "002.024.00000" = "14.11" "002.023.00000" = "14.10" } $UsbDriver64 = @{ "003.028.00000" = "14.15" "003.027.00000" = "14.14" "003.026.00000" = "14.13" "003.025.00000" = "14.12" "003.024.00000" = "14.11" "003.023.00000" = "14.10" } $XipDriver32 = @{ "002.026.00000" = "14.15.1" "002.025.00000" = "14.15" "002.024.00000" = "14.14" "002.023.00000" = "14.13" "002.022.00000" = "14.12" "002.021.00000" = "14.10 or 14.11" } $XipDriver64 = @{ "003.026.00000" = "14.15.1" "003.025.00000" = "14.15" "003.024.00000" = "14.14" "003.023.00000" = "14.13" "003.022.00000" = "14.12" "003.021.00000" = "14.10 or 14.11" } } $ProductCodes = @{ $DriverManager32 = "F1365987-E481-441D-9AFF-2915325128B6" $DriverManager64 = "4201BA84-EC1B-4B75-A1EF-E77D3E958465" $ModbusDriver32 = "B01881D0-6709-4F46-A8AC-53CE8EED4C6A" $ModbusDriver64 = "708DB6DF-6949-46FA-AADD-752937B0FC72" $UnitelwayDriver32 = "3CEB7206-AFB6-4838-B8C9-012E7B67F708" $UnitelwayDriver64 = "889874D3-81AB-4728-ABA5-BF928B9A6963" $UsbDriver32 = "CA29A899-7713-4B15-801D-15C6833BC00B" $UsbDriver64 = "771C6F2F-BCE2-4773-BA33-21B31B14F57B" $XipDriver32 = "358BB4A7-3734-4173-AEB1-858BDEA892D3" $XipDriver64 = "2F6C6C4C-85CB-49B3-9AE2-974DFBC4145D" } $ScrambledProductCodes = @{} $ProductCodes.Keys | ForEach-Object { $ScrambledProductCodes[$_] = ScrambleGuid($ProductCodes[$_]) } $UpgradeCodes = @{ $DriverManager32 = "A20B01E2-0B8D-41FF-9C77-B22AE44634F6" $DriverManager64 = "6C11AB26-4709-4A03-A374-607963A81218" $ModbusDriver32 = "8EF6C4E0-002E-4334-BC81-FF7BD805F487" $ModbusDriver64 = "4AAA104C-4028-40D6-934E-DCA46E78EA48" $UnitelwayDriver32 = "554F8A8C-6106-4FBC-B861-A5144F98B66E" $UnitelwayDriver64 = "2D9B4BA1-475D-47B4-93A5-7910B9BA9824" $UsbDriver32 = "E7985CC1-8199-461D-B4D5-85B8FE4C75B7" $UsbDriver64 = "F75AFF09-85F7-4C89-ABDE-18C0D8EFE8FB" $XipDriver32 = "ACF7B986-BDFF-4845-86E6-CCA465E72A11" $XipDriver64 = "FFD5C1D6-7DA9-4D78-9A6D-C1EDD1079287" } $ScrambledUpgradeCodes = @{} $UpgradeCodes.Keys | ForEach-Object { $ScrambledUpgradeCodes[$_] = ScrambleGuid($UpgradeCodes[$_]) } $CurrentUser = [System.Security.Principal.WindowsIdentity]::GetCurrent() $CurrentUserSidString = $CurrentUser.User.Value Write-Host "Current user is $($CurrentUser.Name) ($CurrentUserSidString) on $env:COMPUTERNAME" # Stop services "NA_Service","UsbConnect" | ForEach-Object { Get-Service $_ -ErrorAction SilentlyContinue | ForEach-Object { if ($dryrun) { Write-Host "would stop service $($_.DisplayName) ($($_.ServiceName))" } else { Write-Host "stopping service $($_.DisplayName) ($($_.ServiceName))" Stop-Service $_ } } } $NothingFound = $True # Delete Windows Installer registry keys # Get user keys to search, skipping LocalSystem and the user who runs the setup $UserDataKey = "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData" $KeyPathLen = $UserDataKey.Length + 1 Write-Host "`nChecking registry at $UserDataKey`n" $LocalSystemSidString = "S-1-5-18" if (Test-Path "Registry::\$UserDataKey\") { $UserKeys = Get-ChildItem "Registry::\$UserDataKey" -Name | Where-Object { (($_ -ne $CurrentUserSidString) -or $includeCurrentUser) -and (($_ -ne $LocalSystemSidString) -or $includePerMachine) } } # Search for installed product and delete respective keys (may be installed for more than one user) $UserKeys | ForEach-Object { $SidString = $_ $ProductsKey = "$UserDataKey\$SidString\Products" if (Test-Path "Registry::\$ProductsKey") { # if there are any installed products at all # Check if InstallProperties subkey of any product has a DisplayName that matches our product name Get-ChildItem "Registry::\$ProductsKey" | ForEach-Object { $installProperties = $_.OpenSubKey("InstallProperties") if ($installProperties -ne $null) { $DisplayName = $installProperties.GetValue("DisplayName", $null) $DisplayVersion = $installProperties.GetValue("DisplayVersion", $null) $InstallDate = $installProperties.GetValue("InstallDate", $null) $InstallDate = $InstallDate.Substring(0, 4) + "-" + $InstallDate.Substring(4, 2) + "-" + $InstallDate.Substring(6, 2) $installProperties.Close() if ($DisplayName -in $ProductNames) { # if we've found one of our products $NothingFound = $False # Get owner and version for display if ($SidString -ne $LocalSystemSidString) { $ProductOwnerSid = New-Object System.Security.Principal.SecurityIdentifier("$SidString") try { $ProductOwnerName = "user " + $ProductOwnerSid.Translate([System.Security.Principal.NTAccount]).Value } catch [System.Security.Principal.IdentityNotMappedException] { $ProductOwnerName = "deleted user account $SidString" } } else { $ProductOwnerName = "all users" } $SuiteVersion = $SuiteVersionsByDriverVersion[$DisplayName][$DisplayVersion] Write-Host "$DisplayName $DisplayVersion ($SuiteVersion) was installed on $InstallDate for $ProductOwnerName" # Delete key $KeyName = ([string]$_).Remove(0, $KeyPathLen) if ($dryrun) { Write-Host " would delete Windows Installer registry key $KeyName" } else { Write-Host " deleting Windows Installer registry key $KeyName" Remove-Item "Registry::\$_" -Recurse } # Delete setup reference files $ReferenceFiles[$DisplayName] | ForEach-Object { "$env:SystemRoot\System32\$_" } | Where-Object { Test-Path $_ } | ForEach-Object { $file = Get-Item $_ $date = $file.LastWriteTime.ToString("yyyy-MM-dd") if ($dryrun) { Write-Host " would delete setup reference file $_, last modified $date" } else { Write-Host " deleting setup reference file $_, last modified $date" Remove-Item $_ } } Write-Host } } } } $ComponentsKey = "$UserDataKey\$SidString\Components" $KeyName = $ComponentsKey.Remove(0, $KeyPathLen) Write-Host "Checking installed components at $KeyName" if (Test-Path "Registry::\$ComponentsKey") { # if there are any installed components at all Get-ChildItem "Registry::\$ComponentsKey" | ForEach-Object { $key = $_ $KeyName = $_.PSChildName $component = $_.Property[0] $ScrambledProductCodes.GetEnumerator() | Where-Object { $_.Value -eq $component } | ForEach-Object { $NothingFound = $False if ($dryrun) { Write-Host " would delete $($_.Name) key $KeyName" } else { Write-Host " deleting $($_.Name) key $KeyName" Remove-Item "Registry::\$key" -Recurse } } } } } $UpgradeCodesKey = "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UpgradeCodes" Write-Host "`nChecking upgrade codes at $UpgradeCodesKey" Get-ChildItem "Registry::\$UpgradeCodesKey" | ForEach-Object { $key = $_ $upgradeCode = $_.PSChildName $ScrambledUpgradeCodes.GetEnumerator() | Where-Object { $_.Value -eq $upgradeCode } | ForEach-Object { $NothingFound = $False if ($dryrun) { Write-Host " would delete $($_.Name) key $upgradeCode" } else { Write-Host " deleting $($_.Name) key $upgradeCode" Remove-Item "Registry::\$key" -Recurse } } } $UninstallKey = "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall" Write-Host "`nChecking uninstall entries at $UninstallKey" Get-ChildItem "Registry::\$UninstallKey" | ForEach-Object { $key = $_ $productCode = $_.PSChildName $productCode = $productCode.Substring(1, $productCode.Length - 2) $ProductCodes.GetEnumerator() | Where-Object { $_.Value -eq $productCode } | ForEach-Object { if ($dryrun) { Write-Host " would delete $($_.Key) key {$productCode}" } else { Write-Host " deleting $($_.Key) key {$productCode}" Remove-Item "Registry::\$key" -Recurse } } } if ($includePerMachine) { $MachineInstallerKey = "HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Installer" Write-Host "`nChecking Windows Installer entries at $MachineInstallerKey" Get-ChildItem "Registry::\$MachineInstallerKey\Products" | ForEach-Object { $key = $_ $productCode = $_.PSChildName $ScrambledProductCodes.GetEnumerator() | Where-Object { $_.Value -eq $productCode } | ForEach-Object { $NothingFound = $False if ($dryrun) { Write-Host " would delete $($_.Name) key Products\$productCode" } else { Write-Host " deleting $($_.Name) key Products\$productCode" Remove-Item "Registry::\$key" -Recurse } } } Get-ChildItem "Registry::\$MachineInstallerKey\Features" | ForEach-Object { $key = $_ $featureCode = $_.PSChildName $ScrambledProductCodes.GetEnumerator() | Where-Object { $_.Value -eq $featureCode } | ForEach-Object { $NothingFound = $False if ($dryrun) { Write-Host " would delete $($_.Name) key Features\$featureCode" } else { Write-Host " deleting $($_.Name) key Features\$featureCode" Remove-Item "Registry::\$key" -Recurse } } } Get-ChildItem "Registry::\$MachineInstallerKey\UpgradeCodes" | ForEach-Object { $key = $_ $upgradeCode = $_.PSChildName $ScrambledUpgradeCodes.GetEnumerator() | Where-Object { $_.Value -eq $upgradeCode } | ForEach-Object { $NothingFound = $False if ($dryrun) { Write-Host " would delete $($_.Name) key UpgradeCodes\$upgradeCode" } else { Write-Host " deleting $($_.Name) key UpgradeCodes\$upgradeCode" Remove-Item "Registry::\$key" -Recurse } } } } if ($includeCurrentUser) { $UserInstallerKey = "HKEY_CURRENT_USER\SOFTWARE\Microsoft\Installer" if (Test-Path "Registry::\$UserInstallerKey\") { Write-Host "`nChecking Windows Installer entries at $UserInstallerKey" Get-ChildItem "Registry::\$UserInstallerKey\Products" | ForEach-Object { $key = $_ $productCode = $_.PSChildName $ScrambledProductCodes.GetEnumerator() | Where-Object { $_.Value -eq $productCode } | ForEach-Object { $NothingFound = $False if ($dryrun) { Write-Host " would delete $($_.Name) key Products\$productCode" } else { Write-Host " deleting $($_.Name) key Products\$productCode" Remove-Item "Registry::\$key" -Recurse } } } Get-ChildItem "Registry::\$UserInstallerKey\Features" | ForEach-Object { $key = $_ $featureCode = $_.PSChildName $ScrambledProductCodes.GetEnumerator() | Where-Object { $_.Value -eq $featureCode } | ForEach-Object { $NothingFound = $False if ($dryrun) { Write-Host " would delete $($_.Name) key Features\$featureCode" } else { Write-Host " deleting $($_.Name) key Features\$featureCode" Remove-Item "Registry::\$key" -Recurse } } } Get-ChildItem "Registry::\$UserInstallerKey\UpgradeCodes" | ForEach-Object { $key = $_ $upgradeCode = $_.PSChildName $ScrambledUpgradeCodes.GetEnumerator() | Where-Object { $_.Value -eq $upgradeCode } | ForEach-Object { $NothingFound = $False if ($dryrun) { Write-Host " would delete $($_.Name) key UpgradeCodes\$upgradeCode" } else { Write-Host " deleting $($_.Name) key UpgradeCodes\$upgradeCode" Remove-Item "Registry::\$key" -Recurse } } } } } if ($NothingFound) { Write-Host "`nNo drivers installed by another user were found." } elseif (!$dryrun) { Write-Host "`nPlease re-install ALL drivers listed above now." } Write-Host