Powershell script in Task Scheduler - spaces and timestamp issue - powershell

following script works in Powershell, but won't work when executed as an action in Task Scheduler:
Copy-Item -Path '\\dfs.com\Risk Manage\Daily_DB\Daily_DB.accdb' -Destination "\\dfs.com\Risk Manage\SharedReports\Database Backup 2014\Daily_DB_backup $(get-date -f yyyy-MM-dd).accdb"
Please note that I need to use double quotes in order to get $(get-date -f yyyy-MM-dd) translate into a timestamp. Doesn't work with single quotes.
Task Scheduler error message: Copy-Item : A positional parameter cannot be found that accepts argument 'Manage\SharedReports\Database'.
To sum it up, does anyone know how to execute Powershell script containing path with spaces and timestamp in it, in Task Scheduler?
Many thanks

You could either call a script or use the -encodedcommand parameter: Using Powershell -encodedcommand to pass parameters

Try this:
$Datestamp = (Get-date -f yyyy-MM-dd)
Copy-Item -Path '\\dfs.com\Risk Manage\Daily_DB\Daily_DB.accdb' -Destination "\\dfs.com\Risk Manage\SharedReports\Database Backup 2014\Daily_DB_backup_$Datestamp.accdb"

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

Reading a file path that contains wildcard characters

I'm working on a script that takes a directory name as input, and writes a log file to that directory.
This works in most cases:
param([string]$output_folder)
$logfile="$output_folder" + "\myscript.log"
Write-Output "logfile: " $logfile
(Get-Date -Format "[yyyy-MM-dd HH:mm:ss]") | Out-file $logfile -Append
except when the file path contains a wildcard:
E:\Publishing\User manual [en]\
This results in an error 'Cannot perform operation because the wildcard path E:\Publishing\User manual [en]\myscript.log did not resolve to a file.
I spent some time trying to sanitize the input, but I haven't found a way that works yet.
$logfile='$output_folder' + "\myscript.log"
This treats the string as a literal, but that prevents $output_folder from being expanded.
param([io.directoryinfo]$output_folder)
doesn't help either.
Edit:
A comment suggested this:
Out-file -LiteralPath $logfile -Append
That works for the instances where I use Out-file.
I also call an external program, and I can't use -LiteralPath here:
"C:\Program Files\Saxonica\SaxonHE9.8N\bin\Transform.exe" -s:"$inputFile" -xsl:"$output_folder\$transformation_filename" -o:"$outputFile" -t 1>>$logfile 2>&1
in fact I have more arguments here that need to be treated as literals. Is there a way so specify this when I create the string?
$logfile="$output_folder" + "\myscript.log"

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

How powershell handles returns from & calls

We have field devices that we decided to use a powershell script to help us handle 'updates' in the future. It runs every 5 minutes to execute rsync to see if it should download any new files. The script, if it sees any file types of .ps1, .exe, .bat ,etc. will then attempt to execute those files using the & operator. At the conclusion of execution, the script will write the file executed an excludes file (so that rsync will not download again) and remove the file. My problem is that the return from the executed code (called by &) behaves differently, depending on how the main script is called.
This is the main 'guts' of the script:
Get-ChildItem -Path $ScriptDir\Installs\* -Include #("*.ps1","*.exe","*.cmd","*.VBS","*.MSI") | ForEach {
Write-Verbose "Executing: $_"
& $_
$CommandName = Split-Path -Leaf $_
Write-Verbose "Adding $CommandName to rsync excludes"
Write-Output "$CommandName" | Out-File -FilePath $ScriptDir\excludes -Append -Encoding ASCII
Write-Verbose "Deleting '$_'"
Remove-Item $_
}
When invoking powershell (powershell.exe -ExecutionPolicy bypass) and then executing the script (.\Update.ps1 -Verbose), the script runs perfectly (i.e. the file is written to excludes and deleted) and you can see the verbose output (writing and deleting).
If you run the following (similar to task scheduler) powershell.exe -ExecutionPolicy bypass -NoProfile -File "C:\Update.ps1" -Verbose, you can see the new script get executed but none of the steps afterwards will execute (i.e. no adding to excludes or removing the file or the verbose outputs).

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.