Path issue with passing a command from Autohotkey to PowerShell - powershell

Mypath := "C:\temp\example1.txt"
Run, powershell -command "get-content -path %Mypath% | Set-Clipboard"
The above works just fine, content is copied to the clipboard by PowerShell but when I do the same thing but with a file that has a space in its file name it fails to run in PowerShell.
Running below
Mypath := "C:\temp\example 1.txt"
Run, powershell -command "get-content -path %Mypath% | Set-Clipboard"
I get this error in PowerShell
Get-Content : A positional parameter cannot be found that accepts argument '1.txt'.
I have also tried to use double quotes on each side and use Autohotkeys escape symbol like so:
Mypath = "`"C:\temp\example 1.txt`""
Run, powershell -command "get-content -path %Mypath% | Set-Clipboard"
As well as
Mypath = ""C:\temp\example 1.txt""
Run, powershell -command "get-content -path %Mypath% | Set-Clipboard"
But on both occasions, PowerShell throws this error;
The string is missing the terminator: ".
What am I doing wrong? any help would be appreciated.

This is quite weird but it is possible to get it working. It's really one escape hell.
Lets go through what's wrong with each of your attempts.
Mypath := "C:\temp\example 1.txt"
Run, powershell -command "get-content -path %Mypath% | Set-Clipboard"
Here you're not using the legacy syntax to assign a value to the variable Mypath, as you should.
It's a good thing to not be using the legacy syntax anymore.
However, since you're not using the legacy syntax, and are using the modern assigning operator :=(docs), you don't have any extra quotes " around the string.
So you're executing PowerShell with the following switches:
-command "get-content -path C:\temp\example 1.txt | Set-Clipboard".
And as you were able to guess, this is wrong because your filename is not quoted.
Mypath = "`"C:\temp\example 1.txt`""
Run, powershell -command "get-content -path %Mypath% | Set-Clipboard"
Here you're again using legacy syntax. So any string is interpreted literally. Therefore, firstly there is no reason to try to escape the quotes ", and secondly you don't escape quotes in AHK with `.
So, in this attempt you're executing PowerShell with the following switches:
-command "get-content -path ""C:\temp\example 1.txt"" | Set-Clipboard".
And this is no good, because first ""s get evaluated to a single ", and then you have
-command "get-content -path "C:\temp\example 1.txt" | Set-Clipboard"
which has unescaped quotes " inside another quotes, so that's no good.
Mypath = ""C:\temp\example 1.txt""
Run, powershell -command "get-content -path %Mypath% | Set-Clipboard"
And then here you have the exact same issue as in the previous one. Because, as we established, you don't escape quotes with `. This code is the exact same as the one above.
So, how should it be done?
You either need one more pair of escaped quotes " around the file path, or then just use a single quote for the inner quotes.
So in legacy syntax you'd want either:
Mypath = """"C:\temp\example 1.txt""""
Run, powershell -command "get-content -path %Mypath% | Set-Clipboard"
or
Mypath = 'C:\temp\example 1.txt'
Run, powershell -noexit -command "get-content -path %Mypath% | Set-Clipboard"
And in the modern expression syntax, you'd want either:
Mypath := """""""""C:\temp\example 1.txt"""""""""
Run, % "powershell -noexit -command ""get-content -path " Mypath " | Set-Clipboard"""
or
Mypath := "'C:\temp\example 1.txt'"
Run, % "powershell -noexit -command ""get-content -path " Mypath " | Set-Clipboard"""

Related

File path with spaces not working in batch file

I am trying to cat a text file containing a PowerShell script from a .bat file into PowerShell running within the command line.
It's kind of a workaround to start a PowerShell script on startup without having permission on the system.
It works perfectly fine until I try paths with spaces. Does someone know how to make this work?
I searched and tried many solutions (see 3,4,5,6) but either this is a very specific case, or I am doing something wrong. My knowledge of scripts in general is lacking some, but I'm trying my best. Please use simple language in your answer.
This works
#echo off
powershell "cat -raw C:\examplenospace\test.txt | invoke-expression"
This works
#echo off
set "file=C:\examplenospace\test.txt"
powershell "cat -raw %file% | invoke-expression"
Not working
#echo off
set "file=C:\example with space\test.txt"
powershell "cat -raw %file% | invoke-expression"
This also doesn't work of course
#echo off
powershell "cat -raw "C:\example with space\test.txt" | invoke-expression"
Also doesn't work
#echo off
powershell ""cat -raw "C:\example with space\test.txt" | invoke-expression"
I tried many variations, nothing seems to work
#echo off
powershell "cat -raw \"\"C:\example with space\test.txt" | invoke-expression"
How can I make it work?
#Compo thank your for your answer, this worked straight away, both of them!
#%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe -NoProfile -Command "Get-Content -LiteralPath 'C:\example with space\test.txt' -Raw | Invoke-Expression"
#%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe -NoProfile -Command "Get-Content -LiteralPath "C:\example with space\test.txt" -Raw | Invoke-Expression"

