Literal quotes in "Powershell Start-Process -ArgumentList" - powershell

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"

Related

Using PowerShell script, Ping a list of host names and output the results to a csv

I have a large list of hostnames I need to ping to see if they are pinging or not. I am new at scripting but I managed to figure this much out but getting error when I run this script, I run the script using "PowerShell.exe script.ps > output.csv".
Error Below:
"pinghost.ps : The term 'pinghost.ps' 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:1
#NAME?
+ ~~~~~~~~~~~
+ CategoryInfo: ObjectNotFound: (pinghost.ps:String) [] CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException :"
Code below:
$names = Get-content ".\hnames.txt"
foreach ($name in $names){
if (Test-Connection -ComputerName $name -Count 1 -ErrorAction SilentlyContinue){
Write-Host "$name,up"
}
else{
Write-Host "$name,down"
}
}
PowerShell will attempt to resolve unqualified file paths passed as command line arguments relative to its working directory - if you launch PowerShell from the Run prompt or as a scheduled task running as a specific local user account, the working directory will default to the users profile folder.
Either pass a rooted file path:
powershell.exe -File C:\Users\Akshay\path\to\pinghost.ps1
Or a file path that's relative to the expected working directory (using / instead of \ will prevent PowerShell from interpreting the path as a module-qualified command name):
powershell.exe -File path/to/pinghost.ps1
In order to make PowerShell's provider cmdlets correctly resolve the hnames.txt file relative to the location of the script itself, prepend the path with the $PSScriptRoot automatic variable:
$names = Get-content (Join-Path $PSScriptRoot hnames.txt)
foreach ($name in $names){
if (Test-Connection -ComputerName $name -Count 1 -ErrorAction SilentlyContinue){
Write-Host "$name,up"
}
else{
Write-Host "$name,down"
}
}
Now it will work as long as the script and text file are in the same directory, regardless of where you call it from.

Several folders into a zip with PowerShell

I have several folders dir_01, dir_02, dir_03 that I want to backup in a zip file, say, backup.zip. This has to be saved in a folder with today's date. I need to get a .bat file to do the job; no additional third party executables allowed.
Here I found how to create a folder with today's date, but I am having problems to pass $destination to -DestinationPath. I created a .bat that calls PowerShell. Code giving me problems:
powershell.exe $destination = New-Item -Path 'C:\path\to\destionation' -ItemType Directory -Name ("$(Get-Date -f yyyy-MM-dd)")
powershell.exe -nologo -noprofile -command Compress-Archive -Path 'C:\path\dir_01', 'C:\path\dir_02', 'C:\path\dir_03' -DestinationPath $destination\backup.zip -Force
The error message is the following:
New-Object : Exception calling ".ctor" with "2" argument(s): "Access to the path 'C:\backup.zip' is denied."
At
C:\WINDOWS\system32\WindowsPowerShell\v1.0\Modules\Microsoft.PowerShell.Archive\Microsoft.PowerShell.Archive.psm1:729
char:30
+ ... ileStream = New-Object -TypeName System.IO.FileStream -ArgumentList $ ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [New-Object], MethodInvocationException
+ FullyQualifiedErrorId : ConstructorInvokedThrowException,Microsoft.PowerShell.Commands.NewObjectCommand
However, the code works if I hard-code the path to destination, like this:
powershell.exe -nologo -noprofile -command Compress-Archive -Path 'C:\path\dir_01', 'C:\path\dir_02', 'C:\path\dir_03' -DestinationPath 'C:\whole\path\backup.zip' -Force
But doing so, I'm unable to save backup.zip in today's folder.
Question: How can I save backup.zip in the folder that I created with today's date?
You can perform both commands in the same PowerShell session by separating them with a semicolon.
powershell.exe $destination = New-Item -Path 'C:\path\to\destionation' -ItemType Directory -Name ("$(Get-Date -f yyyy-MM-dd)"); Compress-Archive -Path 'C:\path\dir_01', 'C:\path\dir_02', 'C:\path\dir_03' -DestinationPath $destination\backup.zip -Force
That will launch PowerShell and have it create the folder and then zip things into it in the same session, rather than create a session, in that session create a folder, close the session, start a new PowerShell session, zip things up, close the second session.

Powershell parameter $args[0] with quotes

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

Cannot figure out why my Powershell script is getting permission errors

