Powershell parameter $args[0] with quotes - powershell

I'm running a PowerShell script invoked from a batch that pass a filename as first parameter.
Inside the script I use:
$file = Get-Item -LiteralPath $args[0]
But when the filenames contains a quote (I.E: my'file.txt) the get-item triggers an error. I've tried to remove the -LiteralPath parameter but the problem is the same.
The syntax of the script is
$file = Get-Item -LiteralPath $args[0]
write-host $file
cmd /c pause
If I run the script against my'file.txt I get:
C:\m\tag\testscript.ps1 'C:\m\tag\my'file.txt' <<<<
CategoryInfo : ParserError: (:String) [], ParentContainsErrorRecordException
FullyQualifiedErrorId : TerminatorExpectedAtEndOfString

Supposing you are passing the path in this way in your file batch:
powershell.exe C:\path\myscript.ps1 "%1%"
you need to escape the quote:
powershell.exe C:\path\myscript.ps1 \"%1%\"

How are you passing the parameter?
This works:
.{gi -literalpath $args[0]} "my'file.txt"

I think that maybe by the time PowerShell sees the filename cmd has stripped off any surround double quotes so PowerShell sees the lone single quote as a parse error. Try specifying the filename like so
my''file.txt

Related

I am unable to change the extension of a multiple files using the powershell

To change the extension of files located at: C:\Users\mohit singh\Desktop\spotlight, I typed the following command in the PowerShell
C:\Users\mohit singh\Desktop\spotlight> ren *.* *.jpg
But I get the following error:
ren : Cannot process argument because the value of argument "path" is not valid. Change the value of the "path"
argument and run the operation again.
At line:1 char:1
+ ren *.* *.jpg
+ ~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Rename-Item], PSArgumentException
+ FullyQualifiedErrorId : Argument,Microsoft.PowerShell.Commands.RenameItemCommand
You're trying to use the ren command from within PowerShell. However, ren in Powershell is an alias to Rename-Item which is a different command. Powershell and cmd are different shells that use different command interpreters.
Your simplest option is just to run your command from a cmd window, instead of Powershell.
But if you wanted to use Powershell, you can do this by getting every file in the current folder, piping it to Rename-Item, then using the ChangeExtension .Net API to change its extension (which is safer than simple string replacement).
Get-ChildItem -File | Rename-Item -NewName { [io.path]::ChangeExtension($_.Name, "jpg") }
If you want to act on subfolders too, add -Recurse to Get-ChildItem.

Powershell cmdlet: move file to Team Drive

I'm having a hard time moving a file from a local directory and into Team Drive.
I have a feeling I may be forced to step away from PS and find another route, which I really don't want to but here goes.
This command does not work:
Move-Item -Path 'C:\Program Files (x86)\FieldSmart View\Logs\BgSync.log' -Destination 'G:\Team Drives\LGE Prints\Logs\$env:computername.txt'
This command does work:
Move-Item -Path 'C:\Program Files (x86)\FieldSmart View\Logs\BgSync.log' -Destination C:\Users\ITAdmin\Desktop\Test\$env:computername.txt
The only difference is the destination.
When trying to move a file into Team Drive this is the error that is returned:
Move-Item : The given path's format is not supported.
At line:1 char:1
Move-Item -Path 'C:\Program Files (x86)\FieldSmart View\Logs\BgSync.l ...
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
CategoryInfo : NotSpecified: (:) [Move-Item], NotSupportedException
FullyQualifiedErrorId : System.NotSupportedException,Microsoft.PowerShell.Commands.MoveItemCommand
What can I do?
My guess is that you are using Single Quotes not Double Quotes when you want a variable replacement in your string. Your 2nd example has no quotes and the command line will turn that "text" into a string with replacement.
Run this:
"single"
'G:\Team Drives\LGE Prints\Logs\$env:computername.txt'
"double"
"G:\Team Drives\LGE Prints\Logs\$env:computername.txt"
This link looks good, or any other search for variable replacement.
https://kevinmarquette.github.io/2017-01-13-powershell-variable-substitution-in-strings/

Literal quotes in "Powershell Start-Process -ArgumentList"

