Error in batch file due to space - powershell

I am having trouble with a seemingly simple script I have which essentially copies an item from the user's PC and places it on another computer; however, the destination file path contains a space in it. I have tried multiple methods of correcting this issue (some I don't completely understand) from using double quotation marks around the string to forcing it to run powershell.
To give a very brief precursor to this situation, I must add that I initially created this script using Powershell on Windows 10 and I should also add that it works completely fine in Powershell, just not as a .bat. I understand there may be some differences in the languages or what is interpreted through the programs.
Here is the string in the question:
Copy-Item $ENV:USERPROFILE\Desktop\VAST.accdb -destination "\\PRECDP19670\C$\Users\WAKE\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup" -Force -PassThru -Verbose
The destination contains the space in the filepath.
Any help is appreciated!

As Bill mentioned, your BAT file needs to call PowerShell as an executable.
PowerShell.exe -command 'Copy-Item $ENV:USERPROFILE\Desktop\VAST.accdb -destination "\\PRECDP19670\C$\Users\WAKE\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup" -Force -PassThru -Verbose

Related

How to pass an array to the arguments in Start-Process in Powershell?

I am writing a script to play certain files in a player. I use Get-ChildItem to get an array of file names. Then I want to use Start-Process to play these files. However, how can I add these file names to the arguments of the player program?
I used Start-Process -FilePath "C:\Program Files\DAUM\PotPlayer\PotPlayerMini64.exe" -ArgumentList $selected_items but it seems it doesn't work and the files are not played.
Notice there are spaces in the file names.
Syntax-wise, your approach should work, but doesn't, due to an unfortunate bug, still present in PowerShell 7.2 - see GitHub issue #5576.
While passing an array of arguments to Start-Process's -ArgumentList parameter does cause the array elements to be passed as individual arguments (which is usually how external CLIs expect multiple file arguments), the necessary double-quoting around elements with spaces is not applied when the command line ultimately used for invocation is constructed behind the scenes.
Also, for robustness you should use the .FullName property of the objects stored in $selected_items, so as to ensure that full paths are passed, because - in Windows PowerShell, situationally - Get-ChildItem's output objects may stringify to the file name only - see this answer.
Workaround: Pass a single argument to -ArgumentList, in which you encode all pass-through arguments, using embedded double-quoting.
Start-Process `
-FilePath "C:\Program Files\DAUM\PotPlayer\PotPlayerMini64.exe" `
-ArgumentList ($selected_items.ForEach({ '"{0}"' -f $_.FullName }) -join ' ')
Taking a step back:
If PotPlayerMini64.exe is a Windows GUI(-subsystem) application, you don't need Start-Process at all, because even direct invocation will then act asynchronously (i.e., the program will launch, and control will return to PowerShell right away; conversely, if you wanted to wait for the program to exit, use Start-Process -Wait).
& "C:\Program Files\DAUM\PotPlayer\PotPlayerMini64.exe" $selected_Items.FullName
Note that in direct invocations such as this, PowerShell does perform the necessary double-quoting behind the scenes, on demand.
Note: I'm unclear on whether passing multiple file paths to PotPlayerMini64.exe alone also starts playback - the alternative solution in the next section may ensure that.
Alternative, clipboard-based solution:
Judging by PotPlayerMini64.exe's available command-line options[1], the following may work (I cannot personally verify):
/clipboard :Appends content(s) from clipboard into playlist and starts playback immediately.
# Copy the full names of the files of interest to the clipboard.
Set-Clipboard -Value $selected_items.FullName
# Launch the player and tell it to start playback of the files on the clipboard.
# Parameters -FilePath and -ArgumentList are positionally implied.
Start-Process 'C:\Program Files\DAUM\PotPlayer\PotPlayerMini64.exe' /clipboard
There are file-arguments-related options such as /new, /insert, and /add, but it's unclear to me whether they - or omitting them altogether, as in your attempt - automatically start playback (may depend on the application's persistent configuration).
[1] Note that this is not the official documentation; I couldn't find the latter.
You can ForEach-Object:
Get-ChildItem . | ForEach-Object {Start-Process -FilePath "C:\Program Files\DAUM\PotPlayer\PotPlayerMini64.exe" -ArgumentList $_.FullName}
You don't need start-process (plus, -argumentlist doesn't handle filenames with spaces as easily).
& "C:\Program Files\DAUM\PotPlayer\PotPlayerMini64.exe"
C:\Program` Files\DAUM\PotPlayer\PotPlayerMini64.exe
$env:path += ';C:\Program Files\DAUM\PotPlayer'; PotPlayerMini64
Even using start-process, it varies with the program. For example, Emacs can take multiple file arguments, separated by spaces. If the filename has a space, it would need to be double quoted. External programs don't know what arrays are, and start-process converts them to one string with spaces in between each element.
start emacs file1,file2,'"my file"'
get-wmiobject win32_process | ? name -eq emacs.exe | % commandline
"c:\program files\emacs\bin\emacs.exe" file1 file2 "my file"
ps emacs | % commandline # ps 7
"c:\program files\emacs\bin\emacs.exe" file1 file2 "my file"

How do i use Get-clipboard output in a powershell script?

i'm trying to use text that is inside the clipboard inside a powershell script. So what the purpose for the script, i want to be able to copy a file directory and then run the script so it uses the copied directory as a automatic destination. So my idea was to do something like this:
Copy-Item C:\Users\gif.gif -Destination "Copied Directory"
I'm very new to powershell scripting, so an explenation of what is going on would be nice but not needed. I origionlly thought that this could work but nope XD, this should have been a simple project but yeah it wasn't meant to be easy.
Copy-Item C:\Users\J.J\Documents\TouchPortal/Make_30fps_gif.bat -Destination | Get-Clipboard
Would love to get some help with this, and thank you in advance!
To complement Steven's helpful answer:
In Windows PowerShell only, you can use Get-Clipboard's -Format parameter to request clipboard data other than text.
In PowerShell [Core, v6+], this is no longer supported, and text is indeed the only data type supported by Get-Clipboard.
In Windows PowerShell, if you've used File Explorer to copy a directory to the clipboard (using the regular Copy shortcut-menu command or the Ctrl+C keyboard shortcut), you can access it as System.IO.DirectoryInfo instance by passing -Format FileDropList to Get-Clipboard.
Note: -Format FileDropList returns a collection of file-system-info objects, so as to also support multiple files/directories having been copied to the clipboard; thanks to member-access enumeration, however, you can treat this collection like a single object - assuming truly only one file or directory was copied.
# Note: Windows PowerShell only.
# The .FullName property returns the full directory path.
Copy-Item C:\Users\gif.gif -Destination (Get-Clipboard -Format FileDropList).FullName
In PowerShell [Core, v6+] you'll indeed have to use the Shift+right-click method and select Copy as path from the shortcut menu, in order to ensure that a file/directory is copied as a (double-quoted, full) path string, as shown in Steven's answer.
In PowerShell core including versions 6 & 7 Get-Clipboard only works with text. If you use it after copying a folder it will return null.
In PowerShell 5.1 (Windows PowerShell) you can use the -Format parameter with Get-Clipboard
See mklement0's answer for a better description and example using -Format.
If you need to use the newer versions, you can use the shift + context menu choice > Copy as Path to get the folder's string path on to the clipboard, but that will quote the path. The quoted path will then be rejected by Copy-Item.
However, you could quickly replace the quotes like below.
Copy-Item 'C:\temp\BaseFile.txt' -Destination (Get-Clipboard).Replace('"',"")
Caution though, this seems hazardous and I wouldn't advise it. I use Get-Clipboard all the time to get data into a console session and can attest that it's too easy to make mistakes. The clipboard is so transient and it's use so ubiquitous that even if you make this work it's bound to burn you at some point.
Maybe you can elaborate on what you're trying to do and why. Then we can brainstorm the best approach.

PowerShell script working as File Explorer extension

I have written a GUI app in PowerShell. It has one parameter.
At the beginning of the script I have:
param (
[string]$Path
)
Before the Form appears, I fill in a control with $Path:
$Form.Add_Load({
$txtSourceFile.Text = $Path
})
When I run the script interactively in PowerShell it seems to be working as expected. The txtSourceFile control is filled in with the argument from the command line.
.\ghead.ps1 -Path C:\src\data\ghead.ps1
However, when I run this as a File Explorer extension, it does not appear to receive the argument from the command line. The registry setting for the command is:
C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.EXE C:\\Users\\lit\\bin\\ghead.ps1 -Path %1
There is no error message. It simply does not fill in the $txtSourceFile.Text field. Am I missing something obvious? How can I get this to work?
The question suggested as a duplicate does not deal with running as a Windows File Explorer extension. I am already using the param() technique.
The core of the problem was an extraneous character in the Users directory name which was not presented in the question. The OP probably needs new glasses glued to his face so that he can see better and not go without them.
C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.EXE -Command C:\Users\pwatson\bin\ghead.ps1 -Path
The final registry entry turned out to be:
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.EXE -WindowStyle Hidden -Command \\ASERVER\D$\Install\Utilities\ghead.ps1 -Path %1

working with relative paths in powershell WebClient and FileStream

I'm tasked with writing a powershell script to perform a file download, which will eventually be executed as a scheduled task once a week. I have no background in programming in the windows environment so this has been an interesting day.
I am experiencing a problem with the unexpected handling of the $pwd and $home of the shell.
I pass into my program a download URL and a destination file. I would like the destination file to be a relative path, e.g., download/temp.txt.gz
param($srcUrl, $destFile)
$client = new-object System.Net.WebClient
$client.DownloadFile($srcUrl, $destFile)
Ungzip-File $destFile
Remove-Item $destFile
This actually fails on the call to Remove-Item. If $destFile is a relative path then the script happily downloads the file and puts it in a file relative to $home. Likewise, I then unzip this and my function Ungzip-File makes use of System.IO.Filestream, and it seems to find this file. Then Remove-Item complains that there is no file in the path relative to $pwd.
I am a bit baffled, as these are all part of the shell, so to speak. I'm not clear why these functions would handle the path differently and, more to the point, I'm not sure how to fix this so both relative and absolute paths work. I've tried looking at the io.path methods but since my $home and $pwd are on different drives, I can't even use the IsPathRooted which was seemed so close when I found it.
Any help?
You have to be aware of where you are in the path. $pwd works just fine on the command shell but let's say you have started your script from a scheduled job. You might think $pwd is where your script resides and code accordingly but find out that it actually uses, say %windir%\system32.
In general, I would use fullpath to destination and for paths relative to script folder I would use $PSScriptRoot/folder_name/file_path.
There are catches there too. For example, I noticed $PSScriptRoot will resolve just fine within the script but not within Param() block. I would highly suggest using write-verbose when coding and testing, so you know what it thinks the path is.
[CMDLETBINDING()] ## you need this!
Param()
write-verbose "path is $pwd"
Write-Verbose "removing $destFile"
Remove-Item $destfile
and add -verbose when you are calling your script/function:
myscript.ps1 -verbose
mydownloadfunction -verbose
To use a relative path, you need to specify the current directory with ./
Example: ./download/temp.txt.gz
You can also change your location in the middle of the script with Set-Location (alias: cd)

Powershell Get-ChildItem doesn't work properly on IIS directory

I was going to write up a simple alias 'iis' to invoke the IIS Manager, which is 'C:\Windows\System32\inetsrv\InetMgr.exe'
set-alias iis "OpenIIS.ps1"
and in the OpenIIS.ps1 I have
$item = "C:\Windows\system32\inetsrv\InetMgr.exe"
invoke-item -path $item
This doesn't work. The error I get is "The system cannot find the file specified"
In fact, just doing a Get-ChildItem on the inetsrv won't show the InetMgr.exe (no difference with -Force switch)
Get-ChildItem C:\Windows\system32\inetsrv\*.exe -force
Obviously I can see it in Explorer and I can launch it using cmd, but not with Powershell it seems. Also, Powershell is running as Administrator.
What is going on?
As a workaround I tried creating a link to the file and then invoking that link from Powershell. I now get a 'NotSpecified' Win32Exception.
I have originally used 64 bit Powershell, but get the same result on the x86 Powershell (both run as Administrator)
Are you at the elevated PowerShell prompt? Some system files may not show up unless you use -Force parameter with Get-ChildItem.
I think evidently the file InetMgr.exe is not there as when I do a get-childitem in the mentioned directory,it lists the "InetMgr.exe" there.
This may not be the problem with Get-ChildItem or the Alias you created but instead with ur IIS Server.