Trying to install software from WIM

Hi,
I’m usually creating WIM files for large software like SolidWorks for example.
It usually works well but for some of them, I get the following error.
This one is for SAP but I have the same error for Autodesk apps.
I don’t understand what this side-by-side configuration means.


Does anyone have an idea what this error means and if there’s a way to avoid it?
Thanks

Most common occurence for that error used to be Microsoft VC++ Redistributables missing… but I think only the earlier 2005/2008 versions used WinSxS. As the error suggests, sxstrace.exe can help you track down which file it’s trying to find, Procmon might show it also.

OK but it would be the case also when the app is not in a WIM file don’t you think?
I only happen when the app is packaged in a WIM file

What’s line 221 in Deploy-Application.ps1?
How are you running the WIM file and why?

Hi,
Hope you’re ok.
Line 221:

	    Write-Log -Message "##### Installing $($appVendor) $($appName)" -Severity 1 -Source $deployAppScriptFriendlyName
        Execute-Process -Path "$($dirFiles)\Sources\Setup\$($appFileEXEx64)" -Parameters "$($appInstallEXEParameters)" -IgnoreExitCodes '129,130,144,145,146'

Variables values are:

    [string]$appFileEXEx64 = "NwSapSetup.exe"
    [string]$appInstallEXEParameters = "/package=`"XXXXX-SUPPLIERS`" /noDlg /silent"

I’m using a script I found a while ago in this tchat… or on GitHub. I don’t remember exactly.
Composed of:
AppDeployToolkit\AppDeployToolkitWim.ps1

Write-Log -Source 'PSADTWIM' "Start of PSADTWIM"

<#
    Not sure why but if Toolkit is loaded with Import-Module $dirFiles and $dirSupportFiles points to .\AppDeployToolkit\Files and .\AppDeployToolkit\SupportFiles
    If you run Deploy-Application.ps1 with no actions, it points to the right folder
#>
$Global:PSADTBasePath = Split-Path -Path $PSScriptRoot -Parent
$Global:PSADTWIMSupportFiles = Join-Path -Path $PSADTBasePath -ChildPath "SupportFiles"
$Global:PSADTWIMFiles = Join-Path -Path $PSADTBasePath -ChildPath "Files"
$Global:WIMFileName = "media.wim"
$Global:WIMPath = Join-Path -Path $PSADTWIMSupportFiles -ChildPath $WIMFileName

# Module is disabled by default
$Global:PSADTWIMEnabled = $false

function Global:New-WIM {
    param(
        [ValidateSet("Max","Fast","None")]
        [string]$CompressionType = "Max",
        [string]$Description = $installName,
        [string]$Name = $installName
    )
    # If the file already exist, do not overwrite
    if (-not (Test-Path -Path $WIMPath)) {
        $Params = @{
            LogPath = "$configToolkitLogDir\$installName-PSADTWIM-New-WindowsImage.log"
            Description = $Description
            Name = $Name
            CompressionType = $CompressionType
            ImagePath = $WIMPath
            CapturePath = $PSADTWIMFiles
        }
        # Create a WIM with the files present in the Files folder
        New-WindowsImage @Params
        # Since there is a WIM-file now, we need to enable this module. If not, Mount-WIM will not work.
        $Global:PSADTWIMEnabled = $true
    }
    else {
        throw "File already exist: '$WIMPath'"
    }
}
function Global:Unmount-WIM {
    param (
        [switch]$Save
    )
    if (-not $Global:PSADTWIMEnabled) {
        Write-Log -Source 'PSADTWIM-Unmount' "PSADTWIM is disabled"
        return
    }
    Write-Log -Source 'PSADTWIM-Unmount' "Dismount '$WIMPath'."
    try {
        
        $Params = @{
            ErrorAction = 'Stop'
            LogPath = "$configToolkitLogDir\$installName-PSADTWIM-Dismount-WindowsImage.log"
        }
        # Default if to discard changes.
        if ($Save.IsPresent) {
            $Params.Add('Save',$true)
        }
        else {
            $Params.Add('Discard',$true)
        }

        # Unmount
        Get-WindowsImage -Mounted -LogPath "$configToolkitLogDir\$installName-PSADTWIM-Get-WindowsImage.log" | 
            Where-Object { $_.ImagePath -eq $WIMPath } | 
                Dismount-WindowsImage @Params
    } catch {
        Write-Log -Source 'PSADTWIM-Unmount' -Message "Failed to dismount $($WIMPath): $_"
        Exit-Script -ExitCode 70101
    }
}
function Global:Mount-WIM {
    param(
        [switch]$Write
    )
    # If no file is found there is no need to process things
    if (-not $Global:PSADTWIMEnabled) {
        Write-Log -Source 'PSADTWIM-Unmount' "PSADTWIM is disabled"
        return
    }
    if ((Test-Path -Path $WIMPath)) {
        Write-Log -Source 'PSADTWIM-Mount' "Mount '$WIMPath'."
        # Check if image is already mounted
        $CurrentlyMounted = Get-WindowsImage -Mounted -LogPath "$configToolkitLogDir\$installName-PSADTWIM-Get-WindowsImage.log" | 
            Where-Object { $_.ImagePath -eq $WIMPath }
        if (-not $CurrentlyMounted) {
            # Check if destination directory is empty
            if ((Get-ChildItem -Path $PSADTWIMFiles).Count -gt 0) {
                Write-Log -Source "PSADTWIM-Mount" -Severity 3 -Message "Failed to mount wim, destination directory is not empty ($PSADTWIMFiles)"
                Exit-Script -ExitCode 70100
            }
            $MountParams = @{
                CheckIntegrity = $true
                Index = 1
                Path = $PSADTWIMFiles
                LogPath = "$configToolkitLogDir\$installName-PSADTWIM-Mount-WindowsImage.log"
            }
            # Default is to mount with ReadOnly because at runtime we usually only need to read.
            if (-not $Write.IsPresent) {
                $MountParams.Add('ReadOnly',$true)
            }
            Get-WindowsImage -ImagePath $WIMPath -LogPath "$configToolkitLogDir\$installName-PSADTWIM-Get-WindowsImage.log" | 
                Mount-WindowsImage @MountParams
        }
        else {
            Write-Log -Source 'PSADTWIM-Mount' "$WIMPath is already mounted"
        }
    }
    else {
        Write-Log -Source 'PSADTWIM-Mount' "$WIMPath does not exist."
    }
}

if (-not (Test-Path -ErrorAction SilentlyContinue -Path "$WIMPath")) {
    Write-Log -Source 'PSADTWIM' "A file with path '$WIMPath' was not found. PSADTWIM will not continue."
    return
}

if (-not $IsAdmin) {
    Write-Log -Severity 3 -Source 'PSADTWIM' "Executing user is not an administrator, can't process wim commands!"
    return
}

if (-not (Get-Command -ErrorAction SilentlyContinue -Name 'Mount-WindowsImage')) {
    Write-Log -Severity 3 -Source 'PSADTWIM' "Command 'Mount-WindowsImage' was not found, can't process wim commands!"
    Exit-Script
}
# Passed the checks, time to enable
$Global:PSADTWIMEnabled = $true

Mount-WIM

Write-Log -Source 'PSADTWIM' "End of PSADTWIM"

Added this line to AppDeployToolkit\AppDeployToolkitExtensions.ps1

# <Your custom functions go here>
. $ScriptRoot\AppDeployToolkitWim.ps1

And these lines at the end of Deploy-Application.ps1

    ##*===============================================
    ##* END SCRIPT BODY
    ##*===============================================

    ## Call the Exit-Script function to perform final cleanup operations
    Unmount-WIM
    Exit-Script -ExitCode $mainExitCode
}
Catch {
    [Int32]$mainExitCode = 60001
    [String]$mainErrorMessage = "$(Resolve-Error)"
    Write-Log -Message $mainErrorMessage -Severity 3 -Source $deployAppScriptFriendlyName
    Show-DialogBox -Text $mainErrorMessage -Icon 'Stop'
    $Params = @{
		ErrorAction = 'Stop'
		LogPath	    = "$configToolkitLogDir\AppDeployToolkitWim $AppName-Dismount-WindowsImage.log"
		Discard	    = $true
	}
	Get-WindowsImage -Mounted -LogPath "$configToolkitLogDir\AppDeployToolkitWim $AppName-Get-WindowsImage.log" | Where-Object { $_.ImagePath -eq $WIMPath } | Dismount-WindowsImage @Params
    Exit-Script -ExitCode $mainExitCode
}

To create my WIM file:

  • I load the AppDeployToolkitMain.ps1
  • Put my installation files in Files directory
  • Type New-Wim ==> creates a media.wim in SupportFiles directory
  • Empty Files directory

I’m trying to create use a Wim file because there are 22k files for this installer and that takes too much time to deploy / download in the cache + size is reduced by almost 50%.

I also know that I don’t need to $($dirFiles) but when I don’t put $($xxxx) in VSCode, it’s unable to find the variable… don’t know why but it’s not a big deal.
Thanks for your help

I’m guessing some files are not found when you mount the Wim files.

Try to mount the Wim file and compare its content to the source files.

Some thing that are bothering is why you need to define those variables and what’s this Import-Module stuff? PSADT doesn’t have PowerShell modules yet (That V4 stuff)

Look into making an admin image and just use the startswimstall. I also use WiM files as well. Its literally the best thing to use .

Can you point me to this?
Have you tried with SAP or Autodesk software?
At the moment, my other WIM files are working correctly.
I only have these problems with those 2 editors.

:frowning:
Files are exactly the same in the original directory and the mounted wim file

I don’t understand what you mean with the Import-Module stuff. The comment in the AppDeployToolkintWim.ps1 file is not mine.
I’m defining variables because I love working with variables. I only need to change the information in one place instead of xx places.

Sorry, I was mobile, and didn’t have the ability to explain more. First off, the extension I use is GitHub - LFM8787/PSADT.WIMFile: Extension for PowerShell App Deployment Toolkit to create and handle .WIM files.. This works wonders. Now I will say that I do not use it to create WIM files. I simply use New-WindowsImage and always set the compression to Max. Then in my main deployment script I have this block of code before pre-installation

    # Mount any WIM file found in script directory (last modified one if multiple)
    # Zero-Config WIM Mounting
    $global:WIMFileExists = $false
    Write-Log "Checking $(Split-Path $invokingScript) for any WIMs"
    if ((Get-ChildItem -Path $(Split-Path $invokingScript) -Filter *.wim).count -ge 1) { 
        Write-Log "Zero-config WIM detected..."
        $WIMFileExists = $true 
        $MountedObject = Mount-WIMFile 
    }
    else { Write-Log "No WIMs found! Proceeding with script..." }

And then right before an Exit-Script and I have the following

    # Dismount the previously mounted/extracted WIM file
    if ($WIMFileExists) { $MountedObject | Dismount-WIMFile }

As far as the administrative images go, look into this: Creating an Administrative Image from SOLIDWORKS Installation Manager - 2024 - SOLIDWORKS Help

That way, when you get ready to install it, you simply need Execute-Process -Path "$dirFiles\startswinstall.exe" -Parameters '/install /now' -IgnoreExitCodes * to install or Execute-Process -Path "$dirFiles\startswinstall.exe" -Parameters '/uninstall /removedata /removeregistry /now' -IgnoreExitCodes * to remove.

I do the same with AutoCAD, Inventor, Mathlab, Labview, or any other app that has either over 3GB of content of over 1,000 files.

SolidWork is ok for me. I’ve been able to use the script I described in my previous reply. And this script doesn’t do anything else than what you’re doing manually:

function Global:New-WIM {
    param(
        [ValidateSet("Max","Fast","None")]
        [string]$CompressionType = "Max",
        [string]$Description = $installName,
        [string]$Name = $installName
    )
    # If the file already exist, do not overwrite
    if (-not (Test-Path -Path $WIMPath)) {
        $Params = @{
            LogPath = "$configToolkitLogDir\$installName-PSADTWIM-New-WindowsImage.log"
            Description = $Description
            Name = $Name
            CompressionType = $CompressionType
            ImagePath = $WIMPath
            CapturePath = $PSADTWIMFiles
        }
        # Create a WIM with the files present in the Files folder
        New-WindowsImage @Params
        # Since there is a WIM-file now, we need to enable this module. If not, Mount-WIM will not work.
        $Global:PSADTWIMEnabled = $true
    }
    else {
        throw "File already exist: '$WIMPath'"
    }
}

I’ve tried the GitHub - LFM8787/PSADT.WIMFile but I don’t like it. I still don’t get why this method is better… and I find it too complex for what it does.
I’m gonna give it a second try…
What is interesting is that you tell me you’re using it for Autodesk AutoCAD… which is not working for me.

That’s the thing, I’m not creating the WIM with PSADT, but outside of it. It’s just a simple command with the capture path and WIM path. What don’t you like about it? It’s really not that complex. You mount the WIM and that’s it. Maybe it’s the set up. But now I have it as a template, so I just throw a WIM file into my package, and it gets mounted when the deploy-app script runs.

The extension simply mount the WIM into the Files folder, and then deletes it.

AutoCAD is the same way, let the WIM mount into Files, and then run this command

Execute-Process -Path "$dirFiles\Installer.exe" -Parameters "-i deploy --offline_mode -q -o `"$dirFiles\Collection.xml`" --installer_version `"$installerVersion`""

