Search code examples
powershellpowershell-2.0sccmquoting

PowerShell execution fails due to space in directory name


I have been handed a PowerShell script that executes to install an executable which is placed in the same directory. This is packaged into SCCM (System Center Configuration Manager) for deployment. However, the deployment fails if during package deployment the temporary director where the package is pushed has a space anywhere in the file path.

For example:

  1. C:\temp\deployment -- This will pass and the software will install.
  2. C:\temp\deployment 1\ -- This will fail due to space between deployment and 1
  3. C:\temporary directory\deployment\ -- This will fail due to space between temporary and directory.

Here is part of the code that I suspect is carrying out the installation:

if ($softwarename -eq "Not Installed") {
    Write-Output "Installing softwarename..."
    #   Build a massive softwarename installation line 
    $tempFile = [System.IO.Path]::GetTempFileName() + ".cmd"
    $installLine = "$scriptPath\softwarename.exe /s /v`"/qn INSTALLDIR=\`"C:\Program Files\directoryname\softwarename\`" AUTHTOKEN=REDACTED FULLCONSOLEADDRESS=$dest`:8413 HOSTNAME=$Env:COMPUTERNAME LOG_SOURCE_AUTO_CREATION_ENABLED=True LOG_SOURCE_AUTO_CREATION_PARAMETERS=`"`"Component1.AgentDevice=DeviceWindowsLog&Component1.Action=create&Component1.LogSourceName=$env:COMPUTERNAME&Component1.LogSourceIdentifier=$env:COMPUTERNAME&Component1.Log.Security=true&Component1.Filter.Security.Enabled=true&Component1.Filter.Security.Param=5156&Component1.Filter.Security.Type=Blacklist&Component1.Log.System=true&Component1.Log.Application=true&Component1.Log.DNS+Server=false&Component1.Log.File+Replication+Service=false&Component1.Log.Directory+Service=false&Component1.Destination.Name=$dest&Component1.RemoteMachinePollInterval=300&Component1.EventRateTuningProfile=High+Event+Rate+Server&Component1.MinLogsToProcessPerPass=1250&Component1.MaxLogsToProcessPerPass=1875`"`"`""
    $installLine | Out-File -Encoding ascii -filepath $tempFile
    Write-Output $tempFile
    cmd.exe /c $tempFile
} else {
    if ($psversiontable.psversion.major -gt 2) {
        $props=ConvertFrom-StringData (Get-Content "c:\Program Files\directoryname\softwarename\config\install_config.txt" -Raw)
        if ($props.ConfigurationServer -eq $dest) {
            Write-Output "Configuration server is correct - no action"
        } else {
            Stop-Service (Get-Service -ErrorAction SilentlyContinue softwarename)
            $props.ConfigurationServer=$dest
            $props.StatusServer=$dest
            $props.GetEnumerator() | % { "$($_.Name)=$($_.Value)" } | Out-File -Encoding ascii -filepath "c:\Program Files\directoryname\softwarename\config\install_config.txt"
            del "c:\Program Files\directoryname\softwarename\config\ConfigurationServer.PEM" 
            Start-Service (Get-Service -ErrorAction SilentlyContinue softwarename)
            Write-Output "Configuration server reset to $dest"
        } 
    } else {
        Write-Output "Powershell version does not support the reset functionality."
    }

I suspect following two lines to be the cause of the problem:

$tempFile = [System.IO.Path]::GetTempFileName() + ".cmd"
    $installLine = "$scriptPath\softwarename.exe /s /v`"/qn

I suspect that since execution will require exact path and a "space" in the directory path will lead to "path not found" (interestingly on my Windows 10 machine change directory [cd] command works without putting filepath with spaces in quotes - "" -- This leads me to believe I'm completely wrong, however at this point I have no other thing to look at).

Can anyone please assist on adding parameters to ensure that patch generated for .cmd file to be executed does not have a space?

I have tried to patch this by adding a batch file that copies the package to a static directory before execution. However, this is failing to deploy via SCCM.


Solution

  • In order to invoke a program from a batch file with a path that contains spaces, that path must be enclosed in "...":

    # PowerShell string that constructs the command line to write to the batch file.
    $installLine = "`"$scriptPath\softwarename.exe`" ..."
    

    `" is how you embed a literal " in a "..." string in PowerShell.

    By contrast, calling cd from a batch file with a path containing spaces also works without enclosing "...", but:

    • that is only possible without ambiguity because cd requires just one operand (the target dir.)
    • due to the inconsistency with how arguments with spaces must be handled by all other commands, supporting this was never a good idea to begin with.