Run PowerShell script with parameters - powershell

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("'")

Related

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"'

How do I pass the Gitlab {CI_COMMIT_SHORT_SHA} variable to powershell script

I have created a script section in Gitlab-CI.yaml file. The format is given below.
script:
- powershell -File script.ps1 folderpath="$env:${CI_PROJECT_DIR}" CommitID="$env:${CI_COMMIT_SHORT_SHA}"
and these variables are calling in my PowerShell script as follows. The script is given below.
$Files = Get-ChildItem $folderpath
foreach($eachFile in $Files)
{
if($eachFile.Name.Contains("myapp"))
{
Rename-Item -Path $eachFile.FullName -NewName "myapp-$CommitID.zip" -Force
}
}
This script is using for changing the name of a zip file. After execting this through gitlab I am getting error like this.
Variable reference is not valid. ':' was not followed by a valid variable name
character. Consider using ${} to delimit the name.
Is it the right format to pass the GitLab env variable to PowerShell script? Can you please suggest some inputs on this?
Assuming that ${CI_PROJECT_DIR} is the value of GitLab's CI_PROJECT_DIR (environment) variable, you can use it as-is in your command line - no need for the $env: indirection, which (a) requires the name of an environment variable and (b) wouldn't work anyway with PowerShell's -File CLI parameter.
Assuming your target script uses regular PowerShell parameter declarations (e.g., param($FolderPath, $CommitId), case doesn't matter), you must pass the values using
-<param> <value> or -<param>:<value> syntax.
To put it all together:
script:
- powershell -File script.ps1 -FolderPath "${CI_PROJECT_DIR}" -CommitID="${CI_COMMIT_SHORT_SHA}"
The alternative is not to use parameters at all, and instead directly access the environment variables from inside your script, using PowerShell's $env:<var_name> notation:
$Files = Get-ChildItem $env:CI_PROJECT_DIR
foreach($eachFile in $Files)
{
if($eachFile.Name.Contains("myapp"))
{
Rename-Item $eachFile.FullName -NewName "myapp-$env:CI_COMMIT_SHORT_SHA.zip" -Force
}
}

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

File path with quotation mark issue of Powershell

I was trying to write a script to test the availability of the file path. One of the process is that user have to input the file path or just drag the file into the Powershell command prompt.
In this process,
User will input the file path like C:\Program Files\7-Zip\7z.exe and the string will become the value of $filePath variable which will be used as the parameter of the Test-Path command.
But sometime, user will just drag the file into the Powershell command prompt so that the string will have a pair of quotation mark included just like the picture 1.
("C:\Program Files\7-Zip\7z.exe")
Picture 1
Then you will see when I try to test the path using Test-Path command with that $filePath variable while the value(string) of the $filePath included a pair of quotation mark, the result will always be False even though the path is existing and valid.
But when I use the same Test-Path command without using variable (I mean just copy and paste the file path into the command), it works normally.
IT'S WEIRD!
I have tried typing the file path by keyboard into the variable instead of dragging the file into Powershell command prompt. (Without Quotation mark)
Then use the same method to test the filepath (using variable for the file path). It works fine.
Picture 2
I don't get it. Aren't they the same thing?
when
$filePath = "C:\Program Files\7-Zip\7z.exe"
Below 2 commands SHOULD have the same result! WHY they are not?
Test-Path -Path $filePath
Test-Path -Path "C:\Program Files\7-Zip\7z.exe"
In case of drag and drop, it looks like if the path has no spaces it will return true . If it has a space then PowerShell places quotes around it. In that case, PowerShell is literally seeing the path as "C:\Program Files\7-Zip\7z.exe"
What you can do is use the -replace operator like this -
Test-Path -path ($filepath -replace '"', "") -PathType Leaf
OR
As suggested by #Josefz in the comments, you could also use Trim() method like -
Test-Path -path ($filepath.Trim('"')) -PathType Leaf
Not exactly an explanation to your problem, but you could use this as a workaround.
If the user types a filename that contains embedded " characters, then Test-Path will return $false. Why? File names cannot contain the " character; the " character is used by parsers to indicate that an argument in a string contains whitespace. So this will of course return $false:
$filePath = '"C:\Program Files\7-Zip\7z.exe"'
Test-Path $filePath
The embedded " characters are not part of the file name; you need to omit them for the result to be $true.
What version of powershell are you using? I get true for both commands
PS C:\Users> $filePath = "C:\Program Files\7-Zip\7z.exe"
PS C:\Users> Test-Path -Path $filePath
True
PS C:\Users> Test-Path -Path "C:\Program Files\7-Zip\7z.exe"
True
PS C:\Users> $PSVersionTable.PSVersion
Major Minor Build Revision
----- ----- ----- --------
5 1 17134 48
EDIT ----------
Got it, the problem is that Read-Host will save the string literally, with the quotes. The simple solution is to remove the quotes
PS C:\Users> $filePath = Read-Host -Prompt "enter input"
enter input: "C:\Program Files\7-Zip\7z.exe"
PS C:\Users> $filePath
"C:\Program Files\7-Zip\7z.exe"
PS C:\Users> Test-Path -Path $filePath
False
PS C:\Users> Test-Path -Path $filePath.replace("`"","")
True

Escape spaces in PowerShell and cmd

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.