Comments in a long-line PowerShell code in a Batch script

I have a large batch script to which I need to add some Powershell code for some regex capture which I am unable to do in batch. I was hoping to have this code integrated in my batch script using the method outlined in Link, but when adding comments I get a missing } error. I've simplified my code just to be able to replicate the issue.
This, without a comment, works:
#echo OFF
setlocal enabledelayedexpansion enableextensions
set "var=variable"
PowerShell ^
foreach ($file in Get-ChildItem -File -Include *.* -Recurse) ^
{ ^
Write-Host $file; ^
Write-Host $env:var; ^
}
%End PowerShell%
echo Test
pause > nul
This, with a comment, does not work:
#echo OFF
setlocal enabledelayedexpansion enableextensions
set "var=variable"
PowerShell ^
foreach ($file in Get-ChildItem -File -Include *.* -Recurse) ^
{ ^
#Comment ^
Write-Host $file; ^
Write-Host $env:var; ^
}
%End PowerShell%
echo Test
pause > nul
I have tried escaping the # in a few different ways, but no matter what I do, I get the error message
Missing closing '}' in statement block or type definition.
+ CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : MissingEndCurlyBrace
The only difference is the comment. Does anyone know how to get around this? (using this long-line method that is). If it's not at all possible I guess I will go for base64 encoding
What works for me if when I do the comment line in between <# and #> as if it were a comment block.
Then of course for cmd you need to escape the < and > characters with a ^:
^<# Comment #^> ^
P.S. Don't forget that using Get-ChildItem without a -Path or -LiteralPath, the cmdlet will use PowerShell's current working folder ($pwd), which is most probably not the same as the current working path cmd uses..
This an hybrid code Batch and Powershell exmaple is just to show you how to put a multiline comment block with powershell and how to execute Batch section and powershell section :
<# : Batch Script Section
#rem # The previous line does nothing in Batch, but begins a multiline comment block in PowerShell. This allows a single script to be executed by both interpreters.
#echo off
Title Wifi Passwords Recovery by Hackoo 2022 & Mode 70,3
setlocal
cd "%~dp0"
Color 0B & echo(
Echo( Please Wait a while ... Getting SSID and Wifi Keys ...
Powershell -executionpolicy bypass -Command "Invoke-Expression $([System.IO.File]::ReadAllText('%~f0'))"
EndLocal
goto:eof
#>
# Powershell Script Section begin here...
# here we execute our powershell commands...
$Var=netsh wlan show profiles|SLS "\:(.+)$"|%{$SSID=$_.Matches.Groups[1].Value.Trim(); $_}|%{(netsh wlan show profile name="$SSID" key=clear)}|SLS "Conte.*:(.+)$"|%{$pass=$_.Matches.Groups[1].Value.Trim(); $_}|%{[PSCustomObject]#{SSID=$SSID;PASSWORD=$pass}}
$var | Format-List | Out-File -FilePath ".\WifiKeys_List_Format.txt"
$var | ConvertTo-Json | Out-File -FilePath ".\WifiKeys_JSON_Format.txt"
$var | OGV -Title "Wifi Passwords Recovery by Hackoo 2022" -wait
ii ".\WifiKeys_JSON_Format.txt"
ii ".\WifiKeys_List_Format.txt"

Difficulty escaping quote character in powershell script (Azure Devops Yaml)

My azure piplines yaml script uses powershell to replace a placeholder string in a .CS file with the current date string. This is the line with the value to be replaced (20200101000000)
[assembly: MyCompany.Net.Attributes.BuildDateAttribute("20200101000000")]
This is the powershell step that does it
pwsh: (get-content -path $(versionFile)) | foreach-object {$_ -replace "20200101000000", (get-date -f 'yyyyMMddhhmmss')} | set-content -path $(versionFile)
displayName: 'Update time stamp file'
I want to alter this step to include the quote characters " around the search string and write them into the new output value along with the new date. But I cannot seem to make that happen.
I mistakenly tried just putting escaped quote characters \" in the search and replace strings. But I guess you cannot escape inside of a single-quoted string so it did not work
pwsh: (get-content -path $(versionFile)) | foreach-object {$_ -replace "\"20200101000000\"", (get-date -f '\"yyyyMMddhhmmss\"')} | set-content -path $(versionFile)
This was the error:
##[command]"C:\Program Files\PowerShell\7\pwsh.exe" -NoLogo -NoProfile -NonInteractive -ExecutionPolicy Unrestricted -Command ". 'D:\a\_temp\80625e52-1302-4e35-a799-223ab893bcf1.ps1'"
ParserError: D:\a\_temp\80625e52-1302-4e35-a799-223ab893bcf1.ps1:3
Line |
3 | … lyInfo.cs) | foreach-object {$_ -replace "\"20200101000000\"", (get-d …
| ~~~~~~~~~~~~~~~~~
| Unexpected token '20200101000000\""' in expression or statement.
##[error]PowerShell exited with code '1'.
I also tried to just using double quotes around the get-date part of the script so I could escape the quote characters but that doesn't seem to work either. I'm guessing that's a limitation of writing script this way.
Is there some other way to achieve what I want?
The escape character in Powershell is backtick (`), not backslash (\). Try e.g. "`"20200101000000`"".
You can use the Get-Date -UFormat instead to add arbitrary characters similar to the DateTime.ToString() function in .NET
'[Attrib("20200101000000")]' -replace '"20200101000000"', (get-date -UFormat '"%Y%m%d%H%M%S"')

Powershell For-Loop throws MissingVariableNameAfterForeach

Why do I get the error "MissingVariableNameAfterForeach" for the following:
powershell.exe -NoProfile -ExecutionPolicy Bypass -Command "foreach($file in Get-ChildItem C:){((Get-Date)-$file.LastWriteTime).ToString('dd')}"
The command is supposed to print out the day since today of the last file/folder write in C:\
From the help text:
PS C:\> powershell.exe /?
If the value of Command is a script block, the script block must be enclosed
in braces ({}). You can specify a script block only when running PowerShell.exe
in Windows PowerShell.
Try this:
powershell.exe -NoProfile -ExecutionPolicy Bypass -Command {Get-ChildItem C: | ForEach-Object{($_.LastWriteTime).ToString('dd')}}
Your command will work if you enclose the Get-ChildItem in parentheses.
powershell.exe -NoProfile -ExecutionPolicy Bypass -Command ^
"foreach($file in (Get-ChildItem C:)){((Get-Date)-$file.LastWriteTime).ToString('dd')}"
I may have understood your question, because the existing answers do not seem to provide the information I thought you were looking for.
Whilst these examples don't specifically answer the question posed in your title, they are intended to output what I think you were looking for.
Here therefore is my batch-file attempt:
#"%__AppDir__%WindowsPowerShell\v1.0\powershell.exe" -NoProfile -Command^
"Get-ChildItem -Path 'C:\'|Sort-Object -Property LastWriteTime|"^
"Select-Object -Last 1|Format-Table -AutoSize -Property Name,"^
"#{Name='DaysOld';Expression={[Int]$((Get-Date)-$_.LastWriteTime).TotalDays}}"
#Pause
And obviously the cmd version, to be on topic:
"%__AppDir__%WindowsPowerShell\v1.0\powershell.exe" -NoProfile -Command "Get-ChildItem -Path 'C:\'|Sort-Object -Property LastWriteTime|Select-Object -Last 1|Format-Table -AutoSize -Property Name,#{Name='DaysOld';Expression={[Int]$((Get-Date)-$_.LastWriteTime).TotalDays}}"
Just in case it is simply my misunderstanding, perhaps this batch-file may work for you:
#"%__AppDir__%WindowsPowerShell\v1.0\powershell.exe" -NoProfile -Command^
"Get-ChildItem -Path 'C:\'|Sort-Object -Property LastWriteTime -Descending|"^
"Format-Table -AutoSize -Property Name,"^
"#{Name='DayInMonth';Expression={($_.LastWriteTime).ToString('dd')}},"^
"#{Name='DaysOld';Expression={[Int]$((Get-Date)-$_.LastWriteTime).TotalDays}}"
#Pause
cmd version:
"%__AppDir__%WindowsPowerShell\v1.0\powershell.exe" -NoProfile -Command "Get-ChildItem -Path 'C:\'|Sort-Object -Property LastWriteTime -Descending|Format-Table -AutoSize -Property Name,#{Name='DayInMonth';Expression={($_.LastWriteTime).ToString('dd')}},#{Name='DaysOld';Expression={[Int]$((Get-Date)-$_.LastWriteTime).TotalDays}}"
In both cases, you'll note because I'm not running a PowerShell script, there is no need to stipulate an execution policy. Commands should work as if being run directly in the PowerShell window.

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.