My WIM looks like this

I also admit that I don’t create the AutoCAD images, I just take them, and package up the deployment.

It’s not that I don’t like it.
It’s just that I still don’t understand where it has to be put in order for it to work…

Do I simply copy PSADT.WIMFile directory in AppDeployToolkit and SupportFiles like this?


EDIT: I’ve read a bit further… I just think I did wrong the first time.
I’m gonna look at it a second time

That looks similar to what I have. Here is my folder structure.

And in the AppDeployToolkitExtensions.ps1 I have the following

##*===============================================
##* FUNCTION LISTINGS
##*===============================================

# <Your custom functions go here>
## Variables: Extensions to load
$ExtensionToLoad = @()
$ExtensionToLoad += [PSCustomObject]@{
	Path   = "PSADT.WIMFile"
	Script = "WIMFileExtension.ps1"
}

Again, I don’t use New-WIMFile as it requires you to run the deploy script once, and then comment it out. I simply just create the WIM file on my own, and then use my “zero-config” to mount it every time. That way, even if I don’t have a WIM located, the script will still run without errors.

I have the same error using your method or the New-WIMFile from PSADT.WIMFile
WIM File is correctly created but I still get the side-by-side error when trying to install.
:frowning:

Hmm, not sure what could be wrong.

sorry that I couldn’t be more help. I never seen that error before. I am using 3.10 if that helps.