I am currently attempting to create a command that opens an admin Powershell from the right click context menu. For context, context menu commands run in CMD.
My issue is that I am trying to cd into the directory where the right click occurs. The below command works just fine for most directories, but if the directory path contains a space, then it will only try to move into the portion of the path before the space, throwing an error. My understanding is that the current directory is passed in through %V but when I run the command echo %V using the same process, it splits paths with a space onto 2 lines, so I assume the parts of the path are stored in separate strings?
Powershell -noexit "Start-Process 'C:\Users\<me>\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Windows PowerShell\Windows PowerShell.lnk' -ArgumentList '-noexit','Set-Location -literalPath `"%V`"' -Verb RunAs"
I have updated the above command to match a suggestion below, and when right clicking on the desktop (which previously worked due to a lack of spaces) I now get the following error:
Set-Location : Cannot find path 'C:\Users\<me>\Desktop`' because it does not exist.
At line:1 char:1
+ Set-Location -literalPath `C:\Users\<me>\Desktop`
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (C:\Users\<me>\Desktop`:String) [Set-Location], ItemNotFoundException
+ FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.SetLocationCommand
Note that in both of the above code blocks, <me> is my actual username.
I've been tearing my hair out trying to put quotes around the path but I can't seem to get Powershell to put the quotes in due to the fact that I already use both single and double quotes.
Any help would be greatly appreciated, thanks in advance.
Edit:
For those still looking for an answer, I ran the following Powershell script to add functional commands to my context menu:
$menu = 'Open Windows PowerShell Here as Administrator'
$command = "$PSHOME\powershell.exe -NoExit -NoProfile -Command ""Set-Location '%V'"""
'directory', 'directory\background', 'drive' | ForEach-Object {
New-Item -Path "Registry::HKEY_CLASSES_ROOT\$_\shell" -Name runas\command -Force |
Set-ItemProperty -Name '(default)' -Value $command -PassThru |
Set-ItemProperty -Path {$_.PSParentPath} -Name '(default)' -Value $menu -PassThru |
Set-ItemProperty -Name HasLUAShield -Value ''
}
The answer was found from How do I start PowerShell from Windows Explorer?
If you want to avoid space issues, you can reuse " by escaping it with ` in a string.
For example :
$command = "Set-Location `"C:\temp\test space`""
String will become this and spaces will be handled correctly :
Set-Location "C:\temp\test space"

Select a string from a tailing log

I have an application log for which I am trying to write a batch file that will tail the log and return strings that contain "queue size" so that the updating queue size can be displayed. Basically the Windows equivalent of:
tail -f app.log | grep "queue size"
From what I've read I would need to use Windows powershell. I have devised the following script:
powershell -command Select-String -Path C:\logs\app.log -Pattern "queue size"
This gives me the following error:
Select-String : A positional parameter cannot be found that accepts
argument 'size'. At line:1 char:1
+ Select-String -Path C:\logs\app.log -Pattern queue size
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Select-String], ParameterBindingException
+ FullyQualifiedErrorId : PositionalParameterNotFound,Microsoft.PowerShell.Commands.SelectStringCommand
Although this as it stands doesn't work, would it constantly update with the current logic?
No, the PowerShell command will not continue to read the log as it's being updated. PowerShell can't really handle this task, so you'd be better off grabbing a Windows port of the Unix tail command (e.g. from GnuWin32 or UnxUtils) and use it with the batch find command:
tail -f C:\path\to\app.log | find "queue size"
You need to wrap the command in double quotes and use single quotes for the pattern:
powershell -command "Select-String -Path C:\logs\app.log -Pattern 'queue size'"
this should do:
cat c:\path\to\app.log -tail 100 -wait | select-string "queue size"
cat is an alias for Get-Content...
The -wait parameter will make it wait for log updates.

Powershell - calling icacls with parantheses included in parameters

I'm pretty new to Powershell, but I have lots of experience in VBScript and Python. I'm trying to be a good Windows admin and get into Powershell more. So, here is what I'm trying to do:
A parent folder contains dozens of sub-folders that are named as AD usernames (ex. Users\username1, Users\username2, where Users is the parent folder). I want to loop through each folder name, parse out the sub-folder name, and pass that to icacls to apply permissions based on the username. I did a multi-liner because I was running into issues piping. This is what I have after trying several different approaches:
$root_folder = "c:\temp\test"
$cmd1 = "icacls "
$cmd2 = " /grant cm\"
$cmd3 = ":`(OI`)`(CI`)F"
$paths_collection = get-childitem $root_folder | foreach-object -process {$_.FullName}
foreach ($path in $paths_collection)
{$string = $path.split("\");$last = $string[-1];$command = $cmd1 + $path +$cmd2 +$last +$cmd3;invoke-expression $command}
It wasn't originally this rough, but I started breaking it apart when I was running into issues.
THE PROBLEM - in $cmd3, the (OI)(CI) is not coming in cleanly to the invoke-expression. If I change $cmd3 to just ":F" it works, but I have to set inheritance using the offending parameters. PLEASE HELP. I've been racking my brain all day on this one. Couldn't really find anything that dealt with this issue specifically (tried backticks, referencing the $command as '$command', etc.)
ERROR:
The term 'OI' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling
of the name, or if a path was included, verify that the path is correct and try again.
At line:1 char:56
+ icacls C:\temp\test\garthwaitm /grant domain\user1:(OI <<<< )(IO)F
+ CategoryInfo : ObjectNotFound: (OI:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
Just to add to this old question, in PowerShell 3.0 you can now use --% to tell PowerShell to stop processing anything else on the line, so you can use something like this:
icacls.exe $path --% /grant "Everyone:(OI)(CI)(F)"
I think you are unnecessarily complicating it.
Get the echoargs.exe from Powershell Community Extensions.
See if something like below is what you wanted:
PS >.\EchoArgs.exe /grant $path "cm\$last" ":(OI)(CI)F"
Arg 0 is </grant>
Arg 1 is <c:\test>
Arg 2 is <cm\user>
Arg 3 is <:(OI)(CI)F>
Then call it with the command you want:
&icacls /grant $path "cm\$last" ":(OI)(CI)F"
BTW, you can use Split-Path to get the $last. And use select -expand fullname instead of the foreach-object -process {$_.FullName}
Have you tried using quotes around $command, e.g. Invoke-Expression "$command"? Other techniques for preventing parentheses from being processed are discussed here: http://msdn.microsoft.com/en-us/library/cc281841.aspx