Hi all,
Based on the answer of @shenx , i found the solution #4 on this Autodesk website: Install Failure: Error 997. Overlapped I/O operation is in progress
With this solution, I was able to reduce the installation/update time on our machines.
Unfortunately, you will need the product codes of all *.msi files of all Autodesk deployments for this solution.
Fortunately, you do not need to install Microsoft Orca, you can also read the required information out with a PowerShell script.
Warning:
- The above solution is overriding a Microsoft security functionality. This can be harmful. Do not change anything if you do not have to.
- The above solution does modify the Windows registry. When working with the registry, you should always create a backup first.
How to get the product codes:
- Copy the script sourcecode
- Start the program "Windows PowerShell ISE"
- Create a new script/page
- Paste the sourcecode
- Change the deployment paths to your server paths
- Execute the script
- Check the created *.reg file on our Desktop
- Import the registry values on your machines

# enter here all directory paths of all deployments
$deploymentPaths = @(
"\\ServerPathToYourDeployments\2020_3ds_Max"
"\\ServerPathToYourDeployments\2020_AutoCAD_Mechanical"
"\\ServerPathToYourDeployments\2020_Inventor"
"\\ServerPathToYourDeployments\2020_Nastran"
"\\ServerPathToYourDeployments\2020_Navisworks"
"\\ServerPathToYourDeployments\2020_Recap"
"\\ServerPathToYourDeployments\2020_Revit"
)
# enter here the desired output file path for the *.reg file
$outputRegistryFile = "$env:USERPROFILE\Desktop\AdskProductCodes.reg"
#
# DO NOT CHANGE ANY VALUE FROM HERE
#
function Get-MsiProductCodes
{
param
(
[Parameter(Mandatory=$true,
Position=0,
ValueFromPipeline=$True,
ValueFromPipelineByPropertyName=$True,
HelpMessage='Full path of the *.reg file, that will be created')]
[IO.FileInfo]$registryOutFilePath,
[Parameter(Mandatory=$true,
Position=1,
ValueFromPipeline=$True,
ValueFromPipelineByPropertyName=$True,
HelpMessage='Array of direcotries, which contain the *.msi files')]
[IO.DirectoryInfo[]]$msiDirectoryPaths
)
try {
$com_object = New-Object -com WindowsInstaller.Installer
Write-Output "Writing registry file header..."
"Windows Registry Editor Version 5.00" | Out-File -FilePath $registryOutFilePath -Encoding Unicode -Width 512 -Force
"" | Out-File -FilePath $registryOutFilePath -Encoding Unicode -Width 512 -Append
"[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\Installer]" | Out-File -FilePath $registryOutFilePath -Encoding Unicode -Width 512 -Append
'"SecureRepairPolicy"=dword:00000002' | Out-File -FilePath $registryOutFilePath -Encoding Unicode -Width 512 -Append
"" | Out-File -FilePath $registryOutFilePath -Encoding Unicode -Width 512 -Append
"[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\Installer\SecureRepairWhitelist]" | Out-File -FilePath $registryOutFilePath -Encoding Unicode -Width 512 -Append
Write-Output "Finding *.msi files and reading their properties..."
$msi_productcodes = New-Object System.Collections.Generic.List[System.String]
$maxi = $msiDirectoryPaths.Count
for($i = 0; $i -lt $maxi; $i++ )
{
$progi = $i * 100 / $maxi
Write-Progress -Activity Updating -Status 'Directories' -PercentComplete $progi -CurrentOperation OuterLoop
$dirPath = $msiDirectoryPaths[$i]
if(![System.IO.Directory]::Exists($dirPath)) {
Write-Output "`tDirectory $dirPath does not exit!"
continue
}
Write-Output "`tFinding *.msi files in $dirPath..."
$msi_files = Get-ChildItem -Path $dirPath -Include *.msi,*.MSI -Recurse -ErrorAction SilentlyContinue -Force
if ($msi_files -ne $null) {
$maxj = $msi_files.Length
for($j = 0; $j -lt $maxj; $j++ )
{
$progj = $j * 100 / $maxj
Write-Progress -Id 1 -Activity Updating -Status 'MSI files' -PercentComplete $progj -CurrentOperation InnerLoop
$msi_path = $msi_files[$j]
Write-Output "`t`tReading properties of $msi_path..."
$database = $com_object.GetType().InvokeMember(
"OpenDatabase",
"InvokeMethod",
$Null,
$com_object,
@($msi_path.FullName, 0)
)
$query = "SELECT * FROM Property"
$View = $database.GetType().InvokeMember(
"OpenView",
"InvokeMethod",
$Null,
$database,
($query)
)
$View.GetType().InvokeMember("Execute", "InvokeMethod", $Null, $View, $Null)
$record = $View.GetType().InvokeMember(
"Fetch",
"InvokeMethod",
$Null,
$View,
$Null
)
$msi_ProductCode = ""
$msi_ProductName = ""
$msi_regstring = ""
while ($record -ne $null) {
$prop_name = $record.GetType().InvokeMember("StringData", "GetProperty", $Null, $record, 1)
$prop_value = $record.GetType().InvokeMember("StringData", "GetProperty", $Null, $record, 2)
$prop_nameUpper = $prop_name.ToUpper()
if ($prop_nameUpper -eq "PRODUCTCODE") {
$msi_ProductCode = $prop_value
}
if ($prop_nameUpper -eq "PRODUCTNAME") {
$msi_ProductName = $prop_value
}
$record = $View.GetType().InvokeMember(
"Fetch",
"InvokeMethod",
$Null,
$View,
$Null
)
}
if ($msi_productcode -ne "") {
$msi_regstring = ('"' + $msi_productcode + '"="' + $msi_productname + '"')
if(!($msi_productcodes.Contains($msi_regstring))) {
$msi_productcodes.Add($msi_regstring)
}
}
}
Write-Progress -Id 1 -Activity Updating -Status 'MSI files' -PercentComplete 100 -CurrentOperation InnerLoop
}
}
Write-Progress -Activity Updating -Status 'Directories' -PercentComplete 100 -CurrentOperation OuterLoop
Write-Output "Writing registry file content..."
foreach($item in $msi_productcodes) {
$item | Out-File -FilePath $registryOutFilePath -Encoding Unicode -Width 512 -Append
}
"" | Out-File -FilePath $registryOutFilePath -Encoding Unicode -Width 512 -Append
Write-Output "Successful! The file was saved here: $registryOutFilePath"
return 0
} catch {
Write-Output "Something has failed: $_"
return 1
}
}
Get-MsiProductCodes $outputRegistryFile $deploymentPaths