I’ve hit the same wall with some Autodesk installs too. What worked for me was checking the Visual C++ Redistributables – sometimes the app needs a specific version that isn’t installed. One time, I was tearing my hair out over a similar issue, and after hours of trial and error, I found that downloading the right package fixed everything. Speaking of which, I stumbled upon https://bnhsoftware.com/ when I was digging around for solutions. It’s got some solid reviews that helped me decide on the tools I use. Might be worth a look.

It seems that it is a sufficiently recurring issue that even AutoDesk have created a couple of guides detailing how to re-install VC++ redistributables entirely:
https://www.autodesk.com/support/technical/article/caas/sfdcarticles/sfdcarticles/How-to-remove-and-reinstall-Microsoft-Visual-C-Runtime-Libraries.html
or reinstall from the software installation package:
https://www.autodesk.com/support/technical/article/caas/sfdcarticles/sfdcarticles/How-to-reinstall-Microsoft-Visual-C-Runtime-Libraries-from-Autodesk-software-installation-package.html
It’s worth noting point 7 in the last link above about the fragility of VC++ installs, they are not cumulative, so if you have a later version already installed, and an earlier version is then subsequently required but not already installed, you will need to take a note of all VC++ versions installed (x86 & x64), then remove all VC++ redistributables back to the one before the required version (x86 & x64).
Then install the required version for the (AutoDesk) app and finally reinstall all later versions that were on the machine before you started (so your other applications will continue to work correctly :man_facepalming:).

I couldn’t comment for certain, but this feels like AutoDesk ‘may’ not be shipping / using the most modern / latest version and are IMHO making it harder for their users :man_shrugging:

I don’t want to drag this conversation off thread, but in case you were not aware
Microsoft publish the release notes for the VC++ redistributables here: Latest supported Visual C++ Redistributable downloads | Microsoft Learn

On that page, they then go on to state:

" Unlike older versions of Visual Studio, which have infrequent redist updates, the version number isn’t listed in the following table for Visual Studio 2015-2022 because the redist is updated frequently. To find the version number of the latest redist, download the redist you’re interested in using one of the following links. Then, look at its properties using Windows File Explorer. In the Details pane, the File version contains the version of the redist."

However, after many years reviewing that page, it does look like Microsoft have (finally!!) backtracked and are publishing the latest release version within this page see: Latest Version Link :tada:
This may mean I (and probably others) can finally stop having to download the latest VC++ redistributable version just to check the Version Info on the download is not newer than the version currently being distributed.

1 Like