Home > PowerShell > Provide A Batch File To Run Your PowerShell Script From; Your Users Will Love You For It

Provide A Batch File To Run Your PowerShell Script From; Your Users Will Love You For It

A while ago in one of my older posts I included a little gem that I think deserves it’s own dedicated post; calling PowerShell scripts from a batch file.

Why call my PowerShell script from a batch file?

When I am writing a script for other people to use (in my organization, or for the general public) or even for myself sometimes, I will often include a simple batch file (i.e. *.bat or *.cmd file) that just simply calls my PowerShell script and then exits.  I do this because even though PowerShell is awesome, not everybody knows what it is or how to use it; non-technical folks obviously, but even many of the technical folks in our organization have never used PowerShell.

Let’s list the problems with sending somebody the PowerShell script alone; The first two points below are hurdles that every user stumbles over the first time they encounter PowerShell (they are there for security purposes):

  1. When you double-click a PowerShell script (*.ps1 file) the default action is often to open it up in an editor, not to run it (you can change this for your PC).
  2. When you do figure out you need to right-click the .ps1 file and choose Open With –> Windows PowerShell to run the script, it will fail with a warning saying that the execution policy is currently configured to not allow scripts to be ran.
  3. My script may require admin privileges in order to run correctly, and it can be tricky to run a PowerShell script as admin without going into a PowerShell console and running the script from there, which a lot of people won’t know how to do.
  4. A potential problem that could affect PowerShell Pros is that it’s possible for them to have variables or other settings set in their PowerShell profile that could cause my script to not perform correctly; this is pretty unlikely, but still a possibility.
      So imagine you’ve written a PowerShell script that you want your grandma to run (or an HR employee, or an executive, or your teenage daughter, etc.). Do you think they’re going to be able to do it?  Maybe, maybe not.

You should be kind to your users and provide a batch file to call your PowerShell script.

