Escape spaces in PowerShell and cmd - powershell

I have a PowerShell script that is calling an .exe from the command line to create an XML file and then the PowerShell script is reading that file.
The problem is if I have a space in the file path I need to wrap in in double quotes to pass it to the command line. When I do that the PowerShell command tries to read the double quotes as part of the file path. Is there a way to escape the spaces that will work for both passing it to the command line and using commands inside PowerShell?
It seems silly to have to pull out the double quotes for one command and leave them in for another.
The issue is with the Get-Content line not liking the double quotes.
$outputpath = '"C:\Users\bob\Desktop\output new.xml"'
Start -FilePath $sqlpackage -ArgumentList "/action:DeployReport /SourceFile:$dacpacpath /Profile:$profilepath /OutputPath:$outputpath" -NoNewWindow -Wait
[xml]$xmldocument = Get-Content -Path $outputpath

Deadly-Bagel almost had it I think. Don't use double quotes in $outputpath to keep Get-Content happy, but add them in your argument list string.
Be sure to escape with backtick `. In fact you might just want to do that with all the paths:
$outputpath = 'C:\Users\bob\Desktop\output new.xml'
Start -FilePath $sqlpackage -ArgumentList "/action:DeployReport /SourceFile:`"$dacpacpath`" /Profile:`"$profilepath`" /OutputPath:`"$outputpath`"" -NoNewWindow -Wait
[xml]$xmldocument = Get-Content -Path $outputpath

-ArgumentList accepts String[] so try the following:
$outputpath = "C:\Users\bob\Desktop\output new.xml"
Start -FilePath $sqlpackage -ArgumentList #("/action:DeployReport", "/SourceFile:$dacpacpath", "/Profile:$profilepath", "/OutputPath:$outputpath") -NoNewWindow -Wait
I suspect passing it all as one parameter causes it to be confused.

Related

Find and execute a file with powershell

I have to find and then execute a .exe file from a script deployed by our asset management software. Currently it looks like this:
Set-Location $PSScriptRoot
$proc = (Start-Process -FilePath "C:\Program Files (x86)\software\software name\Uninstall.exe" -ArgumentList "/S /qn" -Wait -PassThru)
$proc.WaitForExit()
$ExitCode = $proc.ExitCode
Exit($ExitCode)
As far as I understand the location for the location for the file is set and some users do not have it there hence why it fails.
So I understand that you can search for a program with
Get-ChildItem C:\Program Files (x86)\software\
And execute with Start-process -Filepath
But do I simply combine that with a | or is there an easier way/will it even work.
As commenter suggested, you can use Test-Path to test if a path exists:
$uninstallPath = Join-Path ${env:ProgramFiles(x86)} 'software\software name\Uninstall.exe'
if( Test-Path $uninstallPath ) {
$proc = Start-Process -FilePath $uninstallPath -ArgumentList '/S /qn' -Wait -PassThru
$proc.WaitForExit()
$ExitCode = $proc.ExitCode
Exit $ExitCode
}
I've also made the code more robust by avoiding the hardcoded "Program Files (x86)" directory, using an environment variable. Because of the parentheses in the name of the env var, it must be enclosed in curly braces.
For added robustness, you may read the path of the uninstall program from the registry, as detailed by this Q&A. If you are lucky, the program even stores a QuietUninstallString in the registry, which gives you the full command line for silent uninstall.

Extra Space needs to remove while executing powershell

I am executing the below script on the windows server as a PowerShell script -
$today = (Get-Date).ToString('dd_MM_yyyy_HH_mm')
echo "Date & Time : $today"
powershell -Command "Copy-Item -Recurse 'C:\ABC' -Destination 'C:\ABC_"$today"'"
The above script is working fine but there is a blank space between ABC & Date while creating the directory. Please please help me on this how can I remove this blank space.
**Directory Name :** ModelFactoryProducti**on_ 28**_06_2021_11_05
**Directory Name Should be :** ModelFactoryProduction_28_06_2021_11_05
Since you're calling from PowerShell, the best option is to pass a script block to powershell.exe, the Windows PowerShell CLI.
However, this raises the question: why do you need to call the CLI from PowerShell to begin with, given that you could just call your Copy-Item command directly, without the overhead (and potential loss of type fidelity) that comes with creating another PowerShell session, via a child process.
if you still need to call the PowerShell CLI from PowerShell itself, use the following:
$today = (Get-Date).ToString('dd_MM_yyyy_HH_mm')
powershell -Command {
Copy-Item -Recurse 'C:\ABC' -Destination ('C:\ABC_' + $args[0])
} -args $today
As for what you tried:
Removing the " around $today in 'C:\ABC_"$today"' would have worked too - the outer "..." quoting would still have ensured that $today is expanded.
What you thought of as a single string argument,
"Copy-Item -Recurse 'C:\ABC' -Destination 'C:\ABC_"$today"'", was passed as two arguments:
Argument 1: Verbatim Copy-Item -Recurse 'C:\ABC' -Destination 'C:\ABC_, which, due to being a (double-)quoted token became its own argument - despite other characters immediately following it.
Argument 2: The value of $today, immediately followed by a verbatim ' (the value of "'"), e.g., verbatim 06_2021_11_05'
Not being able to compose a single argument from a mix of quoted and unquoted tokens if the first token happens to be quoted is a notable pitfall, discussed in detail in this answer.
When you use -Command and pass multiple arguments, PowerShell simply joins those arguments to form a single string by placing a space between them, before interpreting the resulting string as PowerShell code.
Therefore, your two verbatim arguments, Copy-Item -Recurse 'C:\ABC' -Destination 'C:\ABC_ and (e.g.) 06_2021_11_05' were ultimately interpreted as
Copy-Item -Recurse 'C:\ABC' -Destination 'C:\ABC_ 06_2021_11_05' - note the unwanted space.
See this answer for a comprehensive overview of the PowerShell CLI (covers both powershell.exe and pwsh).
Use the following:
$today = (Get-Date -format 'dd_MM_yyyy_HH_mm')
Copy-Item -Recurse 'C:\ABC' -Destination "C:\ABC_$today"
When possible, avoid using either of these kinds of syntax, as it's very simple to allow accidentally (or maliciously) inserting extra data into the command string. Plus, you're already in powershell - no need to execute powershell again unless you left it to run some cmd commands:
powershell -c "Write-Host $var"
Invoke-Expression -Command 'Write-Host "$var"'

Run PowerShell script with parameters

I have a PowerShell script that needs a path passed to it as parameter and surrounded with double quotation because path may be contains space. But my problem is when the path is root of drive for example "E:\" the passed parameter in the script converted to E:" (must be E:\) how to solve this problem? When I use single quotation the passed strings is 'E:\' and contains the quotations!
Please help
my code sample:
in test.ps1
Write-Host ($args[0])
Result:
.\test.ps1 "E:\"
E:"
.\test.ps1 'E:\'
'E:\'
.\test.ps1 "'E:\'"
'E:\'
.\test.ps1 "E:\Test"
E:\test
I call the script from registry like this: powershell -File "test.ps1" "%V"
I solved problem by changing "%V" to '%V' and in the script I use trim function to removes single quotations
$Arg0 = ($args[0])
$Path = $Arg0.trim("'")

execute a script from a created folder with Powershell

In powershell i can download a script in a specific random name created folder but i cannot find the right way to execute the script from there.Here the code that i used:
$uuid=(Get-WmiObject Win32_ComputerSystemProduct).UUID;
$path = $env:appdata+'\'+$uuid; $h=$path+'\d';
if(!(test-path $path)) { New-Item -ItemType Directory -Force -Path
$path;};
Invoke-WebRequest mywebsitefordownloadingscript -OutFile $path\\test.txt;
start-process -Windowstyle hidden cmd '/C
'powershell.exe' -exec bypass $path\\test.txt';
there was something missing in last string maybe the problem persist if i use '+$path+' too.
Any suggestions??
The problem is your single quotes on the last two lines. Since you have enclosed $path within single quotes it is not expanded and is taken literally. Change to double quotes to expand the variable, and this should work.
$uuid=(Get-WmiObject Win32_ComputerSystemProduct).UUID
$path = $env:appdata+'\'+$uuid
$h=$path+'\d'
if(!(test-path $path)) {
New-Item -ItemType Directory -Force -Path $path
}
Invoke-WebRequest mywebsitefordownloadingscript -OutFile $path\\test.txt
start-process -Windowstyle hidden cmd "/C 'powershell.exe' -exec bypass $path\\test.txt"

Passing a .txt file to a Powershell command

I am trying to pass a .txt file with arguments to an .exe file via powershell. Currently, this is what I have.
Write-Host "starting upgrade at $(Get-Date -format 'U')"
C:\dev\temp.exe.exe /DIR="C:\TEST" /BTPServerHost="Test" /DBInstance="testDB" /Log=C:\path\to\test\testlog.txt
This is calling a function within an InnoScript file that accepts command line input.
How would I format the .txt file, and how would I be able to pass it into the .exe? Any help would be appreciated! Thanks!
If you are saying, in this text file, there are just these argument line on individual rows and you are saying you've already tried something like the below and were not successful?
You also don't need the Write-Host for the message line, since the default is output to screen. You normal only need Write-Host for colorizing screen text, and a few other formatting cases, depending on what you are doing. All-in-All, Write-Host should be avoided.
"starting upgrade at $(Get-Date -format 'U')"
($ConsoleCommand = Get-Content -Path 'd:\temp\input.txt' -Raw)
# Results - showing the commands in the file before process them
whoami
get-date
'hello world'
Without using the -Wait switch, this will spawn 3 separate PowerShell consoles with the results
ForEach($CmdLine in $ConsoleCommand)
{ Start-Process -FilePath powershell -ArgumentList "-NoExit","-Command &{ $CmdLine }" }
you can of course point to your .exe vs what I am doing here.
Start-Process
By adding the -Raw after specifying the .txt file path it ignores newline characters and returns the entire contents of a file in one string with the newlines preserved. By default, newline characters in a file are used as delimiters to separate the input into an array of strings.
This script takes parameters from a txt file and passes them into an executable and auto-populates the fields in the installation wizard. This is what I'm looking to do, but I don't want to start a new process for each argument in the input txt file.
Write-Host "starting upgrade at $(Get-Date -format 'U')" Get-Content -Path C:\TestInput.txt -Raw | foreach {Start-Process C:\dev\test.exe -ArgumentList $_}
The TestInput.txt file passed in looks like this:
/DIR="C:\TEST"
/ServerHost="Test"
/DBInstance="testDB"
/Log=C:\testlog.txt