I cannot figure out why im getting permission errors, even though im running the script as a Domain Admin, which is in the full control group on the files/folders im trying to delete. UAC is not enabled on the pc the script is running from. I get the same errors no matter if i use enter-PSsession to the file server itself.
Its got to be how i approached the solution...ive tried other scripts that im not experienced enough to edit, they used a try/catch method with get-wmiobject and then .delete() command, and that script worked great...with no permission problems, it deletes profiles like a charm...and thats with the same credentials as my homemade script...So i really feel its not a true credential problem, and more to do with a shortcoming of the way im using the remove-item cmdlet.
here is my script...its my first homemade, not copy/pasted script, so feel free to point out the obvious bad practices... here is the script, and the errors will be below. The way i wrote this script is to try each individual command separately, then tie them together, that may be why some of it may be redundant.
##This process deletes ntuser.dat files and user profile folders
$users = (Read-Host "Enter each user (separate with comma)").split(',') | % {$_.trim()}
foreach ($user in $users) {
$datfile = "ntuser.dat"
$servers = Get-Content C:\servers.txt
$path1 = "\\fileserver\d$\TSEProfiles\$user.DOMAIN"
$path2 = "\\fileserver\d$\TSEProfiles\$user.DOMAIN.V2"
## Checks for ntuser.dat file in specified folders, if true, delete.
## Checking 4 locations on fileserver
If (Test-Path \\fileserver\d$\TSEProfiles\$user.DOMAIN\$datfile){
Remove-Item $path1\$datfile -recurse -force
}
if (Test-Path \\fileserver\d$\TSEProfiles\$user.DOMAIN.V2\$datfile){
Remove-Item $path2\$datfile -recurse -force
}
If (Test-Path \\fileserver\d$\roamingprofiles\$user.DOMAIN\$datfile){
Remove-Item $path1\$datfile -recurse -force
}
If (Test-Path \\fileserver\d$\roamingprofiles\$user.DOMAIN.V2\$datfile){
Remove-Item $path2\$datfile -recurse -force
}
## Checking 8 locations, if true, delete.
foreach ($server in $servers) {
If (Test-Path \\$server\c$\users\$user -PathType Container){
Remove-Item \\$server\c$\users\$user -recurse -force
}
}
}
Remove-Item : Access to the path '\\APPS3\c$\users\realdomainuser\AppData\Local\Application Data' is denied.
At C:\Users\admin\Documents\zoink.ps1:35 char:2
+ Remove-Item \\$server\c$\users\$user -recurse -force
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : PermissionDenied: (\\APPS3\c$\users\realdomainuser:String) [Remove-Item], UnauthorizedAccessException
+ FullyQualifiedErrorId : RemoveItemUnauthorizedAccessError,Microsoft.PowerShell.Commands.RemoveItemCommand
Remove-Item : Access to the path '\\APPS4\c$\users\realdomainuser\AppData\Local\Application Data' is denied.
At C:\Users\admin\Documents\zoink.ps1:35 char:2
+ Remove-Item \\$server\c$\users\$user -recurse -force
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : PermissionDenied: (\\APPS4\c$\users\realdomainuser:String) [Remove-Item], UnauthorizedAccessException
+ FullyQualifiedErrorId : RemoveItemUnauthorizedAccessError,Microsoft.PowerShell.Commands.RemoveItemCommand
django - THis is the delete profile output after running the local machine policy script. still getting auth errors.
Remove-Item : Access to the path '\\APPS7\c$\users\someuser\AppData\Local\Application Data' is denied.
At C:\Users\admin\Documents\zoink.ps1:35 char:2
+ Remove-Item \\$server\c$\users\$user -recurse -force
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : PermissionDenied: (\\APPS7\c$\users\someuser:String) [Remove-Item], UnauthorizedAccessException
+ FullyQualifiedErrorId : RemoveItemUnauthorizedAccessError,Microsoft.PowerShell.Commands.RemoveItemCommand
I once was having issues running scripts due to permissions on some of our Citrix VM's that didn't have powershell scripts running, however I was able to run bat files so I created a PS scripted wrapped inside a bat file.
echo "Killing IE"
powershell -Command "stop-process -processname iexplore"
While it is nowhere near an elegant solution it is an easy hack that serves it's purpose.
Try running this script. This is an example of permanently setting your local machine policy for scripts:
# SetExecutionPolicyToRemoteSigned.ps1
Write-Output "Setting local Powershell policy to RemoteSigned"
Write-Output ""
Set-ExecutionPolicy -scope CurrentUser Undefined -Force
#Set-ExecutionPolicy -scope Process Undefined -Force
Set-ExecutionPolicy -scope LocalMachine Undefined -Force
Set-ExecutionPolicy -scope CurrentUser RemoteSigned -Force
#Set-ExecutionPolicy -scope Process RemoteSigned -Force
Set-ExecutionPolicy -scope LocalMachine RemoteSigned -Force
Write-Output "Finished."
Get-ExecutionPolicy -list
Start-Sleep -s 10
It will result in the following output:
PS C:\Users\qa> Get-ExecutionPolicy -list
Scope ExecutionPolicy
----- ---------------
MachinePolicy Undefined
UserPolicy Undefined
Process RemoteSigned
CurrentUser RemoteSigned
LocalMachine RemoteSigned
Then, you can just run a script like this one without a policy prompt. Best of all, the policy should survive rebooting your system :
# Filename: Hello.ps1
Write-Host
Write-Host 'Hello World!'
Write-Host "Good-bye World! `n"
# end of script
And another example of running a script:
powershell.exe -ExecutionPolicy Bypass -NoLogo -NonInteractive -NoProfile
-WindowStyle Hidden -File script_name

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