The beauty of batch file scripts is that by default the script is ran when it is double-clicked (solves problem #1), and all of the other problems can be overcome by using a few arguments in our batch file.

Ok, I see your point. So how do I call my PowerShell script from a batch file?

First, the code I provide assumes that the batch file and PowerShell script are in the same directory.  So if you have a PowerShell script called “MyPowerShellScript.ps1” and a batch file called “RunMyPowerShellScript.cmd”, this is what the batch file would contain:

@ECHO OFF
SET ThisScriptsDirectory=%~dp0
SET PowerShellScriptPath=%ThisScriptsDirectory%MyPowerShellScript.ps1
PowerShell -NoProfile -ExecutionPolicy Bypass -Command "& '%PowerShellScriptPath%'";

Line 1 just prevents the contents of the batch file from being printed to the command prompt (so it’s optional).  Line 2 gets the directory that the batch file is in.  Line 3 just appends the PowerShell script filename to the script directory to get the full path to the PowerShell script file, so this is the only line you would need to modify; replace MyPowerShellScript.ps1 with your PowerShell script’s filename.  The 4th line is the one that actually calls the PowerShell script and contains the magic.

The –NoProfile switch solves problem #4 above, and the –ExecutionPolicy Bypass argument solves problem #2.  But that still leaves problem #3 above, right?

Call your PowerShell script from a batch file with Administrative permissions (i.e. Run As Admin)

If your PowerShell script needs to be run as an admin for whatever reason, the 4th line of the batch file will need to change a bit:

@ECHO OFF
SET ThisScriptsDirectory=%~dp0
SET PowerShellScriptPath=%ThisScriptsDirectory%MyPowerShellScript.ps1
PowerShell -NoProfile -ExecutionPolicy Bypass -Command "& {Start-Process PowerShell -ArgumentList '-NoProfile -ExecutionPolicy Bypass -File ""%PowerShellScriptPath%""' -Verb RunAs}";

We can’t call the PowerShell script as admin from the command prompt, but we can from PowerShell; so we essentially start a new PowerShell session, and then have that session call the PowerShell script using the –Verb RunAs argument to specify that the script should be run as an administrator.

And voila, that’s it.  Now all anybody has to do to run your PowerShell script is double-click the batch file; something that even your grandma can do (well, hopefully).  So will your users really love you for this; well, no.  Instead they just won’t be cursing you for sending them a script that they can’t figure out how to run.  It’s one of those things that nobody notices until it doesn’t work.

So take the extra 10 seconds to create a batch file and copy/paste the above text into it; it’ll save you time in the long run when you don’t have to repeat to all your users the specific instructions they need to follow to run your PowerShell script.

I typically use this trick for myself too when my script requires admin rights, as it just makes running the script faster and easier.

Bonus

One more tidbit that I often include at the end of my PowerShell scripts is the following code:

# If running in the console, wait for input before closing.
if ($Host.Name -eq "ConsoleHost")
{ 
	Write-Host "Press any key to continue..."
	$Host.UI.RawUI.FlushInputBuffer()	# Make sure buffered input doesn't "press a key" and skip the ReadKey().
	$Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyUp") > $null
}

This will prompt the user for keyboard input before closing the PowerShell console window.  This is useful because it allows users to read any errors that your PowerShell script may have thrown before the window closes, or even just so they can see the “Everything completed successfully” message that your script spits out so they know that it ran correctly.  Related side note: you can change your PC to always leave the PowerShell console window open after running a script, if that is your preference.

I hope you find this useful.  Feel free to leave comments.

Happy coding!

Update

Several people have left comments asking how to pass parameters into the PowerShell script from the batch file.

Here is how to pass in ordered parameters:

PowerShell -NoProfile -ExecutionPolicy Bypass -Command "& '%PowerShellScriptPath%' 'First Param Value' 'Second Param Value'";

And here is how to pass in named parameters:

PowerShell -NoProfile -ExecutionPolicy Bypass -Command "& '%PowerShellScriptPath%' -Param1Name 'Param 1 Value' -Param2Name 'Param 2 Value'"

And if you are running the admin version of the script, here is how to pass in ordered parameters:

PowerShell -NoProfile -ExecutionPolicy Bypass -Command "& {Start-Process PowerShell -ArgumentList '-NoProfile -ExecutionPolicy Bypass -File """"%PowerShellScriptPath%"""" """"First Param Value"""" """"Second Param Value"""" ' -Verb RunAs}"
And here is how to pass in named parameters:
PowerShell -NoProfile -ExecutionPolicy Bypass -Command "& {Start-Process PowerShell -ArgumentList '-NoProfile -ExecutionPolicy Bypass -File """"%PowerShellScriptPath%"""" -Param1Name """"Param 1 Value"""" -Param2Name """"Param 2 value"""" ' -Verb RunAs}";
And yes, the PowerShell script name and parameters need to be wrapped in 4 double quotes in order to properly handle paths/values with spaces.
  1. December 3rd, 2013 at 16:12 | #1

    Good idea. But why not simply use %~dpn0 directly? As in

    PowerShell -NoProfile -ExecutionPolicy Bypass -Command “& ‘%~dpn0.ps1′”

  2. December 3rd, 2013 at 16:35 | #2

    @Antonio Bueno
    You can definitely do that; it’s nice and short 🙂

    For my blog posts I try to make things more generalized and easy to understand, as not everybody has the same background knowledge. I would rather have a few clear lines over a confusing one liner. Also, your solution has the additional constraint of requiring the .cmd and .ps1 files to have the same name, which some people may not want.

    Thanks for the tip though!

  3. Tomas
    December 18th, 2013 at 14:23 | #3

    Great!! Exactly what I am looking for. Thank you. Tomorrow I will try if it works. Tomas

  4. Tomas
    December 27th, 2013 at 03:45 | #4

    Thank you it perfectly works. But I have one question I would like to pass some values into power shell script. I would like to call:

    SET PowerShellScriptPath=%ThisScriptsDirectory%MyPowerShellScript.ps1 %1 %2

    but it does not work. Please can you provide what is the syntax when I am using parameters inside of BAT or Shall script.

    Thank you.
    Tomas

  5. December 28th, 2013 at 20:45 | #5

    @Tomas
    You just need to add the parameters in the last line that actually calls PowerShell, so it would be:

    PowerShell -NoProfile -ExecutionPolicy Bypass -Command “& ‘%PowerShellScriptPath%’ ‘%1’ ‘%2′”

    or if you want to use the named powershell parameters (instead of ordered):

    PowerShell -NoProfile -ExecutionPolicy Bypass -Command “& ‘%PowerShellScriptPath%’ -Param1Name ‘%1’ -Param2Name ‘%2′”

  6. Screwuphead
    January 29th, 2014 at 00:41 | #6

    @deadlydog
    Let me start off by saying this is what I have been looking for, thank you so much for documenting it!

    What about passing values with Administrative permissions? I tried using the following an get an error.
    PowerShell -NoProfile -ExecutionPolicy Bypass -Command “”
    Basically I need to pass the current directory that the script was called from because I have other scripts that need to be called from that same directory.

    Thank You!

  7. Jon
    January 30th, 2014 at 11:02 | #7

    Thanks for the good info. I am running a simpler one-liner, from inside a batch file. (Intended to ‘simply’ erase *.xxx files recursively, like “erase *.xxx /s /q”, but without legacy 8.3 issues deleting extra files like *.xxxxx , as per http://support.microsoft.com/kb/164351/en-us; note that Powershell’s remove-item cmdlet still doesn’t work with its -recurse parameter, even in PS 4.0! This is getting crazy complex for something so simple.)

    This works from within a batch file:

    PowerShell “& Get-ChildItem * -Include *.xxx -Recurse | Remove-Item”

    But when I try to add parameter -force to right side, to remove hidden files, this does NOT work:

    PowerShell “& Get-ChildItem * -Include *.xxx -Recurse | Remove-Item -force” [fails]

    Any ideas how to get that to work — pipelining with a parameter, on a single line in a batch file?

  8. February 2nd, 2014 at 00:42 | #8

    @Screwuphead
    Thanks, I’m glad my article could be of help 🙂

    Bringing up a PowerShell command prompt and typing “powershell /?” tells me that you simply provide any parameters you want passed to the script in the -File parameter after the file path. So it will look similar to passing values when not running as admin, as I showed in my comment above to Tomas.

    Here is an example of passing extra values into the script when running it as admin:
    PowerShell -NoProfile -ExecutionPolicy Bypass -Command “& {Start-Process PowerShell -ArgumentList ‘-NoProfile -ExecutionPolicy Bypass -File “”%PowerShellScriptPath%”” -Param1Name “”param 1 Value”” -Param2Name “”param 2 value””‘ -Verb RunAs}”

    or for your specific scenario of passing in the current directory (here I assume the first/only parameter your script takes in is the directory path, as I’m not passing the value in using named parameters as I do above):
    PowerShell -NoProfile -ExecutionPolicy Bypass -Command “& {Start-Process PowerShell -ArgumentList ‘-NoProfile -ExecutionPolicy Bypass -File “”%PowerShellScriptPath%”” “”%ThisScriptsDirectory%””‘ -Verb RunAs}”

  9. February 2nd, 2014 at 01:00 | #9

    @Jon
    I don’t know what you mean when you say it doesn’t work (fails); does it give an error message? or simply just not delete the files? I’m guessing that it just doesn’t delete the files, and that you simply need to also provide the -Force switch to Get-ChildItem, otherwise hidden and read-only files won’t be found and passed to the Remove-Item cmdlet. So basically you want to use this:

    PowerShell “& Get-ChildItem * -Include *.xxx -Recurse -Force | Remove-Item -Force”

    I hope that helps. If you still need an answer I suggest posting your question with more detail on Stack Overflow or the PowerShell.org forums, as there are many others there who are smarter than I who can likely help you out 🙂

  10. Jon
    February 2nd, 2014 at 09:47 | #10

    @deadlydog

    Thanks, deadlydog! I missed that -force was needed on Get-ChildItem, as I am new to PowerShell. That did the trick. [Perhaps my comment thread should be removed, as non-pertinent.]

  11. Tomas
    February 3rd, 2014 at 07:22 | #11

    Hello Daniel!

    You script to run the powershell works perfect, but I think I have something wrong in my powershell code, that maybe you can help me with. I got it from a person on stack overflow.

    Here it is:

    if ($(Get-Item C:\Temp\test\test.log).CreationTime -gt [DateTime]::Today) {
    Write-Host “File Changed at $(Get-Item C:\Temp\test\test.log).CreationTime”
    }
    else {
    Write-Host “File not changed”
    }

    It’s supposed to ceck on test.log, and if that file has changed during the day is shoud display the time of the change and if it has not ben changed during the day it should display: File not changed.

    The problem is that it’s always display “File not changed” even if the file has been changed.

    Hope you have the time to look at it 🙂

    /Tomas

  12. February 3rd, 2014 at 09:58 | #12

    @Tomas
    Hey Tomas, this is a little off topic 😛 but it looks like you just have some syntax issues with the $ symbol. This works for me:

    $path = “C:\Temp\test\test.log”
    if ((Get-Item $path).CreationTime -gt [DateTime]::Today) {
    Write-Host “File Changed at $((Get-Item $path).CreationTime)”
    }
    else {
    Write-Host “File not changed today”
    }

  13. gm
    February 4th, 2014 at 10:33 | #13

    This is great for situations where the batch file and powershell script are in the same location. Is it possible to get the batch file location from within the powershell script? i.e. – for situations where the batch file is executing a powershell script located on a network share but you want to write back to the batch file location.

  14. February 4th, 2014 at 10:53 | #14

    @gm
    You could always pass in the batch file location as a parameter to the PowerShell script (see above comments for how to pass a parameter to the PowerShell script). To get the running batch file’s path use “%~dpnx0” (without the quotes). If the batch file and PowerShell script are on different computers though (e.g. on network shares), you will want to pass in the batch file location relative to the network share (i.e. instead of passing “C:\MySharedFiles\MyBatchFile.cmd” (which is what %~dpnx0 will give you) to the PowerShell script, pass in “\\YourPCsName\MySharedFiles\MyBatchFile.cmd”). It’s easy enough to hard-code that file path in your batch file; I’m not sure how to get it dynamically in batch file code though (fairly easy to do in PowerShell), but I’m sure Google could help you with that. I hope that helps.

  15. gm
    February 4th, 2014 at 12:55 | #15

    I’ve googled and I can’t seem to get a hit for my situation. $Myinvocation doesn’t provide info on the cmd file. Is there something else?

  16. SB
    February 22nd, 2014 at 00:57 | #16

    This is great! Is it possible to hide the powershell window while it runs the script? (like cmd’s @echo off)

  17. February 22nd, 2014 at 20:26 | #17

    @SB
    Yup, just add “-WindowStyle Hidden” at the start of the PowerShell argument list to have the PowerShell window hidden while it runs:

    PowerShell -WindowStyle Hidden -NoProfile -ExecutionPolicy Bypass -Command “& ‘%PowerShellScriptPath%'”

    — EDIT —
    Actually, it looks like using -WindowStyle Hidden may sometimes still cause the window to show for a split second, because that argument is not evaluated until after the window is open (http://social.technet.microsoft.com/Forums/windowsserver/en-US/783ae81a-15d6-4dea-b283-f0020313c7f0/running-hidden-power-shell?forum=winserverpowershell).

  18. Amel
    February 25th, 2014 at 07:34 | #18

    @deadlydog
    Thanks a lot!

    I do have an issue when executing the following command:

    PowerShell -NoProfile -ExecutionPolicy Bypass -Command “”

    It views all the remaining parameters as a part of -File parameter’s value. Any idea on what I’m doing wrong?

  19. February 25th, 2014 at 10:44 | #19

    @Amel
    I’m guessing the blog comments stipped some of your code out here? That line you posted won’t do anything because you haven’t specified a command for PowerShell to execute (i.e. there’s nothing in the double quotes).

  20. Screwuphead
    February 25th, 2014 at 22:27 | #20

    @deadlydog
    That’s what I was afraid of. I tried that and get some type of error that happens so fast I cannot grab it. If I do not run it as administrator it runs okay but that defeats what I am going for. Still hitting my head on the desk to figure out the answer.

  21. February 26th, 2014 at 12:56 | #21

    @Screwuphead
    Sorry, I guess I didn’t test it in a path that has spaces, so I never noticed this problem 😛

    I re-tested and by using the PrintScreen button and GreenShot I was quickly able to see this error:

    Processing -File ‘C:\temp folder\Test.ps1 C:\temp folder’ failed: The given path’s format is not supported. Specify a valid path for the -File parameter.

    The problem was the powershell script name and each of the parameters needs to be wrapped in 4 (yes 4) double quotes. I’ve updated the code on the post to fix this.

    Thanks

  22. Screwuphead
    March 17th, 2014 at 19:55 | #22

    @deadlydog
    HA! Four quotes… I wouldnt of just randomly of guessed. I tried to use print screen but I couldnt grab it fast enough. Thank you sir!

  23. xia
    March 19th, 2014 at 08:49 | #23

    I tried following your tutorial :
    @ECHO off
    SET ThisScriptsDirectory=%~dp0
    SET PowerShellScriptPath=%ThisScriptsDirectory%SQL.ps1
    PowerShell -NoProfile -ExecutionPolicy Bypass -Command “”;
    pause

    but i always get:
    Missing expression after unary operator ‘-‘.
    At line:1 char:2
    + -E <<<< xecutionPolicy Bypass -Command

    any help?

  24. Graham
    March 19th, 2014 at 14:59 | #24

    Thanks Mate that helped

  25. Maverick
    March 23rd, 2014 at 21:28 | #25

    Hi,

    Anyone knows how I can execute .cmd from powershell. I try this but doesnt work

    Invoke-item C:\setup.cmd -ArgumentsList /c -install-setupforced

    Really appreciate your help

  26. March 24th, 2014 at 10:59 | #26

    @Maverick
    You should just be able to do:

    & C:\setup.cmd /c -install -setupforced

  27. April 5th, 2014 at 05:48 | #27

    Hi, great post – I’m a bit of a newbie to PS, but I can’t get the ‘wait’ clause to work…if I run your code from within Powershell I get:

    PS E:\Data\Scripts\Powershell> # Wait for input before closing.
    Write-Host “Press any key to continue…”
    $x = $Host.UI.RawUI.ReadKey(“NoEcho,IncludeKeyUp”)
    Press any key to continue…
    Exception calling “ReadKey” with “1” argument(s): “The method or operation is not implemented.”
    At line:3 char:1
    + $x = $Host.UI.RawUI.ReadKey(“NoEcho,IncludeKeyUp”)
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : NotImplementedException

    Other Googling seems to suggest I can’t use ReadKey with PS?

    Any pointers would be most appreciated.

  28. April 6th, 2014 at 13:51 | #28

    @Tim
    Sorry, that code will throw an exception if you are not running your script from the PowerShell Console; I’ve updated it to wrap it in an IF statement so it only prompts for input when running in the PowerShell Console.

    If you want to prompt for input before continuing regardless of which host the script is running in (e.g. PowerShell ISE), then you can use:

    Read-Host -Prompt “Press Enter to continue…” > $null

    The difference here though is that the user must press Enter to continue, not just any key.

  29. rcf
    April 9th, 2014 at 10:42 | #29

    Very good post. The problem is that we have a mapped drive (S:) that we use for scripts/software installs for IT folks so when you use “-verb RunAs” in the CMD file and use an elevated domain account , you get an error presumably because there is no mapped S: drive for that elevated account. If you hard code the UNC path it works, but would not like to do that.

    Something like this may work if it is incorporated somehow? Any ideas?
    http://superuser.com/questions/29933/get-the-current-unc-path-from-a-local-path-in-powershell

  30. April 9th, 2014 at 10:56 | #30

    @rcf
    Unfortunately I don’t have much experience using network drives in my PowerShell scripts 🙁

    Why don’t you want to hard code the UNC path? You just don’t want the user to see the full UNC path (e.g. \\SomeServer\SomeFolder\SomeOtherFolder\ScriptsFolder) for security reasons? Or you are afraid that if the UNC path ever changes that it will break all your scripts? One possible workaround may be to create another “shortcut” UNC path that simply points to the real UNC path (e.g. \\Shortcuts\ScriptsFolder). This would both hide the absolute UNC path from the user, and you could always change the shortcut UNC path to point somewhere else if needed. I don’t know the proper terms for this or how to set this up myself, but I know at my organization we have several different UNC paths that all point to the same network location, so I’m sure it’s possible to do.

    I hope that helps.

  31. rcf
    April 9th, 2014 at 11:16 | #31

    Thanks for the insight. We use a generic ‘install.cmd’ wrapper for all of our installs so it would really be nice to be able to use one standard script for everything that detects the current path if run from a mapped drive – no modifications wherever it is run from. The other reason that you mentioned is also a concern – that the script will break if the UNC path changes if hard coded. I think I’m close at getting it going based on the link in the previous post. It seems to detect the UNC path from a mapped drive nicely. This would cover us if the script was run from a mapped drive or not.

  32. Charles
    April 9th, 2014 at 12:50 | #32

    Great article!

    You mention how to pass variables into powershell from the .bat files. Would you know how to go the other way and pull out exit codes or variables from the powershell script? If say for instance you wanted to show if the PS script ran successfully from the .bat file?

  33. April 9th, 2014 at 13:25 | #33

    @Charles
    Google and Stack Overflow are your friend 😉

    To read the last running program/scripts exit code, use the ERRORLEVEL variable as they show here:
    http://stackoverflow.com/questions/334879/how-do-i-get-the-application-exit-code-from-a-windows-command-line

    To have your PowerShell script return an exit code (other than zero), be sure to have the script exit using:

    exit [some integer]

    To pull some variable’s value from PowerShell into the batch script I think you would need to write the value in PowerShell using Write-Output, and then capture that output somehow, perhaps by using stream redirection, http://technet.microsoft.com/en-us/library/bb490982.aspx.

    Sorry I don’t have all of the answers, but I hope this helps.

  34. Mike
    April 15th, 2014 at 14:52 | #34

    I’m trying to do something similar but having problems. For ease of use for the users that will be runnning this I want the commands to be in a batch file. I need to create some AD security groups but need to specify the OU to use and the group name in the variables. The user running the script will enter the branch code and OU and the group will be built off those values. Here is what I have so far but I think the space in the group name is causing problems. It seems to think that “Test” is another parameter. I have tried enclosing the name value in double parenthesis but its still gettng the same result.

    Any suggestions?

    SET /P OU=Enter OU:
    Set /P Prefix=Enter Prefix:
    Powershell New-ADGroup -Name “%Prefix%-OWA Test” -SamAccountName “%Prefix%-OWA Test” -GroupCategory Security -GroupScope Global -path “OU=%OU%,OU=Test1,DC=Test2,DC=Test3,DC=Test4,DC=com”

  35. April 15th, 2014 at 15:02 | #35

    @Mike
    This problem is slightly off-topic and better suited for Stack Overflow, as it is more along the lines of “how to execute PowerShell code from within a batch file”, but I’ll take a whack at it. Just from looking at what you have here, the problem is likely that you need to pass your PowerShell command via the actual -Command switch, so something like this:

    Powershell -Command {New-ADGroup -Name “%Prefix%-OWA Test” -SamAccountName “%Prefix%-OWA Test” -GroupCategory Security -GroupScope Global -path “OU=%OU%,OU=Test1,DC=Test2,DC=Test3,DC=Test4,DC=com”}

    From the command prompt just type “PowerShell /?” to get more info on passing parameters to the PowerShell.exe executable.

    Or a hackier way might be to do something like this, which starts up a new powershell session then simulates you typing the command into the console and hitting enter:

    ECHO New-ADGroup -Name “%Prefix%-OWA Test” -SamAccountName “%Prefix%-OWA Test” -GroupCategory Security -GroupScope Global -path “OU=%OU%,OU=Test1,DC=Test2,DC=Test3,DC=Test4,DC=com” | PowerShell

    I hope one of those solutions works for you.

  36. Mike
    April 16th, 2014 at 07:36 | #36

    @deadlydog
    Thanks for the reply. I’ll take your advice and post on Stack Overflow.

    I tried both suggestions and they don’t error out but they don’t create the groups either so I’m not sure what is going on. When I run them, it just echoes the command back to me. I also never see the Active Directory Module being loaded. I think it has something to do with the curly braces because when I remove them the AD Module loads but I get the error shown below. I just started learning about Powershell so I’m still not clear on the specifics of when to use {,”,’,or[.
    I also tried running the command directly without using the variables in my post above but get the same error. Its something related to running from the cmd line though as I can run it in powershell succesfully.
    Here is the error I get when I run without the curly braces.
    New-ADGroup : Cannot convert ‘System.Object[]’ to the type ‘System.String’
    required by parameter ‘Path’. Specified method is not supported.
    At line:1 char:110
    + … e Global -path OU=Groups,OU=Branch1
    ,OU=Test,DC=Test1,DC=Test2,DC=Test3,DC=com -Des …
    + ~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : InvalidArgument: (:) [New-ADGroup], ParameterBin
    dingException
    + FullyQualifiedErrorId : CannotConvertArgument,Microsoft.ActiveDirectory.
    Management.Commands.NewADGroup

  37. April 17th, 2014 at 11:07 | #37

    Excellent! Just the ticket.

  38. Jerome Lacoste
    June 11th, 2014 at 06:43 | #38

    When running the admin version of the script with named parameters, if my parameters are argumnts to the batch script, then I end up having incorrect argument parsing on the PS1 side when the arguments are empty.

    E.g.
    P.BAT:
    PowerShell ….. -P1 “”””%1″””” …

    P.PS1
    param([string]$P1)
    Write-Host -$P1-

    Running P.BAT results in
    -“-

    Any idea how to protect against that ?

  39. June 13th, 2014 at 22:15 | #39

    @Jerome Lacoste
    Hmmmm, that’s strange. Perhaps first save the %1 argument into a variable and pass the variable into the PowerShell command, as I show in my examples. Let me know if that works for you please.

  40. GlwDay
    July 16th, 2014 at 04:12 | #40

    I have been using deleteold.ps1 from Technet http://gallery.technet.microsoft.com/Powershell-script-to-ed34c5f9 to clear up files older than x days on individual nodes in our HPC Cluster. From the headnode I use it with the following parameters .\deleteold.ps1 -FolderPath \\Nodename1\c$\project-9\input-data\temp -FileAge 7 -LogFile Nodename1.log

    The powershell script is on a network share that the headnode and all computenodes can see and write to.

    Jobs being run by users create hundreds of files so the clean up can take 15min to 1 hour depending on what else is happening on the node at the time.

    I would like to run the from the Clusrun command line in the ClusterManager so that it can process the task simultaneously rather than sequentailly as at present. Obviously I modify the -Folderpath parameter to only have the c$\project-9\input-data\temp but I cannot work out how get it to run either directly or via a batch file.

    Can anybody help please?

  41. July 16th, 2014 at 17:30 | #41

    @GlwDay
    A couple ideas:
    1 – Use a remote session to delete files, so the commands run directly from the remote maching. i.e. New-PSSession -ComputerName $Server
    2 – To make them run in parallel, use several Start-Job commands to call your script, and instead of passing in the root directory, pass in folders in the root directory.
    i.e. Start-Job .\deleteold.ps1 -FolderPath \\Nodename1\c$\project-9\input-data\temp\Folder1 -FileAge 7 -LogFile Nodename1.log
    Start-Job .\deleteold.ps1 -FolderPath \\Nodename1\c$\project-9\input-data\temp\Folder2 -FileAge 7 -LogFile Nodename2.log

  42. srinivas
    August 19th, 2014 at 01:19 | #42

    @deadlydog
    Hi i have the same issue i need to create user in active directory from batch files by calling script can u provide any workaround for this problem, am new to this power shell.

  43. Marcello
    September 8th, 2014 at 09:45 | #43

    In the “run as admin” version, when passing parameters, and when the powershell script is passed as an environment variable, the -File parameter does not want any doublequotes, neither 2, nor 4. In other terms, of these three
    -File “”””%myScript%”””” -Param1name “”””Param 1 value”””” -Param2name “”””Param 2 value””””
    -File “”%myScript%”” -Param1name “”””Param 1 value”””” -Param2name “”””Param 2 value””””
    -File %myScript% -Param1name “”””Param 1 value”””” -Param2name “”””Param 2 value””””
    only the third one works.
    This probably solves Jerome’s issue.
    @Jerome Lacoste

  44. Marcello
    September 8th, 2014 at 09:49 | #44

    Oh by the way, deadlydog: You ROCK!
    A caveat, though: under IE11 (whether in compatibility mode or not) the last line of the code snippets is not visible (nor can it be cut’n’pasted). As a consequence, one-line snippets are not visible at all! One has to view the HTML source, but HTML escaping makes it awkward to reproduce the correct source code.
    I don’t know if you can fix that, but just in case…

  45. RC
    September 25th, 2014 at 13:07 | #45

    Nice article!

  46. korook
    November 17th, 2014 at 06:40 | #46

    Hello

    Thank you for the code. It’s exactly what i am looking for. But i just can’t get it working:
    SET “InstallerFolder=\\dc01\e”

    PowerShell -NoProfile -ExecutionPolicy Bypass -Command “”;

    Should this not work?
    The script runs and all is good, but it is not running as administrator 🙁

    Thank you.

  47. phatfish
    November 27th, 2014 at 06:07 | #47

    Very helpful page.

    One issue i had; if your script raises a Windows credential dialog (eg. Add-Computer) then key presses appear to get buffered and can skip through the “Press any key to continue…” code.

    This resolved the issue for me.

    $Host.UI.RawUI.FlushInputBuffer()
    $Host.UI.RawUI.ReadKey(‘NoEcho,IncludeKeyUp’) > $null

  48. November 27th, 2014 at 10:27 | #48

    @phatfish
    Awesome, thanks for the code fix 🙂

  49. Echeb
    December 1st, 2014 at 10:57 | #49

    Great Article.
    I have a tab delimited text file which contains values my bat file will read and pass to the PowerShell script, this is so I can have multiple lines in the input file so can do multiple.
    The bat file does the following:
    FOR /F “tokens=1-1” %%i in (C:\Values.txt) do PowerShell -NoProfile -ExecutionPolicy Bypass -Command “”;

    The test.ps1 is a simple test file which should print Item1 (which needs to have come from the %%1 substituted value):

    param([string]$Item1)

    $text = $Item1
    $text | Set-Content ‘C:\file.txt’

    In my test file I get the word Parameter rather than the word contained in my values.txt file –
    not sure how I go about construction the -commend “” section so that %%i can be used/substituted.
    Anyone done this before?

    Any help appreciated

  50. noobie
    December 4th, 2014 at 06:41 | #50

    Hello,
    I’m a noob so please bear with me. I ave a batch file that calls a ps1. The ps1 seems to run, the last thing it does is creates a log file which indicates that all tasks have bee completed. The problem is that it nevers passes control back to the batch file. Even inputing an exit command after the logging sections does not help. any ideas?

  51. December 4th, 2014 at 16:29 | #51

    @noobie
    Does the PowerShell window exit? I’m guessing that your logging functionality is actually a blocking call and never completes (it waits for something else to happen), so execution is stuck there. I would try asking on StackOverflow with a code example to get an answer if you are still stuck.

  52. David Wohlberg
    February 19th, 2015 at 10:20 | #52

    So I found a problem, when running the powershell script with Administrative permissions (i.e. Run As Admin), it will not wait for user input at the end of the script. Placing -NoExit as part of the argument list works, but then quite obviously after the you press any queue, Powershell does not exit. 🙂 If I run my script without Administrative permissions, then the code you provided above will wait for user input. My question is, how do I get this to work with Administraive permissions? It is useful to be able to capture error messages (if any).

  53. David Wohlberg
    February 19th, 2015 at 10:22 | #53

    @David Wohlberg
    Hmm, I can find an edit post button, so I’ll reply. My fingers were off in la-la-land while typing, I meant to say “…after you press any key…” not any queue. 😉

  54. March 6th, 2015 at 15:09 | #54

    I tried this code in .cmd
    @ECHO OFF
    SET ThisScriptsDirectory=%~dp0
    SET PowerShellScriptPath=%ThisScriptsDirectory%IIS_Restart.ps1

    PowerShell -NoProfile -ExecutionPolicy Bypass -Command “”;

    and below in .ps1 file

    sleep 50

    Write-OutPut “Restarting IIS”

    iisreset

    but still its not working it says ” u need admin access”, can some one help me how can i run powershell script as an admin

  55. March 7th, 2015 at 14:47 | #55

    @Allen
    Did you read this blog post? I give the code for how to run the script as admin just a few lines below the code that you are using for how to run it normally; just use that Run As Admin method instead to call your PowerShell script:

    PowerShell -NoProfile -ExecutionPolicy Bypass -Command “& {Start-Process PowerShell -ArgumentList ‘-NoProfile -ExecutionPolicy Bypass -File “”%PowerShellScriptPath%””‘ -Verb RunAs}”;

  56. March 7th, 2015 at 18:26 | #56

    Thank you for update, I used same code what you gave

    @ECHO OFF
    SET ThisScriptsDirectory=%~dp0
    SET PowerShellScriptPath=%ThisScriptsDirectory%IIS_Restart.ps1

    PowerShell -NoProfile -ExecutionPolicy Bypass -Command “”;

    I am getting error as below

    Access denied, you must be administrator of the remote computer to use this command. either add your account to administrator local group of remote computer or to domain administrator global group.

    I am already admin on that remote computer. still i am getting same error every time.

  57. David Wohlberg
    March 11th, 2015 at 09:44 | #57

    @Allen
    @Allen, as @deadlydog already pointed out, you need to add “-Verb RunAs” without the quotes to your call to launch Powershell, otherwise it is is just running in normal mode, not adminstrative mode.

  58. March 13th, 2015 at 07:51 | #58

    I am using below on the similar lines :

    1. echo %VM_Name%
    2. @ECHO OFF
    3. SET ThisScriptsDirectory=%~dp0
    4. SET PowerShellScriptPath=%ThisScriptsDirectory%Test.ps1
    5. PowerShell -NoProfile -ExecutionPolicy Bypass -Command “”;

    Line number 1 is working and variable %VM_Name% is echoed. But in line 5
    -VM_Name “”””%VM_Name%”””” is not working. I am using variable $VM_Name in my Test.ps1 and powershell says that this variable is null.

  59. March 13th, 2015 at 07:54 | #59

    In line 5 I am trying to pass a parameter like this :
    Start-Process PowerShell -ArgumentList ‘-NoProfile -ExecutionPolicy Bypass -File “”””%PowerShellScriptPath%”””” -VM_Name2 “””” %VM_Name2% “””” ‘ -Verb RunAs

  60. Kalam
    March 31st, 2015 at 19:07 | #60

    Hello there,

    Very good idea!

    However, when running the bat file, instead of executing the script the command open the script in Notepad. Any ideas?

    If I removed the single Quotation mark ‘ ‘ from “& %PowerShellScriptPath%”, the script get executed, but if the file path have any space with the folder, it will resulted in error. Eg S:\Repairs and Backup\test.ps1 will throw an error.

  61. BertMeed
    April 30th, 2015 at 01:19 | #61

    Hello,

    I’m trying to run a powershell command from the command line where I want to use the ‘pipeline’ “|”
    It fails on the command line, but it runs oke witin a powershell environment.

    How can I use the “|” on a commandline powershell command?

    F:\OTA\scripts>Powershell.exe -ExecutionPolicy RemoteSigned -File F:\OTA\scripts\GetGroups.ps1 SwartJ | Export-CSV .\NedstedMembers_SwartJ.csv -NoTypeInformation
    ‘Export-CSV’ is not recognized as an internal or external command,
    operable program or batch file.

    When I use the next command I only get a powershell command prompt.
    Powershell.exe & “-ExecutionPolicy RemoteSigned -File F:\OTA\scripts\GetGroups.ps1 SwartJ | Export-CSV .\NedstedMembers_SwartJ.csv -NoTypeInformation”

  62. Drummer
    May 6th, 2015 at 06:51 | #62

    This is AWESOME! Exactly what I was looking for.
    Thanks a lot.

  63. i+me
    June 26th, 2015 at 06:44 | #63

    Great. I find however embedding Powershell in a DOS batch cleaner
    http://stackoverflow.com/questions/2609985/how-to-run-a-powershell-script-within-a-dos-batch-file

  64. MichaelJ
    June 26th, 2015 at 07:10 | #64

    Thanks for the batch help!
    I’m getting an error that somehow a space is being inserted in the path.
    Batch file:
    SET ThisScriptsDirectory=%~dp0
    SET PowerShellScriptPath=%ThisScriptsDirectory%Delta.ps1
    PowerShell -NoProfile -ExecutionPolicy Bypass -Command “& ‘%PowerShellScriptPath%'”;
    Error:
    & : The term ‘C:\PSLib\ Delta.ps1 ‘ 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.
    There is not a space in the filename. Any clues?

  65. Eduardo
    June 29th, 2015 at 10:51 | #65

    Someone can help me? I am trying to run one powershell script from a batch file just to create a txt file with the list of the software installed on the computer, but it does not work.
    The batch file contains:
    @echo off
    PowerShell -ExecutionPolicy Bypass -Command “& ‘%~dp0′”;
    PAUSE
    The powershell script file which has the same name as the batch file simply contains:
    Get -WmiObject -Class Win32_Product C:\software.txt

  66. Debra Hodges
    September 4th, 2015 at 15:29 | #66

    Daniel, You are so wonderful to post this fantastic information! Thank you! I Googled many, many, many, MANY articles, but YOURS did the trick! I was able to understand it and do it and make my boss happy.

    I created batch files (using your instruction) that stop and start a Windows service. These were used in an InstallShield Basic MSI project. I created Custom Actions that called InstallScripts, that called the batch files, that called Powershell scripts (with Admin privileges) to stop and start the service before and after the install.

    Thanks again, and I hope you will keep posting!

    Debra

  67. Manoj Mittal
    November 5th, 2015 at 02:27 | #67

    Fantastic post, really helpful.

    Thank you

  68. ryan
    November 11th, 2015 at 16:07 | #68

    Great Article!

    Just one question:

    I am using the named parameter admin solution that you showed how to pass variables. The issue that I’m having is that one of my parameters takes an array of strings. I can pass it from the command line no problem. but when I pass the same thing inside 4 double quotes as you showed. It does not parse it correctly.

    Is there a piece I’m missing to pass an array?

  69. Sadiq
    January 19th, 2016 at 20:34 | #69

    Hi Could someone help me.. I am trying to schedule a bat file which is calling Power shell in Task scheduler and schtasks but my bat file is getting executed and when it calls powersell it’s not getting executed. What could be the reason. How should I schedule a bat file which calls power shell.

  70. malberto
    January 20th, 2016 at 12:17 | #70

    Thanks for sharing this! It was really helpful.

  71. Christopher
    March 8th, 2016 at 09:03 | #71

    Thank you for putting so much time into this blog. It is very helpful. I am coming across a problem and I am letting you know now I am a noob when it comes to this.
    I have the following PowerShell script and it runs perfectly if I type it directly in PowerShell…
    CD C:\Temp
    Get-ChildItem -Filter “*-Layout1*” -Recurse | Rename-Item -NewName {$_.name -replace ‘-Layout1’,” }

    When I run it thru a .bat I get the following error…

    “You must provide a value expression on the right-hand side of the ‘-replace’ oerator.
    At C:\Users\Desktop\PowerShell\MyFileRenameUtility.ps1:3 char:85
    Get-ChildItem -Filter “*-Layout1*” -Recurse | Rename-Item -NewName {$_.name -replace <<<< a?~Layout1a?T,' ' }

    I don't understand how PowerSheel recognizes the commands but then doesn't recognize them. Do you have any suggestions?

  72. Christopher
    March 9th, 2016 at 11:26 | #72

    @Christopher
    Basically I am using this because our CADD program adds “-Layout1” or “-Model1” to the file name of each output file. I sometimes have hundreds of these files, each with a different name but they all have “-Layout1” or “-Model1” in common. I can use the script directly in PowerShell and it runs perfectly. Just getting over that hump of passing it from the batch file for other users to use it as well.

  73. dooRun
    March 21st, 2016 at 16:24 | #73

    Old post – if anybody has any input, the PS1 I’m trying to run must be ran on a domain controller. I have a little program I made (Filemaker) that I import powershell scripts, then use the batch coding from this site which is created on the fly from the program to invoke the PS1,,, but, the PS1 for this one script must be ran from the DC,,, I was thinking that instead of rebuilding the PS1, there has to be a way of initiating the PS1 to run from the perspective of it’s current computer host location

    … in other words, I set the location of the PS1 and batch script to export from my program onto the target computer (a domain controller in this case), and execute it,,, but it’s execution ‘perspective’ is from the computer it is executed from, not the computer it is stored on,,, make sense?

  74. Steven Stover
    June 11th, 2016 at 17:33 | #74

    Quote: And yes, the PowerShell script name and parameters need to be wrapped in 4 double quotes in order to properly handle paths/values with spaces.

    This fails when the parameter ends with a backslash character, c:\ would be passed as c:” with a double quote replacing the backslash.

  75. josiannN
    July 21st, 2016 at 18:36 | #75

    This was a huge help. Thank you very much!

  76. techiesat
    July 22nd, 2016 at 08:38 | #76

    Hi i am trying to run as you mentioned here in the below lines replacing script wtih my PS script but its still prompting for UAC and doesn’t proceed without asking for it when scheduled it as task with system user as this is the way i want it run, i ran some .bat files which needs admin permissions and those works fine.
    but the same .bat file when run it from admin cmd prompt it works, i
    @ECHO OFF
    SET ThisScriptsDirectory=%~dp0
    SET PowerShellScriptPath=%ThisScriptsDirectory%MyPowerShellScript.ps1
    PowerShell -NoProfile -ExecutionPolicy Bypass -Command “”;

    Let me know what i am missing here

  77. Nick
    November 21st, 2016 at 09:53 | #77

    I’m running into a problem, trying to have this batch file start my script but nothing happens I need to run this as admin since the execution policy will be set to restricted by default. Do you guys have any idea what is wrong with my code? Thanks.

    @ECHO OFF
    SET ThisScriptsDirectory= %~dp0
    SET PowerShellScriptPath= %ThisScriptDirectory%NameOfMyScript.ps1
    PowerShell -NoProfile -ExecutionPolicy Bypass -Command “”

  78. David Wohlberg
    November 22nd, 2016 at 07:34 | #78

    @Nick

    Take a look at the two examples provided in the blog above, you’re not passing your %PowerShellScriptPath% variable, you just have empty quotes.

  79. Budd McNish
    February 23rd, 2017 at 13:14 | #79

    I have tried all variations of executing a PS1 from a .BAT file that passes a single parameter to the PS1. UNSUCCESSFULLY !!!

    sample1:PowerShell.exe -NoProfile -ExecutionPolicy Bypass -Command “& ‘my.ps1’ -sfn’%1%'”;

    sample2: PowerShell.exe -NoProfile -ExecutionPolicy Bypass -Command “& ‘my.ps1’ ‘%1′”;

    Always the same result:
    Now: 02/23/2017 14:01:57 : filename =
    Now: 02/23/2017 14:01:57 : input filename is missing, run aborted

  80. Shweta
    February 27th, 2017 at 02:14 | #80

    Hi..I am trying to create a batch file to start/stop clusters on a remote server through a powershell script but I keep getting an error that the cmdlet does not exist

    Start-ClusterGroup.bat
    ————————-
    @ECHO OFF
    SET ThisScriptsDirectory=%~dp0
    SET PowerShellScriptPath=%ThisScriptsDirectory%Start-ClusterGroup.ps1
    PowerShell -NoProfile -ExecutionPolicy Bypass -Command “& {Start-Process PowerShell -ArgumentList ‘-NoProfile -ExecutionPolicy Bypass -File “”%PowerShellScriptPath%””‘ -Verb RunAs}”
    ————————————————————————————————
    Start-ClusterGroup.ps1
    ————————-

    Start-ClusterGroup -Name ‘$ClusterGroupName’
    —————————————————————————————–
    Both these files are saved in the same location but when I run the batch file,it does prompt for me to enter the ClusterGroupName but on doing so,get the following error :-

    The term ‘Start-ClusterGroup’ 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 C:\Intel\script\Start-ClusterGroup.ps1:18 char:19
    + Start-ClusterGroup <<<< -Name '$ClusterGroupName'
    + CategoryInfo : ObjectNotFound: (Start-ClusterGroup:String) [],
    CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException

    I did an import-module failoverclusters as well but that doesn't seem to help either.Could you please tell me what is it that I am doing wrong?

    Thanks

  81. March 10th, 2017 at 08:22 | #81

    @Shweta
    It looks to be a problem with your PowerShell script itself. I assume you get the error just when running the PowerShell script without using the batch file? I would post your question along with some code on StackOverflow.com to see if anybody can help you out.

  82. Todd
    March 15th, 2017 at 06:45 | #82

    Hello, thanks for the explanation. I appreciate it. FYI, I did run into a problem because I needed to add “setlocal enabledelayedexpansion” to my batch file before it would work as shown.

  83. HighwayCO
    March 24th, 2017 at 16:08 | #83

    Hi I have a question, I’m receiving the following error when tryyig run the batch file:

    Original Batch File: AppxPackagePowershell.bat
    @ECHO OFF
    SET ThisScriptsDirectory=%~dp0
    SET PowerShellScriptPath=%ThisScriptsDirectory%AppxPackage.ps1
    PowerShell -NoProfile -ExecutionPolicy Bypass -Command “& ‘%PowerShellScriptPath%'”;PowerShell -NoProfile -ExecutionPolicy Bypass -Command “& {Start-Process PowerShell -ArgumentList ‘-NoProfile -ExecutionPolicy Bypass -File “”%PowerShellScriptPath%””‘ -Verb RunAs}”;

    Error:
    C:\Windows\Setup\Scripts>AppxPackagePowerShell.bat
    At line:1 char:101
    + … ps1’;PowerShell -NoProfile -ExecutionPolicy Bypass -Command & {Start- …
    + ~
    The ampersand (&) character is not allowed. The & operator is reserved for future use; wrap an ampersand in double
    quotation marks (“&”) to pass it as part of a string.
    + CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
    + FullyQualifiedErrorId : AmpersandNotAllowed

    I doublequoted the ampersand “&” as instructed in the error message and now get this error

    C:\Windows\Setup\Scripts>AppxPackagePowerShell.bat
    The filename, directory name, or volume label syntax is incorrect.

    Modified Batch File: AppxPackagePowershell.bat
    @ECHO OFF
    SET ThisScriptsDirectory=%~dp0
    SET PowerShellScriptPath=%ThisScriptsDirectory%AppxPackage.ps1
    PowerShell -NoProfile -ExecutionPolicy Bypass -Command “”&” ‘%PowerShellScriptPath%'”;PowerShell -NoProfile -ExecutionPolicy Bypass -Command “& {Start-Process PowerShell -ArgumentList ‘-NoProfile -ExecutionPolicy Bypass -File “”%PowerShellScriptPath%””‘ -Verb RunAs}”;

    PowerShell File: AppxPackage.ps1

    Both files are in the C:\Windows\Setup\Scripts directory as directed in your instructions

    This system is running Windows 10 Enterprise build 1607

  1. December 21st, 2013 at 01:53 | #1
  2. May 3rd, 2014 at 15:42 | #2
  3. August 4th, 2014 at 11:42 | #3
  4. October 22nd, 2014 at 03:20 | #4
  5. November 17th, 2014 at 21:11 | #5
  6. March 19th, 2015 at 07:53 | #6
  7. December 13th, 2015 at 15:52 | #7
  8. March 13th, 2016 at 04:09 | #8
  9. March 13th, 2016 at 04:12 | #9
  10. March 13th, 2016 at 04:33 | #10
  11. March 13th, 2016 at 04:37 | #11
  12. March 13th, 2016 at 04:44 | #12
  13. March 13th, 2016 at 04:45 | #13
  14. March 13th, 2016 at 04:51 | #14
  15. March 13th, 2016 at 04:55 | #15
  16. March 13th, 2016 at 07:55 | #16
  17. March 13th, 2016 at 08:04 | #17
  18. March 13th, 2016 at 10:09 | #18
  19. July 20th, 2016 at 04:30 | #19